JAVA安全-模板注入-Thymeleaf

admin 2024年12月9日23:19:44评论9 views字数 4447阅读14分49秒阅读模式
JAVA安全-模板注入-Thymeleaf
JAVA安全-模板注入-Thymeleaf

点击上方蓝字·关注我们

免责声明
JAVA安全-模板注入-Thymeleaf

由于传播、利用本公众号菜狗安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号菜狗安全及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,会立即删除并致歉。

前言
JAVA安全-模板注入-Thymeleaf

这篇文章作为JAVA模板注入的开篇,分析Thymeleaf模板引擎注入问题后续还会分析FreeMarker、velocity等模板引擎

文章目录
JAVA安全-模板注入-Thymeleaf
介绍项目创建简单使用安全问题实际功能案例漏洞原理分析最后

介绍

Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎

模板引擎?你可能第一次听说模板引擎,估计你会禁不住想问:什么是模板引擎?

  • 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的html文档。从字面上理解模板引擎,最重要的就是模板二字,这个意思就是做好一个模板后套入对应位置的数据,最终以html的格式展示出来,这就是模板引擎的作用。
  • 对于模板引擎的理解,可以这样形象的做一个类比:开会!相信你在上学初高中时候每次开会都要提前布置场地、拿小板凳、收拾场地。而你上了大学之后每次开会再也不去大操场了,每次开会都去学校的大会议室,桌子板凳音响主席台齐全,来个人即可,还可复用……。模板引擎的功能就类似我们的会议室开会一样开箱即用,将模板设计好之后直接填充数据即可而不需要重新设计整个页面。提高页面、代码的复用性

项目创建

我们还是使用springboot创建

JAVA安全-模板注入-Thymeleaf

点击下一步

JAVA安全-模板注入-Thymeleaf

勾选thymeleaf和web服务然后创建,等待项目构建即可

简单使用

我们可以在application.properties中配置我们模板的存放目录

JAVA安全-模板注入-Thymeleaf

我们默认创建是在templates目录下,但是我们没有这个目录所以需要创建

然后在templates目录下创建一个index文件,文件内容随便写点东西

JAVA安全-模板注入-Thymeleaf

然后我们就可以编写我们的访问路由了

@ControllerpublicclassThyremeafController {@GetMapping("/index")publicStringindex() {return"index";    }

注意这里使用的是@Controller而不是@RestController

我们运行一下访问index目录查看返回,是不是访问我们创建的index.html文件

JAVA安全-模板注入-Thymeleaf

安全问题

它这个安全问题产生有两条件

一、存在漏洞的版本

Thymeleaf 3.0.0 至 3.0.11 版

该漏洞在Thymeleaf 3.0.12及以后版本已经得到修复,但还是存在一些 Bypass 的方式

二、可控的写法

  • 1、return内容可控
  • 2、URL路径可控
  • 3、模板内容可控

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

实际功能案例

我们在网上访问一些网站的时候它的url地址中可能会存在一个参数?lang=cn

比如下面这个网站

https://www.nvidia.cn/Download/index.aspx?lang=cn
JAVA安全-模板注入-Thymeleaf

如果我们把lang的参数改为en,那么它就会变成英文

JAVA安全-模板注入-Thymeleaf

这种网站可能就使用了模板引擎来渲染页面。

这里直接上我自己写的代码案例

提前准备好两个文件在模板目录下

JAVA安全-模板注入-Thymeleaf

然后代码也很简单,在我们前面代码的基础上加上参数传递即可

@GetMapping("index")publicStringlang(@RequestParamString lang) {return"index-" + lang;    }

把项目启动,传参访问看下返回结果

JAVA安全-模板注入-Thymeleaf
JAVA安全-模板注入-Thymeleaf

这样我们的功能点就写好了,我们使用网上公开的poc进行测试

__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x
JAVA安全-模板注入-Thymeleaf

计算器弹出来了,复现成功

就像我前面提到的,这个漏洞的利用条件有两个,一个是要满足漏洞版本,第二个才是不安全写法,如果版本不满足,这样写也不会产生安全问题

漏洞原理分析

我们把poc拿出来

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

如果java基础比较好的,应该一眼就看出了,这个poc是spel表达式

new%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()

那么它的安全问题肯定就和spel表达式解析有关,我们深入分析下Thymeleaf模板引擎的渲染过程

首先我们要先了解下Spring MVC架构的执行流程

JAVA安全-模板注入-Thymeleaf
1.用户请求发送到前端控制器 DispatcherServlet。2.前端控制器 DispatcherServlet 接收到请求后,DispatcherServlet 会使用 HandlerMapping 来处理,HandlerMapping 会查找到具体进行处理请求的 Handler 对象。3.HandlerMapping 找到对应的 Handler 之后,并不是返回一个 Handler 原始对象,而是一个 Handler 执行链(HandlerExecutionChain),在这个执行链中包括了拦截器和处理请求的 Handler。HandlerMapping 返回一个执行链给 DispatcherServlet。4.DispatcherServlet 接收到执行链之后,会调用 Handler 适配器去执行 Handler。5.Handler 适配器执行完成 Handler(也就是 Controller)之后会得到一个 ModelAndView,并返回给 DispatcherServlet。6.DispatcherServlet 接收到 HandlerAdapter 返回的 ModelAndView 之后,会根据其中的视图名调用 ViewResolver。7.ViewResolver 根据逻辑视图名解析成一个真正的 View 视图,并返回给 DispatcherServlet。8.DispatcherServlet 接收到视图之后,会根据上面的 ModelAndView 中的 model 来进行视图中数据的填充,也就是所谓的视图渲染。9.渲染完成之后,DispatcherServlet 就可以将结果返回给用户了

因为Spring MVC执行流程不是我们分析的重点,所以这里不着重说,如有需要学习可以参考下面文章:

https://segmentfault.com/a/1190000021848063

在return下断点开始调试

JAVA安全-模板注入-Thymeleaf

触发InvocableHandlerMethod.class#invokeForRequest,然后通过doInvoke开始处理我们传入的参数

JAVA安全-模板注入-Thymeleaf

接着进入invokeAndHandle调用invokeForRequest方法,这个方法主要功能是处理 Web 请求并返回结果,也就是获取我们传入的视图名称

JAVA安全-模板注入-Thymeleaf

往下走,来到handleReturnValue方法,主要功能是处理控制器方法的返回值

JAVA安全-模板注入-Thymeleaf

跟进

JAVA安全-模板注入-Thymeleaf

然后触发第二个handleReturnValue方法,获取视图信息

JAVA安全-模板注入-Thymeleaf

接着来到DispatcherServlet#render方法

JAVA安全-模板注入-Thymeleaf

这里获取视图对象要开始渲染视图了,在746行调用view.render,这里的view就是我们的模板引擎

JAVA安全-模板注入-Thymeleaf

触发ThymeleafView#render

JAVA安全-模板注入-Thymeleaf

接着触发renderFragment方法

JAVA安全-模板注入-Thymeleaf

这里viewTemplateName是我们传入的poc,我们看下后续是着么处理它的,在264行判断viewTemplateName是否包含::

JAVA安全-模板注入-Thymeleaf

这个匹配::是干啥的呢?这个其实是区分片段表达式的,这里简单介绍一下

文本表达式:th:text="${...}":用于设置元素的文本内容。属性表达式:th:attr="attr-name=${...}":用于设置元素的属性值。条件表达式:th:if="${...}":如果条件为真,则显示元素。th:unless="${...}":如果条件为假,则显示元素。循环表达式:th:each="item : ${...}":用于遍历集合。URL 表达式:th:href="@{/path/to/resource}":用于生成 URL。内联表达式:[[${...}]]:用于在文本中嵌入变量。片段插入:th:insert="~{template :: fragment}":插入另一个模板中的片段。th:include="~{template :: fragment}":包含另一个模板中的片段。

那么从之前给到的poc就知道,这里肯定是要满足片段表达式的,我们回到代码,这里如果不满足::就会把viewTemplateName赋值给templateName,然后通过viewTemplateEngine.process方法处

JAVA安全-模板注入-Thymeleaf

然后我们是要满足::,也就是另一条处理流程,通过parser.parseExpression方法处理

JAVA安全-模板注入-Thymeleaf

我们跟进parseExpression方法

JAVA安全-模板注入-Thymeleaf

又会触发一个parseExpression方法,继续跟进

JAVA安全-模板注入-Thymeleaf

接着触发preprocess方法,这里面有两个判断

JAVA安全-模板注入-Thymeleaf
JAVA安全-模板注入-Thymeleaf

第一个判断传入的数据有没有_,第二个是正则匹配\_\_(.*?)\_\_这个也就是我们poc为什么要这样写的原因,最后来到120行,使用StandardExpressionPreprocessor.preprocess解析我们的poc,也就是spel表达式

JAVA安全-模板注入-Thymeleaf

到这里整个流程就跟完了,我们现在再把poc拿出来拆分一下

POC:__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}__::.x

::.x是代码片段表达式的格式,这里的.x是片段表达式对应的名字,可以是任意字符串

__${xxx}__通过正则规则,匹配spel表达式,也就是

$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()%7d
最后

如有技术问题可扫描交流群二维码进群交流

JAVA安全-模板注入-Thymeleaf

如果二维码过期,可以加我联系方式备注“交流群

JAVA安全-模板注入-Thymeleaf

原文始发于微信公众号(菜狗安全):JAVA安全-模板注入-Thymeleaf

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年12月9日23:19:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JAVA安全-模板注入-Thymeleafhttp://cn-sec.com/archives/3478238.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息