
JSFuck – Write any JavaScript with 6 Characters: []()!+ - lukashed
http://www.jsfuck.com/
======
IgorPartola
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 one as it just looks cool.
Since you can translate most functional JS into ASCII, you simply encode every
character into a binary coding using spaces for 0 and tabs for 1. Then you
write a very simple converter + put an eval() around it, and viola, you are
running arbitrary code. To a casual observer it would look like you have
delivered a mostly empty file, while in fact you are delivering perfectly
valid JS. Not unbreakable, but certainly fun.

~~~
frozenport
I am worried about the file size.

~~~
IgorPartola
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.

------
calvinlough
Currently, there is only 5 characters in the HN headline: "[]()+". Maybe a mod
removed the "!" because they thought it was being used for emphasis. It could
be placed before the "+".

~~~
netmare
A human would have probably noticed the "6 characters" part. I bet this was
done automatically.

------
acjohnson55
That's a pretty awesome hack of JS's (rather insane) semantics. It's probably
worth understanding at least the primative examples though if you're a JS
programmer, because this actually happens sometimes to expressions you write.

For a little bit of insight into why []+[] === '', for example, check this
out: [http://www.2ality.com/2012/01/object-plus-
object.html](http://www.2ality.com/2012/01/object-plus-object.html)

------
myndzi
I was interested in how this might be shrunk to something more reasonable... I
got this far before getting bored:
[http://pastie.org/8324713](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.

------
chrisdotcode
Here's an article [0] explaining more about how this works from the author of
Hieroglyphy.

[0] - [http://patriciopalladino.com/blog/2012/08/09/non-
alphanumeri...](http://patriciopalladino.com/blog/2012/08/09/non-alphanumeric-
javascript.html)

------
zekenie
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?

~~~
mjhoy
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 as well.

~~~
bargl
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]

~~~
mjhoy
Ah! You're right. Confusing.

Also confusing that "false"[[1]] works.

------
lysium
While funny looking, what is the ingenuity behind it?

~~~
phillmv
Many people here on HN never took compsci in school, so strictly speaking it's
just a translator -
[http://en.wikipedia.org/wiki/Translator_(computing)](http://en.wikipedia.org/wiki/Translator_\(computing\))
.

It's more a showoff of a js idiosyncrasy - they found an ugly looking subset
of characters that is Turing complete and wrote a translator to it.

If you're new to the concept of Turing tarpits, then this should blow your
mind. On the other hand, this is a sufficiently advanced bit of CS thinking
that no future employer should question the author's basic competency. _I_
certainly have never written a translator.

~~~
acjohnson55
I'm not sure it's a translator by that definition. The input and output are
legal Javascript. It's moreso a demonstration of a functionally complete
subset of the language.

You can get all the primitive values by taking advantage of unary plus, binary
+, empty arrays, array dereferencing, function calls, and the standard strings
returned by some basic expressions. The numbers are straightforward. The
strings are dereferenced with numbers to get some individual letters. You can
get methods by using array dereference on objects with strings. You get the
rest of the letters with btoa and atob. Then you get eval, and you're off to
the races!

I'm sure, but I think the encoder just goes token by token, eval'ing string
conversions to get identifiers. You'll notice that for pretty simple
expressions you get absurdly long strings out.

~~~
phillmv
>I'm not sure it's a translator by that definition. The input and output are
legal Javascript. It's moreso a demonstration of a functionally complete
subset of the language.

Well, okay, so it's still strictly speaking javascript but if we consider the
functionally complete subset to be our 'target' language we end up in the same
place, methinks :).

------
talles
"JSFuck is an esoteric and educational programming style"

How exactly is this educational?

~~~
MattBearman
I took the 'educational' to mean 'this should never be used in a real
application' :)

~~~
talles
If someone cogitates to use this for real... it shouldn't be doing it anything
at all.

------
k__
How are the performance impacts?

~~~
gberger
Huge.

Tested a simple "for" loop: [http://jsperf.com/jsfuck-perf-
testa](http://jsperf.com/jsfuck-perf-testa)

Vanilla I got 225k ops/sec. JSFuck, 4.5 ops/sec.

So about 50000 times slower.

------
sonnym
This is interestingly reminiscent of swearjure[1], clojure without
alphanumerics. The IRC log in that post is very enlightening to see how the
idea evolved into something absolutely frightening. I would like to see the
history of JSFuck.

1\.
[http://hypirion.com/musings/swearjure](http://hypirion.com/musings/swearjure)

------
snappy173
meh. i prefer Acme::EyeDrops

[http://search.cpan.org/dist/Acme-
EyeDrops/lib/Acme/EyeDrops....](http://search.cpan.org/dist/Acme-
EyeDrops/lib/Acme/EyeDrops.pm)

[http://www.99-bottles-of-beer.net/language-
perl-737.html](http://www.99-bottles-of-beer.net/language-perl-737.html)

------
penguat
I don't think this was written with the output size of the code much in mind.
In one example, there was: [+[[!+[]+!+[]]]]

Which breaks down to: [!+[]+!+[]] === [2] +[[!+[]+!+[]]] === 2
[+[[!+[]+!+[]]]] === [2] //again

So I think there might be quite a bit of scope for compression even within the
parameters it's built in.

Highly impressive, in any case.

------
etc_passwd
Here are two more javascript encoders that are useful for getting around
filters:

[http://utf-8.jp/public/jjencode.html](http://utf-8.jp/public/jjencode.html)
[http://utf-8.jp/public/aaencode.html](http://utf-8.jp/public/aaencode.html)

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

------
frik
IE 10 gives me "alertr1(" clicking on the "run this" link (eval source
deactivated). But interesting nevertheless!

------
teeja
This 'code' reminds me of the gobbledy-gook exchanged between the
supercomputers in _Colossus - The Forbin Project_.

------
xerophtye
I dont get it :/ if it says: 1 => +!+[]

Then why does it still translate to 1128 characters? :/

~~~
barrkel
Uncheck "Eval source".

------
aroman
Seems like it would be interesting to use as a cheap form of JS obfuscation.

~~~
CWIZO
Even 'alert(1)' produces over 500 chars. Imagine running a proper app trough
this. It's hardly cheap.

~~~
k__
It's probably easier (and much smaller) to put all js in a file, convert it to
a data-URI and add it into the html.

~~~
CWIZO
That isn't obsfucation though.

~~~
k__
I don't know if the stuff mentioned here isn't reversable. I never tried it
(just with images), wouldn't this not just show a big blob in the HTML file?

------
vbuterin
Here's a quick explanation:

    
    
      > []
      []
      > +[]
      0
      > !+[]
      true
      > +!+[]
      1
    

Lesson: + as a prepend coerces things into numbers

    
    
      > 123
      123
      > 123+[]
      "123"
      > ![]
      false
      > ![]+[]
      "false"
    

Lesson: + as an infix operator between incompatible types coerces everything
into strings

    
    
      > Function("alert(123)")
      function anonymous() {
      alert(123) 
      }
      > Function("alert(123)")()
      [alerts 123]
    

Lesson: the Function object can be called with a string to make a function
that evaluates that string

    
    
      > [].constructor
      function Array() { [native code] }
      > ({}).constructor
      function Object() { [native code] }
      > (function(){}).constructor
      function Function() { [native code] }
      > (function(){}).constructor("alert(123)")()
      [alerts 123]
    

Lesson: the constructor property returns the type of an object, and this gives
you access to the Function object

    
    
      > [].filter.constructor
      function Function() { [native code] }
      > []["filter"]["constructor"]
      function Function() { [native code] }
    

Lesson: an array's "filter" method is a function and has Function as its
constructor. Well, duh.

    
    
      > [][[]]
      undefined
      > [][[]]+[]
      "undefined"
      > !![]+[]
      "true"
      > ![]+[]
      "false"
      > (!![]+[])[1]
      "r"
      > (!![]+[])[+!+[]]
      "r"
    

Lesson: we now have the letters adefilnrstu, so we can construct []["filter"].

    
    
      > [].filter+[]
      "function filter() { [native code] }"
      > ({})+[]
      "[object Object]"
    

Lesson: we now have acdefijlnrstuv, so we can write
[]["filter"]["constructor"] and thus call our pseudo-eval on anything we can
make as well.

    
    
      > Function("return console")()+[]
      "[object Console]"
      > Function("")+[]
      "function anonymous() {
    
      }"
      > 0["constructor"]+[]
      "function Number() { [native code] }"
      > '0'["constructor"]+[]
      "function String() { [native code] }"
      > Function("return assert")()+[]
      "function assert(condition, opt_message) {
        'use strict';
        if (!condition) {
          var msg = 'Assertion failed';
          if (opt_message)
            msg = msg + ': ' + opt_message;
          throw new Error(msg);
        }
      }"
    

Lesson: we now have all the letters we need to make
""["constructor"]["fromCharCode"].

    
    
      > String.fromCharCode(74)
      'J'
    

Lesson: Enjoy the rest of the alphabet. We can now construct arbitrary
programs and eval them.

------
SunboX
How long will it take till we see a decompiler? :D

~~~
prezjordan
Essentially it just builds a new function of a given body text, then eval's
it. You could easily check out that source code before eval'ing with a log
statement.

------
runnr_az
That's ridiculous. Gotta give you props....

------
vezzy-fnord
The woe that is Atwood's Law.

------
qwerty_asdf
IMPORTANT QUESTION:

Why aren't the six special characters defined as follows?

    
    
      fuck()

~~~
rspeer
Because that would not be a Turing-complete subset of JavaScript, and this is.

------
Kristories
Brainfuck flavor

------
bigd
ihihihih... neat how it deals with gzip?

~~~
frik
I just tried it with ZIP format using WinRAR. "alert(1)" encoded and zipped
("best" compression) is 216 bytes vs. "alert(1)" zipped is 162 bytes.

~~~
SunboX
and unzipped it's 8 bytes ... ;)

