spring-cloud-netflix-hystrix-dashboard远程代码执行漏洞分析

前面

在逛snyk的时候,发现了org.springframework.cloud:spring-cloud-netflix-hystrix-dashboard 报了一个任意代码执行(模板解析)的漏洞,编号CVE-2021-22053。
image.png
说是 spring-cloud-netflix-hystrix-dashboard 和spring-boot-starter-thymeleaf 两个依赖一起使用的时候,可以在 /hystrix/monitor;后面提供SpEL表达式,可以造成任意代码执行。

Thymeleaf

Thymeleaf 是Java的一种模板引擎,可以处理HTML,XML,和JavaScript,并且可以完全替代JSP。他可以轻松的与Spring MVC的web框架集成。
特点如下

  • Spring MVC中@Controller中的方法可以直接返回模板名称,接下来Thymeleaf模板引擎会自动进行渲染
  • 模板中的表达式支持Spring表达式语言(Spring EL)
  • 表单支持,并兼容Spring MVC的数据绑定与验证机制
  • 国际化支持

    Spring Cloud Hystrix

    Spring Cloud Hystrix 是Spring Cloud Netflix 子项目的核心组件之一,具有服务容错及线程隔离等一系列服务保护功能。
    添加依赖
    org.springframework.cloud spring-cloud-netflix-hystrix-dashboard 2.2.9.RELEASE
    image.png
    然后在 Spring Boot 的运行文件加注解。

    漏洞分析

    看一下 2.2.9.RELEASE 和 2.2.10.RELEASE 的控制器的不同
    org.springframework.cloud.netflix.hystrix.dashboard.HystrixDashboardController
    前者
    image.png
    后者
    image.png
    可以发现将路由中用户可控的path修改成了 固定的 monitor,问题应该是出在了可控的path。
    直接返回 “hystrix/“+path 应该是找到对应的模板文件,为什么造成了任意代码执行。
    写一个测试的路由跟进分析,
    image.png
    Spring MVC 调用控制器的主要方法是org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
    image.png
    这里面有两个主要的调用
    invokeForRequest 方法用来调用到控制器,然后获取返回数据。
    跟进 handleReturnValue 方法,
    image.png
    image.png
    如果 返回数据是字符类型的,
    ModelAndViewContainer#setViewName 方法来设置viewName,也就是返回值的字符串形式。
    image.png
    后面就是判断是否是 redirect: 开头,来设置属性。
    结束后会返回到,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
    这个方法通过 getModelAndView 方法,用mavContainer的model和viewName来创建一个 ModelAndView对象并返回
    image.png
    image.png
    回到了org.springframework.web.servlet.DispatcherServlet#doDispatch 方法中
    image.png
    变量mv就是 刚刚返回的 ModelAndView 对象
    image.png
    跟进,视图的渲染是由render方法来完成的。
    image.png
    先根据 viewName 和本地的配置来获取对应的视图,最后生成的对象如下。
    image.png
    再次调用获取到的视图(org.thymeleaf.spring5.view.ThymeleafView#render)的render方法
    image.png
    跟进 renderFragment
    获取渲染模板名和渲染模板引擎
    image.png
    模板名是可控的,下面的分析,只需要看准模板名就可以了。
    image.png
    如果模板名中没有 :: 就赋值给 templateName, 有的话则会使用
    IStandardExpressionParser#parseExpression 方法来处理。
    thymeleaf 将包含 :: 的 模板名当作片段表达式,详情可了解。
    https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#including-template-fragments
    继续跟进
    image.png
    这里preprocess 传值为true
    image.png
    preprocess
    image.png
    如果有下划线,就会去执行正则匹配 (.*?) 也就是获取 两边下划线中间的部分,
    这里中间的部分会被当做表达式来执行,
    image.png
    那么这里就可以注入SpEL表达式了。
    image.png
    payload
    http://127.0.0.1:8080/hystrix/__${T(String).getClass().forName("java.lang.Runtime").getRuntime().exec("calc")}__::/
    image.png

    后面

    这个漏洞像是一个模板注入,然后我去搜了一下Java模板注入,发现这是有原型的,
    https://xz.aliyun.com/t/10514#toc-11
    我去github上搜了一下这个
    image.png
    发现了对应的Poc和环境,payload中还有一些Thymeleaf更高版本的bypass技巧。
    https://github.com/SecCoder-Security-Lab/spring-cloud-netflix-hystrix-dashboard-cve-2021-22053