作者: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
Deploying BIG-IP Virtual Edition in ESXi