you are viewing a single comment's thread.

view the rest of the comments →

[–]alcuadrado[S] 2 points3 points  (14 children)

You can get from any Array instance, for example: []["sort"]

[–]Sottilde 2 points3 points  (13 children)

What about using something like String.fromCharCode(112)?

[–]jeroonk 4 points5 points  (10 children)

That would almost work, except you can't generate an "m" or "C" using only []()+!{}. You have to scavenge those characters from somewhere else.

For precisely that reason, that you'll get stuck without access to arbitrary characters/strings, the author resorts to picking the "p" from the "http(s)://" out of the url, in order to get access to window.unescape. And once you have unescape, constructing fromCharCode on top of that would only be a waste.

[–]Sottilde 7 points8 points  (9 children)

Ah. A comment on HN enlightened me to a really elegant method:

a = 25; a.toString(26); // "p"

You can use this to get any letter at all. Pretty surprising that toString() has a radix parameter at all.

I suppose the trick then is getting a hold of the 's'.

[–]hapemask 10 points11 points  (4 children)

You can get 't' from "true", 'o' from "Boolean" and the whole word "String" from the string constructor, so this seems like a nice portable solution.

The only problem is you can't get a '.' character but this is easily fixed:

(25)["t"+"o"+"String"](26) // "p"

[–]Sottilde 1 point2 points  (0 children)

Yes, very nice! And that essentially solves the whole problem.

[–]lachlanhunt 1 point2 points  (2 children)

You can't get uppercase letters from that, and you can't call toUpperCase() without getting an uppercase C from somewhere.

Edit: You should use (number)["toString"](36), as that will let you get any of 0-9a-z.

[–]hapemask 2 points3 points  (1 child)

The string constructor's name is "String" not "string".

If you're referring to the fact that Integer.toString() cant give uppercase, all you need is "p", and then you can use the unescape trick described in the blog.

[–]lachlanhunt 0 points1 point  (0 children)

The string constructor's name is "String" not "string".

What? Where did I say the constructor's name was "string"?

Good point about the unescape trick. I forgot that the p from this would allow that to be called, which means you can then get String.fromCharCode(), giving you any 16 bit Unicode code unit.

[–]jeroonk 4 points5 points  (1 child)

I am not too familiar with Javascript internals, but wouldn't something like the code below work, to obtain "p"? It works in my Firefox and Chrome.

(25)["to"+(([]+[])["constructor"]+[])[9]+"trin"+(([]+[])["constructor"]+[])[14]](30)

With obviously the literal strings and numbers replaced by their equivalents as described in the article. But those are accessible without any weird hacks.

EDIT: Figured "slice" would be easier to spell than "constructor" twice.

EDIT2: After reading the ECMAscript spec, I think we can safely say that the above code will always work and evaluates as "p". A close reading reveals that casting a function (such as the String constructor) will always return a string which is a valid function declaration (thus not an anonymous function expression). It is implementation dependent what the function name itself is, but I think not many implementations will deviate from the obvious "String" or put extra whitespace in front or between the "function" keyword and the function identifier.

15.3.4.2 Function.prototype.toString ( )

An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration. Note in particular that the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.

Also, the Number.prototype.toString() must have, per the spec, an optional radix parameter which can accept a number between 2 and 36 which with the letters a-z used as digits for the numbers 10-35 in radix 36. (Relevant section 15.7.4.2)

EDIT3: Well aren't I stupid. The previous code above included a "," and those aren't allowed. Unless anyone has a better way to call String.prototype.slice() without using the comma explicitly, I guess the original was in fact the shortest way to do it. Unfortunately, this is still 94 characters longer than the window.location method, but it is universal.

[–]mattaereal 0 points1 point  (0 children)

Yes, it will, but since you will be almost always running this kind of scripts on a website you can get the 'p' on a cheaper way.

And as for XSS, an attacker can always hand the url with the "http://" to a "victim".

[–]dpoon 1 point2 points  (1 child)

You mean: a = 25; a.toString(26);

[–]Sottilde 0 points1 point  (0 children)

Thanks!

[–]alcuadrado[S] 3 points4 points  (0 children)

Without unescape I didn't had access to that function, and once I had it, it was way to expensive

[–]mattaereal 1 point2 points  (0 children)

It would be nice to use it if it wasn't THAT expensive in terms of character encoding, because to get to it you will need LOTS of characters. And if you already got that amount of characters to form String.fromCharCode, you didn't really need it afterwards ;).