Java中SSTI漏洞分析

SSTI:Server Side Template Injection,即服务端模板注入

0x00 前言

SSTI:Server Side Template Injection,即服务端模板注入。
在web开发中,为了使用户界面与业务数据分离,提升开发效率,因此会使用模板引擎来生成一个标准的HTML文档用来数据的展示。
本文主要针对java中Velocity、FreeMarker以及Thymeleaf三个模板的注入漏洞进行分析

0x01 velocity

1.1 Velocity简介

Apache Velocity是一个基于Java的模板引擎,它提供了一个模板语言去引用由Java代码定义的对象。Velocity旨在确保Web应用程序在表示层和业务逻辑层之间的隔离(即MVC设计模式)。
语法概要
在 Velocity 中所有的关键字都是以#开头的,而所有的变量则是以$开头
"#"用来标识Velocity的脚本语句,包括#set、#if 、#else、#end、#foreach、#end、#iinclude、#parse、#macro等;
"$"用来标识一个对象(或理解为变量);如$i、$msg、$TagUtil.options(...)等;
"{}"用来明确标识Velocity变量;
"!"用来强制把不存在的变量显示为空白;

1.2 漏洞利用

环境:java-sec-code(https://github.com/JoyChou93/java-sec-code/
服务端代码:

1.jpg

访问/ssti/velocity?template=并提交payload

2.jpg

断点进行拦截提交的payload,并跟进Velocity.evaluate方法进行分析

3.jpg

继续跟进evaluate方法

4.jpg

RuntimeInstance类中封装了evaluate方法

5.jpg

继续跟进分析,可以看到parse方法对reader进行解析

6.jpg

跟进分析,可以看出进行一次判断,如果nodeTree不为空则进入render方法

7.jpg

继续跟进分析,多次循环后会进行execute方法下进行for循环,进行payload的遍历

8.jpg

遍历完成后命令成功执行

9.jpg

0x02 FreeMarker

2.1 FreeMarker简介

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

10.jpg

当需要一个类似Output的页面时,就可以利用FreeMarker模板代码来进行生成。
FreeMarker模板代码:

<html>
<head>
    <title>Welcome</title>
</head>
<body> 
    <h1>Welcome ${user}!</h1>
</body>
</html>

模板文件存放在Web服务器上,就像通常存放静态HTML页面那样。当有人来访问这个页面, FreeMarker将会介入执行,然后动态转换模板,用最新的数据内容替换模板中 ${...} 的部分, 之后将结果发送到访问者的Web浏览器中。
FreeMarker模板注入主要利用freemarker.template.utility里面的Excute类来执行命令,利用FreeMarker中的内建函数new,new是用来创建一个确定的 TemplateModel 实现变量的内建函数,新建一个Excute类,并将需要执行的命令传入其中。
具体的payload的构造按照该内建函数的用法进行构造,可以参考http://freemarker.foofun.cn/ref_builtins_expert.html#ref_builtin_new,具体用法如下:

<#-- Creates an user-defined directive be calling the parameterless constructor of the class -->
<#assign word_wrapp = "com.acmee.freemarker.WordWrapperDirective"?new()>
<#-- Creates an user-defined directive be calling the constructor with one numerical argument -->
<#assign word_wrapp_narrow = "com.acmee.freemarker.WordWrapperDirective"?new(40)>

2.2 漏洞利用

服务端代码:

11.jpg

模板代码:

12.jpg

payload:<#assign ex="freemarker.template.utility.Execute"?new()>${ ex("calc") }

请求/hello获取模板,可以看出成功实现,对应数据提交到了模板中展示

13.jpg

构造payload,请求/template

14.jpg

post提交payload,注入恶意模板代码,并在for循环中进行断点调试

15.jpg

可以看出stringLoader,也就是StringTemplateLoader函数下的putTemplate通过key:value的形式获取到传入的payload,达到注入hello.ftl的效果

16.jpg

再访问/hello获取模板,达到恶意代码执行的效果。

17.jpg

0x03 Thymeleaf

3.1 Thymeleaf简介

Thymeleaf是springboot官方推荐使用的java模板引擎,提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
Thymeleaf简单表达式:

  • 变量表达式: ${...}
  • 选择变量表达式: *{...}
  • 消息表达式: #{...}
  • 链接网址表达式: @{...}
  • 片段表达式: ~{...}

简单的Thymeleaf模板代码


<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Good Thymes Virtual Grocery</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" media="all" 
          href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
  </head>
  <body>
    <p th:text="#{home.welcome}">Welcome to our grocery store!</p>  
  </body>
</html>

3.2 漏洞利用

环境:spring-view-manipulation(https://github.com/veracode-research/spring-view-manipulation/
服务端代码:

18.jpg

模板代码:

19.jpg
漏洞利用方法一:

payload:__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x
uri:/path?lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x

20.jpg

进行数据提交,成功获取到提交的payload

21.jpg

进行跟进,在 org.thymeleaf.spring5.view 中的 ThymeleafView类中thymeleaf 在解析包含 :: 的模板名时,会将其作为表达式去进行执行

22.jpg

继续跟进,在StandarExpressionPreprocessor类中利用正则对__(.*?)__进行匹配,也就是payload__中间的内容

23.jpg

匹配处理完成后为${new.java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}

24.jpg

继续跟进execute

25.jpg

可以看到是使用的SPEL 引擎,满足**(${SPEL})**::格式达到注入的效果

26.jpg

进入后成功执行代码

27.jpg
漏洞利用方法二:

payload:__$%7BT(java.lang.Runtime).getRuntime().exec(%22calc%22)%7D__::.x
uri:/doc/__$%7BT(java.lang.Runtime).getRuntime().exec(%22calc%22)%7D__::.x

28.jpg

因为该请求无返回值,因此返回值无法作为模板名,这个时候传入的参数也就是payload便作为了视图名

29.jpg

进行跟进,在 org.thymeleaf.spring5.view 中的 ThymeleafView类中thymeleaf 在解析包含 :: 的模板名时,会将其作为表达式去进行执行

30.jpg

继续跟进,在StandarExpressionPreprocessor类中利用正则对__(.*?)__进行匹配,也就是payload__中间的内容,匹配处理完成后为${T(java.lang.Runtime).getRuntime().exec(%22calc%22)}

31.jpg

可以看到是使用的SPEL 引擎,满足**(${SPEL})**::格式达到注入的效果

32.jpg

  • 发表于 2022-06-15 09:45:35
  • 阅读 ( 9127 )
  • 分类:漏洞分析

0 条评论

请先 登录 后评论
阿蓝
阿蓝

7 篇文章