前言

Thymeleaf 是一个类似Velocity、FreeMarker 的模板引擎,而且Spring Boot推荐使用Thymeleaf引擎。Michael Stepankin和Aleksei Tiurin发表了两篇文章Spring View Manipulation VulnerabilityExploiting SSTI in Thymeleaf 来讲Thymeleaf模板的安全问题,在此对相关技术进行深入分析。本文相关代码已整合到 thymeleaf-ssti

视图名可控导致SSTI

漏洞代码见HelloController,漏洞特征主要表现为Spring所使用的视图名称中包含攻击者可控的部分。严格意义上来说这个问题不算SSTI,因为漏洞触发时还没有运行到渲染模板的阶段。

根据Michael Stepankin的总结,即使视图名称可控,使用了如下几种方式的代码不受影响

  1. 使用@ResponseBody注解
  2. 模板名称由redirect:forward:开始(不走ThymeleafView渲染)
  3. 参数中有HttpServletResponseresponse已经被处理

漏洞原理分析

使用demo进行调试分析,最开始断点打在控制器的return语句处,尝试从这里开始找Thymeleaf处理视图的入口。但是Spring代码复杂,没能定位到相关逻辑。后从官方文档 Views and View Resolvers in Thymeleaf 中看到 ThymeleafView 和 ThymeleafViewResolver,在其中成功打断。

在Controller中执行return后,Spring会自动调度Thymeleaf引擎寻找并渲染模板。简化的流程如下:

org.thymeleaf.spring5.view.ThymeleafViewResolver.createView() //根据视图名创建对应的View。 对redirect:和forward:有特殊处理,其他情况则使用ThymeleafView进行渲染展示
org.thymeleaf.spring5.view.ThymeleafView.render()
org.thymeleaf.spring5.view.ThymeleafView.renderFragment() //根据视图名解析模板名称
org.thymeleaf.TemplateEngine.process() //渲染模板
……

看看renderFragment中如何解析模板名称。这里将模板名称进行拼接 "~{" + viewTemplateName + "}",然后使用parseExpression进行解析

org.thymeleaf.standard.expression.StandardExpressionParser.parseExpression() 首先会对表达式进行preprocess预处理

org.thymeleaf.standard.expression.StandardExpressionPreprocessor.preprocess(),解析出__xx__中间的部分作为表达式执行。

然后在org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression()中使用SpEL执行表达式,触发RCE

危险的预处理

我们已经知道上文漏洞的触发点是Thymeleaf的预处理功能。那预处理在模板中是否也能工作,是否也会存在SSTI漏洞?
先抛开疑问看下Thymeleaf模板的语法,模板中有以下几种常用的表达式:

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

以上任意一种表达式内嵌使用预处理,只要预处理的数据可控,均能造成SSTI漏洞。以变量表达式为例,对应的模板url.html

1
2
3
4
5
6
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<a th:href="@{__${link}__}">test</a>
</body>
</html>

在控制器中获取参数link并传递给模板

1
2
3
4
5
6
//GET /url?link=($%7bT(java.lang.Runtime).getRuntime().exec('calc')%7d)
@GetMapping("/url")
public String url(@RequestParam(name="link") String link, Model model) {
model.addAttribute("link", link);
return "url";
}

渲染模板时引擎会解析标签处理属性,简化的调用流程如下

org.thymeleaf.util.ProcessorConfigurationUtils.ElementTagProcessorWrapper.process()
org.thymeleaf.processor.element.AbstractElementTagProcessor.process()
org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess()
org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess() //解析属性,执行表达式

此时会通过EngineEventUtils.computeAttributeExpression将属性计算成表达式,经过预处理后表达式如下,执行时将触发恶意SpEL表达式

总结

Thymeleaf模板安全问题主要依赖预处理功能,根据执行入口的不同分为两种情况:

  1. 视图名称可控,即 return ‘xxx’ + var
  2. 模板预处理变量可控,即 @{/xx/${var}}

参考链接

https://raledong.gitbooks.io/using-thymeleaf/content/
https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#views-and-view-resolvers-in-spring-mvc
https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/
https://www.veracode.com/blog/secure-development/spring-view-manipulation-vulnerability




Published with Hexo and Theme by Kael
X