HTTP Request Smuggling について (h11 を用いた例証)

HTTP Request Smuggling についての覚え書きと, h11 で過去に見つかった脆弱性 CVE-2025-43859 についての検証

検証環境

HTTP Request Smuggling の基礎

HTTP/2 について

CVE-2025-43859 について

具体的な問題点

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

7\r\n
Welcome\r\n
1c\r\n
to Mozilla Developer Network\r\n
0\r\n
\r\n
import h11

def parse_chunked_request(footer: bytes) -> tuple[bool, list[str]]:
    request = (
        b"POST / HTTP/1.1\r\n"
        b"Host: localhost\r\n"
        b"Transfer-Encoding: chunked\r\n"
        b"\r\n"
        b"5\r\n"
        b"hello"
        + footer
        + b"0\r\n"
        + b"\r\n"
    )
    connection = h11.Connection(h11.SERVER)
    connection.receive_data(request)
    events = []

    try:
        while True:
            event = connection.next_event()
            if event is h11.NEED_DATA:
                return False, events
            events.append(type(event).__name__)
            if isinstance(event, h11.EndOfMessage):
                return True, events
    except h11.ProtocolError as error:
        events.append(f"{type(error).__name__}: {error}")
        return False, events

for footer in (b"\r\n", b"XX", b"\n\n"):
    accepted, events = parse_chunked_request(footer)
    result = "ACCEPTED" if accepted else "REJECTED"
    print(f"footer={footer!r}: {result} ({', '.join(events)})")
footer=b'\r\n': ACCEPTED (Request, Data, EndOfMessage)
footer=b'XX': ACCEPTED (Request, Data, EndOfMessage)
footer=b'\n\n': ACCEPTED (Request, Data, EndOfMessage)
if self._bytes_in_chunk == 0:
    self._bytes_to_discard = 2
    chunk_end = True

まとめ