由WCTF2020 Thymeleaf分析payload形式

admin 2020年11月30日17:19:20评论48 views字数 2930阅读9分46秒阅读模式

更多全球网络安全资讯尽在邑安全

前段时间参加了WCTF2020比赛,当时主要是通过盲测的方式找到了正确的payload,但是对于网上出现的多种payload形式并不了解其原因,因此有了这篇文章。根据网上出现的payload以及比赛中用到的payload,主要有以下3种。

__${xxx}__::.x
__${xxx}__::
__${xxx}__::x.

Thymeleaf这道题采用的环境是Spring+Thymeleaf,当web应用基于spring,Thymeleaf使用SpEL,否则使用OGNL。

Thymeleaf 预处理

Thymeleaf模版引擎有一个特性叫做表达式预处理(Expression PreProcessing),置于__...__之中会被预处理,预处理的结果再作为表达式的一部分继续处理。举例如下:

#{selection.__${sel.code}__}
#{selection.value}

解析过程分析

01. 获取view

当访问一个api时,spring与Thymeleaf是如何配合的呢?首先定位到org.springframework.web.servlet.DispatcherServlet#doDispatch(),这是都会经过的一个点。

由WCTF2020 Thymeleaf分析payload形式

在该函数中获取ModelAndView对象,看图中的两行代码,会经过2个过程。


  1. ha.handle()

  2. applyDefaultViewName()

首先来看第一个过程,跟进handle()方法,直接跟进到org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal()

由WCTF2020 Thymeleaf分析payload形式

这里可以看到mav的获取方法,跟进invokeHandlerMethod(),直接跟进到invokeAndHandle()。

由WCTF2020 Thymeleaf分析payload形式

这里的returnValue是否有值,决定了2种类型的payload。returnValue的获取会invoke此Request对应的函数获取返回值,例如下面这个例子访问/path时,获取return的值为user/{lang}/welcome作为ModelAndView的view值。


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

但如果例子是下面这样的呢?此时ModelAndView的view值为null。

@DeleteMapping(value = "/{username}")
public void deleteUser(@PathVariable(name = "username") String username) {}
}

接着往下来到第二个过程,跟进applyDefaultViewName()。

由WCTF2020 Thymeleaf分析payload形式

在这里,若ModelAndView对象中的view不为空,则啥也不做,否则会获取DefaultView作为View。来看看defaultview是如何获取的。跟进getDefaultViewName(),继续跟进viewNameTranslator.getViewName()。

由WCTF2020 Thymeleaf分析payload形式

在该方法中首先获取uri的path值,然后进入transformPath()方法,最后和prefix以及suffix进行拼接,即为ViewName。跟进transformPath()。

由WCTF2020 Thymeleaf分析payload形式

在这里会去掉前后的/,它会将.及之后的内容当作扩展名,会截掉.以及之后的内容。因此,这种情况下需要在payload后增加一个.以保证payload内容完整。

02. 解析表达式

由WCTF2020 Thymeleaf分析payload形式

获取到view后,接着往下跟进processDispatchResult()。

由WCTF2020 Thymeleaf分析payload形式

继续跟进render()。

由WCTF2020 Thymeleaf分析payload形式

首先获取viewName,然后调用resolveViewName(),选择bestView,这里的往往会返回ThymeleafView,保持了和view一样的值。然后接着往下,调用了view.render(),即ThymeleafView.render()。跟进。
由WCTF2020 Thymeleaf分析payload形式
继续跟进renderFragment()。
由WCTF2020 Thymeleaf分析payload形式在这里会判断viewTemplateName是否包含::,然后调用IStandardExpressionParser.parseExpression()解析~{viewTemplateName}表达式。
由WCTF2020 Thymeleaf分析payload形式继续调用parseExpression()。

由WCTF2020 Thymeleaf分析payload形式

这里首先调用preprocess对__${}__里的内容进行预处理,结果存入 preprocessedInput,然后调用Expression.parse()进行第二次解析表达式。
在第一次处理时,只要__${}__里面的语法正确,是一定会被执行的。执行完的第二次表达式解析是否正确就不一定了。如果第二次执行失败,则会显示原来的viewTemplateName值,而没有回显,但事实上已经执行了恶意语句。影响第二次执行失败与否与~{}里的语法格式有关。

由WCTF2020 Thymeleaf分析payload形式

~{}中出现::,其后面需要有值。


场景分析

01. 场景一

__${}__:: 在使用veracode-research的环境时,这种类型的payload确实能够成功。这和它一开始获取到的view有着很大的关系。

由WCTF2020 Thymeleaf分析payload形式

像上图的这种,拼接后的结果为~{user/__${}__::/welcome},第一次解析后的结果为~{user/xxx::/welcome}这样的完全是合法的语法。

__${}__::.x 是veracode-research在其github中展现的payload,能成功,但是不需要.x也能成功。

02. 场景二

__${}__::x. 是在wctf中用到的payload,由于是void类型,在获取view时,是使用了path值,并截掉了.及之后的内容。因此需要在::后面有值且在最后有一个.

由WCTF2020 Thymeleaf分析payload形式

03. 场景三

由WCTF2020 Thymeleaf分析payload形式

显而易见,这种情况下不需要::,但是结尾需要.

04. 场景四

由WCTF2020 Thymeleaf分析payload形式

这种情况下,不能成功。因为它设置了@ResponseBody,在这种情况下,sring会将return的值作为响应内容,而不是模版。

05. 更多场景

还有多种场景可自行分析......

小结

综上,在一个spring+thymeleaf的应用中,进行模版注入需要分析当前的场景,然后才能判断是否有漏洞,在做检测时比较难。比较通用的payload形式为__${}__::x.,有回显。在无回显的情况下,只要保证__${}__里的语法正确,以及整个viewTemplateName中包含::即可,无论::的位置在哪儿都行。

原文来自:先知社区

原文链接:https://xz.aliyun.com/t/8568

欢迎收藏并分享朋友圈,让五邑人网络更安全

由WCTF2020 Thymeleaf分析payload形式

欢迎扫描关注我们,及时了解最新安全动态、学习最潮流的安全姿势!


推荐文章

1

新永恒之蓝?微软SMBv3高危漏洞(CVE-2020-0796)分析复现

2

重大漏洞预警:ubuntu最新版本存在本地提权漏洞(已有EXP) 



本文始发于微信公众号(邑安全):由WCTF2020 Thymeleaf分析payload形式

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2020年11月30日17:19:20
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   由WCTF2020 Thymeleaf分析payload形式http://cn-sec.com/archives/193260.html

发表评论

匿名网友 填写信息