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!
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.
LikeLike
i wonder if behavioral protection can do something for these. i mean products like finjan(m86). ever had a chance to test?
LikeLike
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.
LikeLike
This just made my head hurt (thanks!) …
LikeLike
what the ****!!!
LikeLike
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. π
LikeLike
Bet this won't run in IE π
LikeLike
Dang! just dang.. I'll try again when I finished this coffee.
LikeLike
Gah!
LikeLike
I'm wondering where did you find the slide?
LikeLike
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.
LikeLike
too much time on your hands? π
LikeLike
can a Genetic algorithm write these?
LikeLike
what the? someone needs to stop smoking crack
LikeLike
cool
LikeLike
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.
LikeLike
I have to read your post a couple of times before understanding some of it -.-
LikeLike
My addition to the above analysis can be found here: http://www.reddit.com/r/programming/comments/f6xto/_/c1dr729
LikeLike
what would be the best approach to prevents XSS' like these?
LikeLike
When you see it, you'll shit bricks.
LikeLike
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.
LikeLike
this thing just scared the living heck out of me !
LikeLike
You might want to check this out: http://utf-8.jp/public/aaencode.html
π
LikeLike
Nice one
LikeLike
The perfect gag gift for a new dev team member.
“this is an example of our coding style”
LikeLike
A few of months ago I posted something about
http://extraexploit.blogspot.com/2010/10/dollars-javascript-code-yet-another_06.html
enjoy it!
LikeLike
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.
LikeLike
This makes me actually miss COBOL, and want to finally go learn Python.
LikeLike
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 π
LikeLike
Wow.. too much complexity.. too much enjoyment :p
LikeLike
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
LikeLike
$=[] 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
LikeLike
and this don't work on IE because IE don't autorize to execute “sort()” on “no object”.
LikeLike
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
π
LikeLike
I'd like to see something that was valid brainfuck and JavaScript – because this looks like extended brainfuck to me π
LikeLike