icmp_echo_streams_logo

Introducing ICMP Echo Streams (iStreams)

Introduction

With version 2.0, we have added the capability to construct ICMPv4/v6 Echo streams, which we refer to throughout the document as iStreams (note the ‘i’). PacketSmith is the only known tool capable of constructing ICMP (when the version is not specified, both v4 and v6 are considered) Echo streams, similar to TCP/UDP streams. With this feature, we are able to interrogate and dissect the ICMP Echo protocol in different ways to capture certain unique behavioral and semantic characteristics. 

An ICMPv4 Echo request and reply packets are defined by the types 0x08 and 0x00, respectively, and code 0x00. The ICMPv6 Echo request and reply packets are defined by the types 0x80 and 0x81, respectively, and code 0x00.

To accurately track network traffic streams, the iStream system uses a unique key derived from the source and destination IP addresses along with the ICMP identifier (in big-endian). This method works best when the ICMP identifier is unique for each new connection or “invocation” to the same target. This is implemented using a map structure with a key consisting of a custom hash function, to keep track of potentially unique iStreams, leading to grouping all related ICMP Echo request and reply flows into their respective key bucket as a vector.

The challenge lies in how different operating systems and tools handle the ICMP identifier.

For example, on Windows, the kernel sets the ICMP identifier to a fixed value (0x0001). This means if you ping the same host twice, both pings will have the same source IP, destination IP, and ICMP identifier. This causes iStream to treat both pings as part of the same stream, making it difficult to differentiate between them for proper accounting.

On other systems, the ICMP identifier is generated randomly for each new ping request. This ensures that even when you ping the same host multiple times, each ping has a unique identifier, allowing iStream to accurately track them as separate streams.

As per the standard specification for the ICMP protocol, RFC 792, it states the following:

Identifier If code = 0, an identifier to aid in matching echos and replies, may be zero.

Further down on page 15,

The identifier and sequence number may be used by the echo sender to aid in matching the replies with the echo requests. For example, the identifier might be used like a port in TCP or UDP to identify a session, and the sequence number might be incremented on each echo request sent. The echoer returns these same values in the echo reply.

The ICMP standard should have required a unique identifier for each new ping request to prevent ambiguity, which would have been a better approach.

Why Defining iStreams

Based on our research, we realized that the ICMP Echo message type is being exploited by attackers to create hidden communication channels. This technique, known as ICMP tunneling, is used to bypass standard network defenses for various malicious activities, including:

  • Data exfiltration: Secretly stealing data from a network.

  • Command and control (C2): Establishing a hidden way to send commands to compromised systems.

This abuse is not just theoretical; many real-world malware families and open-source hacking tools already use this exact method. Which is why we introduced the concept of iStreams in PacketSmith, that’s to reason about potentially malicious and suspicious traffic using protocol session flows and semantics, instead of relying on a short-lived content match type signatures. The concept and utility of iStreams will prove extremely valuable when writing new detection methods targeting this message type based on the connection flows and relationship between every request and reply packets, across the entire iStream. We have already leveraged the power of iStreams in PacketSmith v2.0 with the implementation of the ICMP Echo detection module (option —Detect icmp), for detecting suspicious and malicious traffic, using protocol semantic analysis. This will be detailed in a future article.

iStreams Information (JSON Output)

With PacketSmith v2.0, You can query a given pcap for all ICMPv4 and ICMPv6 iStreams using the option —Info istreams_j:fids. This command will output ICMPv4/v6 Echo stream information in JSON format, including the frame IDs associated with each stream, or, you could use the option —Info istreams_j without the frame IDs.

Take the following pcap icmpv4_2_istreams for example; it contains 2 ICMPv4 Echo iStreams. The following is the JSON output:

📋
icmp_istreams.json
Copy to clipboard
{
    "istreams": {
        "total": 2,
        "ipv4": {
            "total": 2,
            "istreams": [
                {
                    "id": 0,
                    "ip.src": "192.168.2.16",
                    "ip.src_type": "private",
                    "ip.dst": "66.235.200.147",
                    "ip.dst_type": "public",
                    "iid": 15,
                    "iflows": {
                        "size": 20,
                        "echo_request": 10,
                        "echo_reply": 10
                    },
                    "bytes": {
                        "size": 1120,
                        "echo_request": 560,
                        "echo_reply": 560
                    },
                    "entropy": 5.45435657,
                    "frames": [
                        "5-24"
                    ]
                },
                {
                    "id": 1,
                    "ip.src": "192.168.2.16",
                    "ip.src_type": "private",
                    "ip.dst": "162.241.226.211",
                    "ip.dst_type": "public",
                    "iid": 16,
                    "iflows": {
                        "size": 30,
                        "echo_request": 15,
                        "echo_reply": 15
                    },
                    "bytes": {
                        "size": 1680,
                        "echo_request": 840,
                        "echo_reply": 840
                    },
                    "entropy": 5.38734657,
                    "frames": [
                        "29-58"
                    ]
                }
            ]
        },
        "ipv6": {
            "total": 0,
            "istreams": []
        }
    }
}

This output always starts with the warning message “ – Interpret with Caution –“, to double check the uniqueness of the ICMP identifier.

The “id” value is not important, it is used as a visual counter. The “iid” key is the ICMP identifier, in decimal (big-endian). The “iflows” object is self-explanatory. The “bytes” object represents the cumulative size of all data payloads transferred in both requests and their corresponding replies. It measures the total amount of information exchanged, excluding the packet headers. The “entropy” is based on the combined data payloads of request and reply packets. The “frames” key holds all the frames IDs associated with the iStream in question.

ICMPv4/v6 Echo Request/Reply Packets Details

PacketSmith provides the flexibility to list all ICMPv4/v6 echo/ping frames with their full packet details, including the IP header, frames timestamps (raw and UTC time). This output can be printed to the console in your choice of TXT or JSON format. The entropy of every ICMP Echo data payload is computed individually. The IP and ICMP data structures are printed in big-endian. In ICMPv6, the fragmentation flag is determined by whether a fragmentation extension header is present.

—Tport_lyr icmp<v4|v6>:echo:find_frames:<out:txt|json>:<hexdump_length>

  • The <hexdump_length> is used for specifying the number of bytes to dump from the ICMP Echo packet data payload. 

For example, —Tport_lyr icmpv4:echo:find_frames:txt:64

This produces an output similar to the following (“f” is for frame number, and the data after the pipe ‘|’ character is for the ICMP header):

[ echo_req ] - f:5
192.168.2.16 -> 66.235.200.147     /id:9910  /ttl:64  /frag:1 | /id:15    /seq:1     /len:56     /ent:5.2979

00000000: F9 F8 AE 68 00 00 00 00 07 39 0C 00 00 00 00 00  |...h.....9......|
00000010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F  |................|
00000020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F  | !"#$%&'()*+,-./|
00000030: 30 31 32 33 34 35 36 37                          |01234567        |


 [ echo_rep ] - f:6
 66.235.200.147 -> 192.168.2.16     /id:9713  /ttl:55  /frag:0 | /id:15    /seq:1     /len:56     /ent:5.2979

 00000000: F9 F8 AE 68 00 00 00 00 07 39 0C 00 00 00 00 00  |...h.....9......|
 00000010: 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F  |................|
 00000020: 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F  | !"#$%&'()*+,-./|
 00000030: 30 31 32 33 34 35 36 37                          |01234567        |
 
 ... More Data ...
 
 ------------------------------
found a total of 25 echo_request packets and a total of 25 echo_reply packets
------------------------------

The JSON output is similar to the following: 

The “frag” key is to indicate whether the “Don’t Fragment” IPv4 flag is set or not, for IPv6, this would indicate the presence or the absence of the fragment header extension. The “idata” key holds the ICMP Echo packet payload in hexadecimal.

📋
icmp_echo.json
Copy to clipboard
{
    "icmp_echo": {
        "total": {
            "request_type": 25,
            "reply_type": 25
        },
        "packets": [
            {
                "f": 5,
                "ts": "2025-08-27 12:24:25.801047 UTC",
                "ts_raw": 1756297465801047,
                "type": "request",
                "ipv4": {
                    "src_ip": "192.168.2.16",
                    "dst_ip": "66.235.200.147",
                    "id": 9910,
                    "ttl": 64,
                    "frag": true
                },
                "icmp": {
                    "iid": 15,
                    "iseq": 1,
                    "ilen": 56,
                    "idata": "f9f8ae680000000007390c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637",
                    "ientropy": 5.2979027
                }
            },
            {
                "f": 6,
                "ts": "2025-08-27 12:24:25.806153 UTC",
                "ts_raw": 1756297465806153,
                "type": "reply",
                "ipv4": {
                    "src_ip": "66.235.200.147",
                    "dst_ip": "192.168.2.16",
                    "id": 9713,
                    "ttl": 55,
                    "frag": false
                },
                "icmp": {
                    "iid": 15,
                    "iseq": 1,
                    "ilen": 56,
                    "idata": "f9f8ae680000000007390c0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637",
                    "ientropy": 5.2979027
                }
            },
            // ... More Data ...
            ]
    }
}

The JSON output provides the necessary details to reason about the traffic using your own detection logic.

Conclusion

This article introduces iStreams, a new concept designed to analyze ICMPv4/v6 Echo traffic. The main purpose of iStreams is to help detect suspicious or malicious network activity by providing a structured way to look at ICMP data. We also highlighted the new ICMP Echo packet dissection features included in PacketSmith v2.0.


Author: Mohamad Mokbel (Netomize)

First release: September 01, 2025