Friday, January 21, 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!

61 comments:

  1. 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.

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

    ReplyDelete
  3. 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.

    ReplyDelete
  4. This just made my head hurt (thanks!) ...

    ReplyDelete
  5. 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. :D

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

    ReplyDelete
  7. I'm wondering where did you find the slide?

    ReplyDelete
  8. 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.

    ReplyDelete
  9. can a Genetic algorithm write these?

    ReplyDelete
    Replies
    1. Hi,
      I can see that there is no response to your query. But do you have some ideas in this direction? In other words, what made you think to this query? I am interested in this direction and may be, we can discuss more.
      thanks

      Delete
  10. what the? someone needs to stop smoking crack

    ReplyDelete
  11. 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.

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

    ReplyDelete
  13. My addition to the above analysis can be found here: http://www.reddit.com/r/programming/comments/f6xto/_/c1dr729

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

    ReplyDelete
  15. When you see it, you'll shit bricks.

    ReplyDelete
  16. 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.

    ReplyDelete
  17. this thing just scared the living heck out of me !

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

    :)

    ReplyDelete
  19. The perfect gag gift for a new dev team member.
    "this is an example of our coding style"

    ReplyDelete
  20. A few of months ago I posted something about

    http://extraexploit.blogspot.com/2010/10/dollars-javascript-code-yet-another_06.html

    enjoy it!

    ReplyDelete
  21. Terima kasih infonya ,Brother
    sangat bermanfaat untuk menambah wawasan ^^
    kunjungan baliknya yah brother:
    http://aikoponsel76.blogspot.com
    Blog seputar dunia Handphone
    thangkiuuuu ^^

    ReplyDelete
  22. 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.

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

    ReplyDelete
  24. 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 ;-)

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

    ReplyDelete
  26. 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

    ReplyDelete
  27. $=[] 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

    ReplyDelete
  28. and this don't work on IE because IE don't autorize to execute "sort()" on "no object".

    ReplyDelete
  29. 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

    :D

    ReplyDelete
  30. I'd like to see something that was valid brainfuck and JavaScript - because this looks like extended brainfuck to me :)

    ReplyDelete
  31. This comment has been removed by the author.

    ReplyDelete
  32. This exact same proof-of-concept was done by @sirdarckcat and @thornmaker in their talk at BH Las Vegas 2009. Great explanation though, Adam!

    -Pooja
    http://www.brightaxis.com

    ReplyDelete
  33. Earnlancer.com is a global outsourcing solution and

    freelance jobs website. Here you can find freelance coders,

    writers, programmers, designers, marketers and more.The

    worlds largest outsourcing marketplace ,it is freelance jobs

    website. We have thousands of freelance jobs online for

    freelance programmers, web designers, graphic designers.

    http://www.earnlancer.com

    ReplyDelete
  34. This is a nice article..
    Its very easy to understand ..
    And this article is using to learn something about it..

    c#, dot.net, php tutorial

    Thanks a lot..!

    ReplyDelete
  35. I’m really Glad i ran across this web site.Added pompeiitours.org to my bookmark!

    cheap cialis

    ReplyDelete
  36. I have just started learning computer programming. I found this website very informative. It will help me to get some good programming concepts.
    java tutorial

    ReplyDelete
  37. feeling well by reading this awesome article i m student and now learning Seo visit my blog Freelance Jobs

    ReplyDelete
  38. It seems like little bit complex to understand but it was really interesting to know and learn something about the JavaScript thru ur blog !
    web design company

    ReplyDelete
  39. I can't get this to work. I get TypeError: Cannot convert undefined to object:

    >>> a = []
    []
    >>> b = a['sort']
    sort()
    >>> c = b()
    TypeError: can't convert undefined to object

    ReplyDelete
  40. I truly wish My spouse and i we had not witnessed this kind of as I want 1 currently!


    http://www.buylovejewelry.com/
    http://gamepartygogo.com/

    ReplyDelete
  41. Thanks for sharing this useful information! Hope that you will continue with the kind of stuff you are doing.
    Cheap Wildcard SSL

    ReplyDelete
  42. Good news.This is a great post. I like this topic.This site has lots of advantage. I found many interesting things from this site. It helps me many away..So i want some information for sharing this side with some of my friend. Thanks

    SEO Services

    ReplyDelete
  43. The provided code doesn't work any more in any of the major browsers - Opera 12, FF11+, Webkit 533+

    ReplyDelete
  44. Hi all,

    I'doing a CTF test for work and there is one javascript obfuscation I can't get my hands on. It seems similar to what is being explained here: it contains also an alert()

    $=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+"\\"+$.__$+$.$$_+$.$$_+$.$_$_+"\\"+$.__$+$.$$_+$._$_+"\\"+$.$__+$.___+$.$_$_+"=\\"+$.$__+$.___+"\\\"\\"+$.__$+$.__$+$.$__+$._$+$._$+"\\"+$.__$+$.$_$+$._$$+"\\"+$.$__+$.___+$.$_$_+$.__+"\\"+$.$__+$.___+$.__+"\\"+$.__$+$.$_$+$.___+$.$$$_+"\\"+$.$__+$.___+"\\"+$.__$+$.$$_+$._$$+$._$+$._+"\\"+$.__$+$.$$_+$._$_+$.$$__+$.$$$_+"\\"+$.$__+$.___+$._$+$.$$$$+"\\"+$.$__+$.___+$.__+"\\"+$.__$+$.$_$+$.___+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$$_+$._$$+"\\"+$.$__+$.___+"\\"+$.__$+$.$$_+$.$$$+$.$$$_+$.$_$$+"\\"+$.__$+$.$$_+$.___+$.$_$_+"\\"+$.__$+$.$__+$.$$$+$.$$$_+"\\"+$.$__+$.___+$.$_$_+"\\"+$.__$+$.$_$+$.$$_+$.$$_$+"\\"+$.$__+$.___+"\\"+$.__$+$.$$_+$._$$+$.$$$_+$.$_$_+"\\"+$.__$+$.$$_+$._$_+$.$$__+"\\"+$.__$+$.$_$+$.___+"\\"+$.$__+$.___+$.$$$$+$._$+"\\"+$.__$+$.$$_+$._$_+"\\"+$.$__+$.___+$.__+"\\"+$.__$+$.$_$+$.___+$.$$$_+"\\"+$.$__+$.___+$.$_$_+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.__$+$.$$_+$._$$+"\\"+$.__$+$.$$_+$.$$$+$.$$$_+"\\"+$.__$+$.$$_+$._$_+"!\\\";\\"+$.__$+$._$_+"\\"+$.__$+$.$$_+$.$$_+$.$_$_+"\\"+$.__$+$.$$_+$._$_+"\\"+$.$__+$.___+$.__+"\\"+$.__$+$.$_$+$.___+$.$$$_+"_"+$.$_$_+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.__$+$.$$_+$._$$+"\\"+$.__$+$.$$_+$.$$$+$.$$$_+"\\"+$.__$+$.$$_+$._$_+"\\"+$.$__+$.___+"=\\"+$.$__+$.___+"\\\"\\"+$.__$+$._$_+$.$__+"\\"+$.__$+$.$_$+$.___+$.$$$_+"\\"+$.$__+$.___+$.$_$_+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.__$+$.$$_+$._$$+"\\"+$.__$+$.$$_+$.$$$+$.$$$_+"\\"+$.__$+$.$$_+$._$_+"\\"+$.$__+$.___+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$$_+$._$$+"\\"+$.$__+$.___+"\\"+$.__$+$.__$+$._$_+"\\"+$.__$+$.___+$.__$+"\\"+$.__$+$._$_+$.$$_+"\\"+$.__$+$.___+$.__$+"\\"+$.__$+$._$_+$._$$+"\\"+$.__$+$.___+$._$$+"\\"+$.__$+$._$_+$._$_+"\\"+$.__$+$.__$+$.__$+"\\"+$.__$+$._$_+$.___+"\\"+$.__$+$._$_+$.$__+"_\\"+$.__$+$.___+$.$$_+"\\"+$.__$+$._$_+$.$_$+"\\"+$.__$+$.__$+$.$$_+"\\\";\\"+$.__$+$._$_+$.$$_$+$._$+$.$$__+$._+"\\"+$.__$+$.$_$+$.$_$+$.$$$_+"\\"+$.__$+$.$_$+$.$$_+$.__+".\\"+$.__$+$.$$_+$.$$$+"\\"+$.__$+$.$$_+$._$_+"\\"+$.__$+$.$_$+$.__$+$.__+$.$$$_+"("+$.$_$_+");\\"+$.__$+$._$_+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"("+$.$_$_+");"+"\"")())();

    If someone has a clue where to start, then please!

    ReplyDelete
    Replies
    1. I have the same. Can we see the same analysis for this? We need this so mach? please

      Delete
  45. I was able to do it using console.log() on the last statement in the scrambled JS code.

    ReplyDelete