Live data from Hacker News

JSFuck – Write any JavaScript with 6 Characters: []()!+

jsfuck.com

61–70 of 76 posts

Re: JSFuck – Write any JavaScript with 6 Characters: []()!+

#61
post #48
post #35

Earlier quoted context omitted.

Try it letter by letter. For instance, to get the string "a": (![]+[])[+[[+!+[]]]] Take the first part, `(![]+[])`. `![]` evaluates to `false`. Then `+[]` coerces false into a string, so the expression is `"false"`. The rest of the expression (more complicated) evaluates to `[[1]]`, which will grab the `"a"` from `"false"`. Now why there is the extra surrounding brackets, I'm not sure, because `[1]` would have worked…

It looks like the generator is suboptimal, but still really cool. (![]+[])[+!+[]] evaluates to "a" as well. It looks like it turns it into an array twice. It goes +!+[] === 1 then [+!+[]] === [1] then +[[+!+[]]] === 1 then [+[[+!+[]]]] === [1]

Maybe one could run the output through Closure Compiler to get a bit better code ;-)

(Ok, tried it, it evaluates plenty of numbers on its own already which increases the character set. Not nice).

Re: JSFuck – Write any JavaScript with 6 Characters: []()!+

#62

I saw a very cool security talk a few years ago about how you can use the browser to do all kinds of evil things (did you know that the Same Origin Policy does not prevent you from making the request, but just seeing the response? And even then, you can guess at what kind of response you got). One of the great points in the talk was JS obfuscation. Now, there are many techniques for doing this, but I really like this…

I am worried about the file size.

Don't worry about it? :)

Realistically, how big is your exploit? 30KB? So it'll be 30*7 = 210 KB (JS is actually 7 bit ASCII). That's plenty of code to do something malicious. Nothing is preventing you from minifying the code before converting it to this whitespace encoding.

I suppose you could make your encoding include other whitespace chars, like newlines, carriage returns, etc. Then you could use base 4 instead of base 2.

Re: JSFuck – Write any JavaScript with 6 Characters: []()!+

#64

I saw a very cool security talk a few years ago about how you can use the browser to do all kinds of evil things (did you know that the Same Origin Policy does not prevent you from making the request, but just seeing the response? And even then, you can guess at what kind of response you got). One of the great points in the talk was JS obfuscation. Now, there are many techniques for doing this, but I really like this…

I am worried about the file size.

gzip and a file that contains sequences of only two different characters should compress pretty well.

Re: JSFuck – Write any JavaScript with 6 Characters: []()!+

#67
post #51

Earlier quoted context omitted.

It teaches you the funky behavior of JavaScript. For instance, `[]["filter"]` returns an empty function called filter. In order to get particular characters (for example: f), the script uses "false"[0], where "false" is derived from adding ![] + [], and 0 is derived from +[]. Putting all of that together ($ node): > (![]+[])[+[]] 'f'

Not sure that []["filter"] is all that funky of an example as it's just grabbing the arrays prototype method "filter" using bracket notation. Here's some better examples of JS oddities: http://stackoverflow.com/q/9032856/1538708

The funkiness is really that []["filter"]["constructor"] is a function that behaves like eval(), or rather, it returns a function that when called executes the string that was passed to the constructor function. That's how they're actually running the code.

> []["filter"]["constructor"]("alert(1)")()

Re: JSFuck – Write any JavaScript with 6 Characters: []()!+

#68
This is quite funny. I learned about JSFuck in 2012 when I took some of my fellow students to a JavaScript meetup in Hamburg. JSFuck has since developed to be a kind of running gag among the students at our computer science department when it comes to things with a high WTF factor.

Re: JSFuck – Write any JavaScript with 6 Characters: []()!+

#69
post #14

I put in alert('hello') and it worked. That's awesome. But how? I searched the code it made and didn't see 'hello.' I understand the stuff below, how it uses JS's weird properties to the basic types... but how does it encode characters?

It takes advantage of JS's complicated type coercion semantics and the overloading of the [] and + operators.

We start with [] and [[]].

convert [] to a boolean with !:

    ![] --> false
    !![] --> true
convert [] to undefined by subscripting it:

    [][[]] --> undefined
convert [] [[]] and true to numbers by prefixing them with + and adding them with +:

    +[]   --> 0
    +[[]] --> NaN
    +!![] --> +true --> 1
    +!![]+(+!![]) --> +true+(+true) --> 1+(1) --> 2
    etc.
convert any of these to strings by prefixing them with []+

    []+[]     --> ""
    []+![]    --> []+false     --> "false"
    []+[][[]] --> []+undefined --> "undefined"
    []+(+[])  --> []+0 --> "0"
get individual characters with the array subscript operator:

    ([]+![])[+[]] --> ([]+false)[0] --> "false"[0] --> "f"
    ([]+!![])[+!![]+(+!![])+(+!![])] --> ([]+true)[1+(1)+(1)] --> "true"[3] --> "e"
    etc...
So now we can obtain a limited number of characters:

    "a" "d" "e" "f" "i" "l" "n" "r" "s" "t" "u" "N" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"
which we can combine into strings with the + operator:

    "f"+"i"+"l"+"t"+"e"+"r" --> "filter"
    "1"+"e"+"1"+"0"+"0"+"0" --> "1e1000"
It's not much, but it's enough to obtain large numbers:

    +("1"+"2"+"3"+"4") --> +("1234") --> 1234
    +("1"+"e"+"1"+"0"+"0"+"0") --> +("1e1000") --> Infinity
and, most importantly, to access a property of the array object:

    []["filter"]  --> function filter() { [native code] }
and by converting these back to a string:

    []+[]["filter"] --> "function filter() { [native code] }"
    []+Infinity     --> "Infinity"
we can expand our alphabet still further, and access some even more exciting properties:

    []["constructor"]           --> function Array() { [native code] }
    ([]+[])["constructor"]      --> function String() { [native code] }
    (![])["constructor"]        --> function Boolean() { [native code] }
    (+[])["constructor"]        --> function Number() { [native code] }
    []["filter"]["constructor"] --> function Function() { [native code] }
Almost there now.

By converting these back to strings we can access even more characters, and by passing the strings to the Function() constructor we can can construct functions and evaluate them! In other words, we have "eval". Let's use it to access the window object:

    []["filter"]["constructor"]("return this") --> function anonymous() {return this}
    []["filter"]["constructor"]("return this")() --> window
So now we have access to the global context and eval. We don't quite have access to the full range of letters, but we have enough letters to call toString, and use it's base conversion ability to get the full lowercase alphabet:

    10["toString"](36) --> "a"
    11["toString"](36) --> "b"
    ...
    25["toString"](36) --> "p"
    ...
    35["toString"](36) --> "z"
And now we have "p", we can use escape and unescape to get most of the rest:

    unescape(escape(" ")[0]+4+0) --> "@"
So there you have it!

The source code essentially runs this process backwards: it repeatedly uses regular expressions to convert the code back into "()[]!+" one step at a time.

Re: JSFuck – Write any JavaScript with 6 Characters: []()!+

#70
I was interested in how this might be shrunk to something more reasonable... I got this far before getting bored: http://pastie.org/8324713

That code, run as-is in your browser, should alert 'hi'.

It's constructed with the intent of replacing the variables a-e and various named parameters with short sequences in the given character set that can be cast to strings. For legibility, I shortened many of the encodable sequences to strings (such as []["slice"])

The table holds 5^3 characters, which is 125; you could start the loop at 2 instead of 0 to get 2-127 as target characters, or use 6 input arguments. The 5 I chose were ![], [], +[], +{}, ~[] -- this should let you encode anything after overhead at a ratio of 12:1 with high repetition that gzip can take advantage of. This could be awful, I don't know; but maybe somebody will find this interesting.

Post reply on HN