Tuesday, January 12, 2010

Url-Eval XSS

I had been working on making an XSS POC in a previous post, and had another idea. I got it from Gareth Heyes' comment to my post at sla.ckers.org.

He said something about only having to use
"><script>eval(name)</script>

to accomplish what I was trying to do. This didn't make much sense to me, so I started experimenting, trying to figure out what he meant. I tried running eval(name) in the Firebug console, and of course, nothing happened. The "name" variable was an empty-string. So I started trying to think of other variables that I might influence through only the url (which is how I was injecting script into the page), when it hit me that maybe he meant to eval the URL itself.

I messed around with this for a bit, running small commands in firebug such as:
eval("http://somesite.com/blah/?param=alert('hello')")

to see how javascript might evaluate something like that. None of those worked. Including a space in the url didn't work:
eval(unescape("http://somesite.com/blah/?param=%20alert('hello')"))

Neither did semicolons. However, newlines work just fine:
eval(unescape("http://somesite.com/blah/?param=%0Aalert('xss')"))

But you do have to remember to unescape the %0A

So what use is this? I could only come up with two uses:
  1. The server truncates the javascript you can inject into the page and you can't load external javascript files
  2. A weird type of javascript obfuscation

1 - If the server truncates your input so that only a certain number of characters make it into the page and you don't want to or can't for some reason load an external javascript file, you could do something like I have below. I'm assuming I only have 50 characters that will actually make it into the page:
http://somesite.com/blah/?param=<script>eval(unescape(location.href))</script>%20%20%20%20%0Aalert('xss')

The part of my script that I'm intending to make it into the page is below:
<script>eval(unescape(location.href))</script>%20%20%20%20

The actual script part is 46 characters long. To make sure that only that script made it into the page, I added four spaces (url-encoded: %20) to fill up to 50 characters.

After the first 50 characters comes the newline, %0A, and then the script I want to be evaluated, alert('xss').

The eval() function tries to evaluate everything before the %0A, but can't, so it skips to the next "line", which puts it right at alert('xss'), conveniently and nicely separating the two parts of the script. This reminds of buffer overflows, actually. Neato.

2 - Obfuscation. Since a lot of people like to try and obfuscate their javascript, why not put a bunch of it in the url? You could hide your functions there and call eval() on the url before you plan on needing those functions. I bet this would be a nightmare to debug (Firebug doesn't handle this at all, since they're pretty much dynamic functions).

For example, append this to a url:
#%0Afunction%20SayHello%28%29%7Balert%28%27hello%27%29%3B%7D
which is:
function SayHello(){alert('hello');}
Now open up firebug and go to the console. Eval() the url and run the function:
eval(unescape(location.href))

SayHello();

You should have seen the popup. Once again, interesting. This seems to give you new flexibility with javascript, but it's nothing you can't do in other ways. It does, however, let the user supply their own functions that a web-app should use. Why someone would want to do that, I have no idea. The most I can say about it is that it would be rather unwieldy, different, and interesting.

UPDATE (1/13/09):
I talk more about this in another post: Url-Eval XSS II.

UPDATE (1/13/09):
While writing the post Url-Eval XSS II I finally figured out what Gareth meant by his eval(name) suggestion. When you open a new window with javascript, you can specify the name of the new window. These are the options for the window.open() function:
window.open(URL, NAME, FEATURES, REPLACE)

You could then open a window to the site with the xss vuln and store the javascript in the name of the new window:
window.open("http://some.site.com/with/xss/vuln?input=eval(name)", "alert('xss')")

No comments:

Post a Comment