从0到1挖掘freemaker 模板注入
字数 1717 2025-08-29 08:30:13
FreeMarker 模板注入漏洞分析与利用
1. DataGear 简介
DataGear 是一款开源免费的数据可视化分析平台,具有以下特点:
- 支持多种数据源:SQL、CSV、Excel、HTTP 接口、JSON等
- 支持多种数据库:MySQL、Oracle、PostgreSQL、SQL Server等
- 提供70+开箱即用的图表类型
- 支持自定义HTML网页作为数据看板模板
2. FreeMarker 模板注入漏洞原理
2.1 FreeMarker 的 new 内置函数
FreeMarker 模板引擎中的 new 关键字用于创建新的实例对象:
- 可以实例化Java类
- 可以在创建对象时直接调用构造函数初始化属性
- 允许在模板中动态创建Java对象
2.2 危险内置类
FreeMarker 提供了几个危险的辅助类:
2.2.1 freemarker.template.utility.ObjectConstruct
- 用于创建Java对象并转换为FreeMarker模板数据模型
- 允许模板动态实例化对象
2.2.2 freemarker.template.utility.JythonRuntime
- 用于与Jython(基于Java的Python解释器)交互
- 允许模板执行Python脚本
2.2.3 freemarker.template.utility.Execute
- 重写了Writer类的flush和close方法
- 接收的字符序列会被附加到StringBuilder缓冲区
- 调用flush时会执行缓冲区内容作为Python代码
2.3 利用方式
基于new构建对象的三种payload:
-
使用
<#assign>标签定义变量:<#assign value="freemarker.template.utility.ObjectConstructor"?new()> -
使用JythonRuntime执行Python代码:
<#assign value="freemarker.template.utility.JythonRuntime"?new()> -
使用Execute执行系统命令:
<#assign value="freemarker.template.utility.Execute"?new()>
2.4 API 内置函数
api内建函数用于调用Java API:
- 允许模板访问和调用Java类及其方法
- 可以获取当前对象的类加载器
- 从FreeMarker 2.3.22开始默认禁用
示例payload:
<#assign classLoader=object?api.class.protectionDomain.classLoader>
3. 漏洞复现
3.1 漏洞位置
漏洞存在于DataGear的/dataSet/resolveSql路由,对应代码位于:
org/datagear/web/controller/DataSetController.java
3.2 漏洞触发流程
- 接收请求参数:通过
@RequestBody接收ResolveSqlParam对象 - 调用解析方法:将参数传递给
resolveSqlTemplate方法进行SQL解析 - SQL解析过程:
DataSetFmkTemplateResolvers.SQL.resolve解析SQL语句- SQL查询语句作为实例化
TemplateContext的参数 - 通过
getValues获取模板内容并解析 - 将模板封装在
templateObj对象中 - 调用
process方法解析value
3.3 命令执行
在模板解析过程中,当循环到最内层内容时,会执行注入的命令,并将执行结果作为模板渲染的结果返回。
4. 漏洞利用示例
4.1 环境搭建
- 下载DataGear源码:https://gitee.com/datagear/datagear
- 导入IDEA,使用Maven构建
- 创建数据库并启动应用
4.2 执行系统命令
使用以下payload可以执行任意系统命令:
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("cmd /c whoami") }
成功执行后会返回命令执行结果。
5. 漏洞分析
5.1 关键代码分析
-
DataSetController.java中的resolveSql方法:public String resolveSql(@RequestBody ResolveSqlParam resolveSqlParam) -
resolveSqlTemplate方法:private String resolveSqlTemplate(String sql, Map<String, Object> paramValues, List<DataSetParam> dataSetParams) -
模板解析过程:
TemplateContext templateContext = new TemplateContext(sql, paramValues, dataSetParams); return DataSetFmkTemplateResolvers.SQL.resolve(templateContext);
5.2 安全建议
- 升级FreeMarker到最新版本
- 禁用危险的内置函数和类
- 对用户输入进行严格的过滤和验证
- 使用沙箱环境限制模板的执行权限
6. 总结
DataGear中的FreeMarker模板注入漏洞源于对用户输入的不当处理,攻击者可以通过构造特殊的模板表达式实现任意命令执行。开发人员应当重视模板引擎的安全配置,避免直接使用用户输入作为模板内容。