Master the art of Cross Site Scripting.

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.

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>///

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:

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)//

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!

After a tester or attacker is able to pop an alert box, the next step is to call an external script to do whatever he/she wants to do with the victim. In scenarios where XSS is not possible with “<script src=//HOST>” or similar, we need to build the request to load our remote code.

So let’s see 5 of possible ways to make this happen, in descending order of payload length. All examples will use “//0” as HOST which points to localhost, having the default index file as the injected script. A CORS header is also needed to make this work for different origins.

All the following can be used like in this example form: <svg onload=PAYLOAD>.

1 – XHR

The old way, but uses too much chars. Response is written in the current document with write() so it needs to contain HTML.

In order to make remote calls easier to handle, the following PHP file can be used. It has the CORS requirement and HTML + javascript code combined in such a way that it works with both types of inclusion in the document.

Since the very first days of the world wide web, these applications are being a great target for hackers minds. New ways to interact with systems via HTTP protocol and technologies gave rise to a whole set of attacks. But until now, some of them remain very special: Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF), Structured Query Language injection (SQLi) and Remote Code Execution (RCE).

As you may imagine, they are in an ascending order of danger with all the first 3 leading to the last one, RCE. XSS and CSRF are widespread and overlooked while SQLi and RCE although less prevalent are much more deadly. In theory, it’s possible to mount an attack using all of them at the same time, in an interesting analogy to the four horsemen of the apocalypse.

Let’s analyze this. We have a common XSS vector, “<svg onload”, with a simple GET request to a HOST made by fetch() API. The address used is (theoretically) vulnerable to SQLi by means of the id parameter in the default index page. Of course, this would only make sense if the attacker or tester is not able to make that request by him/herself.

So we have also a cross-site scenario: a XSS payload executing in an internal network, for example, where only the victim can make requests to HOST, our target. Another requirement is that MySQL (in our example) runs as root, which would be hard to find in the wild but not in intranets, where there can be personal or development servers.

So with a “SELECT INTO OUTFILE” SQL statement, a cron job is created (/etc/cron.d/s) and scheduled on target machine to run every minute (* * * * *) by root to run a dangerous version of netcat (-e flag). This executes a shell (/bin/sh) at port 53, the same used for DNS which is more likely to be allowed in a firewall (after port 80). A better approach would be to make a reverse connection to attacker/tester but with only 140 characters to tweet (less the ones from the pic), it seems enough to prove a point: RCE.

Here is a video of this exploitation in a local virtual network with all steps to reproduce here (but it’s old).