Summary

  • RFC 3128 combined tiny-fragment and overlapping-fragment techniques so that a filter could admit a legal first TCP header while endpoint reassembly substituted a different destination port.
  • Its corrective rule was narrow but important: an offset-zero TCP fragment must contain the complete minimum transport header on which policy depends, while offset-one fragments remain disallowed.
  • The attack was conditional on filtering rules and reassembly behavior; an admitted fragment set was not proof of a completed connection, compromised service or universal implementation flaw.

The dangerous packet in RFC 3128 was not any one fragment. It was the disagreement between two observers.

At the perimeter, a packet filter saw an initial IPv4 fragment. Its Fragment Offset was zero. It contained enough of a TCP header to describe an apparently ordinary connection to a port that policy allowed to receive inbound traffic. The filter could inspect the destination port and the relevant control information, find nothing forbidden, and pass it.

At the destination, the IP stack eventually saw a set of fragments. If its reassembly rule allowed later overlapping bytes to replace earlier ones, the TCP segment presented upward could differ from the segment the filter believed it had authorized. A second offset-zero fragment, only eight transport bytes long, could replace the source port, destination port and sequence number while omitting the later TCP flags. The completed datagram might therefore address a port that was supposed to accept only outbound connections.

The filter was not necessarily careless. It was following an earlier defensive model.

RFC 1858 had described two important families of evasion. A tiny-fragment attack split a TCP header so that the first fragment did not expose all the fields a filter needed. An overlapping-fragment attack exploited disagreement about which copy of repeated bytes should survive reassembly. One proposed countermeasure, called the Indirect Method, rejected TCP fragments with Fragment Offset equal to one. Because IPv4 offsets are counted in eight-byte units, offset one begins exactly where a minimal first eight-byte slice ends. Blocking that position prevented a familiar attempt to hide TCP flags in the next fragment.

The rule solved the attack it could see. RFC 3128 showed what happened when the attacker moved the overlap back to offset zero.

Its example used three fragments. The first began at zero and carried at least sixteen bytes of the TCP header. It looked complete enough for the filter and named an allowed inbound service. The second also began at zero, but stopped after eight TCP bytes. It changed the destination port. Considered without the flags that came later in the header, those bytes might satisfy another rule. A third fragment completed the datagram.

On a host whose overlap policy gave the short replacement bytes the decisive value, reassembly produced a new TCP header: the flags inherited from the legal first view, but the destination port inherited from the overlapping second view.

That was the historical insight. Policy had been applied to a temporary representation, not to the transport header finally consumed by the endpoint.

RFC 3128 was careful about scope. The result depended on the destination's precise reassembly implementation. IPv4 had created room for fragments to arrive out of order, to duplicate data and to overlap. RFC 815's reassembly discussion treated overlap as an engineering condition an algorithm had to manage; it did not impose one universal winner for every duplicate byte. Different hosts, middleboxes and operating-system generations could therefore construct different packets from the same fragment train.

This implementation dependency cut both ways. It meant the memo did not prove that every target was vulnerable. It also meant a filter could not safely assume that the endpoint shared its interpretation. A security device that passed fragments onward without normalizing or reassembling them was delegating the final byte selection to another machine.

The repair in RFC 3128 was intentionally smaller than a new architecture. In addition to rejecting TCP fragments at offset one, a filter should reject an offset-zero fragment when its transport portion is shorter than the minimum complete header. In the memo's notation, if Fragment Offset is zero, the protocol is TCP and the transport length is less than the minimum TCP header length, drop the packet.

The rule closes the particular gap because a short offset-zero replacement can no longer pass as an adequate basis for policy. It converts an implicit hope—“the first fragment probably contains what matters”—into a length invariant. If a filter is going to make a decision about TCP ports and control bits, the initial fragment must expose the whole minimum field set required by that decision.

But the rule did not abolish fragmentation ambiguity. It did not require every firewall to perform full reassembly. It did not specify a universal IPv4 overlap policy, and it did not show that the packet reached an application. Even after the fragment set passes a network device, TCP must accept the reconstructed segment, a service must be listening, the handshake must progress, and application behavior must follow. Each is a separate evidence boundary.

Later standards reveal how durable the underlying problem was. RFC 6274 revisited IPv4 security and recommended consistent, conservative handling of fragments. RFC 5722 took a stronger position for IPv6: if fragments overlap, the entire datagram must be discarded. RFC 7112 required the first IPv6 fragment to contain the complete header chain so that middleboxes would not have to authorize a packet whose essential extension headers arrived later. RFC 8900 described fragmentation as operationally fragile because endpoints and middleboxes continued to disagree over support, filtering and packet size.

Those later documents should not be projected backward as proof that every 2001 firewall behaved in one way. Their value is structural. They show a recurring design lesson: security policy fails when the enforcement point and the consuming endpoint do not agree on the object being judged.

The lesson reaches beyond IP fragments. Parsers, gateways and application servers routinely see different stages of the same input. A proxy may normalize a request differently from an origin server. An intrusion detector may decode an encoding once while an application decodes it twice. A schema gateway may validate one representation while downstream code uses another. The details change, but the control failure is the same: policy attaches to bytes or fields that are not stable across the path.

RFC 3128 belongs in Internet history because it made that failure concrete with almost no machinery. The first fragment could be legal. The second could be locally plausible. The third could complete the datagram. The security defect appeared only when the three were interpreted by different authorities at different moments.

The memo also preserved a useful distinction between admission and effect. It described how fragments could evade a filtering intention. It did not claim a successful intrusion. This matters because historical security writing often collapses a protocol possibility into an operational outcome. RFC 3128's own language resists that inflation: significance depends on the security policy, and the result depends on reassembly.

The deepest contribution, then, was not the destination-port trick by itself. It was the demand that an enforcement decision remain true after the network has finished constructing the object. If later processing can replace the bytes that justified admission, the admission was never about the final packet.

Sources