Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect I'm inside an eval() call?

Does there exist a string s such that

(new Function(s))();

and

eval(s);

behave differently? I'm trying to "detect" how a string is being evaluated.

like image 485
Randomblue Avatar asked Sep 01 '12 12:09

Randomblue


People also ask

What is the purpose of the eval () method?

The eval() function in JavaScript is used to evaluate the expression. It is JavaScirpt's global function, which evaluates the specified string as JavaScript code and executes it. The parameter of the eval() function is a string. If the parameter represents the statements, eval() evaluates the statements.

What happens when you eval a string?

The argument of the eval() function is a string. It will evaluate the source string as a script body, which means both statements and expressions are allowed. It returns the completion value of the code. For expressions, it's the value the expression evaluates to.


3 Answers

Check for the arguments object. If it exists, you're in the function. If it doesn't it has been evaled.

Note that you'll have to put the check for arguments in a try...catch block like this:

var s = 'try {document.writeln(arguments ? "Function" : "Eval") } catch(e) { document.writeln("Eval!") }';
(new Function(s))();
eval(s);

Demo

Solution to nnnnnn's concern. For this, I've edited the eval function itself:

var _eval = eval;
eval = function (){
    // Your custom code here, for when it's eval
    _eval.apply(this, arguments);
};

function test(x){
    eval("try{ alert(arguments[0]) } catch(e){ alert('Eval detected!'); }");
}
test("In eval, but it wasn't detected");​
like image 141
Some Guy Avatar answered Oct 03 '22 17:10

Some Guy


The current answer does not work in strict mode since you can't redefine eval. Moreover, redefining eval is problematic for many other reasons.

The way to differenciate them is based on the fact that well... one of them creates a function and what doesn't. What can functions do? They can return stuff :)

We can simply exploit that and do something with return:

// is in function
try {
     return true;
} catch(e) { // in JS you can catch syntax errors
     false; //eval returns the return of the expression.
}

So in example:

var s = "try{ return true; }catch(e){ false; }";
eval(s); // false
Function(s)(); // true
(new Function(s))(); // true, same as line above
(function(){ return eval(s); })(); // the nested 'problematic' case - false
like image 30
Benjamin Gruenbaum Avatar answered Oct 03 '22 18:10

Benjamin Gruenbaum


evaled code can be detected by invoking an error and checking if the native stack-trace contains a lower row/column indicator.

if (typeof window === 'object') {
    // browser
    window.isEvilEval = function () {
        return parseInt(String(new Error().stack).split(':').pop(), 10) < 10;
    };
} else {
    // nodejs (must be global to be callable from within Function)
    global.isEvilEval = function () {
        return (
            new Error().stack
                .split('\n')
                .filter((l) => l.trim().startsWith('at eval') && l.indexOf('<anonymous>:1') > -1).length > 0
        );
    };
}

// test - directly in code => false
console.log(isEvilEval());

// test - in evil eval => true
eval('console.log(isEvilEval())');

// test scoped in function => false
Function('console.log(isEvilEval())')();
like image 26
Ian Carter Avatar answered Oct 03 '22 18:10

Ian Carter