5 Days Left to Save $400 on SANS Security East 2015, New Orleans

Intrusion Detection FAQ: I am seeing odd ICMP traffic, what could this mean?

Discussion

Sites that see incoming echo replies when there are no echo requests may be seeing an advanced probe. Another possibility is that your address space is being used (spoofed) in a smurf style denial of service attack against the source address. Sites that see outgoing echo replies w/o echo requests would do well to investigate. Sites that see outgoing ICMP broadcast packets with the source IP address not part of their own internal address space may well be launching a smurf attack.

ICMP in particular "ping" traffic was once considered to be benign. These days many firewall administrators block ping traffic (but few block echo replies) to their internal sites from an external site. There are a variety of problems that have been noted with respect to echo requests and replies, they include smurf, network mapping and loki or an inverse mapping technique.

Smurf

Smurf is broadcast ICMP from a spoofed address and is a well documented attack. Incoming smurf might have a pattern similar to this:
00:00:05 spoofed.net > 192.168.15.255: icmp: echo request
00:00:05 spoofed.net > 192.168.1.255: icmp: echo request
00:00:05 spoofed.net > 192.168.14.255: icmp: echo request
00:00:05 spoofed.net > 192.168.14.0: icmp: echo request
00:00:05 spoofed.net > 192.168.15.255: icmp: echo request
00:00:05 spoofed.net > 192.168.15.0: icmp: echo request
00:00:05 spoofed.net > 192.168.16.255: icmp: echo request
Note the timestamps in the above probe. This is indicative of a flood attack on the target. Blocking incoming echo requests can help prevent smurf attacks.

For further information about smurf, click here.

Network Mapping

Network mapping can use ICMP echo requests for reconnaissance purposes. By sending a few packets with broadcast and legacy broadcast addresses, probers can find active hosts in your network. This is a very common practice for attackers. Blocking incoming echo requests can help prevent this type of probe but it will affect ping traffic. Network mapping might look similar to this:
00:00:05 non-spoofed.net > 192.168.14.255: icmp: echo request
00:00:10 non-spoofed.net > 192.168.14.0: icmp: echo request
00:00:15 non-spoofed.net > 192.168.15.255: icmp: echo request
00:00:20 non-spoofed.net > 192.168.15.0: icmp: echo request
00:00:25 non-spoofed.net > 192.168.16.255: icmp: echo request
00:00:30 non-spoofed.net > 192.168.16.0: icmp: echo request
One of network mapping's goals is to map the net in a manner that won't arouse suspicion. Packets are sent infrequently or at longer intervals . The timestamps in the above example provide a clue that the probe is a network map and not a Smurf attack.

Covert Channel Communication

ICMP_ECHO traffic can be used to construct covert communications channels through networks. Several members of the SANS community have discovered evidence of this happening on a widespread scale.

The normal "ping" protocol states that one site (the pinger) sends an ICMP_ECHO packet to the target (the pingee). The pingee then sends an ICMP_ECHOREPLY back. ICMP_ECHO packets have an option to include a data section that usually stores timing information to determine round-trip packet times. Firewalls and filtering routers do not check the data content, so it is possible to transmit malicious information in this packet. This is a covert channel. Most network routers pass, drop or return ICMP traffic. Since they don't filter the data content, it is possible to masquerade Trojan packets as valid ICMP_ECHO packets. One example of this type of attack is described in Phrack Magazine and is called Project Loki. A loki packet might look like this:
04:19:31.800000 1.2.3.4 > 192.168.5.5: icmp: echo reply (DF)
4500 0028 b5cb 4000 fe01 b229 0102 0304
c0a8 0505 0000 bc9c bf3c f001 0018 f81b
000d d5f0 000d 63e8 0000 0000 0000
Inverse Mapping

Inverse mapping makes it possible to map an internal network that is protected by a firewall using this technique. An unsolicited ICMP_ECHOREPLY packet is a fake packet that will pass through most firewalls. Most routers will send a HOST_UNREACHABLE packet back to the pinger if they receive an unsolicited ICMP_ECHOREPLY packet sent to a nonexistent host system. If the host exists, the router drops the packet and sends nothing back to the pinger. The hacker can use these responses or lack of response to map active IP addresses on the inside by seeing which HOST_UNREACHABLE packets are returned. That pattern might look like this:
00:58:16 prober> 172.20.179.41: icmp: echo reply
00:58:17 router> prober: icmp: host unreachable

03:11:50 prober> 172.20.54.94: icmp: echo reply
03:11:51 router> prober: icmp: host unreachable
The Implications

Once a hacker knows which internal IP addresses are valid, it is much easier for them to target their efforts on specific hosts. Evidence suggests that once compromised, these hosts may use covert channels to tunnel information from the outside into the internal net and vice versa. The covert channel currently being employed uses the data portion of ICMP echo request packets. This technique is described in Phrack 49 and Phrack 51.

It should be emphasized that this probe is very similar to a Smurf attack. You need to examine the data packets carefully.
  • To read about Project LOKI in Phrack 49, click here
  • To examine the Project LOKI code from Phrack 51, click here
  • To read the CERT advisory on the TFN attack, click here
  • To read more about covert channels in the TCP/IP suite, click here
Solutions and Countermeasures

There are a number of solutions that appear to help stop this probe and the potential subsequent attack.
  • Disable external ICMP_ECHO traffic entirely. This does have serious implications to normal network management since it does break the ping command. However, you should be able to allow internal ping traffic and disable packets coming from the outside.
  • Disable ICMP_ECHO_REPLY traffic on a Cisco router
  • Make sure your routers are configured to NOT send ICMP_UNREACHABLE packets to hosts that don't respond to ARPs.
Sample Filter Code

Here is some code to check for unsolictied ICMP echo requests. You run it like one_day_pat.pl. Need a site (-l) and need a date(-d).

#!/usr/bin/perl
#
# $Id: traffic.php,v 1.1 2006/03/16 21:22:01 bcorcoran Exp $
#
#  Script to scan a tcpdump compressed hourly file using a pre-defined
#  tcpdump script. Parameters are: Date as YYMMDDHH and script name.
#
#  Written by Bill Ralph 3/20/98
#
#  Set up some variables.
#
use Getopt::Long;
use POSIX qw(strftime);
#
#  Catch user interrupt signal and abort the script.
#
sub sig_catch {
   my $signame = shift;
   die("Received SIG$signame.");
}
#
$SIG{INT}=\&sig_catch;
$CID_PATH = "/usr/local/logger";
$ENV{PATH} =
"/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$CID_PATH";
#
sub usage {
      print "Usage: one_day_skew_icmp [-d DATE] [-l SITE].\n";
      exit 2;
}
#
#       Parse the parameters.
#
#
$e_req = "echo request";
$e_rep = "echo reply";
&GetOptions("d:s", \$snifdate, "l=s", \$Site);
##
#
#  Check parameter validity.
#
if ("$Site" eq "")
{
       usage();
}
#
# Once the Site is identified from the command line,
# load the needed external Parameters.
#
unshift(@INC, "$CID_PATH/sites");
die ("No such site: ${Site}.") if ( ! -e "$CID_PATH/sites/${Site}.ph");
require "${Site}.ph";

#
#
#
# If no snifdate specified on command line, assume today.
#
if ($snifdate eq "") {
   $snifdate = strftime("%y%m%d", localtime);
}
#
#  Break up the "snifdate" into its useful components.
#
$year=substr($snifdate,0,2);
$mon=substr($snifdate,2,2) - 1;
$mday=substr($snifdate,4,2);
$subdir=strftime("%h%d", 0, 0, 0, $mday, $mon, $year, 0, 0, 0);
#
#
# Ready to start the work now, find the hourly data files.
#
# print STDOUT ("${ANALYZER_DIR}/${subdir}\n");
#
#
chdir("${ANALYZER_DIR}/${subdir}");
@files=<tcp.*.gz>;
$pattern='"'.$pattern.'"';
if ($files[0] eq "") {
#
# No hourly files, they must have been already condensed into daily ones.
#
   @files=<day*.gz>;
}
foreach $file (@files) {

   $tcpdump_command = "gunzip -c $file | tcpdump -r - -n";

   open(RAWFILE,"$tcpdump_command|");

   while(<RAWFILE>)
   {
     $dataline = $_;
     chomp($dataline);
     if ($dataline =~/$e_req/) {
      @fields = split(/\s+/,$dataline);
       $dest_IP = $fields[3];
       $dest_IP =~ s/\://g;
       $subscript = $fields[1] . ">" . $dest_IP;
       $icmp{$subscript}++;
     }
     if ($dataline =~/$e_rep/) {
      @fields = split(/\s+/,$dataline);
      $dest_IP = $fields[3];
      $dest_IP =~ s/\://g;
      $subscript = $dest_IP . ">" . $fields[1];
      if (!exists($icmp{$subscript})) {
       print "No echo request for record: $dataline\n";
     }
     else {
      $count = $icmp{$subscript};
      if ($count - 1 ge 0) {
        $icmp{$subscript}--;
     }
     else {
      print "No echo request for record: $dataline\n";
     }
    }
   }
   next;
 }
}