Hacker News new | past | comments | ask | show | jobs | submit login
JavaScript ( (__ = $ + $)[+$] + ({} + $)[_/_] +({} + $)[_/_] ) (adamcecc.blogspot.com)
403 points by there on Jan 22, 2011 | hide | past | favorite | 46 comments



Here's a converter from regular JS to using a subset of these characters: http://discogscounter.getfreehosting.co.uk/js-noalnum_com.ph...

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

Superfun. :D


"jjencode" generates more short code: http://utf-8.jp/public/jjencode.html

And "aaencode" Encode any JavaScript program to emoticons: http://utf-8.jp/public/aaencode.html


This is pretty cool. Reminds me of a Defcon presentation that only used whitespace characters to encode the script (and a bit of boilerplate). I think it looks less suspicious than lots of symbols lumped together.

Here it is: https://www.defcon.org/html/links/dc-archives/dc-16-archive....

https://www.defcon.org/images/defcon-16/dc16-presentations/d...


For those like me who stumble upon this type of js expressions for the first time and are scratching their heads, John Resig (of jQuery fame) attempted some basic explanations in this old HN post:

http://news.ycombinator.com/item?id=1154338


Great use of JavaScript's weird + operator.

The whole trick stems from the fact that !$ == false and !$+$ == "false"


var $ = []

![] == false because [] exists.

false + [] == 'false' because anything added to an array will become whatever that is as a string plus the contents inside the array.

2 + [] is also a string "2"

2 + [2,2] will become "22,2" (string)


Wow, I knew the + operator was weird, but didn't realise it allowed you to do stuff like that.

What I don't get though, wouldn't you still need to call eval() on it to do anything with it? Or does javascript do a 'implied eval' when you try to call a string?


Ah found the answer to my own question in the reddit thread about the same thing: http://www.reddit.com/r/programming/comments/f6xto/_/c1dr729


This is what is missing in the article, thank you


I'm missing the purpose. Can someone explain?


Some people think that they can secure their sites against XSS by regexing all the "bad JavaScript" out. If the "security software" sees "document.cookie", then it stops the script from executing. (Or it just replaces it with the empty string, etc.)

Problem is, there are a lot of ways to say document.cookie, and a blacklist is going to miss one of them.

Moral of the story: if people can execute scripts on your page, you're 0wned. Everyone competent knows this, but sometimes the less competent are slow to realize this.

So, the script that the article describes is for their benefit. Good luck writing a regex to stop this one...

(There are also even simpler "exploits", if you regex document.cookie to the empty string, then "document.document.cookiecookie" regexes to "document.cookie". Ooops.)


Very naive indeed. I guess I was overwhelmed by the lack of wow :-) Thanks for the context.


> Problem is, there are a lot of ways to say document.cookie

Could you give an example?


Using the converter linked above[1] I can convert

    alert(document.cookie)
to the equivalent

    ([][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]()[(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]])(([][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]()[([][[]]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+([][[]]+[])[+[]]+((+[])[([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]])[([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+[][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]()[(![]+[])[+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]()+[])[!+[]+!+[]]]((![]+[])[+!+[]]+[+[]])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(!![]+[])[!+[]+!+[]+!+[]]])



    [1] http://news.ycombinator.com/item?id=2129815


How would you protect against that ? is encoding the output enough ?


Sanitize both input and output. Make sure everything outputted is encoded. < to &gt; > to &lt;, " to &quote;, etc. As long as all they can write is normal characters then you're safe [1].

[1] Or rather, safer. There are always obscure ways to get around almost everything. So you really have to take care to exactly the situation you're in at the moment.


Sanitize everything, use multiple redundant sanitizer libraries (there are several out there that handle different things), and use a whitelist, rather than a blacklist, based approach. If you want to allow the use of <a> tags, enforce that they adhere to the exact format of a safe <a> tag, otherwise encode or strip them. One look at the XSS cheatsheet page should be enough to convince any sane developer of the futility of a blacklist-based approach.


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


Is it bad that I first tried to interpret it as Perl, even though it was clearly labeled as JavaScript?


If all those blackhat-efforts could be put to better use somewhere.. although its fascinating what _can_ be done. They are truly creative in their own way. :)


I'm a little confused. It seems like he didn't need to call the sort function in order to call the alert function. Is this correct? He could have built the alert call in the same manner and just call it by itself. I assume the sort function was thrown in there for a larger example?


The reddit link in the post right above yours explains that sort is used to get a reference to the "window" object since sort returns "this" and by assigning it to a variable it returns the default context which in this case is "window".


Searching for this string on Google, as I have no access to blogspot, I fell down on ​http://asdfg.jodi.org (js art, NSFW and may kill your browser). It is related, somewhat.


I saw these long back in a forum that listed such expressions for all printable characters; I am unable to locate them now. Can someone help? Thanks!



I wonder if you could use this in an interview...


This is great idea, if your goal is to not hire anyone.


except HN readers


How many of them can understand this?


Before or after this article was posted?


easy. show it to him and ask "in 1 to 5, how does that code look like the code you ship to production currently".

any answer other than "Zero" or "wtf-look", do not hire.


> any answer other than "Zero" or "wtf-look", do not hire.

What if you're hiring someone to test for XSS exploits?


Testing for XSS exploits isn't production code so the answer should still be zero.


It could certainly appear in the source of an XSS scanner that tried to inject code like that everywhere it could find.


This post makes me feel dumb. :(


Well, that was interesting.


why he needed $=[$=[]] and not just $=[[]]


The second $ (which is actually the first assignment) was used as as an alias to [] before the first $ gets assigned. I guess to reduce the number of characters.


it actually increases the number of chars.

inner $=[] will be overwritten by outer $=[$], which is the same as $=[[]]

or am i missing something?


It doesn't get overwritten until the rest of the expression has been evaluated, thus $ == [] for all the uses of $ within the expression.


still not clear.

the code unobfuscated is: (a=[a=[]]['sort'])()['alert'](1)

my argument is that this is the same, and less chars (a=[]['sort'])()['alert'](1)

I can't see any benefit of the encapsulation of the array assignment there.

edit: also, just noticed that my previous comments i was writting $=[[]] when i was thinking of $=[], but both works the same, and are still less chars :)


Ok here's the best I can do:

(lines are numbered in order of execution, with explanations of each line)

    ($=[                // 14: $ = Array.prototype.sort ([]["sort"] = Array.prototype.sort)
        $=[]            // 1: $ = []
    ][
        (__= !$+$ )[    // 2: __= "false" (![]+[] = false+[] = "false")
            _=-~-~-~$   // 3: _= 3 (-~-~-~[] = -~-~-(-1) = -~-~(1) = -~-(-2) = -~(2) = -(-3) = 3)
        ]+              // 4: "s" ("false[3]" = "s")
        ({}+$)[         // 5: "[object Object]" ({}+[] = "[object Object]")
            _/_         // 6: 1 (3/3 = 1)
        ]+              // 7: "o" ("[object Object]"[1] = "o")
        ($$=            // 12: $$ = "rt"
            ($_=        // 9: $_ = "true"
                !''+$   // 8: "true" (!''+[] = true+[] = "true")
            )[_/_]+     // 10: "r" ("true"[3/3] = "true"[1] = "r")
            $_[+$]      // 11: "t" ("true"[+[]] = "true"[0] = "t")
        )               // 13: "rt"
    ])()[               // 15: window (sort() = window)
        __[_/_]+        // 16: "a" ("false"[3/3] = "false[1]" = "a")
        __[_+~$]+       // 17: "l" ("false"[3+(~$)] = "false"[3+(-1)] = "false"[2] = "l")
        $_[_]+          // 18: "e" ("true"[3] = "e")
        $$              // 19: "rt"
    ](_/_)              // 20: alert(1) (window["alert"](3/3) = alert(1))
[] is assigned to "$" in step one. Several of the steps between 2 and 11 reference "$" to save one character rather than typing

If you wanted to remove the a=[] you'd have to include a bunch of "[]"s inline, e.x.:

    ($=[][
        (__= ![]+[] )[
            _=-~-~-~[]
        ]+
        ({}+[])[
            _/_
        ]+
        ($$=
            ($_=
                !''+[]
            )[_/_]+
            $_[+[]]
        )
    ])()[
        __[_/_]+
        __[_+~$]+
        $_[_]+
        $$
    ](_/_)
Replacing the no-alpha variable names with letters might help:

    (F=[
        A=[]
    ][
        (B= !A+A )[
            C=-~-~-~A
        ]+
        ({}+A)[
            C/C
        ]+
        (D=
            (E=
                !''+A
            )[C/C]+
            E[+A]
        )
    ])()[
        B[C/C]+
        B[C+~F]+
        E[C]+
        D
    ](C/C)
Notice both "A" and "F" were "$". The original code reused "$" to save a character.

I'm not sure I can make it any clearer.


wow that was sure detailed.

but i'm still not convinced of the steps :)

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

here i kept $, only step 11 required [] instead of $

i'm guessing step 14 is actually executed earlier... or that undefined has the same effects as [] for most of those stringfying hacks. Update: no, undefined trhows an error. so step 14 is earlier... let me replace all that with a eval function that also stores the run order. then i will post the correct ordering.


No, step 14 is definitely executed after the rest of that expression. Steps 2, 3, 5, 8, and 10 assume that $ equals [].

If you still refuse to believe me, I give up.


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

on the last string trick to write 'sort' it fails if there's no $=[$=[]]

all the other parts just $=[] works just fine. and they are in the same scope as the 't' i can't understand


Perl puts that ugliness to shame.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: