DEV Community

WangLiwen
WangLiwen

Posted on • Updated on

JavaScript Magic Tricks: Mutable Eval

In JavaScript development, Eval is often used in dark areas to execute some code that is not intended to be seen by others.

However, Eval has distinct characteristics and no matter what function it implements, it can be easily observed directly, causing people to be alert.
However, Eval can also have mutated forms, such as the following line, which is also Eval, but can you identify it as such?

Mutated Eval:

window[(14).toString(32)+(31).toString(32)+(10).toString(32)+(21).toString(32)]
Execute:

Image description

How could such a strange string be Eval? Let's take a look at the technical principle of mutated Eval:

1.Eval() equals to window.eval().
2.Window.eval() equals to window["eval"].
3."eval" can be decomposed into: window["e"+"v"+"a"+"l"].
4."e"+"v"+"a"+"l" can be written as: (14).toString(32)+(31).toString(32)+(10).toString(32)+(21).toString(32).
5.How do we get the characters in 4? It's like this:
parseInt("e",36) = 14;
parseInt("v",36) = 31;
parseInt("a",36) = 10;
parseInt("l",36) = 21;
6.Finally, Eval is transformed into:
window[(14).toString(36)+(31).toString(36)+(10).toString(36)+(21).toString(36)];

Can it still be used normally? Yes, of course.
Here are two examples:

Example 1:

window[(14).toString(32)+(31).toString(32)+(10).toString(32)+(21).toString(32)]("console.log('test');");

Example 2:

window[(14).toString(32)+(31).toString(32)+(10).toString(32)+(21).toString(32)]("var a=1;var b=2;var c=3;console.log(a+b+c);");
Exexute:

Image description

Further mutation:
If the above JS code is obfuscated by JShaman JavaScript Obfuscator, more complex forms can be obtained.

window[(748953 ^ 748951)['\x74\x6f\x53\x74\x72\x69\x6e\x67'](239241 ^ 239273) + (151757 ^ 151762)['\x74\x6f\x53\x74\x72\x69\x6e\x67'](430630 ^ 430598) + (671610 ^ 671600)['\x74\x6f\x53\x74\x72\x69\x6e\x67'](930617 ^ 930585) + (944302 ^ 944315)['\x74\x6f\x53\x74\x72\x69\x6e\x67'](186206 ^ 186238)](";)c+b+a(gol.elosnoc;3=c rav;2=b rav;1=a rav"['\x73\x70\x6c\x69\x74']("")['\x72\x65\x76\x65\x72\x73\x65']()['\x6a\x6f\x69\x6e'](""));

At this point, who would have guessed that this was an eval?

Top comments (14)

Collapse
 
lionelrowe profile image
lionel-rowe • Edited
  1. eval() equals to window.eval().

That's only half-true. For example, JS itself will tell you it's true:

eval === window.eval // true
Enter fullscreen mode Exit fullscreen mode

However, calling eval directly and calling window.eval don't always give identical results. This is due to the special semantics of direct eval:

Although the expression eval(x) looks like a normal function call, it actually takes on special behavior in JavaScript. Using eval in this way means that the evaluated code stored in x can reference any variable in any containing scope by name. For example, the code let y = 123; return eval('y') will return 123.

Here's a more complete example:

{
    const x = true

    const codeStr = `
        try {
            console.log(x)
        } catch {
            console.log(false)
        }
    `

    eval(codeStr)        // logs `true`
    window.eval(codeStr) // logs `false`
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
wangliwen profile image
WangLiwen

you are right,professional enough.

Collapse
 
bwca profile image
Volodymyr Yepishev

Got to love how JavaScript can take forms which look more like cryptic magic spells than the actual code 🙃

Collapse
 
wangliwen profile image
WangLiwen

JavaScript is cool,my favorite programming language.

Collapse
 
joelbonetr profile image
JoelBonetR 🥇

So true 😂

Collapse
 
efpage profile image
Eckehard

you can prevent the accidential use of eval by overloading this function:

        window.eval = function(){}
        console.log(eval("1+2+3"))  
Enter fullscreen mode Exit fullscreen mode
Collapse
 
wangliwen profile image
WangLiwen

it's a good idea!

Collapse
 
tailcall profile image
Maria Zaitseva

The lesson to learn here would be: anything could be an eval, cut and paste code carefully.

Collapse
 
wangliwen profile image
WangLiwen

YES!

Collapse
 
manchicken profile image
Mike Stemle

Eval is great fun, just be careful to never eval on user-supplied strings for security reasons. Even if you sanitize it, there are still likely holes. One of the safe-eval modules on NPM would be helpful if you need to do such a thing.

Collapse
 
wadecodez profile image
Wade Zimmerman

This is very true, even if you instantiate functions instead of eval, everything is a prototype with access to the Function constructor. Here is the most common occurrence I see.

<div> We found { count } hits for { search } </div>
Enter fullscreen mode Exit fullscreen mode

then a user searches for something like this

window.constructor.__proto__.constructor('alert("hello JS framework")')()
Enter fullscreen mode Exit fullscreen mode
Collapse
 
wadecodez profile image
Wade Zimmerman

eval is also a code smell. devs use it in frameworks and libraries to be clever, but there is no reason to use it. if you're making something to handle user input, you're better off writing a customer parser to handle your specific use case.

Collapse
 
pavlopaska profile image
Pavlo Paska

It is still not safe. You can use jspython interpreter (jspython.dev) for safe evaluation within JavaScript (browser or NodeJS)

Collapse
 
johnthemilesi profile image
Joao Milesi

Nice