The quest after an impactful XSS PoC

If you are a pentester, you probably already know that critical vulnerabilities don’t necessarily have the most glamourous Proof of Concepts. Additionally, as a security expert you probably don’t need a flashy PoC to understand the severity of the vulnerability.

However, if you are trying to convey the importance of a finding to someone who isn’t proficient in cyber security, you might find that clear, straightforward presentations could be what makes-or-breaks a deal.

Here is a small case study of finding the most impactful PoC of XSS in a WAF protected environment.

First and foremost, if you are unsure about what XSS’s are or how they could manifest, I recommend first heading over to Eddie’s blog post at https://www.ultrared.ai/from-simple-xss-to-one-click-account-takeover - which has a very clear explanation.

Learning first-hand about the limits of automatic XSS scanners:

The story begins with an indication of are reflective XSS in one of our client’s sites.

The indication was provided by one of our automatic tools, and as such required no manual testing. It revealed that the parameter “id” in the GET request:

https://github.com/hahwul/dalfox)– in which we would get the following output:

When decoding the output, our payload for the sake of the PoC is as follows:

This should pop a confirmation alert, right?

But when our client received notice of the found vulnerability (and the corresponding PoC), a question rose: Why am I not seeing an alert?

The story of the Big Bad WAF(W00f):

Indeed, when checking the PoC manually, we can see that no JS code was initiated.

Does this mean that the site is not vulnerable to XSS? Let’s check where things went wrong.

Our first step is of course to check if any rouge HTML was added to the site as a result of our request:

As seen in the snippet above, it seems like the word “confirm” found its way into the code, and that the class “dalfox” was added successfully. Alas, the word “on mouse leave” seems to have disappeared.

This is critical because without an event such as on mouse leave, we would have to initiate a script tag in order to run JScode.

When trying to input other events (eg.on error, onload etc. ) we get the same result – the word representing an event is removed. This seemingly leaves us with only one other option: using the script tag.

So let’s try the payload:

Once again, we see that even though something was reflected back to us, no confirm window popped up.

Frustrated, we return to good-ol’ developer tools and see:

Huh, the word “script” also seems to disappear. Time to see who we’re dealing with.

Using telnet, we can access the server and see that the response comes from a server called AkamaiGHost. This indicates that whatever we send to www.example.com, will first be examined by some sort of WAF (Web Application Firewall) used by Akamai to sanitize all user-supplied input.

The many tries (and fails) of WAF bypassing

There are countless different strategies to bypass a WAF, most of which can be summarized as one of the following approaches:

●       Try to prevent the WAF from identifying the malicious payload, for example by introducing special characters or encoding some or all of the payload.

●       Let the WAF handle the payload, but try to bypass its internal logic using special characters (such as ‘{‘ and‘\’).

Unfortunately (for us) none of these worked. We could start extensive research of the WAF and maybe some day find away to bypass it, or we could use what we can get through.

 

Trust me I’m an expert

It’s important to note that at this point we have a functioning PoC of an XSS even though we couldn’t run JS.

We can still create any non-black listed tag, and even break out of the current tag.

If we were to discuss this issue with a cyber-security specialist, we would simply show them the following POC:

in which we created an image tag with a source containing the word “XSS”.

But again, we want to create something a bit more intimidating.

We’ve established before that we cannot use an event to trigger a JS code execution, so the image tag, as useful as it usually is, would be worthless for us now.

After a long process of trial and error, I found that the tag that makes the most visual difference is marquee.

Conclusion

It’s important to understand the client’s view point when it comes to presenting a vulnerability, sometimes you might want to invest in some manual labor – but always choose your battles wisely.