服务端模板注入(SSTI)沙箱逃逸技术
服务端模板注入(SSTI)沙箱逃逸技术
服务端模板注入(Server-Side Template Injection, SSTI) 是一种随着现代 Web 框架(如 Python 的 Flask/Django,Java 的 Spring,PHP 的 Twig)普及而兴起的高危漏洞。当应用将用户输入直接作为模板内容进行渲染时,攻击者可以注入模板引擎的专有语法,不仅能读取敏感数据,更可通过沙箱逃逸(Sandbox Escape)直击底层操作系统,实现 RCE。
本文将深度剖析主流模板引擎(Jinja2、FreeMarker、Twig 等)的底层机制与沙箱逃逸实战技巧。
1. SSTI 漏洞的成因与识别
与 XSS 不同,XSS 是在客户端(浏览器)渲染,而 SSTI 是在服务端渲染。 漏洞成因:开发者错误地将用户输入拼接到模板字符串中,而不是将其作为变量传入模板。 例如(Python Flask):
识别与探测:
向参数输入 {{7*7}} 或 ${7*7}。如果返回页面中包含 49,则明确存在模板引擎解析。
红队通常使用特定的探测序列来确定具体的模板引擎:
${7*7}->49-> 可能是 FreeMarker (Java) 或 Smarty (PHP){{7*7}}->49-> 可能是 Jinja2 (Python) 或 Twig (PHP)<%= 7*7 %>->49-> 可能是 ERB (Ruby)
2. Python Jinja2 / Tornado 沙箱逃逸
Python 体系下的 SSTI 是最为经典的沙箱逃逸场景。由于 Python 的万物皆对象特性,我们可以通过魔术方法顺藤摸瓜,从一个普通的字符串对象一路爬升到系统模块(os / subprocess)。
2.1 逃逸利用链 (Gadget Chain)
以字符串 "" 为起点,寻找执行系统命令的类:
- 获取所属类:
"".__class__(返回<class 'str'>) - 获取基类:
"".__class__.__mro__[1](返回<class 'object'>) - 获取所有子类:
"".__class__.__mro__[1].__subclasses__()(返回环境中加载的所有类的列表) - 寻找利用类:在子类列表中寻找包含
__builtins__、可以调用os或eval的类。常用的跳板类有:<class 'os._wrap_close'>(包含popen)<class 'warnings.catch_warnings'>(可导入sys模块)
2.2 实战 Payload 构造
假设我们通过脚本遍历,发现 os._wrap_close 位于子类列表的第 132 位。我们可以构造如下 Payload 实现 RCE:
2.3 WAF 绕过技巧
- 过滤了
__class__或.: 利用attr()过滤器或[]获取属性:""['__class__']或""|attr("__class__") - 过滤了单/双引号:
利用
request.args传参:{{ ().__class__.__bases__[0].__subclasses__()[132].__init__.__globals__[request.args.cmd1](request.args.cmd2).read() }}&cmd1=popen&cmd2=id - 过滤了
_(下划线): 利用 Hex 或 Unicode 编码配合request.args绕过。
3. Java FreeMarker / Thymeleaf 注入
Java 的模板引擎通常拥有严格的安全限制,但一旦配置不当,依然会被撕破防线。
3.1 FreeMarker RCE
FreeMarker 提供了一个内置的 freemarker.template.utility.Execute 类,可以用于执行系统命令。
Payload:
如果内置的新建对象功能(?new)被禁用,红队可以尝试寻找应用上下文中暴露的 Spring Bean(如 request, response)进行反射调用。
3.2 Thymeleaf 表达式注入
Thymeleaf 广泛应用于 Spring Boot 中。如果模板路径可控,或者模板内容中使用了 __${...}__ 预处理语法,攻击者可以通过 Spring EL (SpEL) 表达式实现代码执行。
SpEL RCE Payload:
由于 Thymeleaf 较新版本的限制,有时需要通过反射结合字符拼接绕过类加载黑名单。
4. PHP Twig / Smarty 注入
PHP 模板引擎的沙箱逃逸相对直接,通常围绕全局变量与内置函数展开。
4.1 Twig (常用于 Symfony 框架)
Twig 早期版本允许通过 _self 全局变量获取环境对象,进而调用过滤器注册函数执行代码。
Payload (Twig 1.x):
Payload (Twig 3.x 绕过):利用 map 或 filter 配合箭头函数,或调用应用暴露的其他危险函数。
4.2 Smarty
Smarty 支持使用 {php} 标签直接写 PHP 代码,但现代版本默认禁用。如果启用了危险标签或未禁用静态类调用,可通过反射执行。
Payload:
5. 总结
服务端模板注入(SSTI)将传统的“代码与数据分离”原则彻底打破。它的本质是受限环境下的元编程(Metaprogramming)攻击。 无论是 Python 的对象继承链、Java 的 SpEL 反射,还是 PHP 的环境劫持,SSTI 都在向安全人员证明:当开发者给予用户渲染界面的画笔时,如果不加上沙箱的枷锁,这支画笔也能轻易改写底层系统的命运。