前言
Thymeleaf 是一个类似Velocity、FreeMarker 的模板引擎,而且Spring Boot推荐使用Thymeleaf引擎。Michael Stepankin和Aleksei Tiurin发表了两篇文章Spring View Manipulation Vulnerability 、Exploiting SSTI in Thymeleaf 来讲Thymeleaf模板的安全问题,在此对相关技术进行深入分析。本文相关代码已整合到 thymeleaf-ssti
视图名可控导致SSTI
漏洞代码见HelloController,漏洞特征主要表现为Spring所使用的视图名称中包含攻击者可控的部分。严格意义上来说这个问题不算SSTI,因为漏洞触发时还没有运行到渲染模板的阶段。
根据Michael Stepankin的总结,即使视图名称可控,使用了如下几种方式的代码不受影响
- 使用
@ResponseBody
注解 - 模板名称由
redirect:
或forward:
开始(不走ThymeleafView渲染) - 参数中有
HttpServletResponse
,response
已经被处理
漏洞原理分析
使用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 |
|
在控制器中获取参数link并传递给模板
1 | //GET /url?link=($%7bT(java.lang.Runtime).getRuntime().exec('calc')%7d) |
渲染模板时引擎会解析标签处理属性,简化的调用流程如下
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模板安全问题主要依赖预处理功能,根据执行入口的不同分为两种情况:
- 视图名称可控,即 return ‘xxx’ + var
- 模板预处理变量可控,即 @{/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