You can see RFC 9113 which is for HTTP/2 to get more information about H2 and multiplexing itself. The descriptions here are from the RFC mentioned above.
In HTTP/2 we can have multiplexing with a new feature called Frames, each frame has an ID called Stream Identifier. Requests are separated by Stream IDs and for this reason, we have no Head of Line Blocking at HTTP/2 compared to HTTP/1.
You can see in this picture that multiple Frames with different Stream IDs are in a single packet in Wireshark:
Nagle’s algorithm helps have more bytes(requests) in a single packet to improve the efficiency of TCP/IP networks by removing the “small packet problem”.
Nagle’s algorithm is a means of improving the efficiency of TCP/IP networks by reducing the number of packets that need to be sent over the network. It was defined by John Nagle while working for Ford Aerospace. It was published in 1984 as a Request for Comments (RFC) with title Congestion Control in IP/TCP Internetworks in RFC 896.
The RFC describes what Nagle calls the “small-packet problem”, where an application repeatedly emits data in small chunks, frequently only 1 byte in size. Since TCP packets have a 40-byte header (20 bytes for TCP, 20 bytes for IPv4), this results in a 41-byte packet for 1 byte of useful information, a huge overhead. This situation often occurs in Telnet sessions, where most keypresses generate a single byte of data that is transmitted immediately. Worse, over slow links, many such packets can be in transit at the same time, potentially leading to congestion collapse.
To enable Nagle’s Algorithm, you can just disable TCP_NODELAY option. In Python, simply disable TCP_NODELAY on your TCP socket object:
In last-byte technique, you send the whole request except the last byte, and in the end, you send the last byte of all requests together.
Synced last-byte is a technique to mitigate network congestion and ensure a group of requests get processed by the target server simultaneously. You send everything but the final byte of each request, wait till that’s done, then send a single packet to complete each request.
By combining these techniques on HTTP/2, we can have a great Race Condition. But before all, I want to explain why the name is like that. Why Single Packet Attack? Single Packet?
Network jitter refers to the variation in the delay of received packets in a network. In other words, it measures the variability of packet arrival time.
OK, we said that it means: a variation in the delay of received packets, not a single packet. So when we send multiple packets, they do not arrive at the same time because there is network jitter and we can not easily and without trying many times to send packets that are arrived together.
If we have a single packet, network jitter is not a problem, because there are no other packets that need to be sent together. All requests are in a single packet. The “Single Packet Attack” is named like that because in this attack we do not have network jitter and all requests are in a single packet and not multiple packets.
Thanks to HTTP/2 Multiplexing feature we can send multiple frames in a single packet without Head of Line Blocking(Mixing up requests wrongly). But we have a limit! In a TCP Packet, we can have approximately 1500 bytes of data. So we have a limit, for example, how many POST requests with body we can send in a single packet! If the body is so big maybe we can just put 1 request in a packet! So what is the solution?
With the last-byte sync method + enabling Nagle’s Algorithm mentioned above, we can do Single Packet Attack more easily and put about 20 requests in a single packet. We can send all requests without the last byte for each request, wait some time, and send the remaining byte of each request all together.
Normal POST request with data is like this:
We keep the last byte of the last DATA frame and remove the END_STREAM flag. New Request frames are like this:
I show the steps:
I created a tool(library) called H2SpaceX for exploiting this type of race condition for two reasons:
I explained all in the Wiki if you would like to use my tool and also have some examples for using the tool and solve Portswigger race condition labs.
I’m Mohammad Amin Nasiri (Xenon), a Application Security Engineer with 2+ years of hands-on security assessment and auditing experience, trying to expand my hacking skills and research on web security. Find me on Github, LinkedIn, and Twitter.