I just learned a neat XSS trick from a blog post by Andy Wingo. This is old news to the more proficient web application testers among my readers, but it was new to me and I like it. I wasn’t aware that one could redirect function calls in JavaScript so easily:
somefunction = otherfunction;
somewhere in a script makes somefunction a reference to otherfunction. This works with functions of the built-in API, too, so any function can become eval:
alert = eval;
or
window.alert = eval;
So if you can inject a small amount of script somewhere, and a function parameter elsewhere, you can turn the function that happens to be called into the eval you need. This PHP fragment illustrates the approach:
<?php // XSS vulnerability limited to 35 characters print substr($_GET["inject1"], 0, 35); ?> <script> // URL parameter goes into a seemingly harmless function - which we // can redefine to become eval <?php $alertparam = htmlspecialchars(addslashes($_GET["inject2"]), ENT_COMPAT ); ?> alert('<?=$alertparam?>'); </script>
The first PHP block allows up to 35 characters to be injected into the page unfiltered through the inject1 URL parameter, just enough to add to the page this statement:
<script>alert=eval;</script>
or
<script>window.alert=eval;</script>
The second block embeds the value of the inject2 URL parameter in JavaScript as the parameter of alert() after some (imperfect) escaping. This one has unlimited length but goes into a seemingly harmless function – until somebody exchanges the function behind the identifier alert.
To see it work, put the PHP code on your web server and call it with a URL like this:
xss.php?inject1=<script>window.alert=eval;</script>&inject2=prompt('Did you expect this? (Yes/No)');
This works fine with Firefox 9 and, if XSS filter is disabled, IE 9. Safari 5.1.2 silently blocks the exploit, telling me about it only in debug mode. If you really need to, you’ll probably find an evasion technique against client-side XSS filters. IE seems to need window.alert, while Firefox is happy with just alert in inject1.