RFC 5927
ICMP Attacks against TCP
ICMP Attacks against TCP ๐ฆ
Okay bestie, paperwork first, then the fun stuff ๐ . This is RFC 5927, titled ICMP Attacks against TCP. It was written by F. Gont from UTN/FRH and published in July 2010. It's Informational, which means it's published for information and isn't a Standards Track spec ๐. It has ISSN 2070-1721. The title block doesn't list anything it obsoletes or updates, so it isn't replacing or changing any other RFC ๐.
Abstract โจ
This doc is about using ICMP (the Internet Control Message Protocol) to launch a bunch of attacks on TCP. It also describes a bunch of widely used tweaks to how TCP handles ICMP error messages, which help fix these issues ๐ก๏ธ.
Status of This Memo
Quick vibe check: this document is not an Internet Standards Track specification. It's published for information ๐.
It's a product of the IETF (Internet Engineering Task Force) and represents the consensus of the IETF community ๐ซถ. It went through public review and got approved for publication by the IESG (Internet Engineering Steering Group). Not everything the IESG approves is eligible for any level of Internet Standard, so see Section 2 of RFC 5741 for the details ๐ .
For the current status, any errata, and how to send feedback, check http://www.rfc-editor.org/info/rfc5927 ๐.
Copyright Notice
Copyright (c) 2010 IETF Trust and the people listed as the document's authors. All rights reserved ยฉ๏ธ.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info), as they stand on the publication date. Please read those carefully, because they describe your rights and restrictions. Code components pulled out of this document have to include the Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, same as that license says ๐.
This document may contain material from IETF Documents or IETF Contributions that were published or made publicly available before November 10, 2008. Some of the people who own the copyright in that material may not have given the IETF Trust permission to allow modifications outside the IETF Standards Process. Unless you get an adequate license from those copyright holders, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside that process. The one exceptions are formatting it for publication as an RFC or translating it into languages other than English ๐.
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
2. Background . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1. The Internet Control Message Protocol (ICMP) . . . . . . . 5
2.1.1. ICMP for IP version 4 (ICMPv4) . . . . . . . . . . . . 5
2.1.2. ICMP for IP version 6 (ICMPv6) . . . . . . . . . . . . 6
2.2. Handling of ICMP Error Messages . . . . . . . . . . . . . 6
2.3. Handling of ICMP Error Messages in the Context of IPsec . 7
3. Constraints in the Possible Solutions . . . . . . . . . . . . 8
4. General Counter-Measures against ICMP Attacks . . . . . . . . 10
4.1. TCP Sequence Number Checking . . . . . . . . . . . . . . . 10
4.2. Port Randomization . . . . . . . . . . . . . . . . . . . . 11
4.3. Filtering ICMP Error Messages Based on the ICMP Payload . 11
5. Blind Connection-Reset Attack . . . . . . . . . . . . . . . . 12
5.1. Description . . . . . . . . . . . . . . . . . . . . . . . 12
5.2. Attack-Specific Counter-Measures . . . . . . . . . . . . . 13
6. Blind Throughput-Reduction Attack . . . . . . . . . . . . . . 16
6.1. Description . . . . . . . . . . . . . . . . . . . . . . . 16
6.2. Attack-Specific Counter-Measures . . . . . . . . . . . . . 16
7. Blind Performance-Degrading Attack . . . . . . . . . . . . . . 16
7.1. Description . . . . . . . . . . . . . . . . . . . . . . . 16
7.2. Attack-Specific Counter-Measures . . . . . . . . . . . . . 18
7.3. The Counter-Measure for the PMTUD Attack in Action . . . . 22
7.3.1. Normal Operation for Bulk Transfers . . . . . . . . . 22
7.3.2. Operation during Path-MTU Changes . . . . . . . . . . 24
7.3.3. Idle Connection Being Attacked . . . . . . . . . . . . 25
7.3.4. Active Connection Being Attacked after Discovery
of the Path-MTU . . . . . . . . . . . . . . . . . . . 26
7.3.5. TCP Peer Attacked when Sending Small Packets Just
after the Three-Way Handshake . . . . . . . . . . . . 26
7.4. Pseudo-Code for the Counter-Measure for the Blind
Performance-Degrading Attack . . . . . . . . . . . . . . . 27
8. Security Considerations . . . . . . . . . . . . . . . . . . . 30
9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 32
10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 32
10.1. Normative References . . . . . . . . . . . . . . . . . . . 32
10.2. Informative References . . . . . . . . . . . . . . . . . . 33
1. Introduction ๐ธ
Okay so ICMP [RFC0792] [RFC4443] is a core part of the TCP/IP suite, and it's mainly used for reporting network errors ๐จ. The problem is that the current specs don't recommend any kind of validation checks on the ICMP error messages it receives. That leaves the door wide open for attacks on TCP [RFC0793] using ICMP. The big ones are blind connection-reset, blind throughput-reduction, and blind performance-degrading attacks ๐. The wild part is that all of these work even when the attacker is off-path, so they don't need to sniff the packets of the TCP connection they're attacking ๐.
People in the research community have known about the security risks of ICMP for a long time, but there's never been an official proposal for dealing with these vulnerabilities ๐. In 2005, the UK's National Infrastructure Security Co-ordination Centre (NISCC), which is now CPNI (Centre for the Protection of National Infrastructure), ran a disclosure process with help from other computer emergency response teams. A huge number of implementations were found vulnerable to all or some of the attacks in this document [NISCC][US-CERT]. The affected systems ran from desktop TCP/IP stacks all the way up to stacks running on core Internet routers ๐ฑ.
Honestly, implementations need to be way more careful when they process ICMP error messages, so the use of ICMP to attack TCP gets eliminated or at least mitigated [RFC4907] ๐ซถ.
This document wants to raise awareness of ICMP-based attacks on TCP, and it walks through several counter-measures that either eliminate these attacks or shrink their impact ๐ก๏ธ. Most of these counter-measures can be built while still staying compliant with the current specs. They basically just explain why you'd skip the advice written as "SHOULDs" in the specs, but they still follow the requirements written as "MUSTs" โ .
Heads up: the counter-measures in this document are not part of standard TCP behavior, and this document doesn't change that. The TCPM WG (TCP Maintenance and Minor Extensions Working Group) decided to document this widespread implementation of nonstandard TCP behavior, but not to change the TCP standard itself ๐.
Here's the map. Section 2 gives background on ICMP. Section 3 talks about the constraints on the general counter-measures that can be built against the attacks in this document. Section 4 describes several general validation checks that can mitigate any ICMP-based attack. Then Sections 5, 6, and 7 dive into different ICMP attacks on TCP and describe attack-specific counter-measures that eliminate them or greatly reduce their impact ๐บ๏ธ.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC2119] ๐.
2. Background ๐ง
2.1. The Internet Control Message Protocol (ICMP)
ICMP is mainly used in the Internet architecture to do fault isolation. That's the group of actions hosts and routers take to figure out that some network failure is happening [RFC0816] ๐.
When an intermediate router runs into a network problem while forwarding an IP packet, it usually sends an ICMP error message back to the source system so it knows what went wrong ๐ฎ. End systems can also generate ICMP error messages when they hit a problem while processing a datagram. The received ICMP errors get handed to the matching transport-protocol instance, which usually does some kind of fault recovery ๐ฉน.
Important bit: ICMP error messages are sent unreliably. They can get thrown away because of data corruption, network congestion, or rate-limiting ๐ญ. So even though they're useful, upper-layer protocols can't depend on ICMP for correct operation.
There are also no timeliness requirements for ICMP error messages. They can get delayed for all sorts of reasons, and in theory they could show up after an arbitrarily long delay โณ. For example, there's no existing requirement that a router flush its queued ICMP error messages when it reboots ๐.
2.1.1. ICMP for IP version 4 (ICMPv4)
[RFC0792] specifies ICMP for use with IPv4 (Internet Protocol version 4). From here on, that's called "ICMPv4" ๐. Among other things, it defines a bunch of error messages that end systems and intermediate systems can use to report errors back to the sending system. The Host Requirements RFC [RFC1122] sorts ICMPv4 error messages into "soft errors" and "hard errors", which roughly defines what each one means ๐ง.
The ICMPv4 specification [RFC0792] also defines the ICMPv4 Source Quench message (type 4, code 0). It's meant to give a mechanism for flow control and congestion control ๐.
[RFC1191] defines Path MTU Discovery (PMTUD). It uses ICMPv4 error messages of type 3 (Destination Unreachable), code 4 (fragmentation needed and DF bit set), so systems can figure out the MTU of an arbitrary internet path ๐.
Finally, [RFC4884] redefines some ICMPv4 messages so they can include an extension structure and a length attribute. That lets those messages carry extra information by encoding it in the extension structure ๐.
Appendix D of [RFC4301] has info on which ICMPv4 error messages get produced by hosts, by intermediate routers, or by both ๐๏ธ.
2.1.2. ICMP for IP version 6 (ICMPv6) โจ
okay so [RFC4443] specifies ICMPv6 ๐ฆ, and it's meant to be used with IPv6 [RFC2460] ๐
[RFC4443] defines the "Packet Too Big" (type 2, code 0) error message ๐, which is basically the ICMPv4 "fragmentation needed and DF bit set" (type 3, code 4) error message's glow-up ๐ [RFC1981] defines the Path MTU Discovery mechanism for IP version 6, and it uses these messages to figure out the MTU of an arbitrary internet path ๐ธ
Finally, [RFC4884] redefines some ICMPv6 messages so they can include an extension structure and a length attribute โจ That means those messages can carry extra info by encoding it in the extension structure ๐ง
Appendix D of [RFC4301] tells you which ICMPv6 error messages get produced by hosts, by intermediate routers, or by both ๐
2.2. Handling of ICMP Error Messages
ngl this part is kind of the main event ๐ The Host Requirements RFC [RFC1122] says in Section 4.2.3.9 that TCP MUST act on an ICMP error message passed up from the IP layer, directing it to the connection that triggered the error ๐ฅ
To let the receiving system demultiplex ICMP messages (aka figure out which conversation they belong to) ๐, part of the original packet that triggered the message gets included in the payload of the ICMP error message. So the receiver can use that info to match the ICMP error to the transport protocol instance that triggered it ๐ซถ
Neither the Host Requirements RFC [RFC1122] nor the original TCP specification [RFC0793] recommends any validation checks on received ICMP messages ๐ญ So as long as the ICMP payload contains the info that identifies an existing communication instance, it gets processed by the corresponding transport-protocol instance, and the corresponding action gets performed ๐
Therefore, for TCP, an attacker could send a crafted ICMP error message to the attacked system ๐ And as long as they can guess the four-tuple (i.e., Source IP Address, Source TCP port, Destination IP Address, and Destination TCP port) that identifies the communication instance to be attacked, they'll be able to use ICMP to pull off a variety of attacks. this is the scary part, bestie ๐ฅ
Generally, the four-tuple needed for these attacks is not known ๐ค However, as discussed in [Watson] and [RFC4953], there are a number of scenarios (notably TCP connections established between two BGP routers [RFC4271]) where an attacker may be able to know or guess the four-tuple that identifies a TCP connection ๐ In that case, if we assume the attacker knows the two systems involved in the TCP connection being attacked, both the client-side and the server-side IP addresses could be known or be within a reasonable number of possibilities ๐ Plus, since most Internet services use the so-called "well-known" ports, only the client port number might need to be guessed ๐ฏ So in such a scenario, an attacker would need to send, in principle, at most 65536 packets to perform any of the attacks described in this document ๐ฌ These issues get worse because most systems choose the port numbers they use for outgoing connections from a subset of the whole port number space, which cuts down the work needed to successfully perform these attacks ๐
The need to be more cautious when processing received ICMP error messages, in order to mitigate or eliminate the impact of the attacks described in this RFC, has been documented by the Internet Architecture Board (IAB) in [RFC4907] ๐
2.3. Handling of ICMP Error Messages in the Context of IPsec
okay so Section 5.2 of [RFC4301] describes the processing of inbound IP traffic in the case of "unprotected-to-protected" ๐ For ICMP, when an unprotected ICMP error message is received, it gets matched to the corresponding security association using the SPI (Security Parameters Index) included in the payload of the ICMP error message ๐๏ธ Then local policy is applied to decide whether to accept or reject the message and, if accepted, what action to take as a result โจ For example, if an ICMP Destination Unreachable message is received, the implementation must decide whether to act on it, reject it, or act on it with constraints ๐ง Section 8 ("Path MTU/DF Processing") talks about how to handle unauthenticated ICMPv4 "fragmentation needed and DF bit set" (type 3, code 4) and ICMPv6 "Packet Too Big" (type 2, code 0) messages when an IPsec implementation is configured to process (vs. ignore) those messages ๐ซง
Section 6.1.1 of [RFC4301] notes that processing unauthenticated ICMP error messages may result in denial or degradation of service, so it would be desirable to ignore those messages ๐ซ BUT it also notes that in many cases, ignoring these ICMP messages can degrade service, e.g., because PMTUD and redirection messages don't get processed, so there's also a motivation for accepting and acting on them ๐คทโโ๏ธ It finally says that, to accommodate both ends of this spectrum, a compliant IPsec implementation MUST permit a local administrator to configure it to accept or reject unauthenticated ICMP traffic, and that this control MUST be at the granularity of ICMP type and MAY be at the granularity of ICMP type and code ๐๏ธ Additionally, an implementation SHOULD incorporate mechanisms and parameters for dealing with such traffic ๐ ๏ธ
Thus, the policy for processing unprotected ICMP error messages is left up to the implementation and the administrator ๐
3. Constraints in the Possible Solutions
If a host wants to do validation checks on received ICMP error messages before acting on them, it's limited by how much of the packet that triggered the error the sender chose to include in the ICMP payload ๐ค That constrains the possible validation checks, because the number of bytes of the triggering packet included in the ICMP payload is limited ๐
For ICMPv4, [RFC0792] states that the IP header plus the first 64 bits of the packet that triggered the ICMPv4 message are to be included in the payload of the ICMPv4 error message ๐ฐ So it's assumed that all the data needed to identify a transport protocol instance and process the ICMPv4 error message is contained in the first 64 bits of the transport protocol header ๐ Section 3.2.2 of [RFC1122] states that "the Internet header and at least the first 8 data octets of the datagram that triggered the error" are to be included in the payload of ICMPv4 error messages, and that "more than 8 octets MAY be sent" ๐ท This lets implementations include more data from the original packet than the original ICMPv4 specification requires ๐ซ The "Requirements for IP Version 4 Routers" RFC [RFC1812] states that ICMPv4 error messages "SHOULD contain as much of the original datagram as possible without the length of the ICMP datagram exceeding 576 bytes" ๐ฆ
So for ICMPv4 messages generated by hosts, we can only expect to get the entire IP header of the original packet, plus the first 64 bits of its payload ๐ฅฒ For TCP, that means the only fields included in the ICMPv4 payload are the source port number, the destination port number, and the 32-bit TCP sequence number ๐ This clearly puts a constraint on the possible validation checks that can be performed, because there isn't much info to work with ๐ซ
This means, for example, that even if TCP were signing its segments with the TCP MD5 signature option [RFC2385], this mechanism couldn't be used as a counter-measure against ICMP-based attacks ๐ซ Why? Because ICMP messages include only a piece of the TCP segment that triggered the error, so the MD5 [RFC1321] signature couldn't be recalculated ๐ In the same way, even if the attacked peer were authenticating its packets at the IP layer [RFC4301], only a part of the original IP packet would be available, so the signature used for authentication couldn't be recalculated ๐ต That means the authentication header in the original packet couldn't be used as a counter-measure for ICMP-based attacks against TCP ๐ก๏ธ
[RFC4884] updated [RFC0792] and specified that ICMPv4 Destination Unreachable (type 3), Time Exceeded (type 11), and Parameter Problem (type 12) messages that have an ICMP Extension Structure appended include at least 128 octets in the "original datagram" field ๐ That would make things better, but at the time of this writing, [RFC4884] is not yet widely deployed for end-systems ๐ฅบ
For IPv6, the payload of ICMPv6 error messages includes as many octets from the IPv6 packet that triggered the ICMPv6 error message as will fit without making the resulting ICMPv6 error message exceed the minimum IPv6 MTU (1280 octets) [RFC4443] ๐ So more info is available than in the IPv4 case ๐
Hosts could require ICMP error messages to be authenticated [RFC4301] before acting on them ๐ But while that requirement could make sense for ICMP error messages sent by hosts, it wouldn't be feasible for ICMP error messages generated by routers ๐ โโ๏ธ That would imply either that the attacked system has a security association [RFC4301] with every existing intermediate system, or that it can establish one dynamically ๐ธ๏ธ Current levels of deployment of protocols for dynamic establishment of security associations make this unfeasible ๐ฉ Plus, this would require routers to use certificates with paths compatible for all hosts on the network ๐ Finally, there may be some scenarios, like embedded devices, where the processing power requirements of authentication might not allow IPsec authentication to be implemented effectively ๐ค
4. General Counter-Measures against ICMP Attacks โจ
the following subsections describe a bunch of mitigation techniques that help eliminate or mitigate the impact of the attacks discussed in this document ๐ง Rather than being alternative counter-measures, they can be implemented together to increase protection against these attacks ๐ซถ๐
4.1. TCP Sequence Number Checking ๐
okay so bestie, the current specs don't check anything about the TCP segment sitting inside an ICMP payload ๐ Nobody verifies that a received ICMP error was actually triggered by a segment that was "in flight" to the destination. So even stale ICMP error messages get acted upon. not okay ๐ญ
BUT lots of TCP implementations added a validation check to fix this โจ They only react to ICMP error messages that look like they belong to segments currently "in flight" to the destination system. The check looks like this:
SND.UNA =< SEG.SEQ < SND.NXT
So the sequence number has to fall inside the range of data that's already been sent but not yet acknowledged. If an ICMP error message doesn't pass this check, it gets discarded ๐๏ธ
Even if an attacker managed to guess the four-tuple that identifies the TCP connection, this extra check would shrink their chances of getting a spoofed ICMP packet accepted to Flight_Size/2^^32 (where Flight_Size is the number of data bytes already sent to the remote peer, but not yet acknowledged [RFC5681]). For connections in the SYN-SENT or SYN-RECEIVED states, the odds drop to 1/2^^32. And for a TCP endpoint with no data "in flight", the check completely kills the chance of these attacks working ๐
โโ๏ธโจ
This validation check has been around for ages: it's been in Linux [Linux] for many years, in OpenBSD [OpenBSD] since 2004, and in FreeBSD [FreeBSD] and NetBSD [NetBSD] since 2005 ๐ฆ
Now the caveat, because it's important ๐ This check makes the number of packets needed for any of the attacks in this document way bigger. BUT it might not be enough when bandwidth is easy to come by and/or large TCP windows [RFC1323] are in use ๐ฌ Also, this check does NOT help against on-path attacks, meaning the scenarios where the attacker can sniff the packets belonging to the target TCP connection.
It should be noted that, since ICMP error messages have no timeliness requirements, the TCP Sequence Number check described in this section might cause legitimate ICMP error messages to get discarded ๐ฅฒ And even when this check is enforced, TCP might still end up responding to stale ICMP error messages (for example, if the Sequence Number for the corresponding direction of the data transfer wraps around) ๐
4.2. Port Randomization ๐ธ
Like we talked about in the earlier sections, to pull off any of the attacks in this document, an attacker would need to guess (or know) the four-tuple that identifies the connection they want to attack ๐ต๏ธโโ๏ธ So if you increase the port number range used for outgoing TCP connections, AND randomize the port number chosen for each outgoing TCP connection, it gets way harder for attackers to do any of this stuff ๐
[PORT-RANDOM] recommends that transport protocols randomize the ephemeral ports used by clients, and it proposes a bunch of randomization algorithms ๐ฒโจ
4.3. Filtering ICMP Error Messages Based on the ICMP Payload ๐ง
Here's the thing: the source address of ICMP error messages doesn't need to be spoofed to pull off the attacks in this document, because those ICMP error messages might legitimately come from an intermediate system ๐คทโโ๏ธ So simple filtering based on the source address of ICMP error messages does NOT work as a counter-measure against these attacks.
HOWEVER, more advanced packet filtering can be set up in middlebox devices like firewalls and NATs ๐ฅ These middleboxes look inside the payload of the ICMP error messages, and do ingress and egress packet filtering based on the source address of the IP header contained in that payload. And since the source address inside the payload DOES need to be spoofed to pull off these attacks, this kind of advanced filtering actually works as a counter-measure ๐
Just like traditional egress filtering [IP-filtering], egress filtering based on the ICMP payload can help stop users of the network protected by the firewall from successfully running ICMP attacks against TCP connections between external systems. Ingress filtering based on the ICMP payload can also keep TCP connections between internal systems from getting attacked by external systems ๐ก๏ธ [ICMP-Filtering] has examples of ICMP filtering based on the ICMP payload.
This filtering technique has been implemented in OpenBSD's Packet Filter [OpenBSD-PF], which has been ported to a bunch of systems, FreeBSD [FreeBSD] included ๐ก
5. Blind Connection-Reset Attack ๐ฅ
5.1. Description ๐
okay so when TCP gets handed an ICMP error message, it does its fault recovery thing, like this:
- If the network problem being reported is a "hard error", TCP will abort the corresponding connection.
- If the network problem being reported is a "soft error", TCP will just record this information, and repeatedly retransmit its data until they either get acknowledged, or the connection times out.
The Host Requirements RFC [RFC1122] says (in Section 4.2.3.9) that a host SHOULD abort the corresponding connection when it receives an ICMPv4 error message that indicates a "hard error". It also says that ICMPv4 error messages of type 3 (Destination Unreachable), codes 2 (protocol unreachable), 3 (port unreachable), and 4 (fragmentation needed and DF bit set) should be considered as indicating "hard errors" ๐ Now the ICMPv4 port unreachable part is kind of messy ๐ Section 4.2.3.9 of [RFC1122] says TCP SHOULD abort the corresponding connection in response to them, but Section 3.2.2.1 of the same RFC ([RFC1122]) says TCP MUST abort the connection in response to them. Conflicting vibes, honestly ๐ค
While [RFC4443] didn't exist when [RFC1122] was published, you could extrapolate the concept of "hard errors" to ICMPv6 error messages of type 1 (Destination Unreachable), codes 1 (communication with destination administratively prohibited), and 4 (port unreachable) ๐ง
So an attacker could use ICMP to run a blind connection-reset attack by sending any ICMP error message that indicates a "hard error" to either of the two TCP endpoints of the connection ๐ Because of TCP's fault recovery policy, the connection would be immediately aborted. Yikes.
Some stacks are known to extrapolate ICMP "hard errors" across TCP connections, which makes this attack hit even harder ๐ญ A single ICMP packet could bring down ALL the TCP connections between the corresponding peers.
It's really important to know that even if TCP itself were protected against the blind connection-reset attack described in [Watson] and [TCPM-TCPSECURE], by network layer authentication [RFC4301], by the TCP MD5 signature option [RFC2385], by TCP-AO [RFC5925], or by the mechanism specified in [TCPM-TCPSECURE], the blind connection-reset attack described in this document would STILL succeed ๐ซ
5.2. Attack-Specific Counter-Measures
Okay so, this is where it gets spicy ๐ถ๏ธ Looking at the situations where ICMP messages signaling "hard errors" can show up is actually a super smart way to find chances to soften ICMP-based blind connection-reset attacks ๐ฆ
ICMPv4 type 3 (Destination Unreachable), code 2 (protocol unreachable)
This error means the host that sent it got a packet meant for a transport protocol it doesn't support ๐ For connection-oriented protocols like TCP, you'd totally expect this when someone's trying to set up a connection. But getting it during a connection? That's weird, bestie. It would mean support for that transport protocol got removed from the sending system while your connection was alive ๐
ICMPv4 type 3 (Destination Unreachable), code 3 (port unreachable)
This one says the system that sent it got a packet aimed at a socket (IP address, port number) where nobody's listening ๐ Transport protocols that have their own way of saying "this port is closed" shouldn't be getting these messages, because the protocol would already signal that port unreachable condition with its own mechanisms ๐ซถ And since a transport protocol usually doesn't swap out or reload itself once a connection is up, these errors should be pretty rare.
ICMPv4 type 3 (Destination Unreachable), code 4 (fragmentation needed and DF bit set)
This message means an intermediate node needed to fragment a datagram, but the DF (Don't Fragment) bit in the IP header was set ๐ง It counts as a "soft error" when TCP implements PMTUD, and as a "hard error" when TCP doesn't. TCP/IP stacks that skip PMTUD (or have turned it off) but can handle IP fragmentation/reassembly shouldn't be sending their IP packets with the DF bit set, so they shouldn't be getting these ICMP error messages either. Some TCP/IP stacks don't do PMTUD and can't do IP fragmentation/reassembly, and they're known to set the DF bit anyway. Those stacks could legitimately get these ICMP error messages ๐ญ
ICMPv6 type 1 (Destination Unreachable), code 1 (communication with destination administratively prohibited)
This error says the destination can't be reached because of an administrative policy ๐ For connection-oriented protocols like TCP, you'd expect it during connection setup. Getting it while the connection is in any of the synchronized states would mean the administrative policy changed mid-connection. But just like this condition showed up out of nowhere (it wasn't there when the connection started), it could also get sorted out pretty quickly ๐
ICMPv6 type 1 (Destination Unreachable), code 4 (port unreachable)
This one's basically the twin of the ICMPv4 type 3 (Destination Unreachable), code 3 (port unreachable) message we just talked about ๐ฏ So the same considerations apply โจ
Now here's the tea โ The Host Requirements RFC [RFC1122] says in Section 4.2.3.9 that TCP SHOULD abort the corresponding connection when it gets ICMPv4 messages of type 3 (Destination Unreachable), codes 2 (protocol unreachable), 3 (port unreachable), and 4 (fragmentation needed and DF bit set). But Section 3.2.2.1 says TCP MUST accept an ICMPv4 port unreachable (type 3, code 3) for the same purpose as a RST. So for ICMPv4 messages of type 3, codes 2 and 4, there's room to go against the advice in the existing specs ๐ For type 3, code 3, the specs are kind of ambiguous, so there may or may not be room to go against that advice ๐คทโโ๏ธ
Based on all that, most popular TCP implementations treat every ICMP "hard error" received for connections in any of the synchronized states (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, or TIME-WAIT) as a "soft error." Meaning they don't abort the connection when they get one ๐
They also don't extrapolate ICMP errors across TCP connections ๐ฆ The reasoning is that TCP should be as robust as possible. Aborting the connection would mean ignoring the iconic Internet feature where, for many internal failures, it rebuilds its function without any disruption to the endpoints [RFC0816] ๐
Just so you know, treating ICMP "hard errors" as "soft errors" for connections in those synchronized states might stop TCP from responding quickly to a legit ICMP error message ๐
Also, ICMP error messages are sent unreliably, so transport protocols shouldn't depend on them to work correctly ๐ If one of these messages were legit, the connection would eventually time out anyway. And applications can still be notified asynchronously about the error condition, so they can still abort their own connections if they think that's the move ๐
Now, in scenarios where an intermediate system sets the DF bit in segments sent by a TCP that doesn't implement PMTUD, or where the TCP at one endpoint gets dynamically disabled, TCP would only abort the connection after a USER TIMEOUT [RFC0793]. That's a responsiveness hit ๐ฌ But these scenarios are super unlikely in production, so it's probably better to maybe lose some responsiveness for the sake of robustness ๐ธ Applications can still get the async notification and abort on their own too.
In multipath routing or route-change situations, failures on some (but not all) of the paths may trigger ICMP error messages that probably wouldn't cause a connection abort if any of these counter-measures were in place. Again, aborting would mean ignoring that Internet magic where it rebuilds itself after internal failures without disrupting the endpoints [RFC0816]. The vibe is that communication should survive as long as there's still a working path to the destination system [DClark] โจ And applications can still be notified asynchronously and abort on their own if they want to.
This counter-measure has been running in BSD-derived TCP/IP implementations (like [FreeBSD], [NetBSD], and [OpenBSD]) for more than ten years [Wright][McKusick] ๐ The Linux kernel has also been doing this for more than ten years [Linux] ๐ง
6. Blind Throughput-Reduction Attack
6.1. Description
Okay so this one's about ICMPv4 Source Quench messages ๐ซ The Host Requirements RFC [RFC1122] says in Section 4.2.3.9 that hosts MUST react to ICMPv4 Source Quench messages by slowing transmission on the connection. So an attacker could send ICMPv4 Source Quench (type 4, code 0) messages to a TCP endpoint and make it slow down how fast it sends data to the other endpoint ๐ค [RFC1122] also adds that the RECOMMENDED procedure is to put the connection into the slow-start phase of TCP's congestion control algorithm [RFC5681] ๐ For implementations that use an initial congestion window of one segment, a sustained attack would cut the throughput of the attacked connection to about SMSS (Sender Maximum Segment Size) [RFC5681] bytes per RTT (round-trip time) ๐ The throughput during an attack might be a little higher if a larger initial congestion window is in use [RFC3390] โจ
6.2. Attack-Specific Counter-Measures
As discussed in the "Requirements for IP Version 4 Routers" RFC [RFC1812], research seems to suggest that ICMPv4 Source Quench messages are an ineffective (and unfair) antidote for congestion ๐ โโ๏ธ [RFC1812] also says that routers SHOULD NOT send ICMPv4 Source Quench messages in response to congestion. And TCP has its own congestion control mechanisms ([RFC5681] [RFC3168]) that don't depend on ICMPv4 Source Quench messages at all ๐
So a bunch of implementations just completely ignore ICMPv4 Source Quench messages meant for TCP connections ๐ This has been in Linux [Linux] since 2004, and in FreeBSD [FreeBSD], NetBSD [NetBSD], and OpenBSD [OpenBSD] since 2005 ๐ But it must be noted that this behavior goes against the requirement in [RFC1122] to react to ICMPv4 Source Quench messages by slowing transmission on the connection ๐ฌ
7. Blind Performance-Degrading Attack
7.1. Description โจ
Okay bestie, so picture this: one IP system has a ton of data to send to another system ๐ฆ. That data gets chopped into a series of IP datagrams. Ideally, you want those datagrams to be the biggest size possible without needing fragmentation anywhere along the path from source to destination ๐ . That magic number is the Path MTU (PMTU), and it's equal to the minimum MTU of each hop in the path ๐ฆ. The technique that lets IP systems figure out the Path MTU of any internet path is called "Path MTU Discovery" (PMTUD). [RFC1191] specifies it for IPv4, and [RFC1981] specifies it for IPv6 ๐ซถ.
For IPv4, PMTUD uses the Don't Fragment (DF) bit in the IP header to find the Path MTU dynamically ๐ฅ. The basic idea is that the source system assumes the path MTU is the same as the first hop's MTU, and sends everything with the DF bit set. If a datagram is too big for some intermediate router to forward without fragmentation, the router discards it and sends back an ICMPv4 "Destination Unreachable, fragmentation needed and DF set" (type 3, code 4) error message to the sender. That message reports the MTU of the constricting hop, so the sender can lower its assumed Path-MTU to match ๐ธ.
For IPv6, intermediate systems don't fragment packets at all. So there's an "implicit" DF bit set on every packet sent on a network ๐ง. If a datagram is too big to be forwarded without fragmentation by some intermediate router, the router discards it and returns an ICMPv6 "Packet Too Big" (type 2, code 0) error message to the sending system. Same energy as IPv4: that message reports the MTU of the constricting hop, so the sender can reduce its assumed Path-MTU accordingly โจ.
Here's the tea โ. As discussed in both [RFC1191] and [RFC1981], PMTUD can be used to attack TCP ๐. An attacker could send a crafted ICMPv4 "Destination Unreachable, fragmentation needed and DF set" packet (or its ICMPv6 counterpart) to the sending system, advertising a small Next-Hop MTU. Then the attacked system shrinks the size of the packets it sends for that connection. Not iconic at all ๐.
The effect is two-fold ๐ญ. On one hand, the headers-to-data ratio goes up, so sending data to the remote TCP endpoint takes more overhead. On the other hand, if the attacked system wants to keep the same throughput it had before, it has to increase its packet rate. On virtually all systems, that means more processing overhead and an overall performance hit ๐.
There's a particularly chaotic scenario ๐ช๏ธ. The attacker reports a Next-Hop MTU that's smaller than or equal to the number of bytes needed for headers (IP header plus TCP header). For example, if the attacker reports a Next-Hop MTU of 68 bytes, and the headers (IP header plus TCP header) take up more than 68 bytes, the assumed Path-MTU won't even let the attacked system send a single byte of application data without fragmentation. This can lead to unpredictable results, bestie ๐ซ .
Another possible scenario is when a TCP connection is secured with IPsec ๐. If the attacker's reported Next-Hop MTU is smaller than the bytes needed for headers (IP and IPsec, in this case), the assumed Path-MTU won't even let the attacked system send a single byte of the TCP header without fragmentation. Also unpredictable results, so yikes ๐.
Now for the numbers, because they matter ๐ค. For IPv4, the reported Next-Hop MTU could be as small as 68 octets, since [RFC0791] requires every internet module to be able to forward a datagram of 68 octets without further fragmentation ๐. For IPv6, the required minimum IPv6 MTU is 1280, but the reported Next-Hop MTU can be smaller than 1280 octets [RFC2460] ๐. If the reported Next-Hop MTU is smaller than the minimum IPv6 MTU, the receiving host is not required to reduce the Path-MTU to a value smaller than 1280. It is required to include a fragmentation header in the outgoing packets to that destination from that moment on ๐ฆ๐.
7.2. Attack-Specific Counter-Measures ๐
okay so the IETF standardized a Path-MTU Discovery mechanism called "Packetization Layer Path MTU Discovery" (PLPMTUD) that doesn't depend on ICMP error messages at all ๐ซถ. Swapping it in for the traditional PMTUD (specified in [RFC1191] and [RFC1981]) gets rid of this vulnerability. The catch is that it can make PMTUD convergence time go up ๐ญ.
This section describes a modification to the PMTUD mechanism from [RFC1191] and [RFC1981] that OpenBSD and NetBSD have shipped since 2005 ๐ธ. It's meant to improve TCP's resistance to the blind performance-degrading attack from Section 7.1. The counter-measure basically ignores ICMP messages while a connection is making progress, and it doesn't break any of the requirements in [RFC1191] and [RFC1981] ๐ฆ.
From here on, we'll call both ICMPv4 "fragmentation needed and DF bit set" messages and ICMPv6 "Packet Too Big" messages "ICMP Packet Too Big" messages ๐.
On top of the general validation check from Section 4.1, these implementations change how TCP reacts to ICMP "Packet Too Big" error messages ๐ฅ. TCP ignores them while the connection is making progress, and only honors them after the corresponding data has been retransmitted a specified number of times. So when one of these messages shows up, TCP just makes a note of it, and it only acts on that note once the corresponding data has already been retransmitted that many times ๐.
This basic policy would seriously calm down the attack on PMTUD, but it has a downside: TCP might take longer to figure out the Path-MTU for a connection ๐. That's extra annoying for brand-new connections, because TCP might need several transmission attempts (and the timeouts that come with them) before it finds the PMTU. So this policy would push back the moment data starts arriving at the destination host ๐ฅฒ.
To protect TCP from the PMTUD attack and still let it quickly find the initial Path-MTU for a connection, these implementations split the traditional PMTUD mechanism into two stages: Initial Path-MTU Discovery and Path-MTU Update โจ.
The Initial Path-MTU Discovery stage is when TCP tries to send segments bigger than the ones it has sent and gotten acknowledged so far for this connection. In that stage, TCP has no record of those large segments ever reaching the destination host, so these implementations trust the network when it says those packets are too large to reach the destination without being fragmented ๐ง.
The Path-MTU Update stage is when TCP tries to send segments that are equal to or smaller than the ones already sent and acknowledged for this connection. By then TCP already knows the estimated Path-MTU for the connection, so these implementations are more cautious about the errors the network reports ๐.
To let TCP tell apart segments doing Initial Path-MTU Discovery from segments doing Path-MTU Update, two new variables get added to TCP: maxsizesent and maxsizeacked ๐.
The maxsizesent variable holds the size (in octets) of the largest packet sent so far for this connection. It starts at 68 (the minimum IPv4 MTU) when the underlying Internet Protocol is IPv4, and at 1280 (the minimum IPv6 MTU) when it's IPv6. Whenever a packet larger than maxsizesent octets gets sent, maxsizesent is set to that value ๐.
maxsizeacked holds the size (in octets) of the largest packet (data plus headers) acknowledged so far for this connection. It also starts at 68 for IPv4 and 1280 for IPv6. Whenever an acknowledgement comes in for a packet larger than maxsizeacked octets, maxsizeacked is set to the size of that acknowledged packet. Here's the tea: because TCP acknowledgements are cumulative, a single ACK can acknowledge more than one packet. When that happens, the algorithm may "incorrectly" think it's in the "Path-MTU Update" stage instead of the "Initial Path-MTU Discovery" stage (as described below) ๐.
When an ICMP "Packet Too Big" error message arrives, the Next-Hop MTU it claims (from here on, "claimedmtu") gets compared with maxsizesent. If claimedmtu is larger than maxsizesent, the ICMP error message is silently discarded ๐๏ธ. The reasoning is that the error can't be legit if it claims to be triggered by a packet bigger than the largest one we've sent on this connection so far.
If that check passes, claimedmtu gets compared with maxsizeacked. If claimedmtu is equal to or larger than maxsizeacked, TCP is supposed to be in the Initial Path-MTU Discovery stage, so the ICMP "Packet Too Big" error message is honored right away. The assumed Path-MTU gets updated to the Next-Hop MTU the ICMP message claimed. Also, maxsizesent gets reset to the minimum MTU of the Internet Protocol in use (68 for IPv4, and 1280 for IPv6) ๐ฆ.
On the other hand, if claimedmtu is smaller than maxsizeacked, TCP is supposed to be in the Path-MTU Update stage. Since these implementations are more cautious about reported errors at this stage, they just record the error message they received and delay updating the assumed Path-MTU ๐ซ .
To pull off that delay, one new variable and one new parameter get added to TCP: nsegrto and MAXSEGRTO. The nsegrto variable holds the number of times a given segment has timed out. It starts at zero and goes up by one every time the corresponding segment times out. MAXSEGRTO sets how many times a given segment has to time out before an ICMP "Packet Too Big" error message can be honored, and in principle it can be set to any value greater than or equal to 0 ๐.
So if nsegrto is greater than or equal to MAXSEGRTO, and there's a pending ICMP "Packet Too Big" error message, that error message gets processed. At that point, maxsizeacked is set to claimedmtu, and maxsizesent is set to 68 (for IPv4) or 1280 (for IPv6) โญ.
Now, if an ICMP "Packet Too Big" error message is pending and the TCP SEQ it claims has been acknowledged (meaning an ACK acknowledging that sequence number was received), the "pending error" condition gets cleared ๐งน.
The reason this delayed processing works: if the connection is making progress, the ICMP "Packet Too Big" errors have to be a false claim ๐ . By checking for progress on the connection instead of just checking whether the ICMP messages are stale, TCP stays protected even when the offending ICMP messages are "in window". As a bonus, it also gets more robust against spurious ICMP messages triggered by things like corrupted TCP segments ๐ธ.
MAXSEGRTO can, in principle, be set to any value greater than or equal to 0. Setting it to 0 would make TCP perform the traditional PMTUD mechanism defined in [RFC1191] and [RFC1981] ๐. A MAXSEGRTO of 1 gives enough protection for most cases. Either way, implementations are free to pick higher values for this constant โจ. MAXSEGRTO could also be a function of the Next-Hop MTU claimed in the received ICMP "Packet Too Big" message. That means higher values for MAXSEGRTO could be used when the received message claims a Next-Hop MTU smaller than some specified value ๐ง . Both OpenBSD and NetBSD set MAXSEGRTO to 1 ๐.
If you want an even higher level of protection and you're okay with a longer delay before the Path-MTU is discovered, an implementation could treat TCP as always being in the Path-MTU Update stage. That way, updates to the assumed Path-MTU are always delayed ๐ข.
Section 7.3 shows this counter-measure in action, and Section 7.4 shows it in pseudo-code ๐.
It's important to note that this mechanism is an improvement on the current Path-MTU discovery mechanism, meant to reduce its security implications ๐ฅ. The current PMTUD mechanism, as specified by [RFC1191] and [RFC1981], still has some functionality problems [RFC2923], and this document doesn't aim to fix those. A mechanism that does address those issues is described in [RFC4821] ๐ฆ.
7.3. The Counter-Measure for the PMTUD Attack in Action ๐ฌ
This section shows the counter-measure for the ICMP attack against the PMTUD mechanism that's been implemented in OpenBSD and NetBSD ๐ง. It shows how the fix protects TCP from being attacked, and how the counter-measure behaves in normal scenarios too. As discussed in Section 7.2, this section assumes the PMTUD-specific counter-measure is implemented alongside the TCP sequence number checking described in Section 4.1 ๐.
Figure 1 illustrates a hypothetical scenario in which two hosts are connected by means of three intermediate routers. It also shows the MTU of each hypothetical hop. Every subsection that follows assumes the network setup in this figure ๐.
Also, for simplicity's sake, every subsection assumes an IP header of 20 octets and a TCP header of 20 octets. So, for example, when the PMTU is assumed to be 1500 octets, TCP will send segments containing at most 1460 octets of data ๐.
For simplicity's sake, all of the following subsections assume the TCP implementation at Host 1 (H1) has chosen a MAXSEGRTO of 1 โญ.
+----+ +----+ +----+ +----+ +----+
| H1 |--------| R1 |--------| R2 |--------| R3 |--------| H2 |
+----+ +----+ +----+ +----+ +----+
MTU=4464 MTU=2048 MTU=1500 MTU=4464
Figure 1: Hypothetical Scenario
7.3.1. Normal Operation for Bulk Transfers
okay so this subsection shows the counter-measure just vibing in normal operation ๐ no attack, just a TCP connection moving huge amounts of data. it assumes that right after the connection is set up, one of the endpoints starts sending packets that are as big as possible ๐
Host 1 Host 2
1. --> <SEQ=100><CTL=SYN> -->
2. <-- <SEQ=X><ACK=101><CTL=SYN,ACK> <--
3. --> <SEQ=101><ACK=X+1><CTL=ACK> -->
4. --> <SEQ=101><ACK=X+1><CTL=ACK><DATA=4424> -->
5. <--- ICMP "Packet Too Big" MTU=2048, TCPseq#=101 <--- R1
6. --> <SEQ=101><ACK=X+1><CTL=ACK><DATA=2008> -->
7. <--- ICMP "Packet Too Big" MTU=1500, TCPseq#=101 <--- R2
8. --> <SEQ=101><ACK=X+1><CTL=ACK><DATA=1460> -->
9. <-- <SEQ=X+1><ACK=1561><CTL=ACK> <--
Figure 2: Normal Operation for Bulk Transfers
so the nsegrto variable starts at zero ๐งธ and both maxsizeacked and maxsizesent start at the minimum MTU for whichever Internet Protocol is in use (68 for IPv4, and 1280 for IPv6) โจ
in lines 1 to 3, the three-way handshake happens and the connection is established ๐ค then in line 4, H1 tries to send a full-sized TCP segment. as [RFC1191] and [RFC1981] describe, TCP will try a segment with 4424 bytes of data, which makes an IP packet of 4464 octets ๐ฆ so maxsizesent gets set to 4464. when that packet hits R1, it triggers an ICMP "Packet Too Big" error message ๐
in line 5, H1 gets that ICMP error, which reports a Next-Hop MTU of 2048 octets. after it does the TCP sequence number check from Section 4.1, the reported Next-Hop MTU (claimedmtu) gets compared with maxsizesent. it's smaller than maxsizesent, so it passes and then gets compared with maxsizeacked. since claimedmtu is bigger than maxsizeacked, TCP figures that segment was doing the Initial PMTU Discovery ๐ so the TCP at H1 honors the ICMP message and updates the assumed Path-MTU. maxsizesent gets reset to the minimum MTU of the Internet Protocol in use (68 for IPv4, and 1280 for IPv6) ๐
in line 6, the TCP at H1 sends a segment with 2008 bytes of data, which makes an IP packet of 2048 octets. so maxsizesent is now 2008 bytes ๐ and when that packet reaches R2, it triggers another ICMP "Packet Too Big" error message ๐ญ
in line 7, H1 gets that one too, which reports a Next-Hop MTU of 1500 octets. after the TCP sequence number check, claimedmtu gets compared with maxsizesent. it's smaller, so it passes, then gets compared with maxsizeacked. claimedmtu is bigger than maxsizeacked, so TCP again assumes the segment was doing the Initial PMTU Discovery ๐ง and the TCP at H1 honors the message and updates the assumed Path-MTU. maxsizesent gets reset to the minimum MTU of the Internet Protocol in use.
in line 8, the TCP at H1 sends a segment with 1460 bytes of data, which makes an IP packet of 1500 octets. so maxsizesent is set to 1500 ๐ this packet reaches H2, which sends back an acknowledgement (ACK) segment.
in line 9, H1 finally gets the ACK for that data segment ๐ฅน since the packet was bigger than maxsizeacked, TCP updates maxsizeacked and sets it to 1500. at this point TCP has discovered the Path-MTU for this connection, and we are SO done ๐
7.3.2. Operation during Path-MTU Changes
okay so let's say a TCP connection between H1 and H2 is already up, and the PMTU for it has already been discovered to be 1500 ๐ธ at this point, both maxsizesent and maxsizeacked equal 1500 and nsegrto equals 0. then later, the PMTU drops to 1492 ๐ to keep it simple, let's say the Path-MTU dropped because the MTU of the link between R2 and R3 went from 1500 to 1492. Figure 3 shows how the counter-measure handles this ๐
Host 1 Host 2
1. (Path-MTU decreases)
2. --> <SEQ=100><ACK=X><CTL=ACK><DATA=1460> -->
3. <--- ICMP "Packet Too Big" MTU=1492, TCPseq#=100 <--- R2
4. (Segment times out)
5. --> <SEQ=100><ACK=X><CTL=ACK><DATA=1452> -->
6. <-- <SEQ=X><ACK=1552><CTL=ACK> <--
Figure 3: Operation during Path-MTU Changes
in line 1, the Path-MTU for this connection goes from 1500 down to 1492 ๐ป in line 2, the TCP at H1 doesn't know about the change yet, so it sends a 1500-byte packet to H2. when that packet reaches R2, it triggers an ICMP "Packet Too Big" error message ๐ฌ
in line 3, H1 gets the ICMP error, which reports a Next-Hop MTU of 1492 octets. after the TCP sequence number check, claimedmtu gets compared with maxsizesent. since claimedmtu is smaller than maxsizesent, it gets compared with maxsizeacked. claimedmtu is smaller than maxsizeacked too (full-sized packets were still reaching the remote endpoint), so this packet is assumed to be doing a Path-MTU Update, and a "pending error" condition gets recorded ๐
in line 4, the segment times out. so nsegrto goes up by 1 โฐ since nsegrto is greater than or equal to MAXSEGRTO, the assumed Path-MTU gets updated. nsegrto is reset to 0, maxsizeacked is set to claimedmtu, and maxsizesent is set to the minimum MTU of the Internet Protocol in use.
in line 5, H1 retransmits the data using the updated PMTU, so maxsizesent is set to 1492 ๐ the packet reaches H2, which sends back an acknowledgement (ACK) segment.
in line 6, H1 finally gets the ACK for the data segment. at this point TCP has discovered the new Path-MTU for this connection ๐ฆ
7.3.3. Idle Connection Being Attacked
let's say a TCP connection between H1 and H2 is already established, and the PMTU for it has been discovered to be 1500 ๐ Figure 4 is a sample time-line diagram of an idle connection getting attacked.
Host 1 Host 2
1. --> <SEQ=100><ACK=X><CTL=ACK><DATA=50> -->
2. <-- <SEQ=X><ACK=150><CTL=ACK> <--
3. <--- ICMP "Packet Too Big" MTU=68, TCPseq#=100 <---
4. <--- ICMP "Packet Too Big" MTU=68, TCPseq#=100 <---
5. <--- ICMP "Packet Too Big" MTU=68, TCPseq#=100 <---
Figure 4: Idle Connection Being Attacked
in line 1, H1 sends its last bunch of data. in line 2, H2 acknowledges that it got those data. then the connection goes idle ๐ด in lines 3, 4, and 5, an attacker sends forged ICMP "Packet Too Big" error messages to H1. it doesn't matter how many packets the attacker sends or what TCP sequence number each ICMP packet has ๐ โโ๏ธ none of them pass the TCP sequence number check from Section 4.1, because H1 has no unacknowledged data "in flight" to H2. so the attack just doesn't work ๐
7.3.4. Active Connection Being Attacked after Discovery of the Path-MTU
let's say an attacker goes after a TCP connection where the PMTU has already been discovered. like in Figure 1, the PMTU would be 1500 bytes here ๐ฏ Figure 5 shows a possible packet exchange.
Host 1 Host 2
1. --> <SEQ=100><ACK=X><CTL=ACK><DATA=1460> -->
2. --> <SEQ=1560><ACK=X><CTL=ACK><DATA=1460> -->
3. --> <SEQ=3020><ACK=X><CTL=ACK><DATA=1460> -->
4. --> <SEQ=4480><ACK=X><CTL=ACK><DATA=1460> -->
5. <--- ICMP "Packet Too Big" MTU=68, TCPseq#=100 <---
6. <-- <SEQ=X><CTL=ACK><ACK=1560> <--
Figure 5: Active Connection Being Attacked after Discovery of PMTU
since we're assuming the PMTU was already discovered, we also assume both maxsizesent and maxsizeacked equal 1500. and we assume nsegrto is zero, since there have been no segment timeouts ๐
in lines 1, 2, 3, and 4, H1 sends four data segments to H2. in line 5, an attacker sends a forged ICMP error message to H1. we're going to assume the attacker is lucky enough to guess both the four-tuple that identifies the connection AND a valid TCP sequence number ๐ฑ since the Next-Hop MTU in the ICMP "Packet Too Big" message (claimedmtu) is smaller than maxsizeacked, this packet is assumed to be doing a Path-MTU Update. so the error message gets recorded ๐
in line 6, H1 gets an acknowledgement for the segment from line 1, before it times out. at this point the "pending error" condition is cleared, and the recorded ICMP "Packet Too Big" error message gets ignored ๐ซ so the attack doesn't succeed. slay ๐
7.3.5. TCP Peer Attacked when Sending Small Packets Just after the Three-Way Handshake
this section looks at a scenario where a TCP peer that's sending small segments right after the connection is established gets attacked ๐ the connection could be used by protocols like SMTP [RFC5321] and HTTP [RFC2616], for example, which usually act like this.
Figure 6 shows a possible packet exchange for this scenario.
Host 1 Host 2
1. --> <SEQ=100><CTL=SYN> -->
2. <-- <SEQ=X><ACK=101><CTL=SYN,ACK> <--
3. --> <SEQ=101><ACK=X+1><CTL=ACK> -->
4. --> <SEQ=101><ACK=X+1><CTL=ACK><DATA=100> -->
5. <-- <SEQ=X+1><ACK=201><CTL=ACK> <--
6. --> <SEQ=201><ACK=X+1><CTL=ACK><DATA=100> -->
7. --> <SEQ=301><ACK=X+1><CTL=ACK><DATA=100> -->
8. <--- ICMP "Packet Too Big" MTU=150, TCPseq#=201 <---
Figure 6: TCP Peer Attacked when Sending Small Packets
Just after the Three-Way Handshake
nsegrto starts at zero, and both maxsizesent and maxsizeacked start at the minimum MTU for the Internet Protocol being used (68 for IPv4, and 1280 for IPv6) ๐ฃ
in lines 1 to 3, the three-way handshake happens and the connection is established ๐ค at this point, the assumed Path-MTU for this connection is 4464. in line 4, H1 sends a small segment (which makes a 140-byte packet) to H2, so maxsizesent is set to 140. in line 5, that segment gets acknowledged, so maxsizeacked is set to 140 โ
in lines 6 and 7, H1 sends two small segments to H2. then in line 8, while those segments from lines 6 and 7 are still "in flight" to H2, an attacker sends a forged ICMP "Packet Too Big" error message to H1 ๐ if the attacker guesses a valid TCP sequence number, this ICMP message passes the TCP sequence number check. then the Next-Hop MTU in the ICMP error message (claimedmtu) gets compared with maxsizesent. since claimedmtu is bigger than maxsizesent, the ICMP error message gets silently discarded ๐ซถ so the attack doesn't succeed, periodt ๐
โจ
7.4. Pseudo-Code for the Counter-Measure for the Blind Performance-Degrading Attack
Okay so this section is the pseudo-code version of the Section 7.2 counter-measure for the blind performance-degrading attack from Section 7. It's basically guidance for developers who want to actually build this thing, so bestie, read it like a recipe ๐โจ
The pseudo-code uses these variables, constants, and functions:
ack: the acknowledgement number in the TCP segment that just arrived. ๐acked_packet_size: the packet size (data plus headers) that the ACK we just got is acknowledging. ๐ฆadjust_mtu(): a function that adjusts the MTU for the connection based on the ICMP "Packet Too Big" that was last received. ๐claimedmtu: the Next-Hop MTU advertised in that ICMP "Packet Too Big" error message. ๐ฆclaimedtcpseq: the TCP sequence number sitting in the payload of the ICMP "Packet Too Big" message that just came in or was last recorded. ๐งcurrent_mtu: the Path-MTU we're currently assuming for this connection. ๐drop_message(): a function that does whatever is needed to drop the ICMP message being processed. ๐๏ธinitial_mtu: the MTU for new connections, as explained in [RFC1191] and [RFC1981]. ๐ธmaxsizeacked: the biggest packet size (data plus headers) that's been acked so far for this connection, as explained in Section 7.2. ๐maxsizesent: the biggest packet size (data plus headers) that's been sent so far for this connection, as explained in Section 7.2. ๐nsegrto: how many times this segment has timed out, as explained in Section 7.2. โฑ๏ธpacket_size: the size of the IP datagram being sent. ๐ฎpending_message: a flag that says whether there's an ICMP "Packet Too Big" message waiting to be processed. ๐ฉsave_message(): a function that records the ICMP "Packet Too Big" message that just came in. ๐พMINIMUM_MTU: a constant holding the minimum MTU for the Internet Protocol in use (68 for IPv4, and 1280 for IPv6). ๐MAXSEGRTO: a constant holding the number of times a given segment has to time out before an ICMP "Packet Too Big" error message can be honored. โญ
Now the events, which are the fun part ๐
EVENT: New TCP connection
current_mtu = initial_mtu;
maxsizesent = MINIMUM_MTU;
maxsizeacked = MINIMUM_MTU;
nsegrto = 0;
pending_message = 0;
EVENT: Segment is sent
if (packet_size > maxsizesent)
maxsizesent = packet_size;
EVENT: Segment is received
if (acked_packet_size > maxsizeacked)
maxsizeacked = acked_packet_size;
if (pending_message)
if (ack > claimedtcpseq){
pending_message = 0;
nsegrto = 0;
}
EVENT: ICMP "Packet Too Big" message is received
if (claimedmtu <= MINIMUM_MTU)
drop_message();
if (claimedtcpseq < SND.UNA || claimedtcpseq >= SND.NXT)
drop_message();
else {
if (claimedmtu > maxsizesent || claimedmtu >= current_mtu)
drop_message();
else {
if (claimedmtu > maxsizeacked){
adjust_mtu();
current_mtu = claimedmtu;
maxsizesent = MINIMUM_MTU;
}
else {
pending_message = 1;
save_message();
}
}
}
EVENT: Segment times out
nsegrto++;
if (pending_message && nsegrto >= MAXSEGRTO){
adjust_mtu();
nsegrto = 0;
pending_message = 0;
maxsizeacked = claimedmtu;
maxsizesent = MINIMUM_MTU;
current_mtu = claimedmtu;
}
Notes:
All comparisons between sequence numbers MUST be performed using sequence number arithmetic. ๐ฅ
The pseudo-code implements the mechanism described in Section 7.2, the TCP sequence number checking described in Section 4.1, and the validation check on the advertised Next-Hop MTU described in [RFC1191] and [RFC1981]. ๐ซถ
8. Security Considerations โ ๏ธ
Okay bestie, this section is seriously important, so no giggling ๐ This document describes how ICMP error messages can be used to pull off a bunch of attacks against TCP, and it also describes a bunch of widely implemented counter-measures that either wipe out these attacks or make them way less impactful when they're run by off-path attackers. ๐ญ
Section 4.1 describes a validation check that could be enforced on ICMP error messages, so TCP only reacts to ICMP error messages that seem to relate to segments currently "in flight" to the destination system. This makes an off-path attacker work a lot harder, but the trade-off is that TCP might be a little less responsive to real network errors. ๐
Section 4.2 describes how randomizing TCP ephemeral ports makes the attacker work harder to successfully exploit any of the attacks in this document. ๐ฆ
Section 4.3 describes how ICMP error messages could possibly be filtered based on their payload, so users on the local network can't easily attack connections belonging to third parties. This is kind of like ingress filtering and egress filtering of IP packets [IP-filtering]. ๐ง
Section 5.2 describes an attack-specific counter-measure for the blind connection-reset attack. It describes processing ICMP "hard errors" as "soft errors" when they're received for connections in any of the synchronized states. This counter-measure gets rid of the vulnerability in synchronized connections, but it might make things less responsive in some network scenarios. ๐ธ
Section 6.2 describes an attack-specific counter-measure for the blind throughput-reduction attack. It suggests that the vulnerability can be eliminated by ignoring ICMPv4 Source Quench messages meant for TCP connections. This matches research showing that ICMPv4 Source Quench messages are ineffective and are an unfair way to deal with congestion. ๐ โโ๏ธ๐
Finally, Section 7.2 describes an attack-specific counter-measure for the blind performance-degrading attack. It's the validation check from Section 4.1, with a tweak that makes TCP react to ICMP "Packet Too Big" error messages by processing them when an outstanding TCP segment times out. This counter-measure parallels the Packetization Layer Path MTU Discovery (PLPMTUD) mechanism [RFC4821]. It should be noted that if this counter-measure is implemented, TCP may respond more slowly to valid ICMP "Packet Too Big" error messages in some scenarios. ๐ข
A discussion of these and other attack vectors for performing similar attacks against TCP (along with possible counter-measures) can be found in [CPNI-TCP] and [TCP-SECURITY]. ๐
9. Acknowledgements ๐ซถ
This document was inspired by Mika Liljeberg, while discussing some issues related to [RFC5461] by private e-mail. The author would like to thank (in alphabetical order): Bora Akyol, Mark Allman, Ran Atkinson, James Carlson, Alan Cox, Theo de Raadt, Wesley Eddy, Lars Eggert, Ted Faber, Juan Fraschini, Markus Friedl, Guillermo Gont, John Heffner, Alfred Hoenes, Vivek Kakkar, Michael Kerrisk, Mika Liljeberg, Matt Mathis, David Miller, Toby Moncaster, Miles Nordin, Eloy Paris, Kacheong Poon, Andrew Powell, Pekka Savola, Donald Smith, Pyda Srisuresh, Fred Templin, and Joe Touch for contributing many valuable comments. ๐
Juan Fraschini and the author of this document implemented freely available audit tools to help vendors audit their systems by reproducing the attacks discussed in this document. These tools are available at http://www.gont.com.ar/tools/index.html. ๐ ๏ธ
Markus Friedl, Chad Loder, and the author of this document produced and tested in OpenBSD [OpenBSD] the first implementation of the counter-measure described in Section 7.2. This first implementation helped to test the effectiveness of the ideas introduced in this document, and has served as a reference implementation for other operating systems. ๐
The author would like to thank the UK's Centre for the Protection of National Infrastructure (CPNI) -- formerly the National Infrastructure Security Co-ordination Centre (NISCC) -- for coordinating the disclosure of these issues with a large number of vendors and CSIRTs (Computer Security Incident Response Teams). ๐
The author wishes to express deep and heartfelt gratitude to Jorge Oscar Gont and Nelida Garcia, for their precious motivation and guidance. ๐ฅน๐
10. References ๐
10.1. Normative References
[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791,
September 1981.
[RFC0792] Postel, J., "Internet Control Message Protocol",
STD 5, RFC 792, September 1981.
[RFC0793] Postel, J., "Transmission Control Protocol", STD 7,
RFC 793, September 1981.
[RFC1122] Braden, R., "Requirements for Internet Hosts -
Communication Layers", STD 3, RFC 1122,
October 1989.
[RFC1191] Mogul, J. and S. Deering, "Path MTU discovery",
RFC 1191, November 1990.
[RFC1812] Baker, F., "Requirements for IP Version 4 Routers",
RFC 1812, June 1995.
[RFC1981] McCann, J., Deering, S., and J. Mogul, "Path MTU
Discovery for IP version 6", RFC 1981, August 1996.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2460] Deering, S. and R. Hinden, "Internet Protocol,
Version 6 (IPv6) Specification", RFC 2460,
December 1998.
[RFC4301] Kent, S. and K. Seo, "Security Architecture for the
Internet Protocol", RFC 4301, December 2005.
[RFC4443] Conta, A., Deering, S., and M. Gupta, "Internet
Control Message Protocol (ICMPv6) for the Internet
Protocol Version 6 (IPv6) Specification", RFC 4443,
March 2006.
[RFC4884] Bonica, R., Gan, D., Tappan, D., and C. Pignataro,
"Extended ICMP to Support Multi-Part Messages",
RFC 4884, April 2007.
10.2. Informative References โจ
okay bestie, these are the extra reads ๐ not required to implement anything, but they're the receipts behind the whole doc ๐งพ๐ (and some of them are lowkey iconic). they're listed in the order the original gives them ๐
- [CPNI-TCP] CPNI, "Security Assessment of the Transmission Control Protocol (TCP)",
http://www.cpni.gov.uk/Docs/tn-03-09-security-assessment-TCP.pdf, 2009. ๐ - [DClark] Clark, D., "The Design Philosophy of the DARPA Internet Protocols", Computer Communication Review Vol. 18, No. 4, 1988. ๐๏ธ
- [FreeBSD] The FreeBSD Project,
http://www.freebsd.org. ๐ - [ICMP-Filtering] Gont, F., "Filtering of ICMP error messages",
http://www.gont.com.ar/papers/filtering-of-icmp-error-messages.pdf. ๐งน - [IP-filtering] NISCC, "NISCC Technical Note 01/2006: Egress and Ingress Filtering",
http://www.cpni.gov.uk/Docs/re-20060420-00294.pdf, 2006. ๐ง - [Linux] The Linux Project, "
http://www.kernel.org". ๐ง - [McKusick] McKusick, M., Bostic, K., Karels, M., and J. Quarterman, "The Design and Implementation of the 4.4 BSD Operating System", Addison-Wesley, 1996. ๐โจ
- [NISCC] NISCC, "NISCC Vulnerability Advisory 532967/NISCC/ICMP: Vulnerability Issues in ICMP packets with TCP payloads",
http://www.cpni.gov.uk/docs/re-20050412-00303.pdf?lang=en, 2005. ๐จ - [NetBSD] The NetBSD Project, "
http://www.netbsd.org". ๐ฉต - [OpenBSD] The OpenBSD Project, "
http://www.openbsd.org". ๐ก - [OpenBSD-PF] The OpenBSD Packet Filter, "
http://www.openbsd.org/faq/pf/". ๐ก๏ธ - [PORT-RANDOM] Larsen, M. and F. Gont, "Transport Protocol Port Randomization Recommendations", Work in Progress, April 2010. ๐ฒ
- [RFC0816] Clark, D., "Fault isolation and recovery", RFC 816, July 1982. ๐
- [RFC1321] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April 1992. ๐งฎ
- [RFC1323] Jacobson, V., Braden, B., and D. Borman, "TCP Extensions for High Performance", RFC 1323, May 1992. ๐
- [RFC2385] Heffernan, A., "Protection of BGP Sessions via the TCP MD5 Signature Option", RFC 2385, August 1998. ๐
- [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. ๐
- [RFC2923] Lahey, K., "TCP Problems with Path MTU Discovery", RFC 2923, September 2000. ๐
- [RFC3168] Ramakrishnan, K., Floyd, S., and D. Black, "The Addition of Explicit Congestion Notification (ECN) to IP", RFC 3168, September 2001. ๐ฆ
- [RFC3390] Allman, M., Floyd, S., and C. Partridge, "Increasing TCP's Initial Window", RFC 3390, October 2002. ๐ช
- [RFC4271] Rekhter, Y., Li, T., and S. Hares, "A Border Gateway Protocol 4 (BGP-4)", RFC 4271, January 2006. ๐บ๏ธ
- [RFC4821] Mathis, M. and J. Heffner, "Packetization Layer Path MTU Discovery", RFC 4821, March 2007. ๐ฆ
- [RFC4907] Aboba, B., "Architectural Implications of Link Indications", RFC 4907, June 2007. ๐
- [RFC4953] Touch, J., "Defending TCP Against Spoofing Attacks", RFC 4953, July 2007. ๐ญ
- [RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321, October 2008. ๐
- [RFC5461] Gont, F., "TCP's Reaction to Soft Errors", RFC 5461, February 2009. ๐ฉน
- [RFC5681] Allman, M., Paxson, V., and E. Blanton, "TCP Congestion Control", RFC 5681, September 2009. ๐
- [RFC5925] Touch, J., Mankin, A., and R. Bonica, "The TCP Authentication Option", RFC 5925, June 2010. ๐
- [TCP-SECURITY] Gont, F., "Security Assessment of the Transmission Control Protocol (TCP)", Work in Progress, February 2010. ๐ต๏ธ
- [TCPM-TCPSECURE] Ramaiah, A., Stewart, R., and M. Dalal, "Improving TCP's Robustness to Blind In-Window Attacks", Work in Progress, May 2010. ๐ช๐ก๏ธ
- [US-CERT] US-CERT, "US-CERT Vulnerability Note VU#222750: TCP/IP Implementations do not adequately validate ICMP error messages",
http://www.kb.cert.org/vuls/id/222750, 2005. ๐จ๐จ - [Watson] Watson, P., "Slipping in the Window: TCP Reset Attacks", CanSecWest Conference, 2004. ๐ช๐ฅ
- [Wright] Wright, G. and W. Stevens, "TCP/IP Illustrated, Volume 2: The Implementation", Addison-Wesley, 1994. ๐
Author's Address ๐
and here's who wrote it ๐ซถ (the contact details are exactly as the original gives them)
Fernando Gont
Universidad Tecnologica Nacional / Facultad Regional Haedo
Evaristo Carriego 2644
Haedo, Provincia de Buenos Aires 1706
Argentina
Phone: +54 11 4650 8472
EMail: fernando@gont.com.ar
URI: http://www.gont.com.ar
๐ฆ where this page comes from
- ietf: rfc5927 2010-07
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms