Analyzing ICMP Traffic with NetMon

The Internet Control Message Protocol (ICMP) is one of the foundational internet protocols that define how systems talk to each other. Commands such as ping and traceroute are supported by ICMP. Based on request for comments (RFC) 792, ICMP has been around since the early days of the internet, circa 1981.

So why should you care about analyzing one of the oldest internet-networking protocols? Hasn’t everything that can be done to this protocol already been done?

The recent EternalBlue vector used by the WannaCry malware exposed vulnerabilities in another ancient protocol, Server Message Block (SMB). This proves that no matter how old a protocol is, you must still consider it in your security operations program. In fact, over the years, numerous malware applications have exploited ICMP. Examples include:

  • Malicious application of the protocol for DDoS (i.e. The Smurf Attack or ICMP Source Quench Request abuse)
  • Use of ICMP for tunneling, enabling covert communications, data exfiltration, and reverse shells
  • Use of ICMP for reconnaissance, including gathering network topology, detecting ACLs, trace routes, OS fingerprinting, and port scanning

I recently participated in a Tips and Tricks webinar and spoke about ICMP in regards to Network Threat Detection. Here is the detailed blog on that topic to show you how to analyze ICMP traffic with Network Monitor(NetMon).

Dissecting ICMP

An ICMP packet follows a very simple and well-defined format. Let’s look at and understand what can learn from each component.

structure-of-an-icmp-packet

Figure 1: The Structure of an ICMP Packet

IP Header

Because IMCP is built on the core IP protocol, every packet has 20 bytes of standard IP header. There’s very little value in the information from the header because many security tools already pull out the source IP, destination IP, and TTL information.

Type

The Type tells what ICMP command was sent. Out of approximately 30 valid type codes, around four can be the most useful within NetMon’s Framework. Specifically, Destination Unreachable, Redirections, Time Exceeded, and Parameter Problems.

Checksum

The Checksum is usually not valuable as it merely verifies the Type and Code is valid.
Varies by Protocol

The next four bytes were originally unused in this piece, but they have been repurposed several times over the years. Now, the four bytes may contain padding data. They may also be an identifier and a sequence number of the packet used to help manage ICMP over NAT.

Data

The data block is of variable size and content depending on the type and code. It’s also the most interesting part (after Type and Code) because it was designed to be extensible. This means anyone using ICMP for any purpose has to support a variable size/purpose data block. Ultimately, supporting a variable size/purpose data block opens up pathways for all sorts of malicious network shenanigans.

ICMP in NetMon

NetMon natively classifies ICMP. Without any modifications, you can use NetMon to look at ICMP traffic going to or from a specific system or crossing inside/outside the network using the Ingress Egress Traffic Dashboard.

Click images to expand

LogRhythm

Figure 2: LogRhythm NetMon Ingress Egress Traffic Dashboard

Note: The above screenshot is from a test network with simulated traffic. Best practice dictates to limit or block egress ICMP traffic except for controlled systems. Nothing should be receiving unmonitored ICMP results from your internal systems!

For next steps, look to deep packet analytics (DPA) rules to parse out this information and extract packet data for deeper analysis.

Working with a DPA Rules and ICMP

As referenced in the recent blog titled Using Deep Packet Analytics to Extract Specific Bytes, you can use DPA rules to extract specific bytes out of each packet. In the case of ICMP, the information from those bytes allow you to do a number of things including:

  1. Identify the Type
  2. Based on the Type, possibly extract the Code
  3. Possibly extract, or at least examine, the body to find signatures
  4. Possibly raise alarms based on suspicious traffic

The complete source code for the rules described in this article is available in the LogRhythm Community under the NetMon DPA Rules section.

ICMP as a Connectionless Protocol

One caveat to work through in this use case is that ICMP is a connectionless protocol. ICMP does not have the concept of a session, even though NetMon does. This means that each ICMP session inside NetMon is actually a series of independent ICMP requests. ICMP sessions and NetMon are related by:

  1. The source IP/MAC Address
  2. The destination IP/MAC address
  3. The time between packets

ICMP packets going from the same source to the same destination (or vice versa) are considered part of the same ICMP session until there is a long enough time gap to trigger a session closure.

As you work through the packet-level DPA rules, you have to be aware of the possibility of multiple ICMP commands in the same session. However, due to this disconnect, there is no guarantee that you will always see the complete conversation. If the ping request and the echo reply are separated by many seconds, they may end up in different sessions.

Building the NetMon DPA Rule

As mentioned in the previous blog, Using Deep Packet Analytics to Extract Specific Bytes, writing a packet rule is all about performing as few tasks as possible and exiting as fast as possible.

For this use case, the logic for our rule will look like the following.

  1. Exit if the packet isn’t classified.
  2. Exit if the packet isn’t ICMP.
  3. Exit if you’ve already parsed the first type/code in the session (ignore all the subsequent traffic in the session).
  4. Extract the Type byte and parse it back into English.
  5. If the Type is 3 (Destination Unreachable), 5 (Redirect), or 11 (Time Exceeded), extract the Code field for additional data.
  6. Write the Type, Type message, Code, and Code message out as metadata.

Starting the Rule

Remember that this is a packet rule. The basic rule shell should look like this:

NetMon

Figure 3: NetMon DPA Rule Shell

As you set up the rule, select Packet as the scope. Also, ensure the function header accepts the dpiMsg and the packet.

Performance 101: Exit Quick

Exiting the rule fast is fairly straightforward. First, determine if the flow is ICMP by checking if an ICMP_Type has been generated. You can improve rule performance even more by looking for the ICMP application type (an integer) rather than the application name (a string), as string comparisons are generally slower.

NetMon

Figure 4: NetMon DPA Rul Quick Exit

The second check for the custom field uses some interesting LUA syntax . In a DPA rule, custom fields are returned as a table. You have to get the table using GetCustomField(). Once you have the table, you can then check to see if there are any entries. If the next entry (the very first one) has a populated value, then the custom field has already been created.

Extracting the Type

Extracting the Type requires pulling a specific byte out of the ICMP packet. Ignoring any wrapper traffic, you want the first byte. However, things get a little difficult because the packet will at least have 20 bytes of IP header. It will also have Ethernet frame wrapping. It may also have VLAN wrapping.

ICMP

Figure 5: ICMP Ping Request with a VLAN Wrapper

In this sample, you want byte 39, but you also have four bytes of VLAN wrapper to start the packet. This means you actually want byte number 35 in a normal packet (39 minus the four bytes of VLAN wrapper).

Fortunately, in the previous blog, I’ve described a standard way to determine the offset for a VLAN wrapper. Here is that code:

Code

Figure 6: Code to Determine the Offset for a VLAN Wrapper

As you work to write the rule, remember that the function for GetPacketBytes uses a one-based counting system rather than the standard octet display from Wireshark. Meaning, the first byte in the packet is #1 (not #0 as would show in Wireshark). For example, the above rule is asking for byte #35 in the packet, which would be byte #34 in Wireshark.

Converting the Extracted Byte Type into English

Representing the byte as an integer is only helpful for those who have memorized the various ICMP Types. To make this more usable, you should translate the integer into English. To do this, create a global table of Type values matched to the representative text.

Best practice is to create this table as a global value and wrap the creation in a check to determine if it already exists. This way, this creation only runs the first time the rule runs.

Table

Figure 7: Table of Type Values Matched to Representative Text

Once you’ve built your table to convert integers to plain English, you can use your Type value to extract the string and write the values out as metadata fields. Make sure to wrap your check call to reveal if you parsed out an invalid Type. If you see the resulting message, it may indicate strange hardware, malicious traffic or possibly garbled network traffic.

Code

Figure 8: Code to Save ICMP Information as Metadata Fields

Extracting the Code

If the Type is 3 (Destination Unreachable), 5 (Redirect), or 11 (Time Exceeded), you want to follow the same basic pattern and parse out the next byte (the Code). All three types use the same pattern of steps, but use different look up tables. Type 3, Code 0 is “Net Unreachable,” but Type 11, Code 0 is “TTL Exceeded.”

I’ll quickly walk through how to build out the code that will extract the Code from Type 3. You can use this same format for the other two ICMP Types that use meaningful Code values. To start, create a data table.

Data

Figure 9: Data Table

Next, take the Code byte and have the script perform a lookup.

Script

Figure 10: Script to Lookup Code Byte

There you have it: Now you have a DPA rule to analyze ICMP traffic. All that is left is to tune the rule and add your personal coding style. As mentioned earlier, the complete rule can be found on the LogRhythm Community under the DPA Rules section. Here you can download the complete code, add a comment on the rule, or make suggestions for changes there.

Running the DPA Rule

Once you’ve created the rule in NetMon, save it and verify that you don’t have any syntax errors. To reveal the IMPC information, open any dashboard and filter for ICMP traffic. Next, open up the table on any session, and you’ll see ICMP_TypeMsg_NM and ICMP_Type_NM values.

Resulting

Figure 11: Resulting ICMP_TypeMsg_NM and ICMP_Type_NM Fields

If you happen to grab a 3, 5, or 11, you’ll also see the ICMP_Code_NM and ICMP_CodeMsg_NM fields.

Resulting

Figure 12: Resulting ICMP_Code_NM and ICMP_CodeMsg_NM Fields

Now that you have the rule set up and you are parsing the data, you can use the resulting information to do several things, including:

  • Identify which of your systems are getting hit with which kind of ICMP traffic
  • Create a dashboard to organize traffic by source, destination, ICMP type, and count
  • Capture ICMP so you can look at the packet details
  • Write Flow Rules to raise alarms when NetMon sees suspicious ICMP on specific secure systems

If this post inspires you to develop your own network security use case, check out our free network monitoring and forensic tool NetMon Freemium. Then submit your use case into our Rule Your Network Challenge for a chance to win over $18,000 USD in cash and prizes!