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!

35 responses to “JavaScript ( (__ = !$ + $)[+$] + ({} + $)[_/_] +({} + $)[_/_] )

  1. Dan Tentler January 21, 2011 at 11:44 pm

    Okay, after I picked my brains up off the floor the first thing I thought of was “Can someone build a translator for this?” – kinda of like rsnakes xss cheatsheet page? because Hoooooooly crap.

    Like

  2. hybridus January 22, 2011 at 2:07 am

    i wonder if behavioral protection can do something for these. i mean products like finjan(m86). ever had a chance to test?

    Like

  3. Dan Tentler January 22, 2011 at 2:12 am

    if this is a case for anything, its a BRILLIANT SHINING example of why devs should always whitelist instead of blacklisting or relying on magic quotes.

    Like

  4. Mark January 22, 2011 at 2:15 am

    This just made my head hurt (thanks!) …

    Like

  5. Paul Irish January 22, 2011 at 3:23 am

    Here's a full converter using a subset of the characters used above: http://discogscounter.getfreehosting.co.uk/js-noalnum_com.php

    And the forum thread where this technique was explored at length: http://sla.ckers.org/forum/read.php?24,33349,33405

    Superfun. πŸ˜€

    Like

  6. Eric Fickes January 22, 2011 at 3:42 am

    Bet this won't run in IE πŸ˜‰

    Like

  7. Danny January 22, 2011 at 7:43 am

    Dang! just dang.. I'll try again when I finished this coffee.

    Like

  8. Khalid Buanget !!! January 22, 2011 at 9:03 am

    I'm wondering where did you find the slide?

    Like

  9. breaknenter.org January 22, 2011 at 9:11 am

    First of all, that made my head hurt… Many whitelists would fail to protect from this type of XSS attack as well, this is a brilliant example of why input validation isn't a walk in the park.

    Like

  10. donotfold January 22, 2011 at 9:34 am

    too much time on your hands? πŸ˜‰

    Like

  11. jdavid_net January 22, 2011 at 10:02 am

    can a Genetic algorithm write these?

    Like

  12. Napoleon January 22, 2011 at 11:49 am

    what the? someone needs to stop smoking crack

    Like

  13. Moshe Basanchig January 22, 2011 at 12:52 pm

    hybridus – yes, the M86 SWG (formerly Finjan) deals with such samples just fine.

    Basically, this is plain (standard) JavaScript. While not very much readable to the human eye, the SWG engine couldn't care less.

    Like

  14. a3log January 22, 2011 at 1:02 pm

    I have to read your post a couple of times before understanding some of it -.-

    Like

  15. n0mad January 22, 2011 at 2:59 pm

    what would be the best approach to prevents XSS' like these?

    Like

  16. Anon7jazarAr January 22, 2011 at 3:06 pm

    When you see it, you'll shit bricks.

    Like

  17. James January 22, 2011 at 3:21 pm

    Thanks. Every once in a while I need a reminder that I'm not as good at some programming skill as I thought I was. At first glance, I would have bet money that the JavaScript above was invalid. Wow.

    Like

  18. Ravikiran January 22, 2011 at 3:56 pm

    this thing just scared the living heck out of me !

    Like

  19. Phillip January 22, 2011 at 4:22 pm

    You might want to check this out: http://utf-8.jp/public/aaencode.html

    πŸ™‚

    Like

  20. Mark Essel January 22, 2011 at 6:08 pm

    The perfect gag gift for a new dev team member.
    “this is an example of our coding style”

    Like

  21. bastawhiz January 23, 2011 at 2:54 am

    Mozilla has a script in early-stage development that detects code like this submitted in add-ons to addons.mozilla.org. It's here:

    https://github.com/mattbasta/amo-validator/blob/master/validator/testcases/scripting.py

    The idea is that if you emulate the behavior of the JS interpreter by evaluating expressions that involve literals and predefined, static functions, you can programmatically determine when a script is being malicious.

    Certainly there are more sophisticated ways to carry out an attack like this, but anything more complicated would likely attract the attention of a human editor for AMO.

    Like

  22. Steve Piper January 24, 2011 at 1:36 am

    This makes me actually miss COBOL, and want to finally go learn Python.

    Like

  23. Greg January 24, 2011 at 5:33 am

    Your explanation is close, but not quite right.

    You say “$ derefs to the value 0.” That's not true. $ is an empty array for the entire expression that retrieves the Array.prototype.sort method. It's just that this empty array is used in string/number contexts (i.e. its toString() method is being called when used in these contexts) that allows the code to produce what it needs.

    So, because the binary + operator does string concatenation, and [].toString() returns an empty string:
    1) ![] + “” === “false”
    2) ({}+””) === “[object Object]”
    3) !'' + “” === “true” (as a string, not a boolean)

    And the others:
    4) bitwise not (~) with any non-numeric value === -1
    5) +[] === 0 (Unary + tries to convert its operand to number, which actually calls Array.prototype.toString for its primitive value (as Array.prototype.valueOf does not return a primitive), and then converts that empty string to a 0)

    But otherwise, good job figuring this out πŸ˜‰

    Like

  24. Saleh January 24, 2011 at 12:24 pm

    Wow.. too much complexity.. too much enjoyment :p

    Like

  25. theharmonyguy January 24, 2011 at 6:20 pm

    If people are interested in more details on this style of JavaScript, I did a video presentation on the basics a few months ago: http://vimeo.com/15961577

    Like

  26. Google Master January 26, 2011 at 3:47 pm

    $=[] is a blank array

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

    So $ derefs to the value 0.

    ——————

    at the first time, $ value is only a blank array (toInt == 0)
    once all inside the second [], the $ value become “function sort()” .. but the $ never value “an array with a reference to an array”

    and in the second part, for the “l” of “alert” :
    __[_+~$]

    the ~$ == ~Array.prototype.sort == -1

    Like

  27. Google Master January 26, 2011 at 3:58 pm

    and this don't work on IE because IE don't autorize to execute “sort()” on “no object”.

    Like

  28. TiTi January 28, 2011 at 1:05 pm

    I DID make a translator of that kind : https://github.com/TiTi/jswtf

    I did it only with thoses caracters : ()![]+{}

    Nice trick here:
    a = [];
    b = a[“sort”];
    c = b();
    c

    πŸ˜€

    Like

  29. skilldrick January 28, 2011 at 5:40 pm

    I'd like to see something that was valid brainfuck and JavaScript – because this looks like extended brainfuck to me πŸ™‚

    Like

Leave a comment