Constructing an XSS vector, using no letters

At the risk of spoiling a somewhat-well-known XSS game, I want to share an XSS vector I had never thought of before it forced me to. The premise of this level was, essentially, that you couldn’t use any letters whatsoever in the attack vector, and you had to call alert(1).

So, without further ado, here it is:

""[(!1+"")[3]+(!0+"")[2]+(''+{})[2]][(''+{})[5]+(''+{})[1]+((""[(!1+"")[3]+(!0+"")[2]+(''+{})[2]])+"")[2]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+(''+{})[5]+(!0+'')[0]+(''+{})[1]+(!0+'')[1]](((!1+"")[1]+(!1+"")[2]+(!0+"")[3]+(!0+"")[1]+(!0+"")[0])+"(1)")()

What a mess, right?! What the hell are we doing here? Let’s take it piece-by-piece.

First we start with an empty string. (Off to an exciting start, right?)

Next we access a property of that string with bracket notation instead of the familiar dot notation. Why? Well, we’ll see in a minute that we can construct strings, but we can’t reference Object properties with constructed string names using dot notation, so we switch to bracket notation.

So now, what’s the property we’re accessing? Here’s the “string”:

(!1+"")[3]+(!0+"")[2]+(''+{})[2]

Okay, so let’s start with !1 (false). Adding “” to a non-String value is basically a quick and dirty toString(). So with (!1+””) we get “false”.

Now we take the character in index 3 of the word “false” (which happens to be “s”). Try this again with (!0+””)[2], or “true”[2], and you’ll get the letter “u”. The last bit takes the character at index 2 of the string “[object Object]”, which is “b”.

Hopefully you can start to see what we’re doing here now. Without using any letters, I am constructing a string to access the “sub” property of the empty String object. But “sub” isn’t just a property, it’s a function.

At this point you may be thinking we’re going to subvert the filter with a call to the String.sub function. Perhaps we could, but actually I want to go deeper than that. What built-in properties does a function have? How about “constructor”?

If you open a JavaScript console, and type “”[“sub”][“constructor”], what do you get? Why, you get the Function() function! Seems like we could probably do something with that…

Now we need to use some more tricks to get the string “constructor.” Using characters from the strings “true”, “false”, and “[object Object]” get us most of the way there, but we need an “n”…

I’ll give you a hint: the “n” is right here:

((""[(!1+"")[3]+(!0+"")[2]+(''+{})[2]])+"")[2]

We have the familiar “”[“sub”]:

((""["sub"])+"")[2]

then we add “” to it, giving us the string “function sub() { [native code] }”. Take the character at index 2, and we get our “n”.

Let’s recap. We now have “”[“sub”][“constructor”], which is equal to Function(). If we call that, we can define a function (gasp!) using only a string. Since we’re trying to call alert(1), we have to string together a few more “true”s and “false”s to construct the string “alert”, then we just tack on +”(1)”.

Now with our call to Function(“alert(1)”), we’re almost home free! Just tack on a call to the returned anonymous function, and we get our popup! Here’s the code above, with a little nicer spacing:

// empty string
""

// ["sub"]
[(!1+"")[3]+(!0+"")[2]+(''+{})[2]]

// ["constructor"]
[(''+{})[5]+(''+{})[1]+((""[(!1+"")[3]+(!0+"")[2]+(''+{})[2]])+"")[2]+(!1+'')[3]+(!0+'')[0]+(!0+'')[1]+(!0+'')[2]+(''+{})[5]+(!0+'')[0]+(''+{})[1]+(!0+'')[1]]

// ("alert(1)")
(((!1+"")[1]+(!1+"")[2]+(!0+"")[3]+(!0+"")[1]+(!0+"")[0])+"(1)")

// call anonymous function returned by Function()
()

So that big, nasty mess at the start of this post basically just gets us Function(“alert(1)”)(), but of course does so while being completely illegible, and without using any identifiable strings. You can test it out by typing “javascript:” into your URL bar, then copying and pasting the code at the top, and hitting enter. You should see a little alert box with the number 1 in it.

I hope you’ve enjoyed this dive into some of the interesting obscurities of the JavaScript language as much as I have. Happy hacking!

5 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *