### Install H2SpaceX and Scapy Source: https://context7.com/nxenon/h2spacex/llms.txt Install the H2SpaceX library using pip. If Scapy encounters errors, upgrade it. ```bash pip install h2spacex # If Scapy errors occur: pip install --upgrade scapy ``` -------------------------------- ### Install H2SpaceX Source: https://github.com/nxenon/h2spacex/blob/main/README.md Install the H2SpaceX library using pip. If you encounter Scapy-related errors, upgrade Scapy. ```bash pip install h2spacex ``` ```bash pip install --upgrade scapy ``` -------------------------------- ### Setup H2OnTlsConnection Source: https://github.com/nxenon/h2spacex/wiki/Quick-Start-Examples Establishes an H2 over TLS connection to a specified hostname and port. Ensure the hostname and port are correct for your target. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection( hostname='http2.github.io', port_number=443 ) h2_conn.setup_connection() ``` -------------------------------- ### Proxy Connection Example (Python) Source: https://github.com/nxenon/h2spacex/wiki/Quick-Start-Examples Configure an H2OnTlsConnection to use a proxy server by specifying the proxy's hostname and port number. ```python h2_conn = H2OnTlsConnection( hostname='http2.github.io', port_number=443, proxy_hostname='127.0.0.1', proxy_port_number=10808 ) ``` -------------------------------- ### Parse Response with Timing (Python) Source: https://github.com/nxenon/h2spacex/wiki/Quick-Start-Examples Use this method to get response times in nanoseconds after setting up the connection or sending requests. It starts a threaded response parser and waits for completion. ```python import time from h2.connection import H2OnTlsConnection h2_conn = H2OnTlsConnection( hostname='http2.github.io', port_number=443 ) h2_conn.setup_connection() # ...Send Requests with Single Packet Attack Technique... h2_conn.start_thread_response_parsing(_timeout=3) while not h2_conn.is_threaded_response_finished: time.sleep(1) if h2_conn.is_threaded_response_finished is None: print('Error has occurred!') exit() frame_parser = h2_conn.threaded_frame_parser h2_conn.close_connection() for x in frame_parser.headers_and_data_frames.keys(): d = frame_parser.headers_and_data_frames[x] print(f'Stream ID: {x}, response nano seconds: {d["nano_seconds"]}') ``` -------------------------------- ### Setup HTTP/2 TLS Connection Source: https://github.com/nxenon/h2spacex/blob/main/README.md Import and initialize H2OnTlsConnection to establish an HTTP/2 connection over TLS. The ssl_log_file_path is optional for logging SSL keys to Wireshark. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection( hostname='http2.github.io', port_number=443, ssl_log_file_path="PATH_TO_SSL_KEYS.log" # optional (if you want to log ssl keys to read the http/2 traffic in wireshark) ) h2_conn.setup_connection() ... ``` -------------------------------- ### Setup Connection and Send PING Frame Source: https://github.com/nxenon/h2spacex/wiki/SPA-New-Method Initializes the H2 connection and sends a PING frame as a prerequisite for subsequent requests in the improved SPA method. ```python h2_conn.setup_connection() h2_conn.send_ping_frame() <--- Important Line h2_conn.send_frames(temp_headers_bytes) sleep(0.1) h2_conn.send_ping_frame() h2_conn.send_frames(temp_data_bytes) # last frames with last bytes ``` -------------------------------- ### Override POST Method to GET via Header Source: https://github.com/nxenon/h2spacex/wiki/GET-SPA-Methods This technique involves sending a POST request with an 'x-method-override' or 'x-http-method-override' header set to 'GET'. A single byte is sent in a DATA frame for each request, effectively performing a GET request disguised as a POST. ```text :method: POST\nOTHER_HEADERS\nx-method-override: GET\n+\nDATA_FRAME\n. ``` -------------------------------- ### Override POST Method to GET via URL Parameter Source: https://github.com/nxenon/h2spacex/wiki/GET-SPA-Methods This method uses URL parameters 'x-method-override' or 'x-http-method-override' set to 'GET' within a POST request. Similar to the header override, a single byte is sent in a DATA frame for each request to execute the GET method. ```text :method: POST\n:path: /path?x-method-override=GET\nOTHER_HEADERS\n+\nDATA_FRAME\n. ``` -------------------------------- ### Send HTTP/2 PING Frame for Connection Warm-up Source: https://context7.com/nxenon/h2spacex/llms.txt Use `send_ping_frame()` to warm up the connection path immediately after setup or before sending final frames. This is a key technique for improved SPA performance. ```python from h2spacex import H2OnTlsConnection from time import sleep h2_conn = H2OnTlsConnection(hostname='target.example.com', port_number=443) h2_conn.setup_connection() # Improved SPA method (Black Hat 2024): h2_conn.send_ping_frame() # Step 1: warm up immediately after setup # ... build and send leading frames ... h2_conn.send_frames(headers_bytes) sleep(0.1) # brief pause h2_conn.send_ping_frame() # Step 2: warm up just before final burst h2_conn.send_frames(data_bytes) # final bytes arrive together ``` -------------------------------- ### send_ping_frame() Source: https://context7.com/nxenon/h2spacex/llms.txt Sends an HTTP/2 PING frame to the server. This is used for connection warm-up, either immediately after setup or just before sending final frames in the SPA technique. ```APIDOC ## send_ping_frame() ### Description Sends an HTTP/2 PING frame to the server. Serves two purposes in SPA: (1) as an initial warm-up immediately after `setup_connection()` to pre-establish the connection path, and (2) as a pre-burst warm-up just before sending the final last-byte frames. This is the key addition of the Black Hat 2024 improved SPA technique. ### Method ```python h2_conn.send_ping_frame() ``` ### Usage Example ```python from h2spacex import H2OnTlsConnection from time import sleep h2_conn = H2OnTlsConnection(hostname='target.example.com', port_number=443) h2_conn.setup_connection() # Improved SPA method (Black Hat 2024): h2_conn.send_ping_frame() # Step 1: warm up immediately after setup # ... build and send leading frames ... h2_conn.send_frames(headers_bytes) sleep(0.1) # brief pause h2_conn.send_ping_frame() # Step 2: warm up just before final burst h2_conn.send_frames(data_bytes) # final bytes arrive together ``` ``` -------------------------------- ### Parse Response with Threading for Timing Attacks Source: https://github.com/nxenon/h2spacex/wiki/SPA-New-Method Starts a threaded response parser after setting up the connection or sending requests. It monitors the parsing status and retrieves response times in nanoseconds. ```python ...IMPORTS... h2_conn = H2OnTlsConnection( hostname='http2.github.io', port_number=443 ) h2_conn.setup_connection() # ...Send Requests with Single Packet Attack Technique... h2_conn.start_thread_response_parsing(_timeout=3) while not h2_conn.is_threaded_response_finished: sleep(1) if h2_conn.is_threaded_response_finished is None: print('Error has occurred!') exit() frame_parser = h2_conn.threaded_frame_parser h2_conn.close_connection() for x in frame_parser.headers_and_data_frames.keys(): d = frame_parser.headers_and_data_frames[x] print(f'Stream ID: {x}, response nano seconds: {d["nano_seconds"]}') ``` -------------------------------- ### Create HTTP/2 GET Request Frames for SPA Source: https://context7.com/nxenon/h2spacex/llms.txt Builds HTTP/2 frames for a Single Packet Attack on a GET request using the 'Remove END_STREAM' method. Returns frames split into two parts: all frames except the last byte, and an empty DATA frame with the END_STREAM flag. The empty DATA frame serves as the terminal signal. ```python from h2spacex import H2OnTlsConnection from h2spacex import h2_frames from time import sleep host = 'target.example.com' h2_conn = H2OnTlsConnection(hostname=host, port_number=443) h2_conn.setup_connection() headers = """cookie: session=abc123 accept: */*""" stream_ids = h2_conn.generate_stream_ids(number_of_streams=3) all_headers_frames = [] all_data_frames = [] for s_id in stream_ids: head_frames, last_frame = h2_conn.create_single_packet_http2_get_request_frames( method='GET', authority=host, scheme='https', path='/api/resource', headers_string=headers, stream_id=s_id, body=None ) all_headers_frames.append(head_frames) all_data_frames.append(last_frame) headers_bytes = b''.join(bytes(f) for f in all_headers_frames) data_bytes = b''.join(bytes(f) for f in all_data_frames) h2_conn.send_bytes(headers_bytes) sleep(0.1) h2_conn.send_ping_frame() h2_conn.send_bytes(data_bytes) resp = h2_conn.read_response_from_socket(_timeout=3) parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(resp) parser.show_response_of_sent_requests() h2_conn.close_connection() ``` -------------------------------- ### Exploit GET Request with Content-Length: 1 Source: https://github.com/nxenon/h2spacex/wiki/GET-SPA-Methods This method exploits servers that wait for a DATA frame when a Content-Length header is present in a GET request. It involves sending multiple requests with 'Content-Length: 1' and a single-byte DATA frame for each in one packet. ```text .\ncontent-length: 1\nOTHER_HEADERS\n. ``` -------------------------------- ### Generate HTTP/2 Stream IDs Source: https://context7.com/nxenon/h2spacex/llms.txt Generate sequential, odd-numbered HTTP/2 stream IDs starting from the last used ID. Client-initiated streams require odd IDs incremented by 2. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() stream_ids = h2_conn.generate_stream_ids(number_of_streams=5) print(stream_ids) # Output: [3, 5, 7, 9, 11] # Calling again continues from the last used ID more_ids = h2_conn.generate_stream_ids(number_of_streams=3) print(more_ids) # Output: [13, 15, 17] ``` -------------------------------- ### Remove END_STREAM Flag in HTTP/2 GET Request Source: https://github.com/nxenon/h2spacex/wiki/GET-SPA-Methods This Python script demonstrates how to craft and send HTTP/2 GET requests by manipulating frames to remove the END_STREAM flag. It's useful for sending the last bytes of a request in a single packet, potentially bypassing certain security checks. ```python from h2spacex import H2OnTlsConnection from time import sleep from h2spacex import h2_frames # change this host name to new generated one host = 'example.com' h2_conn = H2OnTlsConnection( hostname=host, port_number=443 ) h2_conn.setup_connection() headers = """HEADERS ... """ try_num = 3 stream_ids_list = h2_conn.generate_stream_ids(number_of_streams=try_num) all_headers_frames = [] # all headers frame + data frames which have not the last byte all_data_frames = [] # all data frames which contain the last byte for i in range(0, try_num): header_frames_without_last_byte, last_data_frame_with_last_byte = h2_conn.create_single_packet_http2_get_request_frames( # noqa: E501 method='GET', headers_string=headers, scheme='https', stream_id=stream_ids_list[i], authority=host, path='/', body=None ) all_headers_frames.append(header_frames_without_last_byte) all_data_frames.append(last_data_frame_with_last_byte) # concatenate all headers bytes temp_headers_bytes = b'' for h in all_headers_frames: temp_headers_bytes += bytes(h) # concatenate all data frames which have last byte temp_data_bytes = b'' for d in all_data_frames: temp_data_bytes += bytes(d) h2_conn.send_bytes(temp_headers_bytes) # # wait some time sleep(0.1) # send ping frame to warm up connection h2_conn.send_ping_frame() # send remaining data frames h2_conn.send_bytes(temp_data_bytes) resp = h2_conn.read_response_from_socket(_timeout=3) frame_parser = h2_frames.FrameParser(h2_connection=h2_conn) frame_parser.add_frames(resp) frame_parser.show_response_of_sent_requests() sleep(3) h2_conn.close_connection() ``` -------------------------------- ### generate_stream_ids(number_of_streams) Source: https://context7.com/nxenon/h2spacex/llms.txt Generates the correct number of sequential, odd-numbered HTTP/2 stream IDs starting from the last used stream ID. HTTP/2 requires client-initiated streams to use odd IDs, incremented by 2. Returns a list of integers. ```APIDOC ## generate_stream_ids(number_of_streams) Generates the correct number of sequential, odd-numbered HTTP/2 stream IDs starting from the last used stream ID. HTTP/2 requires client-initiated streams to use odd IDs, incremented by 2. Returns a list of integers. ### Usage ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() stream_ids = h2_conn.generate_stream_ids(number_of_streams=5) print(stream_ids) # Output: [3, 5, 7, 9, 11] # Calling again continues from the last used ID more_ids = h2_conn.generate_stream_ids(number_of_streams=3) print(more_ids) # Output: [13, 15, 17] ``` ``` -------------------------------- ### create_single_packet_http2_get_request_frames Source: https://context7.com/nxenon/h2spacex/llms.txt Generates HTTP/2 frames for a Single Packet Attack on a GET request using the 'Remove END_STREAM' method. It returns a tuple containing frames without the last byte and an empty DATA frame with the END_STREAM flag, which acts as the terminal signal. ```APIDOC ## create_single_packet_http2_get_request_frames() Builds HTTP/2 frames for a Single Packet Attack on a GET request using the "Remove END_STREAM" method. Returns the same `(frames_without_last_byte, empty_data_frame)` tuple as the POST variant. The empty DATA frame with END_STREAM serves as the terminal signal sent in the final burst. ```python from h2spacex import H2OnTlsConnection from h2spacex import h2_frames from time import sleep host = 'target.example.com' h2_conn = H2OnTlsConnection(hostname=host, port_number=443) h2_conn.setup_connection() headers = """cookie: session=abc123 accept: */*""" stream_ids = h2_conn.generate_stream_ids(number_of_streams=3) all_headers_frames = [] all_data_frames = [] for s_id in stream_ids: head_frames, last_frame = h2_conn.create_single_packet_http2_get_request_frames( method='GET', authority=host, scheme='https', path='/api/resource', headers_string=headers, stream_id=s_id, body=None ) all_headers_frames.append(head_frames) all_data_frames.append(last_frame) headers_bytes = b''.join(bytes(f) for f in all_headers_frames) data_bytes = b''.join(bytes(f) for f in all_data_frames) h2_conn.send_bytes(headers_bytes) sleep(0.1) h2_conn.send_ping_frame() h2_conn.send_bytes(data_bytes) resp = h2_conn.read_response_from_socket(_timeout=3) parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(resp) parser.show_response_of_sent_requests() h2_conn.close_connection() ``` ``` -------------------------------- ### setup_connection() Source: https://context7.com/nxenon/h2spacex/llms.txt Establishes the underlying socket (raw or TLS), sends the HTTP/2 connection preface, and transmits the client's initial SETTINGS frame. Must be called before any other operation. Raises the underlying exception if the connection fails. ```APIDOC ## setup_connection() Establishes the underlying socket (raw or TLS), sends the HTTP/2 connection preface (`PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n`), and transmits the client's initial SETTINGS frame. Must be called before any other operation. Raises the underlying exception if the connection fails. ### Usage ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='http2.github.io', port_number=443) try: h2_conn.setup_connection() print('Connection ready:', not h2_conn.is_connection_closed) # True except Exception as e: print(f'Connection failed: {e}') ``` ``` -------------------------------- ### Establish Connection with setup_connection() Source: https://context7.com/nxenon/h2spacex/llms.txt Call setup_connection() to establish the socket, send the HTTP/2 preface, and transmit the initial SETTINGS frame. This must be called before other operations. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='http2.github.io', port_number=443) try: h2_conn.setup_connection() print('Connection ready:', not h2_conn.is_connection_closed) # True except Exception as e: print(f'Connection failed: {e}') ``` -------------------------------- ### Initialize H2OnTlsConnection Source: https://context7.com/nxenon/h2spacex/llms.txt Create a TLS HTTP/2 connection instance. Configure hostname, port, timeouts, proxy, and optional SSL key logging. ```python from h2spacex import H2OnTlsConnection # Basic TLS connection with optional SSL key logging for Wireshark h2_conn = H2OnTlsConnection( hostname='example.com', port_number=443, read_timeout=3, # socket read timeout in seconds proxy_hostname='127.0.0.1', # optional SOCKS5 proxy host proxy_port_number=8080, # optional SOCKS5 proxy port ssl_log_file_path='/tmp/ssl_keys.log' # optional: log TLS session keys ) h2_conn.setup_connection() # Output: # + Connected to: example.com:443 --> 192.168.1.10:54321 # + TLS connection established # + H2 connection preface sent # + Client initial SETTINGS frame sent ``` -------------------------------- ### Customize HTTP/2 Client Settings Source: https://context7.com/nxenon/h2spacex/llms.txt Modify the DEFAULT_SETTINGS dictionary before calling setup_connection() to control SETTINGS parameters sent during the handshake. Setting a value to None suppresses that setting. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) # Customize before setup h2_conn.DEFAULT_SETTINGS['SETTINGS_MAX_CONCURRENT_STREAMS']['value'] = 250 h2_conn.DEFAULT_SETTINGS['SETTINGS_INITIAL_WINDOW_SIZE']['value'] = 131072 h2_conn.DEFAULT_SETTINGS['SETTINGS_MAX_HEADER_LIST_SIZE']['value'] = None # do not send # Available keys: # SETTINGS_HEADER_TABLE_SIZE (id=1, default=4096) # SETTINGS_ENABLE_PUSH (id=2, default=0) # SETTINGS_MAX_CONCURRENT_STREAMS (id=3, default=100) # SETTINGS_INITIAL_WINDOW_SIZE (id=4, default=65535) # SETTINGS_MAX_FRAME_SIZE (id=5, default=16384) # SETTINGS_MAX_HEADER_LIST_SIZE (id=6, default=None → not sent) h2_conn.setup_connection() ``` -------------------------------- ### create_simple_http2_request / send_simple_http2_request Source: https://context7.com/nxenon/h2spacex/llms.txt These methods are used to build or send a standard HTTP/2 request that is not split for SPA. `create_simple_http2_request()` returns the assembled frame object, while `send_simple_http2_request()` builds and sends it immediately. They are suitable for warm-up, preflight, or non-race-condition scenarios. ```APIDOC ## create_simple_http2_request() / send_simple_http2_request() Builds or sends a standard HTTP/2 request (not split for SPA). `create_simple_http2_request()` returns the assembled frame object; `send_simple_http2_request()` builds and immediately sends it. Useful for warm-up requests, preflight requests, or any non-race-condition usage. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='http2.github.io', port_number=443) h2_conn.setup_connection() stream_ids = h2_conn.generate_stream_ids(number_of_streams=1) # Send a normal GET request h2_conn.send_simple_http2_request( method='GET', authority='http2.github.io', scheme='https', path='/', headers_string='accept: text/html\nuser-agent: h2spacex', stream_id=stream_ids[0], body=None ) from h2spacex import h2_frames resp = h2_conn.read_response_from_socket(_timeout=3) parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(resp) parser.show_response_of_sent_requests() # Output: # #- Stream ID: 3 -# # -Headers- # :status 200 # content-type: text/html; charset=utf-8 # ... # -Body- # ... ``` ``` -------------------------------- ### Initialize H2Connection for Plain HTTP/2 Source: https://context7.com/nxenon/h2spacex/llms.txt Create a plain (non-TLS) HTTP/2 connection instance. This is useful for testing h2c endpoints. ```python from h2spacex.h2_connection import H2Connection h2_conn = H2Connection( hostname='example-h2c.com', port_number=80, read_timeout=3 ) h2_conn.setup_connection() ``` -------------------------------- ### start_thread_response_parsing() Source: https://context7.com/nxenon/h2spacex/llms.txt Launches a background thread to read from the socket and timestamp each response chunk. This is essential for timing-attack analysis. ```APIDOC ## start_thread_response_parsing() — Threaded Response Parser with Timing ### Description Launches a background thread that reads from the socket and timestamps each response chunk in nanoseconds. Required when performing timing-attack analysis. Poll `is_threaded_response_finished` to wait for completion, then access results via `threaded_frame_parser`. ### Method ```python h2_conn.start_thread_response_parsing(_timeout=3) ``` ### Usage Example ```python from h2spacex import H2OnTlsConnection from h2spacex import h2_frames from time import sleep h2_conn = H2OnTlsConnection(hostname='target.example.com', port_number=443) h2_conn.setup_connection() h2_conn.send_ping_frame() # improved SPA warm-up # ... build frames and perform SPA send sequence ... # Start background response collection h2_conn.start_thread_response_parsing(_timeout=3) # Wait for thread to finish while not h2_conn.is_threaded_response_finished: sleep(0.5) if h2_conn.is_threaded_response_finished is None: print('Error during response parsing!') exit(1) parser = h2_conn.threaded_frame_parser h2_conn.close_connection() # Inspect timing per stream for stream_id, resp in parser.headers_and_data_frames.items(): print(f'Stream {stream_id}: {resp["nano_seconds"]} ns') print(f' Status headers: {resp["header"][:80]}') print(f' Body: {resp["data"][:80]}') # Output: # Stream 3: 1714500001234567890 ns # Status headers: :status 200\ncontent-type: application/json\n... # Body: b'{"result":"ok"}' # Stream 5: 1714500001234589100 ns # ... ``` ``` -------------------------------- ### Create and Send Simple HTTP/2 Request Source: https://context7.com/nxenon/h2spacex/llms.txt Builds or sends a standard HTTP/2 request. `create_simple_http2_request()` returns the assembled frame object, while `send_simple_http2_request()` builds and immediately sends it. This is suitable for non-race-condition scenarios like warm-up or preflight requests. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='http2.github.io', port_number=443) h2_conn.setup_connection() stream_ids = h2_conn.generate_stream_ids(number_of_streams=1) # Send a normal GET request h2_conn.send_simple_http2_request( method='GET', authority='http2.github.io', scheme='https', path='/', headers_string='accept: text/html\nuser-agent: h2spacex', stream_id=stream_ids[0], body=None ) from h2spacex import h2_frames resp = h2_conn.read_response_from_socket(_timeout=3) parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(resp) parser.show_response_of_sent_requests() # Output: # #- Stream ID: 3 -# # -Headers- # :status 200 # content-type: text/html; charset=utf-8 # ... # -Body- # ... ``` -------------------------------- ### DEFAULT_SETTINGS Source: https://context7.com/nxenon/h2spacex/llms.txt Customizes the HTTP/2 client settings sent during the handshake. Modify values in the `DEFAULT_SETTINGS` dictionary before calling `setup_connection()`. Setting a value to `None` suppresses that setting. ```APIDOC ## DEFAULT_SETTINGS — Customizing HTTP/2 Client Settings The `DEFAULT_SETTINGS` dict on the connection object controls which SETTINGS parameters are sent during the handshake. Modify values before calling `setup_connection()`. Setting a value to `None` suppresses that setting entirely. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) # Customize before setup h2_conn.DEFAULT_SETTINGS['SETTINGS_MAX_CONCURRENT_STREAMS']['value'] = 250 h2_conn.DEFAULT_SETTINGS['SETTINGS_INITIAL_WINDOW_SIZE']['value'] = 131072 h2_conn.DEFAULT_SETTINGS['SETTINGS_MAX_HEADER_LIST_SIZE']['value'] = None # do not send # Available keys: # SETTINGS_HEADER_TABLE_SIZE (id=1, default=4096) # SETTINGS_ENABLE_PUSH (id=2, default=0) # SETTINGS_MAX_CONCURRENT_STREAMS (id=3, default=100) # SETTINGS_INITIAL_WINDOW_SIZE (id=4, default=65535) # SETTINGS_MAX_FRAME_SIZE (id=5, default=16384) # SETTINGS_MAX_HEADER_LIST_SIZE (id=6, default=None → not sent) h2_conn.setup_connection() ``` ``` -------------------------------- ### Default Settings Keys and Values (Python) Source: https://github.com/nxenon/h2spacex/wiki/Quick-Start-Examples This dictionary defines the default HTTP/2 settings, including their IDs and initial values. Settings with a value of None will not be sent. ```python DEFAULT_SETTINGS = { 'SETTINGS_HEADER_TABLE_SIZE': { 'id': 1, 'value': 4096 }, 'SETTINGS_ENABLE_PUSH': { 'id': 2, 'value': 0 }, 'SETTINGS_MAX_CONCURRENT_STREAMS': { 'id': 3, 'value': 100 }, 'SETTINGS_INITIAL_WINDOW_SIZE': { 'id': 4, 'value': 65535 }, 'SETTINGS_MAX_FRAME_SIZE': { 'id': 5, 'value': 16384 }, 'SETTINGS_MAX_HEADER_LIST_SIZE': { 'id': 6, 'value': None # this Setting will not be sent, bcs its value is None }, } ``` -------------------------------- ### Change Default Client Settings (Python) Source: https://github.com/nxenon/h2spacex/wiki/Quick-Start-Examples Modify the library's default HTTP/2 settings before establishing a connection. Set a setting's value to None to prevent it from being sent. ```python h2_conn = H2OnTlsConnection( hostname='nxenon.ir', port_number=443 ) # change the library default value h2_conn.DEFAULT_SETTINGS['SETTINGS_MAX_CONCURRENT_STREAMS']['value'] = 100 # you can also change other Settings values . h2_conn.setup_connection() ``` -------------------------------- ### Control Library Output with Logger Source: https://context7.com/nxenon/h2spacex/llms.txt Use the module-level logger object to control library console output. Set be_silent_key to True to suppress all output, or debug to True for verbose messages. Do not combine both. ```python from h2spacex import logger # Suppress all library output logger.be_silent_key = True # --- OR enable debug output --- # logger.debug = True # do NOT combine with be_silent_key from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() # prints nothing when be_silent_key=True ``` -------------------------------- ### Threaded HTTP/2 Response Parsing with Timing Source: https://context7.com/nxenon/h2spacex/llms.txt Launch a background thread with `start_thread_response_parsing()` for non-blocking response collection and nanosecond timestamping. Poll `is_threaded_response_finished` and access results via `threaded_frame_parser`. ```python from h2spacex import H2OnTlsConnection from h2spacex import h2_frames from time import sleep h2_conn = H2OnTlsConnection(hostname='target.example.com', port_number=443) h2_conn.setup_connection() h2_conn.send_ping_frame() # improved SPA warm-up # ... build frames and perform SPA send sequence ... # Start background response collection h2_conn.start_thread_response_parsing(_timeout=3) # Wait for thread to finish while not h2_conn.is_threaded_response_finished: sleep(0.5) if h2_conn.is_threaded_response_finished is None: print('Error during response parsing!') exit(1) parser = h2_conn.threaded_frame_parser h2_conn.close_connection() # Inspect timing per stream for stream_id, resp in parser.headers_and_data_frames.items(): print(f'Stream {stream_id}: {resp["nano_seconds"]} ns') print(f' Status headers: {resp["header"][:80]}') print(f' Body: {resp["data"][:80]}') # Output: # Stream 3: 1714500001234567890 ns # Status headers: :status 200\ncontent-type: application/json\n... # Body: b'{"result":"ok"}' # Stream 5: 1714500001234589100 ns # ... ``` -------------------------------- ### Configure SOCKS5 Proxy Support Source: https://context7.com/nxenon/h2spacex/llms.txt Tunnel all traffic through a specified SOCKS5 proxy by providing proxy_hostname and proxy_port_number parameters to H2OnTlsConnection or H2Connection. Uses PySocks for tunneling. ```python from h2spacex import H2OnTlsConnection # Route through a local SOCKS5 proxy (e.g., Burp Suite or SSH tunnel) h2_conn = H2OnTlsConnection( hostname='target.example.com', port_number=443, proxy_hostname='127.0.0.1', proxy_port_number=1080 ) h2_conn.setup_connection() # Output: + Connected through Proxy: target.example.com:443 --> 127.0.0.1:54321 ``` -------------------------------- ### H2OnTlsConnection Source: https://context7.com/nxenon/h2spacex/llms.txt The primary connection class for HTTPS/HTTP2 targets. It wraps the raw socket in an SSL/TLS context with ALPN set to h2, sends the HTTP/2 connection preface, and negotiates initial SETTINGS frames. It inherits all frame-building and sending methods from H2Connection. ```APIDOC ## H2OnTlsConnection ### Description The primary connection class for HTTPS/HTTP2 targets. Wraps the raw socket in an SSL/TLS context with ALPN set to `h2`, sends the HTTP/2 connection preface, and negotiates initial SETTINGS frames. Inherits all frame-building and sending methods from `H2Connection`. ### Usage ```python from h2spacex import H2OnTlsConnection # Basic TLS connection with optional SSL key logging for Wireshark h2_conn = H2OnTlsConnection( hostname='example.com', port_number=443, read_timeout=3, # socket read timeout in seconds proxy_hostname='127.0.0.1', # optional SOCKS5 proxy host proxy_port_number=8080, # optional SOCKS5 proxy port ssl_log_file_path='/tmp/ssl_keys.log' # optional: log TLS session keys ) h2_conn.setup_connection() # Output: # + Connected to: example.com:443 --> 192.168.1.10:54321 # + TLS connection established # + H2 connection preface sent # + Client initial SETTINGS frame sent ``` ``` -------------------------------- ### Enable Debug Logging Source: https://github.com/nxenon/h2spacex/wiki/Quick-Start-Examples Enables detailed debug logging by setting `logger.debug` to True. Ensure `be_silent_key` is not enabled when debug mode is active. ```python from h2spacex import logger logger.debug = True ``` -------------------------------- ### SOCKS5 Proxy Support Source: https://context7.com/nxenon/h2spacex/llms.txt Enables routing traffic through a SOCKS5 proxy by providing `proxy_hostname` and `proxy_port_number` parameters to `H2OnTlsConnection` or `H2Connection`. ```APIDOC ## SOCKS5 Proxy Support Both `H2OnTlsConnection` and `H2Connection` accept optional `proxy_hostname` and `proxy_port_number` parameters. When set, all traffic is tunneled through the specified SOCKS5 proxy using PySocks. ```python from h2spacex import H2OnTlsConnection # Route through a local SOCKS5 proxy (e.g., Burp Suite or SSH tunnel) h2_conn = H2OnTlsConnection( hostname='target.example.com', port_number=443, proxy_hostname='127.0.0.1', proxy_port_number=1080 ) h2_conn.setup_connection() # Output: + Connected through Proxy: target.example.com:443 --> 127.0.0.1:54321 ``` ``` -------------------------------- ### Create HTTP/2 POST Request Frames for SPA Source: https://context7.com/nxenon/h2spacex/llms.txt Builds HTTP/2 frames for a Single Packet Attack on a POST request. Returns frames split into two parts: all frames except the last byte, and a final DATA frame with the END_STREAM flag containing the last byte. This separation is crucial for the SPA technique. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='target.example.com', port_number=443) h2_conn.setup_connection() headers = """cookie: session=abc123 content-type: application/x-www-form-urlencoded accept: */*""" body = "param=value&token=xyz789" stream_ids = h2_conn.generate_stream_ids(number_of_streams=3) all_headers_frames = [] all_data_frames = [] for s_id in stream_ids: head_frames, last_frame = h2_conn.create_single_packet_http2_post_request_frames( method='POST', authority='target.example.com', scheme='https', path='/api/action', headers_string=headers, stream_id=s_id, body=body, check_headers_lowercase=True # auto-lowercases header names (HTTP/2 requirement) ) all_headers_frames.append(head_frames) all_data_frames.append(last_frame) # Concatenate frames into byte streams headers_bytes = b''.join(bytes(f) for f in all_headers_frames) data_bytes = b''.join(bytes(f) for f in all_data_frames) # --- SPA send sequence --- h2_conn.send_frames(headers_bytes) # send all leading frames from time import sleep sleep(0.1) # brief pause h2_conn.send_ping_frame() # warm up the connection h2_conn.send_frames(data_bytes) # deliver all final bytes in one packet ``` -------------------------------- ### FrameParser Source: https://context7.com/nxenon/h2spacex/llms.txt A stateful class for incrementally parsing raw HTTP/2 response bytes, handling control frames, and storing headers and body per stream ID. It supports automatic decompression of common compression formats. ```APIDOC ## FrameParser — HTTP/2 Response Frame Parser ### Description A stateful class that incrementally parses raw HTTP/2 response bytes, handles SETTINGS ACK/PING exchanges, and stores headers and body per stream ID. Supports automatic decompression of gzip, brotli, and deflate response bodies. Access collected data via `headers_and_data_frames` dict keyed by stream ID. ### Method ```python parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(raw) ``` ### Usage Example ```python from h2spacex import H2OnTlsConnection, h2_frames h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() # ... send requests ... raw = h2_conn.read_response_from_socket(_timeout=3) parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(raw) # Pretty-print all responses (handles gzip/br/deflate automatically) parser.show_response_of_sent_requests() # Or access raw data per stream for stream_id, data in parser.headers_and_data_frames.items(): headers = data['header'] # str of response headers body = data['data'] # bytes of response body ns_time = data.get('nano_seconds') # int nanosecond timestamp or None print(f'[{stream_id}] {headers.splitlines()[0]} | body_len={len(body)} | t={ns_time}') ``` ``` -------------------------------- ### H2Connection Source: https://context7.com/nxenon/h2spacex/llms.txt Raw HTTP/2 connection without TLS. Available since version 1.2.1. Uses the same API as H2OnTlsConnection but operates over a plain TCP socket. Useful for testing HTTP/2 cleartext (h2c) endpoints. ```APIDOC ## H2Connection — Plain (Non-TLS) HTTP/2 Connection Raw HTTP/2 connection without TLS. Available since version 1.2.1. Uses the same API as `H2OnTlsConnection` but operates over a plain TCP socket. Useful for testing HTTP/2 cleartext (h2c) endpoints. ### Usage ```python from h2spacex.h2_connection import H2Connection h2_conn = H2Connection( hostname='example-h2c.com', port_number=80, read_timeout=3 ) h2_conn.setup_connection() ``` ``` -------------------------------- ### HTTP/2 FrameParser for Response Analysis Source: https://context7.com/nxenon/h2spacex/llms.txt Use `FrameParser` to incrementally parse raw HTTP/2 response bytes, handling various compression formats and SETTINGS/PING exchanges. Access collected headers and bodies via `headers_and_data_frames`. ```python from h2spacex import H2OnTlsConnection, h2_frames h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() # ... send requests ... raw = h2_conn.read_response_from_socket(_timeout=3) parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(raw) # Pretty-print all responses (handles gzip/br/deflate automatically) parser.show_response_of_sent_requests() # Or access raw data per stream for stream_id, data in parser.headers_and_data_frames.items(): headers = data['header'] # str of response headers body = data['data'] # bytes of response body ns_time = data.get('nano_seconds') # int nanosecond timestamp or None print(f'[{stream_id}] {headers.splitlines()[0]} | body_len={len(body)} | t={ns_time}') ``` -------------------------------- ### read_response_from_socket() / read_response_from_socket_with_time() Source: https://context7.com/nxenon/h2spacex/llms.txt Reads raw bytes from the socket until a timeout occurs. `read_response_from_socket_with_time()` additionally feeds chunks to a `FrameParser` with timestamps for timing analysis. ```APIDOC ## read_response_from_socket() / read_response_from_socket_with_time() ### Description `read_response_from_socket()` reads raw bytes from the socket until timeout and returns them. `read_response_from_socket_with_time()` reads in a loop and feeds each chunk directly to the `FrameParser` with a nanosecond timestamp for timing-attack analysis—used internally by `start_thread_response_parsing()`. ### Method ```python raw_response = h2_conn.read_response_from_socket(_timeout=5) ``` ### Usage Example ```python from h2spacex import H2OnTlsConnection from h2spacex import h2_frames h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() # ... send requests ... # Manual (recommended) response reading raw_response = h2_conn.read_response_from_socket(_timeout=5) # waits up to 5s parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(raw_response) parser.show_response_of_sent_requests() # Output per stream: # #- Stream ID: 3 -# # -Headers- # :status 302 # location: /dashboard # -Body- # (empty) ``` ``` -------------------------------- ### create_single_packet_http2_post_request_frames Source: https://context7.com/nxenon/h2spacex/llms.txt Builds HTTP/2 frames for a Single Packet Attack on a POST request. It returns frames split into two parts: those without the last byte and a final DATA frame containing the last byte with the END_STREAM flag. This separation is crucial for the SPA technique. ```APIDOC ## create_single_packet_http2_post_request_frames() Builds the HTTP/2 frames for a Single Packet Attack on a POST request. Returns a tuple of `(frames_without_last_byte, last_data_frame)`. The first element contains HEADERS + DATA frames with all but the terminal byte; the second contains a single DATA frame with the END_STREAM flag holding only that final byte. Sending these separately is the key to the SPA technique. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='target.example.com', port_number=443) h2_conn.setup_connection() headers = """cookie: session=abc123 content-type: application/x-www-form-urlencoded accept: */*""" body = "param=value&token=xyz789" stream_ids = h2_conn.generate_stream_ids(number_of_streams=3) all_headers_frames = [] all_data_frames = [] for s_id in stream_ids: head_frames, last_frame = h2_conn.create_single_packet_http2_post_request_frames( method='POST', authority='target.example.com', scheme='https', path='/api/action', headers_string=headers, stream_id=s_id, body=body, check_headers_lowercase=True # auto-lowercases header names (HTTP/2 requirement) ) all_headers_frames.append(head_frames) all_data_frames.append(last_frame) # Concatenate frames into byte streams headers_bytes = b''.join(bytes(f) for f in all_headers_frames) data_bytes = b''.join(bytes(f) for f in all_data_frames) # --- SPA send sequence --- h2_conn.send_frames(headers_bytes) # send all leading frames from time import sleep sleep(0.1) # brief pause h2_conn.send_ping_frame() # warm up the connection h2_conn.send_frames(data_bytes) # deliver all final bytes in one packet ``` ``` -------------------------------- ### convert_request_headers_dict_to_string() Source: https://context7.com/nxenon/h2spacex/llms.txt Converts a Python dictionary of HTTP headers into a newline-delimited string format, automatically lowercasing header names as required by the HTTP/2 specification. ```APIDOC ## utils.convert_request_headers_dict_to_string() Converts a Python dict of HTTP headers into the newline-delimited string format expected by all `create_*` and `send_*` methods. Automatically lowercases header names to satisfy the HTTP/2 specification. ```python from h2spacex.utils import convert_request_headers_dict_to_string headers_dict = { 'Cookie': 'session=abc123', 'Content-Type': 'application/json', 'Accept': '*/*', 'User-Agent': 'h2spacex/1.2.1', } headers_string = convert_request_headers_dict_to_string(headers_dict) print(repr(headers_string)) # Output: # 'cookie: session=abc123\ncontent-type: application/json\naccept: */*\nuser-agent: h2spacex/1.2.1\n' ``` ``` -------------------------------- ### Read Raw HTTP/2 Response from Socket Source: https://context7.com/nxenon/h2spacex/llms.txt Use `read_response_from_socket()` to retrieve raw bytes from the socket. Feed these bytes into `FrameParser` for detailed analysis, including timing information. ```python from h2spacex import H2OnTlsConnection from h2spacex import h2_frames h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() # ... send requests ... # Manual (recommended) response reading raw_response = h2_conn.read_response_from_socket(_timeout=5) # waits up to 5s parser = h2_frames.FrameParser(h2_connection=h2_conn) parser.add_frames(raw_response) parser.show_response_of_sent_requests() # Output per stream: # #- Stream ID: 3 -# # -Headers- # :status 302 # location: /dashboard # -Body- # (empty) ``` -------------------------------- ### Logger Control Source: https://context7.com/nxenon/h2spacex/llms.txt Controls library console output using the module-level `logger` object. Set `be_silent_key = True` to suppress all output, or `debug = True` for verbose debug messages. Do not combine both. ```APIDOC ## Logger — Controlling Output The module-level `logger` object controls all library console output. Set `be_silent_key = True` to suppress all output, or `debug = True` to enable verbose debug messages (do not combine both). ```python from h2spacex import logger # Suppress all library output logger.be_silent_key = True # --- OR enable debug output --- # logger.debug = True # do NOT combine with be_silent_key from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() # prints nothing when be_silent_key=True ``` ``` -------------------------------- ### Gracefully Close HTTP/2 Connection Source: https://context7.com/nxenon/h2spacex/llms.txt Sends a GOAWAY frame to shut down the HTTP/2 connection gracefully and closes the underlying sockets. Always call this to cleanly terminate the session. ```python from h2spacex import H2OnTlsConnection h2_conn = H2OnTlsConnection(hostname='example.com', port_number=443) h2_conn.setup_connection() # ... perform requests ... h2_conn.close_connection() # Output: - Connection closed print(h2_conn.is_connection_closed) # True ```