A recent vulnerability discovered in HTTP/2 endpoints (CVE-2023-45288) allows attackers to send an excessive number of CONTINUATION frames, causing the endpoint to read arbitrary amounts of header data. This exploit forces the receiver to parse and process header data associated with a rejected request, potentially resulting in a denial of service (DoS) attack. The vulnerability stems from the HTTP/2 endpoint processing too many header frames without memory allocation limits.

To mitigate this vulnerability, a fix has been implemented to set a limit on the number of excess header frames that an HTTP/2 endpoint will process before closing the connection.

Here is a simple example of the vulnerability

def vulnerable_server(recv_stream, send_stream):
    http2_state = HTTP2State()

    while True:
        frame = read_frame(recv_stream)
        if frame is None:
            break

        if isinstance(frame, (HEADERS, CONTINUATION)):
            http2_state.process_header_data(frame)
            if http2_state.read_header_bytes > MaxHeaderBytes:
                # Header size exceed limit, no memory allocated
                pass

        elif isinstance(frame, (DATA, PRIORITY, RESET_STREAM, SETTINGS, PUSH_PROMISE, PING, GO_AWAY, WINDOW_UPDATE, ALT_SVC, UNIDIRECTIONAL_STREAM)):
            process_other_frame(frame)

Exploit Details

When an attacker sends an excessive number of CONTINUATION frames to an HTTP/2 endpoint, the endpoint continues to read and process header data associated with a rejected request. This behavior allows the attacker to send arbitrary amounts of header data, which can include Huffman-encoded data that is significantly more expensive for the receiver to decode than for the attacker to send.

An attacker can craft a sequence of HEADERS and CONTINUATION frames that cause the receiving system to exhaust its computational resources, leading to a denial of service (DoS) attack.

!HTTP2 Endpoint Arbitrary Header Data Read via CONTINUATION Frames

Fixes and Patches

To mitigate this vulnerability, set a limit on the number of excess header frames that an HTTP/2 endpoint will process before closing the connection. In the example below, we limit the number of excess header frames to 10, and the connection will be closed if this limit is exceeded:

MaxExcessHeaderFrames = 10

def fixed_server(recv_stream, send_stream):
    http2_state = HTTP2State()
    excess_header_frames = 

    while True:
        frame = read_frame(recv_stream)
        if frame is None:
            break

        if isinstance(frame, (HEADERS, CONTINUATION)):
            http2_state.process_header_data(frame)
            if http2_state.read_header_bytes > MaxHeaderBytes:
                # Header size exceed limit, check excess header frames
                excess_header_frames += 1
                if excess_header_frames >= MaxExcessHeaderFrames:
                    break

        elif isinstance(frame, (DATA, PRIORITY, RESET_STREAM, SETTINGS, PUSH_PROMISE, PING, GO_AWAY, WINDOW_UPDATE, ALT_SVC, UNIDIRECTIONAL_STREAM)):
            process_other_frame(frame)

Original References

1. CVE-2023-45288 Official Description
2. HTTP/2 Specification - CONTINUATION
3. Mitigating HTTP/2 Endpoint Vulnerabilities in HPACK State

Conclusion

CVE-2023-45288 is a critical vulnerability affecting HTTP/2 endpoints, potentially leading to DoS attacks. Implementing the fix to limit the number of excess header frames that an endpoint will process before closing the connection can help mitigate this issue, ensuring a secure and stable network infrastructure.

Timeline

Published on: 04/04/2024 21:15:16 UTC
Last modified on: 05/01/2024 18:15:10 UTC