RFC 5927

ICMP Attacks against TCP

๐Ÿ“… published July 2010, from ietf

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 (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