📜 ⬆️ ⬇️

Why JavaScript security analysis cannot be truly automated?

Why in the case of JavaScript it is necessary to manage with simple approaches of static analysis, when there are more interesting approaches to automatic code analysis?

In response to this question, my colleague Alexey Goncharov kukumumu answered succinctly: “JavaScript is a punk language” and threw a link to the Jasper Cashmore article “A Javascript journey with only six characters” , which really plunges us into the esoteric world of JSFuck and all at once puts in its place.
I liked it so much that I decided to translate the article into Russian.


image
')

Translation of the article “A Javascript journey with only six characters”


Javascript is a strange and wonderful language that allows you to write crazy code that still works. He tries to help us by converting data into certain types based on how we handle it.

If we add plus or minus signs before something, JS will assume that we want to add text, and convert the data type to String .
JS decides that we mean a number, and the data will be converted to the Number type (if possible).

If we deny any data, they will be translated into Boolean .
We can use JS to get up all sorts of magical things using only the symbols [, ] , ( , ) , ! + [, ] , ( , ) , ! + .

If you are not reading this from a mobile device, you can open the JS console to follow the story and test the performance of the examples given by simply copying them.

Let's start with the basics. A few golden rules to remember:

Starting from ! get type Boolean
Starting with + we get the type Number
Adding [] we get type String

Here are the rules in action:

 ![] === false +[] === 0 []+[] === "" 

Another thing that is important to know is that you can return certain characters from strings using parentheses, like this:

 "hello"[0] === "h" 

In addition, remember that you can get numbers by adding their components as strings, and then converting the result to the Number type using rule No. 2:

 +("1" + "1") === 11 

Like this. Now let's combine all of the above to get the character a .

 ![] === false ![]+[] === "false" +!![] === 1 ------------------------ (![]+[])[+!![]] === "a" // same as "false"[1] 

Cool

It turns out that with relatively simple combinations we can get any of the letters that make up the words true and false . a , e , f , l , r , s , t , u . So how can we get the rest of the letters?

Well, there is, for example, undefined , which we can get by writing nonsense like [][[]] . We translate into type String , using one of our Golden Rules, and in addition we get the letters d , i and n .

 [][[]] + [] === "undefined" 

Of all the letters that we already have, we can get words such as fill , filter and find . Of course, others can be obtained, but these are remarkable in that they are array methods . This means that they are Array objects and can be called directly in arrays, for example, [2,1].sort() .

Another important thing to know about JS is that the properties of an object can be accessed using dot or bracket notation . Since the array methods mentioned above are properties of the array itself, we can call these methods using square brackets instead of dotted notation.

So it turns out that [2,1]["sort"]() is the same as [2,1].sort() .

Let's go ahead and see what happens if we try to use one of our array methods, written using the current collection of letters, without calling it.

 []["fill"] 

It turns out function fill() { [native code] } . We can turn this method into a string using our golden rule:

 []["fill"]+[] === "function fill() { [native code] }" 

This is how we get the following characters: c , o , v , ( , ) , { , [ , ] , } ,   .

With newly acquired c and o we can form the word constructor . constructor is a method that all JS objects have that returns their constructor function.

Let's get as a string the representation of the constructor functions for the objects we have dealt with so far:

 true["constructor"] + [] === "function Boolean() { [native code] }" 0["constructor"] + [] === "function Number() { [native code] }" ""["constructor"] + [] === "function String() { [native code] }" []["constructor"] + [] === "function Array() { [native code] }" 

So we will add the following symbols to our arsenal: B , N , S , A , m , g , y .

Now we can create " toString ", a function that can be used with square brackets.

 (10)["toString"]() === "10" 

But we can turn anything into a string using our golden rule, so how can this be useful?

What if I tell you that the toString method of type Number has a secret argument, a secret argument called radix , which can change the base of a given number before converting to a string? Take a look:

 (12)["toString"](10) === "12" // base 10 - normal to us (12)["toString"](2) === "1100" // base 2, or binary, for 12 (12)["toString"](8) === "14" // base 8 (octonary) for 12 (12)["toString"](16) === "c" // hex for 12 

But why stop at 16? The maximum is 36, which essentially gives us all the characters from 0-9 and az . So we can call any number or letter:

 (10)["toString"](36) === "a" (35)["toString"](36) === "z" 

Wonderful! But what about other characters such as capital letters and punctuation? Digging deeper.

Depending on where your code is executed, you may have access to pre-installed objects or data. If you run the code in a browser, chances are that you have access to some HTML wrapper methods.

For example, bold is a String method that adds < b > tags.

 "test"["bold"]() === "<b>test</b>" 

This gives us the characters < , > and / .

It converts the string into a URI-compatible format that simple browsers are able to digest. This feature is an important part of our quest, so we need to access it. We can write it, but can we do it? This is not a typical function, like all previous ones, but a function of the global level.

What is the constructor function?

The answer is function Function() { [native code] } , the Function object itself is the constructor.

 . []["fill"]["constructor"] === Function 

Using this, we can pass a string of code to create a function.

 Function("alert('test')"); 

It turns out:

 Function anonymous() { alert('test') } 

Already this code we are able to call, simply using () at the end.
So now we use the escape function as follows:

 []["fill"]["constructor"]("return escape(' ')")() === "%20" 

If we pass our < described earlier to the escape function, we get %3C . This capital C very important to get the rest of the characters that we miss.

 []["fill"]["constructor"]("return escape('<')")()[2] === "C" 

Using it, we can write a function fromCharCode , which returns Unicode characters from a given decimal representation. This is part of the String objects, which we can get in the same way as we did before.

 ""["constructor"]["fromCharCode"](65) === "A" ""["constructor"]["fromCharCode"](46) === "." 

We can check for any decimal representations of Unicode characters here: Unicode lookup .

Fuh. Look like that's it!

Now we have the opportunity to call almost any character in the world, make a code out of them, and even execute. This means that we get Turing completeness in Javascript using a total of six characters: [ , ] , ( , ) , + and ! .

Want proof? Run this code in your browser:

Reveal code
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(+(!+[]+!+[]+!+[]+[!+[]+!+[]]))[(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(+![]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]+!+[]])+(!![]+[])[+[]]+(![]+[])[+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

If you are reading this from a mobile, the code above is an alert (“wtf”).

There is even a tool called JSFuck that automates the conversion, and here you can see how it translates each character.

What is the practical application?


None No True, eBay recently did a few bad things , thanks to which sellers can now inject JS code into their pages using only these characters, but this is a rather unusual attack vector. Some people will remember about obfuscation, but let's be honest, there are better ways to obfuscate this.

Excuse me.

Hope you enjoyed the trip!

Thanks to VladimirKochetkov and Ksenya Kirillov for help with the translation.

Source: https://habr.com/ru/post/337212/


All Articles