服务器端模版注入SSTI分析与归纳

Qu3een 2022-01-27 10:19:00

0x00 背景

本文针对基于java的三种常见的模版引擎(FreeMarker、Velocity、Thymeleaf)所引起的服务端模版注入漏洞SSTI进行分析、整理和总结。所谓模版引擎,简单来讲就是利用模版语言的特定语法处理模版中的特定参数,帮助动态渲染数据到view层或生成电子邮件、配置文件、HTML网页等输出文本。

0x01 FreeMarker

模板文件存放在Web服务器上,当访问指定模版文件时, FreeMarker会动态转换模板,用最新的数据内容替换模板中 ${...}的部分,然后返回渲染结果。

FreeMarker模版语言说明

文本:包括 HTML 标签与静态文本等静态内容,该部分内容会原样输出
插值:语法为 ${}, 这部分的输出会被模板引擎计算的值来替换。
指令标签:<# >或者 <@ >。如果指令为系统内建指令,如assign时,用<# >。如果指令为用户指令,则用<@ >。利用中最常见的指令标签为<#assign>,该指令可创建变量。
注释:由 <#---->表示,注释部分的内容会 FreeMarker 忽略

FreeMarker模版注入分析

这里介绍FreeMarker的两个内置函数—— newapi

内置函数new

可创建任意实现了TemplateModel接口的Java对象,同时还可以触发没有实现 TemplateModel接口的类的静态初始化块。
以下两种常见的FreeMarker模版注入poc就是利用new函数,创建了继承TemplateModel接口的freemarker.template.utility.JythonRuntimefreemarker.template.utility.Execute

<#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("calc")</@value>
<#assign value="freemarker.template.utility.Execute"?new()>${value("calc")}

防御措施:
2.3.17版本以后,官方版本提供了三种TemplateClassResolver对类进行解析:
1、UNRESTRICTED_RESOLVER:可以通过 ClassUtil.forName(className) 获取任何类。
2、SAFER_RESOLVER:不能加载 freemarker.template.utility.JythonRuntimefreemarker.template.utility.Executefreemarker.template.utility.ObjectConstructor这三个类。
3、ALLOWS_NOTHING_RESOLVER:不能解析任何类。
可通过freemarker.core.Configurable#setNewBuiltinClassResolver方法设置TemplateClassResolver,从而限制通过new()函数对freemarker.template.utility.JythonRuntimefreemarker.template.utility.Executefreemarker.template.utility.ObjectConstructor这三个类的解析。
11.png

api内置函数

value?api 提供对 value 的 API(通常是 Java API)的访问,例如 value?api.someJavaMethod()value?api.someBeanProperty。可通过 getClassLoader获取类加载器从而加载恶意类,或者也可以通过 getResource来实现任意文件读取。
但是,当api_builtin_enabled为true时才可使用api函数,而该配置在2.3.22版本之后默认为false。

FreeMarker模版注入示例:

测试版本——2.3.23
12.png

模版注入执行任意命令
渲染内容:

<#assign value="freemarker.template.utility.Execute"?new()>${value("open /Applications/Calculator.app")}

13.png

若配置如下,执行命令失败。

cfg = new Configuration();
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);

image.png

总结

FreeMarker模版注入已有不错的安全防御措施,可通过配置来禁止解析常见的危险类,同时限制对api函数的使用。

0x02 Velocity

近年来,不少中间件服务器,如Solr、协同办公软件,如confluenceJria等被爆存在velocity模版注入漏洞(CVE-2019-17558、CVE-2019-3394、CVE-2021-43947等)。Velocity较FreeMarker而言更加常见。

基本语法

# 关键字
Velocity关键字都是使用#开头的,如#set、#if、#else、#end、#foreach等
$变量
Velocity变量都是使用\$开头的,如:$name$msg
{}变量
Velocity对于需要明确表示的Velocity变量,可以使用{}将变量包含起来。
变量
如果某个Velocity变量不存在,那么页面中就会显示$xxx的形式,为了避免这种形式,可以在变量名称前加上!。如页面中含有$msg,如果msg有值,将显示msg的值;如果不存在就会显示$msg。这是我们不希望看到的,为了把不存在的变量显示为空白,可以使用$!msg

Velocity模版注入示例

111.png

Velocity 模版注入执行任意命令
222.png

有多种Velocity模版渲染进行命令执行的方式,可根据velocity模版的语法对poc进行变形利用,这里不进行详细阐述。

0x03 Thymeleaf

Thymeleaf是一款Spring官方支持的一款服务端模板引擎,一般用于Spring项目中渲染数据到View层。默认前缀:/templates/,默认后缀:.html

Thymeleaf模版渲染示例

Controller代码:
121.png

根据return "hello"渲染 resources/templates/下的hello.html文件到view层。将参数name作为要渲染的内容放入Model中。
hello.html内容:
b82810d5-83ac-49bb-8a7c-1f95e04a31fe.png

渲染结果:
3.png

模版文件中使用th:fragment、th:text属性包含的内容才可以被thymeleaf进行渲染处理。渲染过程中在${xx}中的内容可执行SPEL表达式。

Thymeleaf模版注入漏洞原理和场景

Thymeleaf模版注入漏洞分两种场景,按照经Servlet处理后得到的viewTemplateName包含"::"和不包含"::"两种情况。
4.png
1. 当不包含"::"时
直接处理viewTemplateName对应的模版文件。如果模版文件中包含th:text等形式的属性且内容可控,即可通过向th:text属性值中注入SPEL表达式,经渲染后可执行该表达式。如下图所示:
image.png

2. 当包含“::”时
触发绝大多数Thymeleaf模版注入漏洞的场景是这种情况。

如果符合__(.*?)__正则匹配,则取出(.*?)的数据当作表达式解析执行。

10.png

由此可见,获取的viewTemplateName值是触发漏洞的关键。如果viewTemplateName可控,则可设计viewTemplateName值使之成功被渲染从而执行SPEL表达式。

下面介绍2种用户可控viewTemplateName的场景:

1、return 语句中包含用户可控数据

比如 return语句中包含请求参数或者路径变量
5.png

2、没有return语句且路由可控

形如:
6.png
没有return语句的情况下,会通过org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator#getViewName方法从请求路径中获取ViewName。处理逻辑如下:

总结该逻辑,取路由中第一个/和最后一个.之间的部分,因此在路由可控的情况下,设计路由形如:
::__spel__.xx即可实现模版注入从而执行任意表达式。
7.png

防御措施

1、配置@ResponseBody或者@RestController
经以上注解后不会进行View解析而是直接返回。
2、在方法参数中加上 HttpServletResponse参数
此时spring会认为已经处理了response响应而不再进行视图解析。
3、在返回值前面加上 "redirect:"——经RedirectView处理。

0x04 总结

本文抛砖引玉,对Java常见的三种服务端模版引擎的渲染原理和模版注入场景进行简单说明和总结。其中每种引擎在渲染过程中,如何绕过安全沙箱,如何进行表达式的各种变形从而实现更多利用等仍然是很值得研究和探讨的问题。

评论

Qu3een

这个人很懒,没有留下任何介绍

twitter weibo github wechat

随机分类

逻辑漏洞 文章:15 篇
Android 文章:89 篇
无线安全 文章:27 篇
前端安全 文章:29 篇
数据安全 文章:29 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Yukong

🐮皮

H

HHHeey

好的,谢谢师傅的解答

Article_kelp

a类中的变量secret_class_var = "secret"是在merge

H

HHHeey

secret_var = 1 def test(): pass

H

hgsmonkey

tql!!!

目录