Diaries

Published: 2026-11-02

Mutipath TCP: Use and Detection

Last week, an often-ignored TCP option, introduced in 2020, made the news due to a new vulnerability in Linux's implementation (RFC 8684,  CVE-2026-98432)

Instead of looking at the vulnerability, I am using this diary to talk a bit about multipath TCP (MPTCP) and how you may see it used in your network.

What is MPTCP?

Traditionally, TCP is a connection-oriented protocol. Connections are established between a client and server, and host IP addresses are not expected to change for a specific connection. This restriction to a specific path does not always match modern system architecture. For example, mobile devices may switch from a local WIFI network to a cellular network at any time. Having to re-establish TCP connections may break applications. At the same time, servers often have a hard time "filling" high-bandwidth links using a single TCP connection due to limits on Window Size and the sequence number range [RFC 6182]. MPTCP is supposed to solve these problems by allowing connections to be split and handed over between different IP addresses.

The only widely used implementation I have observed is iOS/iPadOS. In this case, IPv4 connections to Apple (17.0.0.0/8) often utilize MPTCP [Apple]. MPTCP was initially used for Siri, and later for other services like Apple Music.

Two versions of MPTCP are currently defined and used: v0 and v1. At first, 

MPTCP Options

The MPTCP Option (0x1e, 30) is followed by a byte containing 4 bits indicating the subtype and 4 bits indicating the version (0 or 1).

+----------------+--------------+----------------+----------------+
|   TCP Option   | Option Length|Subtype| Version|     Flags      |
+----------------+--------------+----------------+----------------+
|      30        | variable     |       | 0 or 1 |                |
+----------------+--------------+----------------+----------------+

MP_CAPABLE (subtype 0): Indicates MPTCP support. Both sides must include it in the TCP handshake for MPTCP support to be enabled. Each MP_CAPABLE option also carries an 8-byte key that will later be used to identify and authenticate the different sub-sessions.

MP_JOIN (subtype 1): A second TCP connection may join an initial connection using the MP_JOIN option. This connection will typically be initiated by the client, but may originate from a different IP address. The RFC does specifically allow the server to initiate the second (or additional) connection. The RFC states: "It is permissible for either host in a connection to initiate the creation of a new subflow, but it is expected that this will normally be the original connection initiator." Ports should be the same, but do not have to be. Of course, this also accounts for common firewall rules. The web server will likely listen only on port 443, and the client's firewall will reject inbound SYN packets.

DSS (Data Sequence Signal, subtype 2): Each TCP connection which is part of MPTCP maintains its own sequence numbers, and acts just like any other "normal" TCP connection. To stitch the content of multiple connections together, the DSS option is used. It maps the respective's TCP sequence numbers to the sequence numbers of the combined connection.

ADD_ADDR/REMOVE_ADDR (subtypes 3, 4): these options are somewhat similar to MP_JOIN, but instead of actually setting up an additional connection, they advertise (or remove) additional addresses or ports that can be used.

MPTCP Detection

The best way to detect MPTCP is to look for TCP Option 30. Here are a few ways to do so:

Wireshark/tshark: Wireshark has a "mptcp" display filter keyword. As so often, Wireshark does make it easy.

tcpdump: There is no great way to match TCP options in tcpdump. But MPTCP packets, particularly SYN packets, tend to have large TCP headers, so a quick match on TCP header length can help. For example: 'tcp[12]>0xd0'

Suricata: Use the "tcp.hdr" keyword to inspect TCP options. The tricky part is that the option length isn't always the same. But there should be at least one MP_CAPABLE message that includes both the sender and receiver key, making this option 20 bytes long. The first three bytes are |1e 14 00| for version 0 or |1e 14 01| for version 1.

Snort: Snort does not have a keyword to inspect TCP options, and as far as I know, no way to filter for multipath TCP. The snort_decoder "experimental TCP option" alert only triggers on specific option types reserved for experimental use.

Zeek: By default, zeek does not log options, but it does offer the tcp_option and tcp_options events that can easily be used to log MPTCP. For example:

event tcp_option(c: connection, is_orig: bool, opt: count, optlen: count) {
      if ( opt == 30 ) {
            print(fmt("MPTCP between %s and %s", c$id$orig_h, c$id$resp_h));
      }
}

[Apple] https://support.apple.com/en-us/101905
[RFC8694] https://www.rfc-editor.org/info/rfc8684
[CVE-2026-98432] https://www.openwall.com/lists/oss-security/2026/10/30/1

 

--
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
Twitter|

0 Comments

Published: 2026-11-01

OneNote File Extraction

Recently, I had to extract embedded files from a set of OneNote files (extension .one).

My onedump.py tool can extract individual files, so I would have to run this many times. To avoid this, I added a new feature to my onedump.py tool: producing JSON data. Several of my tools already have such a feature: they produce JSON data with the content of their analysis results.

onedump's option --jsonoutput produces JSON output with the content of each embedded file found inside the OneNote file. And it can do this for many .one files in one go:

onedump.py --jsonoutput *.one

To write these files to disk you can use my myjson-filter.py tool, like this:

onedump.py --jsonoutput *.one | myjson-filter.py -W hashvir

This will write all the embedded files to disk, their name will be the sha256 hash of their content plus extension .vir (hashvir).

 

Didier Stevens
Senior handler
blog.DidierStevens.com

0 Comments