某系统模板注入分析
字数 1075 2025-08-06 08:35:14

某系统模板注入与SQL注入漏洞分析

漏洞概述

本文分析某系统中存在的两个安全漏洞:SQL注入和FreeMarker模板注入。漏洞点在于程序对传入的SQL语句处理时使用了FreeMarker模板渲染导致的问题。

环境准备

  1. 下载源码并导入IDEA运行(使用MySQL数据库)
  2. 漏洞依赖包反编译后导入IDEA

SQL注入分析

漏洞接口

POST /jeecg-boot/jmreport/queryFieldBySql HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Content-Length: 100

{
    "sql": "select '<#assign value=\"freemarker.template.utility.Execute\"?new()>${value(\"whoami\")}'"
}

代码分析流程

  1. 全局搜索queryFieldBySql定位漏洞代码
  2. 关键过滤方法i.a()定义SQL关键字黑名单:
String[] var1 = " exec |peformance_schema|information_schema|extractvalue|updatexml|geohash|gtid_subset|gtid_subtract| insert | alter | delete | grant | update | drop | chr | mid | master | truncate | char | declare |user()|".split("\\|");
  1. 过滤逻辑:

    • 调用b()方法匹配内联注释
    • 将传入值全部转为小写
    • 调用c()方法判断是否有sleep()函数关键字
    • 与黑名单数组中的关键字逐一匹配,匹配到则拦截并抛出异常
  2. 后续处理:

    • 去除传入参数末尾的分号(如果有)
    • 再次进行i.a()方法的SQL关键字拦截
    • 正则匹配"${"和"}"之间的字符串存入HashMap

绕过方法

分析发现程序漏掉了exp()函数关键字的匹配,使用exp()函数可实现报错注入。

FreeMarker模板注入分析

攻击Payload

select '<#assign value=\"freemarker.template.utility.Execute\"?new()>${value(\"whoami\")}'

代码执行流程

  1. sql参数值作为var1传入FreeMarker处理函数

  2. 创建名为"template"的模板对象

  3. process()方法处理var1var3

  4. accept()方法匹配FTL表达式:

    • 将插值和插值传参赋值给templateElementsToVisit
    • 第一次调用visit()处理<#assign value=\"freemarker.template.utility.Execute\"?new()>
    • 该语句创建一个继承自freemarker.template.TemplateModel类的变量
  5. FreeMarker处理FTL语句后:

    • targetMethod被赋值为freemarker.template.utility.Execute
    • freemarker.template.utility.Execute.exec(argumentStrings)
  6. 第二次调用visit()处理${value(\"calc\")}

  7. 进入关键调用exec(),执行系统命令

漏洞修复方案

官方最新版本使用以下方法修复:

setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER)

该方法禁用了FreeMarker模板注入中常用的三个类的解析。

总结

  1. SQL注入漏洞源于不完善的黑名单过滤,可通过exp()函数绕过
  2. 模板注入漏洞源于未对FreeMarker模板解析进行安全限制
  3. 修复方案通过限制可解析的类来防止危险操作
某系统模板注入与SQL注入漏洞分析 漏洞概述 本文分析某系统中存在的两个安全漏洞:SQL注入和FreeMarker模板注入。漏洞点在于程序对传入的SQL语句处理时使用了FreeMarker模板渲染导致的问题。 环境准备 下载源码并导入IDEA运行(使用MySQL数据库) 漏洞依赖包反编译后导入IDEA SQL注入分析 漏洞接口 代码分析流程 全局搜索 queryFieldBySql 定位漏洞代码 关键过滤方法 i.a() 定义SQL关键字黑名单: 过滤逻辑: 调用 b() 方法匹配内联注释 将传入值全部转为小写 调用 c() 方法判断是否有 sleep() 函数关键字 与黑名单数组中的关键字逐一匹配,匹配到则拦截并抛出异常 后续处理: 去除传入参数末尾的分号(如果有) 再次进行 i.a() 方法的SQL关键字拦截 正则匹配"${"和"}"之间的字符串存入HashMap 绕过方法 分析发现程序漏掉了 exp() 函数关键字的匹配,使用 exp() 函数可实现报错注入。 FreeMarker模板注入分析 攻击Payload 代码执行流程 sql 参数值作为 var1 传入FreeMarker处理函数 创建名为"template"的模板对象 process() 方法处理 var1 和 var3 accept() 方法匹配FTL表达式: 将插值和插值传参赋值给 templateElementsToVisit 第一次调用 visit() 处理 <#assign value=\"freemarker.template.utility.Execute\"?new()> 该语句创建一个继承自 freemarker.template.TemplateModel 类的变量 FreeMarker处理FTL语句后: targetMethod 被赋值为 freemarker.template.utility.Execute 即 freemarker.template.utility.Execute.exec(argumentStrings) 第二次调用 visit() 处理 ${value(\"calc\")} 进入关键调用 exec() ,执行系统命令 漏洞修复方案 官方最新版本使用以下方法修复: 该方法禁用了FreeMarker模板注入中常用的三个类的解析。 总结 SQL注入漏洞源于不完善的黑名单过滤,可通过 exp() 函数绕过 模板注入漏洞源于未对FreeMarker模板解析进行安全限制 修复方案通过限制可解析的类来防止危险操作