Monthly Archives: January 2011

JavaScript ( (__ = !$ + $)[+$] + ({} + $)[_/_] +({} + $)[_/_] )

First off credit where credit is due.

Update 1: Well hello reddit and hackernews.

1) I didn’t write this JavaScript.
2) I didn’t find this JavaScript.

I saw it in a slide deck from BlackHat DC 2011. Called XSS Street-Fight. Most of the presentation was dry JavaScript /mod_security, but this caught my eye.

($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+
($$=($_=!”+$)[_/_]+$_[+$])])()[__[_/_]+__
[_+~$]+$_[_]+$$](_/_)

Care to guess what that does?

How about if I type it like this.

($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+
($$=($_=!”+$)[_/_]+$_[+$])])()[__[_/_]+__
[_+~$]+$_[_]+$$](document.cookie)

That’s right this is an alert() if it lands anywhere in
an executable section of JavaScript/dom it pops up the cookie.

Go ahead and put it in a script tag in your browser it will pop up a “1”

That’s when I couldn’t put this down.

First there are really two lines here.

($ = [ $=[]] [ (__ = !$ + $ )[ _ = -~-~-~$] + ({} + $)[_/_] + ( $$ = (
$_ = !” + $)[_/_] + $_[+$] ) ] )()

becomes sort()

[__[_/_]+__[_+~$]+$_[_]+$$](_/_)

becomes alert(1)

Let’s start to tear this apart.

$=[] is a blank array

$=[$=[]] is an array with a reference to an array.

So $ derefs to the value 0.

Now we have a 0 we can freely reference.

__ = “false”via (__ = !$ + $ )
_ = -~-~-~$

(The ~ operator in JavaScript means -(N+1) so -~ = +1
if $ = 0 then -~-~-~$ = 3

_ = 3

thus _/_ = 3/3 = 1

(__ = !$ + $ )[ _ = -~-~-~$]
(“false”)[_]
(“false”)[3]
“false”[3] = s

({} + $)[_/_]
(” object”)[_/_]
(” object”)[1]
” object”[1] = o

$$ = ( $_ = !” + $)[_/_]
$$ = ( “true”)[1]
“true”[1] = r

$_[+$] = “true”[0] = t

$_ = “true”null
$$ = rt via

($$ = ( $_ = !” + $)[_/_] + $_[+$] ))

!” = “true”
$_ = (true)
$_[1] = r
$_[0] = t
$$ = rt

Thus the first line becomes sort()

($ = [ $=[]] [“s” + “o”+ “r”+ “t” ] )()

Sort takes a function as it’s parameter to
execute thus firing the second line. It turns out this assumption was wrong on my first go. Scroll to the bottom for the updated explanation I quote from Benjaminsen .

[__[_/_]+__[_+~$]+$_[_]+$$](_/_)

$ = 0
_ = 3
__ = “false”
$_ = “true”
$$ = “rt”

[__[_/_]+__[_+~$]+$_[_]+$$](_/_)

becomes
[__[1] + __[3 + -1] + $_[3] + $$)(1);

becomes
[“false”[1] + “false”[3 + -1 ] + “true”[3] + “rt”] (1)

[ a + l + e + r + t ](1)

alert(1)

From Benjaminsen @ reddit.


($=[]["sort"])()["alert"](1)

We can further break that into

a = []          // Create array
b = a["sort"] // Get reference to sort method
c = b() // Execute sort outside the context of an array to return a reference to window
d = c["alert"] // Get reference to window.alert
d(1) // Execute window.alert with the argument 1

So what happens is

window["alert"](1)

not

[1,2].sort(alert)

Enjoy!