免责声明

漏洞复现过程全部在本地虚拟环境下进行,请勿用于恶意攻击,未授权的攻击属于非法行为!传播、利用本文章所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。

漏洞描述

F5 BIG-IP是由美国F5 Networks公司开发的一种应用交付控制(Application Delivery Controller,ADC)解决方案。它提供负载均衡、SSL加速、应用安全、Web应用防火墙、WAN优化和其他功能。是一个VPN防火墙设备。

NVD与2023年10月26日发布CVE-2023-46747漏洞。该漏洞可以让未经验证的攻击者,通过管理端口来访问BIG-IP设备,执行任意系统命令。该漏洞评分为9.8。可以使用更新版本、运行F5官网发布的补丁来进行紧急设备。

影响版本

BIG-IP系列 影响版本 修复版本
13.x 13.1.0 - 13.1.5 13.1.5.1
14.x 14.1.0 - 14.1.5 14.1.5.6
15.x 15.1.0 - 15.1.10 15.1.10.2
16.x 16.1.0 - 16.1.4 16.1.4.1
17.x 17.1.0 17.1.0.3

漏洞原理

到官网去申请试用,选择一个有漏洞的虚拟版本下载运行。查看官网补丁,从官网的补丁mitigation.txt中可以看出,F5修改了一些web服务配置。分别修改了httpd(apache)的proxy_ajp.conf文件和tomcat的server.xml文件。启用了ajp协议的secret功能。

proxy_ajp.conf:

1
2
3
4
5
6
7
8
9
10
11
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

#...
#secret是打补丁后添加的内容

ProxyPassMatch "^/tmui/Control/jspmap/([A-Za-z0-9_/]*\??)$" "ajp://localhost:8009/tmui/Control/$1" retry=5 #secret=eddd552162d5dd6de1c1718e6112308a0969018b
ProxyPassMatch "^/tmui/Control/form(\??)$" "ajp://localhost:8009/tmui/Control/form$1" retry=5 #secret=eddd552162d5dd6de1c1718e6112308a0969018b
ProxyPassMatch "^/tmui/deal$" "ajp://localhost:8009/tmui/deal" retry=5 #secret=eddd552162d5dd6de1c1718e6112308a0969018b
ProxyPassMatch "^/tmui/deal/upload/([0-9]*)$" "ajp://localhost:8009/tmui/deal/upload/$1" retry=5 #secret=eddd552162d5dd6de1c1718e6112308a0969018b
ProxyPassMatch "^/tmui/service/([A-Za-z0-9/_]*\??)$" "ajp://localhost:8009/tmui/service/$1" retry=5 #secret=eddd552162d5dd6de1c1718e6112308a0969018b
ProxyPassMatch "^/tmui/([a-zA-Z0-9-_/]*(?:\.jsp|\.html)\??)$" "ajp://localhost:8009/tmui/$1" retry=5 #secret=eddd552162d5dd6de1c1718e6112308a0969018b

server.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml"
readonly="true" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8009" protocol="AJP/1.3"
redirectPort="8443"
enableLookups="true"
address="127.0.0.1"
maxParameterCount="32500"
tomcatAuthentication="false" requiredSecret="eddd552162d5dd6de1c1718e6112308a0969018b"/>
<!--原本没有requiredSecret,运行补丁后添加了requiredSecret-->

<Connector address="127.0.0.1" port="9832" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">
</Host>
</Engine>
</Service>
</Server>

可以看出,这又是httpd和tomcat对数据处理不一致导致的问题。早在2020年,F5 BIG-IP就爆出过CVE-2020-5902,当时httpd与tomcat在处理URL时候存在差异导致了RCE,但这次问题出在ajp1.3协议上。ajp1.3是定向包协议。因为性能原因,使用二进制格式来传输可读性文本。WEB服务器通过TCP连接和SERVLET容器连接。为了减少进程生成socket的花费,WEB服务器和SERVLET容器之间尝试保持持久性的TCP连接,对多个请求/回复循环重用一个连接。这个协议在2020年爆了请求走私漏洞CVE-2022-26377

这个请求走私漏洞影响版本为Apache HTTP Server < 2.4.54。F5 BIG-IP的httpd版本是2.4.6,但它是定制版,目前官网上还没有这个版本。F5 BIG-IP使用的httpd仍然受这个漏洞的影响。通过学习ajp漏洞原理和ajp协议包的构造方式,我们恶意构造、执行任意ajp协议请求。

漏洞复现

复现实验在BIG-IP 17.1.0上进行。F5 BIG-IP的httpd受AJP请求走私的影响,攻击者可以构造任意AJP请求执行。在proxy_ajp.conf中可以看到/tmui/Control/form是走AJP协议的:

1
ProxyPassMatch "^/tmui/Control/form(\??)$" "ajp://localhost:8009/tmui/Control/form$1" retry=5

在这个路由下,可以通过/tmui/system/user/create.jsp创建用户。也就是说,通过构造AJP请求走私,可以在未授权的情况下通过该路由创建用户。
创建用户后可以通过/mgmt/shared/authn/login功能可以给登录用户提供一个token,使用该token作为X-F5-Auth-Token可以通过/mgmt/tm/util/bash来执行任意系统命令(CVE-2022-1388)。

漏洞利用步骤如下:

  1. 构造AJP请求走私,通过/tmui/Control/form访问/tmui/system/user/create.jsp,创建任意用户。
  2. 通过PATCH /mgmt/shared/authz/users/{用户名}来更新密码有效期(创建用户后通过配置界面登录时会提示密码过期,需要重置密码。)
  3. 使用该用户通过/mgmt/shared/authn/login登录,获取token。
  4. 通过token访问/mgmt/tm/util/bash,执行任意指令。

以上的请求都可以通过本地模拟执行后抓包来进行查看修改。在F5 BIG-IP上使用tcpdump可以将mgmt接口的流量抓获保存为pcapng格式,导出到wireshark进行查看。

构造AJP请求走私

AJP请求走私的原理请大家看参考文献进行学习,它的原理与http请求走私类似。http请求的编码格式为Transfer-Encoding而不是Content-Length时,tomcat不会调用AjpProcessor.receive()来接受body数据,同时也不会做任何处理。所以后续的数据会被当作Forward request。

image

而mod_proxy_ajp.c中虽然对Transfer-Encoding: chunked进行了过滤,但攻击者可以通过Transfer-Encoding: a, chunked来进行绕过。

image

所以,http请求的传输编码构造为Transfer-Encoding: a, chunked,即可将分块传输的数据作为Forward Request进行提交。

根据AJP1.3协议文档(其实官方文档并不是协议开发者写的,这个协议实在是有些老。),可以知道,Forward Request是server转发到container的请求,前两个字节为0x1234,紧跟的两个字节为数据包长度(不包括前四个字节),第五个字节是2,第六个字节是方法(如果是POST方法则为4)。之后的数据都是请求体。

而对于Data包,前四个字节和Forward Request是一样的,但第五个字节、第六个字节是Data包的长度(实际上,比第三个字节和第四个字节表示的数据包长度的值小2)。**构造Data包时,将Data包长度控制为0x0204,则可在走私时让第五个字节和第六个字节分别为0x02(对应Forward Request)、0x04(POST方法)。**这样Data包就会当作Forward Request进行处理,从而提交POST包。

image

image

既然我们有本地环境,直接正常地创建一个用户,然后用tcpdump抓包导入wireshark查看具体内容,走私时可以直接重复利用该内容。
目前,github上已经有了poc,走私时直接重复利用AJP协议包内容也是可以的。如果自己动手构造AJP协议包,需要阅读AJP文档,尤其需要注意AJP协议的字符串定义和我们平常使用的字符串定义不同。

image

我们直接将这个数据包拉下来,然后使用AJP请求走私的方式重新投放即可,注意原数据包大小比较大,需要删除很多数据,但需要保留tmsh的防csrf检测部分。走私的请求体长度应该正好为0x204。

image

其中tmsh的防csrf检测部分原理为:

image

更新有效期

这一步可以手动通过配置页面登录来进行更新,也可以通过Burpsuite发包实现,也可以通过python脚本集成该功能。我编写的python exp在参考文献中给出,下面不详细给出exp的具体内容。

image
这一步需要填写Authorization头,内容为Basic+空格+base64(用户名+冒号+密码)。数据部分需要填充oldPassword和password,不变即可。

获取token

使用Burpsuite工具发包。
image

命令执行

获取token后,轻松执行任意系统命令:
image

通过脚本也可以直接一步到位:

image

参考文献

[1] https://h4cking2thegate.github.io/posts/38810/index.html

[2] https://www.ctfiot.com/44809.html

[3] https://github.com/projectdiscovery/nuclei-templates/blob/e41934f4bfe7d9cb4a622a966e6c786af10ef480/http/cves/2023/CVE-2023-46747.yaml

[4] https://github.com/wbohan/CVE/blob/main/CVE-2023-46747.py