
Executing non-alphanumeric JavaScript without parentheses - kkl
http://blog.portswigger.net/2016/07/executing-non-alphanumeric-javascript.html
======
drostie
Ctrl-F template strings... yep, there they are.

So if you didn't know, ES6 added template strings, which are these really
awesome things because they have multiline and string interpolation
capabilities (and they're safely far away from JSON, which in my opinion
shouldn't have such capabilities). They are very pretty and incredibly handy;
you write

    
    
        console.log(`
        I'm so ${scared} in case ${ I.fall.off() } my chair
        And I'm wonderin' how I'll get down the stair
        `);
    

and this gets converted into

    
    
        console.log("\nI'm so " + scared + " in case " + I.fall.off() +
            " my chair\nAnd I'm wonderin' how I'll get down the stair\n");
    

Except for one thing: they're called "template strings" because actually this
is a sort of "default behavior" which can be metaprogrammed. There is a
default interpreter which could be written:

    
    
        function interpret(text_segments, ...split_segments) {
            var out = "";
            for (var i = 0; i < split_segments.length; i++) {
                out += text_segments[i] + split_segments[i];
            }
            return out + text_segments[i];
        }
    

but... you can write one of your own, if you want, and put it on the
beginning. Therefore:

    
    
        > console.log(`abc ${[1,2,3]} def`)
        abc 1,2,3 def
        undefined
        > console.log `abc ${[1,2,3]} def`
        [ 'abc ', ' def' ] [ 1, 2, 3 ]
        undefined
    

Notice that the side effect of console.log has happened with the arguments
given to it, allowing for code execution.

As for mitigation... add detection of backticks to whatever code was detecting
parentheses. It's not a very widely used symbol in any context other than
shell scripting and LaTeX anyways, so you're probably good to go if you just
outlaw that character before calling eval() on the whole.

~~~
jerf
"add detection of backticks to whatever code was detecting parentheses."

No, stop trying to "detect" whether something is code and just properly encode
things in the first place. If this allows someone to get code into your
website, that is not a minor flaw to be fixed with a quick tweak, it is
indicative of a fundamental flaw in the understanding of whoever wrote that
code. When things are properly encoded, browsers won't execute them. (Give or
take some issues around content type detection.)

~~~
drostie
I mean, that's certainly a great ideal. The real world is somewhat less-than.
I don't fault anyone for having to maintain a legacy codebase developed by
people who rolled their own, say, JSON-parsing functions. (If you want to see
what this sort of exploit mitigation looks like in practice, see
[https://github.com/douglascrockford/JSON-
js/blob/master/json...](https://github.com/douglascrockford/JSON-
js/blob/master/json2.js#L464) ; think that this was the most popular JSON
parsing library ever. Thank goodness IE8 is a goner.)

------
taternuts
Spent a couple minutes figuring out how to spell "butts":

[[]+{}][+[]][++[[]][+[]]+[++[[]][+[]]][+[]]]+[!![]+[]][+[]][++[[]][+[]]+[++[[]][+[]]][+[]]]+[!![]+[]][+[]][+[]]+[!![]+[]][+[]][+[]]+[![]+[]][+[]][++[[]][+[]]+[++[[]][+[]]][+[]]+[++[[]][+[]]][+[]]]

------
nubs
I've done something similar with PHP, by casting an array to a string (The
string "Array") and using "variable variables". If only there was a way to
call functions in PHP without using letters in the code...
[https://gist.github.com/nubs/5849633#file-
nodigitsorquotesei...](https://gist.github.com/nubs/5849633#file-
nodigitsorquoteseither-php)

~~~
TazeTSchnitzel
You can call a function by name:

    
    
        $foo = "file_get_contents";
        $bar = "http://example.com/";
        $baz = $foo($bar);
    

In PHP 7 this doesn't even require you to give the function name its own
variable:

    
    
        ("file_get_contents")("http://example.com/");

------
amarpatel
I found this article had more depth:
[http://patriciopalladino.com/blog/2012/08/09/non-
alphanumeri...](http://patriciopalladino.com/blog/2012/08/09/non-alphanumeric-
javascript.html)

~~~
pythonistah
The parentheses-less javascript dialect in the title of this HN article relies
on ES6 and uses 6 characters:

    
    
        !+[]`$
    

The parent link above is ES5 and uses 8 characters:

    
    
        !+[](){}
    

The jsfuck.com ES6 dialect uses 6 characters:

    
    
        !+[]()
    

jsfuck was previously ES5 but they now rely on ES6isms to shorten their code.

------
posterboy
what's the use case? Circumventing code insertion filters?

~~~
jerf
Yes, and dually, demonstrating to people that their code insertion filters are
inadequate. You may know better, but there's still a lot of people in the real
world who try to "sanitize" Javascript with thing like "Remove all ()[]'";"
and think they're security masters whose code is unassailable.

That last bit isn't snark; it's my personal experience.

As mentioned in the article, there are filters in the real world that will be
penetrated by this.

------
sarreph
This article did give me the _out-loud-at-the-office_ chuckle and a whispered
"what the f°°°" that only awe-inspiring hacks far above my programming
intelligence level can provoke. :)

------
jerluc
Reminds me of Church encoding or even iota reductions, where you reduce a set
of higher level symbols to primitive symbols that in combination have provably
the same meaning.

------
Retr0spectrum
If you want to automate this process:
[http://www.jsfuck.com/](http://www.jsfuck.com/)

~~~
thomasfoster96
As far as I know, JSFuck still uses parentheses.

~~~
Retr0spectrum
Ah, so it does. I didn't realise.

