In a previous article we saw how HTTP/2 enhanced the performance of the Web, compared to the predecessors (HTTP/1.x). We also saw how these enhancements can be used by an attacker to exploit some vulnerabilities in web applications.
In this article I’d like to introduce HTTP/3 (the successor of HTTP/2) which is based on QUIC, a connection oriented transport protocol which further improves performances (and security) but at the same time it can introduce new security risks and attack vectors.
A (very) QUIC introduction
We can summarize the evolution of the HTTP protocol as follows:
- HTTP/0.9 (80’s)
- simple client-server data communication protocol
- only GET requests support
- server always expect replies with HTML
- HTTP/1.x (1996)
- support to multiple HTTP methods (POST, HEAD, PUT, DELETE, etc..)
- support of status codes
- support of HTTP headers
- reuse of HTTP connections and pipelining
- HTTP/2 (2015) -> binary multiplexed over TCP
- it’s a binary protocol (the previous ones are ASCII based)
- improve performances reducing the overhead of multiple connections and supporting multiplexing
- compression of HTTP headers
- many additional improvements from a performance standpoint
However HTTP/2 itself already shown its own limitations. For example, it doesn’t solve the TCP head-of-line blocking: even though multiplexing requests solve this issue at the application layer, it still exists at the transport layer. This happens because if there is a packet loss in the TCP stream, all HTTP/2 streams need to wait until the packet is re-transmitted and received.
In 2022 HTTP/3 has been proposed as standard in RFC9114. It relies on QUIC, a new transport layer (developed in user-space) protocol based on UDP.
So basically QUIC includes many features of TCP (such as retransmissions, congestion and flow control) but without the need of establish a TCP connection (it relies on UDP which is a connection less transport protocol).
We can say that QUIC is a reliable protocol based on a non reliable protocol (UDP) just like TCP is based on IP protocol.
An important feature of QUIC is that it has streams just like HTTP/2 but here streams are logical and independent flow of data within single connection. This feature solves the TCP head-of-line blocking issue that was present in HTTP/2.
Another interesting improvement is the ability to migrate the connections between IP addresses and network interfaces (for example when switching from a WiFi to a 4G network). Since each connection between two endpoints is identified by a unique connection ID, if the client (or the server) switch to a different network (or IP address and port number) the original connection can still be used and they don’t need to setup a new connection from scratch.
Furthermore QUIC enhances the security of the data transmitted on the wire because it incorporates CRYPTO
frames to transmit the TLS 1.3 cryptographic handshake messages and only few messages are in clear-text.
However even if QUIC was designed with security in mind, security researchers already found interesting attacks that can apply to this protocol.
Using QUIC to send attacker controlled packets
A recent research shown an interesting scenario that leverages the QUIC design to perform a client-side request forgery attack. In this class of attacks, the attacker (client) is able to to trigger the victim (server) to send one or more “unintended” network requests to another host (target). From an attacker perspective, this is really interesting because it allows to achieve at least two goals:
- accessing internal/restricted networks or services not publicly accessible
- utilizing the higher bandwidth available from the server to a target
The paper illustrates how an attacker (the QUIC client) could force the victim (the QUIC server) to perform traffic amplification and protocol impersonation attacks. In this article I’ll only focus on the former one but I strongly recommend you to read the entire paper.
Protocol impersonation is a known technique commonly used by attackers in order to impersonate legitimate protocol and bypass network filtering. In this context is a bit different and the idea is the following: can we leverage QUIC features to force the victim (the QUIC server) to send requests that are actually interpreted as a different protocol?
The short answer is yes. Let’s see how.
During the handshake, the QUIC client send the INITAL
packet. Among other information, this packet includes the QUIC version. If the client version is unknown/invalid, the QUIC server responds with a version negotiation packet. Now imagine if the client (attacker) spoofs the source IP address of the UDP datagram: the server will initiate a version negotiation with the spoofed address. This behavior is depicted below:
The version negotiation packet follows a specific format:
Version Negotiation Packet {
Header Form (1) = 1,
Unused (7),
Version (32) = 0,
Destination Connection ID Length (8),
Destination Connection ID (0..2040),
Source Connection ID Length (8),
Source Connection ID (0..2040),
Supported Version (32) ...,
}
What the researcher found is that many of the bits can be controlled by the attacker. For example we know that QUIC needs a set of connection IDs (CIDs) to identify connections (the Source Connection IDs and the Destination Connection IDs). Generally speaking the CIDs are variable in lengths but at most 20 bytes. However during the version negotiation exchange, the CID lengths are not restricted to 20 bytes (because the QUIC specification states “future versions of QUIC could have different requirements for the lengths of connection IDs”) Since the CIDs are generated independently by the endpoints, an attacker can set arbitrary values of the CIDs, so he has control over 512 bytes of the version negotiation packet sent by the server (256 bytes for the source ID and 256 for the destination ID, including the 2 bytes for the lengths of the fields).
With these assumptions, the researcher was able to craft a valid datagram that can leverages the version negotiation mechanism to force the QUIC server to send a valid DNS request (and receiving a valid DNS response) to the spoofed IP address (ideally a DNS server such as 8.8.8.8
) for a specific domain (tu-berlin.de
).
The image below shows how a valid QUIC negotiation packet is mapped to a valid DNS query.
Notice how the SCID length byte is actually the first character t
(0x74) of the domain name tu-berlin.de
.
Finally, this is a Wireshark capture that shows the QUIC interpretation on the left and the DNS interpretation on the right for the same packets.
Now one might ask: is it possible to apply the same technique to impersonate different protocols other than DNS? The paper states that even if it might be hard (due to the difficulty of finding a valid combination of bytes that works with the boundary imposed by the QUIC protocol) it’s quite likely that there are number of valid datagram protocols that can be crafted by using this technique (with lot of debugging and creativity..).
The paper also includes several mitigations (at the protocol level) to avoid request forgery to reduce the controllability of the payload, such as preventing CID Reflection: a server should not mirroring the DCID proposed by the client and it should always choose a new CID in the handshake as its own DCID.
Conclusion
I found this paper really interesting as it shows how a modern and “secure by design” protocol can still have security implications, especially when it comes to hacker creativity. As QUIC continues to gain adoption across the internet, it becomes increasingly important for network administrators and security professionals to implement measures to detect and mitigate these potential vulnerabilities, ensuring the safe and secure deployment of QUIC in today’s interconnected digital landscape.