CVE-2021-22986:F5 BIG-IP iControl REST未授权远程命令执行漏洞分析

 

作者:Lucifaer@360CERT

0x01 漏洞概述

F5 BIG-IP在今年3月补丁日中修复了 CVE-2021-22986 ,未经身份验证的攻击者可以向 iControl REST 发送精心构造的恶意请求,最终在目标服务器上执行任意命令。

 

0x02 环境配置

F5 BIG-IP官方 提供了对应版本的 Virtual Edition 版本,所以直接下载导入到 vmware 中即可。本篇所使用的漏洞版本为16.0.1,diff版本为16.0.1.1。具体的步骤及操作可以参考这篇文章进行基础配置,完成F5 BIG-IP的启动。

2.1 允许ssh远连

可以根据这篇文章配置允许ssh远连,这里推荐直接用 tmsh 来进行配置。

2.2 寻找具体服务

在F5 BIG-IP中, TMUI 与 iControl REST 是部署在不同的端口上的。我们可以看一下我们访问的443端口的服务是什么:

可以看到是由Apache httpd进行请求承接,并将请求转发到不同端口的服务上完成对应的处理。我们可以看一下httpd的配置文件,在 /config/httpd/conf/httpd.conf :

这里可以注意到两点:

  • AuthPAM开启,说明调用了httpd的某个 .so 文件进行预先的认证
  • 将所有向 /mgmt 发送的请求都转发到了 http://localhost:8100/mgmt/

通过阅读官方文档,我们可以知道所有REST API的目录前缀都是含有 mgmt 的,所以可以看一下8100端口的服务及其进程信息是什么:

可以看到其 classpath 为 /usr/share/java/rest/ 目录。之后我们可以通过 PID 在 /proc/ 目录下查看进程信息:

这样也知道了进程运行目录为 /var/service/restjavad 。

2.3 允许远程调试

根据2.2中找到的进程信息,我们直接到 /var/service/restjavad 目录,然后向运行文件中添加相关的jdwp配置:

这里看到运行文件为 /etc/bigstart/scripts/restjavad ,直接修改该文件即可:

当添加完jdwp配置后,还需要利用 tmsh 将jdwp监听端口8777开放出去,这里可以直接参考这篇文章。这里为了防止链接失效,截一个这篇文章的关键图:

2.4 导出分析代码

在2.2中已经进行了详细的叙述,直接把 /usr/share/java/rest/ 下的代码导出就行了。如果遇到无法导出的问题,可能是由于 /usr 目录无写权限,重新挂载一下 /usr 即可:

mount -o remount w /usr

 

0x03 diff信息

3.1 ssrf

3.2 命令执行

 

0x04 漏洞分析

该漏洞可以分解为两部分:

  • 认证绕过
  • 命令执行端点

该漏洞有两种方式可以达成认证绕过:

  • 认证不完全导致绕过
  • ssrf获取token导致认证绕过

本文将使用动静态跟踪结合的方式,将两部分进行串流分析。

4.1 iControl REST处理逻辑

在开始分析认证绕过前,首先来分析一下程序执行流。

4.1.1 RestServerServlet

RestServerServlet 是整个 iControle REST 的入口,首先看一下其 service 方法:

从 service 方法中,可以获得以下几个信息:

  • RestServerServlet 以异步执行,并注册了一个 ReadListener
  • 在处理请求时,为每一个请求创建了一个 RestOperation
  • 因为向 RestOperation 注册了一个 RestRequestCompletion ,后续逻辑将以回调的方式执行

由于是注册了 ReadListener ,所以我们直接跟进看 com.f5.rest.app.RestServerServlet.ReadListenerImpl#onAllDataRead (具体原因可以看ReadListener官方文档):

跟进看一下 com.f5.rest.common.RestOperationIdentifier#setIdentityFromAuthenticationData :

这里会监测请求中是否包含相关认证,并将其设置到 RestOperation 中。注意这里涉及到两种身份设置方法,第一种是检测是否存在 X-F5-Auth-Token ,第二种是通过Basic认证来设置身份。其中 setIdentityFromBasicAuth 即为diff点:

在 setIdentityData 中只会判断Basic头信息中是否存在 username ,当存在时,将 userReference 初始化为 /mgmt/shared/authz/users/[username] 。

在完成设置后,便会执行 completion.run() 方法,即:

关键逻辑为 com.f5.rest.common.RestServer#trySendInProcess :

其中会根据请求端口来寻找相关的 RestWorker ,并执行 OnRequest 方法。这里因为是 8100 端口,其映射为 RestServer 对象:

在 findWorker() 方法中,将以请求的路径为查询条件,匹配 RestServer 的 pathToWarkerMap 。之后便会执行 worker.onRequest() 方法,在这里会将worker添加到 RestServer.readyWorkerSet 中。后面会以该 Set 为消费者队列,并执行各个worker。

4.1.2 RestServer

RestServer 中主要工作是维护队列,并执行相关的worker。入口点为其构造方法:

这里明显为一个消费者,所以直接看 callRestMethodHandler 即可,一路向下跟进到 callDerivedRestMethod 方法:

这里即会调用对应worker的处理方法并完成对应的链调用。

4.2 认证绕过

该漏洞的重点是认证绕过这一部分,两种绕过方式采用了不同的思路,本篇主要分析第二种绕过方式,针对第一种方式只进行基础的分析,如果想要了解详情,可以阅读斗象的研究文章

4.2.1 认证不完全导致绕过

BIG-IP由两部分组成,首先是通过 Apache httpd 接收443的请求,并将请求转发给本地8100端口的Jetty服务,最终通过Jetty的servlet将不同的路由分发到不同的worker中,完成请求的处理。

而第一种利用方式正是利用了Jetty服务不会对通过httpd认证的请求进行二次认证的缺陷,导致了未认证的攻击者可以绕过认证访问任意worker,最终完成pre auth rce。

在2.2中,从 httpd.conf 中已经看到 httpd 在进行转发时启用了 AuthPAM ,其具体的 .so 文件为 /usr/lib/httpd/modules/mod_auth_pam.so 。

用IDA分析一下逻辑:

httpd只查看请求中是否存在 X-F5-Auth-Token ,若存在,则直接将请求转发到Jetty进行后续处理。

在Jetty这端,首先会判断 X-F5-Auth-Token 是否为空,当设置为空时,对访问路径进行校验,但是这里不匹配任何一种情况。最终进入到else中。这里只会判断 userReference 是否为空,以及 userReference 是否为 admin的userReference 。

回看 userReference 的生成过程(在 com.f5.rest.common.RestOperationIdentifier#setIdentityFromBasicAuth):

可以发现这里的 userReference 就是默认admin的 userReference :

从而导致了绕过。

4.2.2 ssrf获取token导致认证绕过

在diff中可以明显的看到在 com.f5.rest.workers.authn.AuthnWorker#onPost 方法中增加了对 loginReference.link 的校验。在跟踪了代码逻辑后,可以发现这里存在一处ssrf。

可控输入点为:

向下看ssrf点:

这里 state.loginReference.link 是可控的。首先会new一个 RestRequestCompletion ,并将其封装到 RestOperation 中,最后向 state.loginReference 发起请求。注意到在 RestRequestCompletion 中存在 completed() 方法,其中会调用 AuthnWorker.generateToken() 方法生成一个token,跟进可以看到:

这里又新创建了一个 RestOperation ,其中的 completed 方法完成了token的映射及返回。具体的token生成在 com.f5.rest.workers.AuthTokenWorker#generatePrimaryKey 中:

调用栈为:

如果想要静态跟踪到token生成点的话,直接跟进 RestRequestSender.sendPost() 方法即可。

4.2.3 ssrf获取token总结

根据4.1中对处理逻辑的分析,想要找到获取token的点的话,只需要在所有的 RestWorker 子类中寻找符合以下两个条件的子类即可:

  • 存在 onPost 方法可以处理 POST 请求
  • onPost 方法中可以控制执行流到 RestOperation.complete() 方法

由于F5采用了回调的方式完成执行流的构建,最终都会通过回调的逻辑执行 RestRequestCompletion.completed() 方法。

4.3 命令执行端点

命令执行端点主要是配合认证绕过最终达成远程pre auth rce的效果。

4.3.1 /mgmt/tm/util/bash

从[F5 BIG IP官方sdk][7]中找到 /mgmt/tm/util/bash 可以直接执行命令:

4.3.2 /mgmt/tm/access/bundle-install-tasks

从diff中可以看到 /mgmt/tm/access/bundle-install-tasks 直接将可控参数与 tar -xf 拼接,直接执行命令。可以通过反引号直接执行命令。

 

0x05 漏洞利用

5.1 认证不完全导致绕过

第一种方法,可以直接构造如下的包,便可以直接执行命令:

POST /mgmt/tm/util/bash HTTP/1.1
Host: 192.168.59.7
Content-Type: application/json
X-F5-Auth-Token: 
Authorization: Basic YWRtaW46
Content-Length: 52

{
    "command": "run",
    "utilCmdArgs": "-c id"
}

5.2 ssrf获取token

参考4.2.3的总结,寻找相应获取token的端点,然后配合 X-F5-Auth-Token 头向命令执行端点发送请求即可。

 

0x06 Reference

斗象的研究文章

F5 BIG-IP官方下载链接

Deploying BIG-IP Virtual Edition in ESXi

Specify allowable IP ranges for SSH access m01e对于F5的漏洞配置文章

ReadListener官方文档

F5 BIG IP官方sdk

(完)