ICMP
____________________________________________________________________
ICMP or The Internet Control
Message Protocol is the de facto protocol used to communicate error messages
reporting errors that might have occurred while transferring data over networks.
Besides, the normal use of reporting error messages, ICMP also plays an
extremely important role in gathering information about the remote system. This
manual explores everything about ICMP, its uses and how to use ICMP to gather
more information on the target system and of course, countermeasures.
The ICMP
protocol communicates error messages and other malfunctions or problems that
might have occurred while the data transactions between two systems were taking
place. Thus, it can also be called the ‘Network Problem Diagnosis’ protocol. It
is basically the protocol, which reports any error that might have occurred
while the data transfer was still taking place.
All
ICMP messages are transmitted as IP datagrams. A Typical ICMP message
encapsulated within an IP datagram would be as follows:
_______________________________________________________
|
|
|
|
IP Header
|
ICMP Message
|
|
|
|
|____________________|_________________________________
|
20 Bytes
|-------------------------------IP
Datagram-----------------------------------|
The
first 4 bytes have the same format and specification for all the messages;
however, the remaining part of the datagram differs from message to message
depending upon the kind or message i.e. the type of error message carried by the
datagram. This means that the first 4 bytes are common to all ICMP messages,
while the remaining bytes are different for different error messages, depending
upon the type of error transmitted by that particular
message.
The
format of a typical ICMP message is as follows:
0
7 8
15 16
31
____________________________________________________________________
|
|
|
|
| 8-Bit Type
|
8-bit Code
|
16-Bit Checksum
|
|
|
|
|
|_____________
|____________________ |_________________________________|
|
|
|
|
|
|
|
(Contents depending upon Type and Code)
|
|
|
|
|
|
|
|___________________________________________________________________|
The
‘type’ field can have any of the 15 different values, which determine or
represent a particular ICMP error message. For Example, a value of 3 in the type
field specifies the ‘Destination unreachable’ error message. Like this there are
15 different values, which the ‘type’ field can have, with each value
representing a particular specific error type.
An
error message like the above was a very general or rather a very broad error
message. It does not tell you the exact cause of the error or where exactly or
what exactly caused the error to occur. Thus, it is not that useful for diagnose
purposes. In order to ensure that the user or application running on either the
client side or the server side knows about the error occurred in a more detailed
fashion, ICMP has the provision whereby, each main error specified by the ‘type’
value has a number of sub errors, which give a more specific reason or cause of
the error.
Such sub-errors, which are
more specific and more helpful, are specified in ICMP in the ‘code’
field.
For Example,
a ‘Type’ Value of 3 and a ‘code’ value of 0 specify that the error caused is:
‘Network Unreachable’. While a ‘Type’ Value of 3 and a ‘code’ value of 1
specifies that the error caused is: ‘Host Unreachable’
The
following table gives the complete list of type values, code values and their
corresponding errors, which are allowed by ICMP:
Type |
Name |
Code |
|
0 |
Echo
Reply |
0 No
Code |
|
1 |
Unassigned |
|
|
2 |
Unassigned |
|
|
3 |
Destination
Unreachable: |
0 Net Unreachable1 Host Unreachable2 Protocol Unreachable3 Port Unreachable4 Fragmentation Needed and Don't Fragment was Set5 Source Route Failed6 Destination Network Unknown7 Destination Host Unknown8 Source Host Isolated9 Communication with DestinationNetwork is Administratively Prohibited10 Communication with Destination Host isAdministratively Prohibited6 11 Destination Network Unreachable for Type ofService.12 Destination Host Unreachablefor Type of Service.13 Communication Administratively Prohibited.14 Host Precedence Violation
15 Precedence cutoff in
effect |
|
4 |
Source Quench |
0 No Code |
|
5 |
Redirect |
|
|
|
|
0 Redirect Datagram for the Network (or subnet) |
|
|
|
1 Redirect Datagram for the Host |
|
|
|
2 Redirect Datagram for the Type of Service andNetwork |
|
|
|
3 Redirect Datagram for the Type of Service andHost |
|
6 |
Alternate Host Address |
0 Alternate Address for Host |
|
7 |
Unassigned |
|
|
8 |
Echo Request |
0 No Code |
|
9 |
Router Advertisement |
0 No Code |
|
10 |
Router Selection |
0 No Code |
|
11 |
Time Exceeded |
|
|
|
|
0 Time to Live exceeded in Transit |
|
|
|
1 Fragment Reassembly Time Exceeded |
|
12 |
Parameter Problem |
|
|
|
|
0 Pointer indicates the error |
|
|
|
1 Missing a Required Option |
|
|
|
2 Bad Length |
|
13 |
Timestamp |
0 No Code |
|
14 |
Timestamp Reply |
0 No Code |
|
15 |
Information Request |
0 No Code (Obsolete) |
|
16 |
Information Reply |
0 No Code (Obsolete) |
|
17 |
Address Mask Request |
0 No Code |
|
18 |
Address Mask Reply |
0 No Code |
As soon as
TCP/IP encounters an error in the data transfer from the source to the
destination, ICMP is used to inform the client, server and the user process
about the details of the error encountered. Thus, the prime usage of ICMP is in
relaying error occurred in the data transit.
The various
ICMP messages having different code and type values can be used to get different
kinds of information on the remote system. Information gathering is the first
step that a hacker goes through in his attempt to detect any loopholes in the
target system. Although sending ICMP messages will not tell you everything that
you will need to know about the target system, but still they will give you
quite a lot of information.
The
Echo request message is the ICMP message with a type value of 8 and a
code value of 0, while the Echo reply message is the ICMP message with a
type value of 0 and a code value of 0. We can use the ICMP Echo Request and Echo
Reply messages to determine whether or not the target host is connected to the
Internet (is alive) or not.
In
order to determine whether the target host is alive or not, all we have to do is
send an Echo Request message to the remote system and wait for an Echo reply
message.
However, one note of
caution, it is more than possibility that the target host to whom you send out
the Echo request datagram might have a filtering device installed which discards
all Echo Request ICMP messages, thus showing that the remote system is not
connected to the Internet even though it might as well be connected. Some better
firewalls even send out spoofed Echo Replies on encountering such echo requests,
thus throwing the malicious intruders off the track.
***********************
HACKING
TRUTH: Does the working of the Echo Request and Echo Reply Messages
sound familiar? You guessed it, they are indeed same as the popular Unix network
diagnosing command: ping.
**********************
How
exactly do the ICMP Echo Request and Reply Messages work? To understand their
working, let us first take a look at their structures:
The
format of a typical ICMP ‘echo request’ and ‘echo reply’ message would be as
follows:
0
7 8
15 16
31
____________________________________________________________________
|
|
|
|
| Type =0or 8 |
Code =0
|
16-Bit Checksum
|
|
|
|
|
|_____________
|____________________ |________________________________ |
|
|
|
|
Identifier
|
sequence number
|
|__________________________________|_________________________________|
|
|
|
|
|
(Optional Data)
|
|
|
|___________________________________________________________________|
The
sender initializes an ICMP echo request message giving the Identifier field the
value of the Process ID of the sending process, the sequence number field a
sequence number and adding some binary data to the data field. The target system
then on receiving the request, simply echoes back the identifier, data
(unchanged) and sequence number fields in the form of an ICMP reply message.
When the sender receives this message, it can deduce that the target system is
alive.
This method can easily be
carried out using the ping utility. For Example,
# ping
hackingtruths.box.sk
Pinging hackingtruths.box.sk
[194.x.yyy.227] with 32 bytes of data:
32 bytes from 194.x.yyy.227:
icmp_seq=0 ttl=225 time=0 ms
32 bytes from 194.x.yyy.227:
icmp_seq=1 ttl=225 time=0 ms
32 bytes from 194.x.yyy.227:
icmp_seq=2 ttl=225 time=0 ms
32 bytes from 194.x.yyy.227:
icmp_seq=3 ttl=225 time=0 ms
32 bytes from 194.x.yyy.227:
icmp_seq=4 ttl=225 time=0 ms
32 bytes from 194.x.yyy.227:
icmp_seq=5 ttl=225 time=0 ms
32 bytes from 194.x.yyy.227: icmp_seq=6 ttl=225 time=0 ms
……..
Countermeasures
Echo Requests
or Ping is widely carried out over the Internet and almost all servers are bound
to encounter such instances (wherein they are on the receiving end) every now
and then. One easy method in which you can block ping requests at the router
level is by adding the following ACL:
access-list 101 deny icmp
any any 8
This line will filter out all echo
request packets at the router level and discard them. There will be no echo
replies sent back to the attacker. However, if you want to filter out all echo
requests coming to your network except those coming from your ISP, (who send out
echo requests for routine checks) then the following ACL rules will do the job
for you:
access-list 101 permit icmp xx.xx.xx.xx
0.0.0.255 any 8
access-list 101 deny icmp any any
8
The above access rules will discard all
echo requests except those that are coming from your ISP, whose IP Address is
xx.xx.xx.xx.
Using the Timestamp Request and Timestamp
Reply Messages
The ICMP Timestamp Request message has a
type value of 13, while an ICMP Timestamp Reply message has a type value of 14.
These messages in conjugation with one another help one system to query another
system for the current time in the latter system. The time returned is actually
the number of milliseconds since midnight, Coordinated Universal Time. (UTC)
The typical format of a Timestamp message
is as follows:
0
7 8
15 16
31
____________________________________________________________________
|
|
|
|
| Type =13or14 |
Code =0
|
16-Bit Checksum
|
|
|
|
|
|_____________
|____________________ |________________________________ |
|
|
|
|
Identifier
|
sequence number
|
|_________________________________
|_________________________________|
|
|
|
|
|
32-bit originate timestamp
|
|
|
|_________________________________________________________________ _|
|
|
|
|
|
32-bit receive Timestamp
|
|
|
|
|
|__________________________________________________________________ |
|
|
|
|
|
32-bit transmit Timestamp
|
|
|
|
|
|__________________________________________________________|
How exactly
does the Timestamp process work? The sender prepares a datagram of the above
type and fills in the time at which the message was sent in the Originate
Timestamp field. Then, the receiving end fills in the time at which it receives
the ICMP Time request message in the Receive Timestamp field. After that, the
time at which the receiving end sends back the Timestamp reply message is
recorded in the Transmit Timestamp field. However, nowadays the same value
filled in the receive Timestamp field is filled in the transmit Timestamp field
also.
Thus, if you
receive a Timestamp reply message from the remote system to which you had sent
the Timestamp request message it means that particular host is alive.
************************
HACKING
TRUTH: One can also
use the Timestamp messages to differentiate between the types of Operating
System running on the target host. For Example, Some versions of Windows NT are
known to not reply to a Timestamp request.
***********************
To actually
implement the ICMP Timestamp feature, all you need is a Unix box and a kewl
utility named icmpquery whose source code is as follows: (This utility can also
be used for ICMP Address Mask Requests, which are discussed later in the
manual)
----------------------
/* * icmpquery.c - send and receive ICMP queries for address mask * and current time. * * Version 1.0 * * Copyright 1998, 1998 David G. Andersen * http://www.angio.net/ * * Verified to work on: * FreeBSD (2.x, 3.x) * Linux 2.0.x * NetBSD 1.3 * * Should work on Solaris and other platforms with BSD-ish stacks. * * If you compile it somewhere else, or it doesn't work somewhere, * please let me know. * * Compilation: gcc icmpquery.c -o icmpquery
*/ /* Some portions of this code are taken from FreeBSD's ping source. * Those portions are subject to the BSD copyright, which is appended * at the end of this file. */ #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */#define SET(bit) (A(bit) |= B(bit))#define CLR(bit) (A(bit) &= (~B(bit)))#define TST(bit) (A(bit) & B(bit))
#include
<time.h>
#include
<sys/time.h>
#include
<stdio.h>
#include
<sys/types.h>
#include
<sys/socket.h>
#include
<netdb.h>
#include
<netinet/in.h>
#include
<netinet/in_systm.h>
#include
<netinet/ip.h>
#include
<netinet/ip_icmp.h>
#include
<errno.h>
#include
<string.h>
#include
<signal.h>
/* * We perform lookups on the hosts, and then store them in a chain * here. * * Yes, it's linear. No, I don't care. */ struct hostdesc { char *hostname; struct in_addr hostaddr; struct hostdesc *next;}; struct hostdesc *hostnames;struct hostdesc *hosttail; void resolv_from(char *hostfrom, struct in_addr *fromaddr){ struct hostent *hp; if (hostfrom == NULL) { fromaddr->s_addr = 0; return; } if ((hp = gethostbyname(hostfrom)) == NULL) { if ((fromaddr->s_addr = inet_addr(hostfrom)) == -1) { fprintf(stderr, "could not resolve from address\n"); exit(0); } } else { bcopy(hp->h_addr_list[0], &fromaddr->s_addr, hp->h_length); }} /* * Set up the list of hosts. Return the count. */ int makehosts(char **hostlist){ int i; struct hostent *hp; struct in_addr tmpaddr; int hostcount = 0; for (i = 0; hostlist[i]; i++) {#ifdef DEBUG printf("Resolving %s\n", hostlist[i]);#endif if ((hp = gethostbyname(hostlist[i])) == NULL) { if (tmpaddr.s_addr = inet_addr(hostlist[i])) { /* Could not resolve it. Skip it. */ fprintf(stderr, "%s: unknown host\n", hostlist[i]); continue; } } else { bcopy(hp->h_addr_list[0], &tmpaddr.s_addr, hp->h_length); } /* The host has been resolved. Put it in the chain */ /* We want to stick it on the end. */ if (hostnames == NULL) { hostnames = (struct hostdesc *) malloc(sizeof(*hostnames)); if (hostnames == NULL) { perror("hostnames malloc failed"); exit(-1); } hosttail = hostnames; } else { hosttail->next = (struct hostdesc *) malloc(sizeof(*hostnames)); if (hosttail->next == NULL) { perror("hosttail->next malloc failed"); exit(-1); } hosttail = hosttail->next; } hosttail->hostname = strdup(hostlist[i]); if (hosttail->hostname == NULL) { perror("strdup failed"); exit(-1); } hosttail->hostaddr = tmpaddr; hosttail->next = NULL; hostcount++; } return hostcount;} void usage(char *prog){ fprintf(stderr, "%s <-querytype> [-f fromhost] [-d delay] [-T time] destination list\n" " where is one of:\n" " -t : icmp timestamp request\n" " -m : icmp address mask request\n" " The delay is in microseconds to sleep between packets.\n" " The destination list is a list of hostnames or addresses\n" " -T specifies the number of seconds to wait for a host to\n" " respond. The default is 5.\n" " If you're on a modem, you may wish to use a larger -d and -T\n" , prog);} /* * Set up a packet. Returns the length of the ICMP portion. */ int initpacket(char *buf, int querytype, struct in_addr fromaddr){ struct ip *ip = (struct ip *)buf; struct icmp *icmp = (struct icmp *)(ip + 1); int on = 1; /* things we customize */ int icmplen = 0; int icmptype = 0; int offset; int typevar; int subtype; ip->ip_src = fromaddr; /* if 0, have kernel fill in */ ip->ip_v = 4; /* Always use ipv4 for now */ ip->ip_hl = sizeof *ip >> 2; ip->ip_tos = 0; ip->ip_id = htons(4321); ip->ip_ttl = 255; ip->ip_p = 1; ip->ip_sum = 0; /* kernel fills in */ icmp->icmp_seq = 1; icmp->icmp_cksum = 0; icmp->icmp_type = querytype; icmp->icmp_code = 0; switch(querytype) { case ICMP_TSTAMP: gettimeofday( (struct timeval *)(icmp+8), NULL); bzero( icmp+12, 8); icmplen = 20; break; case ICMP_MASKREQ: *((char *)(icmp+8)) = 255; icmplen = 12; break; default: fprintf(stderr, "eek: unknown query type\n"); exit(0); } ip->ip_len = sizeof(struct ip) + icmplen; return icmplen;} void sendpings(int s, int querytype, struct hostdesc *head, int delay, struct in_addr fromaddr) { char buf[1500]; struct ip *ip = (struct ip *)buf; struct icmp *icmp = (struct icmp *)(ip + 1); struct sockaddr_in dst; int icmplen; bzero(buf, 1500); icmplen = initpacket(buf, querytype, fromaddr); dst.sin_family = AF_INET; while (head != NULL) {#ifdef DEBUG printf("pinging %s\n", head->hostname);#endif ip->ip_dst.s_addr = head->hostaddr.s_addr; dst.sin_addr = head->hostaddr; icmp->icmp_cksum = 0; icmp->icmp_cksum = in_cksum(icmp, icmplen); if (sendto(s, buf, ip->ip_len, 0, (struct sockaddr *)&dst, sizeof(dst)) < 0) { perror("sendto"); } if (delay) usleep(delay); /* Don't flood the pipeline..kind of arbitrary */ head = head->next; }} void myexit(int whatsig){ exit(0);} /* * Listen for 'hostcount' pings, print out the information, and * then exit. */ void recvpings(int s, int querytype, struct hostdesc *head, int hostcount){ char buf[1500]; struct ip *ip = (struct ip *)buf; struct icmp *icmp; int err = 0; long int fromlen = 0; int hlen; struct timeval *tp; struct timeval tv; int recvd = 0; char *hostto; char hostbuf[128]; /* We'll print the address here otherwise */ struct hostdesc *foundhost; gettimeofday(&tv, NULL); while (recvd < hostcount) { if ((err = recvfrom(s, buf, sizeof buf, 0, NULL, (int *)&fromlen)) < 0) { perror("icmpquery: recvfrom"); } hlen = ip->ip_hl << 2; icmp = (struct icmp *)(buf + hlen); /* Find the host */ hostto = 0; for (foundhost = head; foundhost != NULL; foundhost = foundhost->next) { if (foundhost->hostaddr.s_addr == ip->ip_src.s_addr) { hostto = foundhost->hostname; break; } } if (!hostto) { sprintf(hostbuf, "unknown (%s)", inet_ntoa(ip->ip_src)); hostto = hostbuf; } /* For time */ switch(icmp->icmp_type) { case ICMP_TSTAMPREPLY: fromlen = ntohl(icmp->icmp_ttime); /* ms since midnight. yuch. */ tv.tv_usec = fromlen; tv.tv_usec = 0; tv.tv_sec -= tv.tv_sec%(24*60*60); tv.tv_sec += (fromlen/1000); tv.tv_usec = (fromlen%1000); printf("%-40.40s: %s", hostto, ctime(&(tv.tv_sec))); break; case ICMP_MASKREPLY: fromlen = ntohl(icmp->icmp_dun.id_mask); printf("%-40.40s: 0x%lX\n", hostto, fromlen); break; default: printf("Unknown ICMP message received (type %d)\n", icmp->icmp_type); } recvd++; }} intmain(int argc, char **argv){ int s; char *progname; extern char *optarg; /* getopt variable declarations */ char *hostfrom = NULL; extern int optind; extern int optopt; extern int opterr; char ch; /* Holds the getopt result */ int on = 1; int hostcount; int delay = 0; int querytype = ICMP_TSTAMP; struct in_addr fromaddr; int timeout = 5; /* Default to 5 seconds */ fromaddr.s_addr = 0; progname = argv[0]; while ((ch = getopt(argc, argv, "tmf:d:T:")) != EOF) switch(ch) { case 'd': delay = (int) strtol(optarg, NULL, 10); break; case 't': /* timestamp request */ querytype = ICMP_TSTAMP; break; case 'm': /* address mask request */ querytype = ICMP_MASKREQ; break; case 'f': hostfrom = optarg; resolv_from(hostfrom, &fromaddr); break; case 'T': timeout = (int) strtol(optarg, NULL, 10); break; default: usage(progname); exit(-1); } argc -= optind; argv += optind; if (!argv[0] || !strlen(argv[0])) { usage(progname); exit(-1); } hostcount = makehosts(argv); if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { perror("socket"); exit(1); } if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) { perror("IP_HDRINCL"); exit(1); } signal(SIGALRM, myexit); alarm(timeout); sendpings(s, querytype, hostnames, delay, fromaddr); recvpings(s, querytype, hostnames, hostcount);} /* * in_cksum -- * Checksum routine for Internet Protocol family headers (C Version) * From FreeBSD's ping.c */ in_cksum(addr, len) u_short *addr; int len;{ register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), we add * sequential 16 bit words to it, and at the end, fold back all the * carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } /* add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return(answer);} /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Muuss. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */
-----------------------
The following
was carried out on a Linux system, using a modified version of the icmpquery
utility:
#ankitbox
icmpquery –t xx.xx.xx.xx
xx.xx.xx.xx
: 04:15:19
An easier
manner, in which one can obtain the system time of a remote system, is by
telnetting to its daytime port.
Countermeasures
One easy
method in which you can block Timestamp messages at the router level is by
adding the following ACL’s:
access-list 101 permit icmp xx.xx.xx.xx
0.0.0.255 any 13
access-list 101 deny icmp any any
13
The above access rules will discard all
Timestamp requests except those that are coming from your ISP, who’s IP Address
is xx.xx.xx.xx.
Using the Address Mask Request and
Address Mask Reply Messages
The Address Mask Request message has a
type value of 17, while an Address Mask Reply Message has a type value of 18.
The address mask request and reply messages are used in order to obtain the
address mask of the target system.
Once we know the IP Address of the remote
system, then all we need to do is send an Address Mask request message to the
broadcast address of the network in which that system resides. Once we do that,
we will receive an ICMP Address Mask Reply message containing the Subnet Address
of the target system.
The typical structure of Address Mask
Request and reply message is as follows:
0
7 8
15 16
31
____________________________________________________________________
|
|
|
|
| Type =17, 18 |
Code =0
|
16-Bit Checksum
|
|
|
|
|
|_____________
|___________________
|_________________________________|
|
|
|
|
Identifier
|
sequence number
|
|__________________________________|_________________________________|
|
|
|
|
|
32-bit Subnet Mask
|
|
|
|___________________________________________________________________
|
The sender system fills in the Identifier
and Sequence Number fields, while the receiving end replies with these fields
and its Subnet Mask in the Subnet Mask field. As a result, the bottom line
being, the ICMP Address Mask messages can be used to obtain the Subnet Mask of
the target system.
Again, in order to implement ICMP Address
Mask Requests, one can use the nifty utility named icmpquery:
#ankitbox
icmpquery –m xx.xx.xx.xx
xx.xx.xx.xx
: The Subnet Mask Here
Countermeasures
One easy
method in which you can block ICMP Address Mask request messages at the router
level is by adding the following ACL’s:
access-list 101 permit icmp xx.xx.xx.xx
0.0.0.255 any 17
access-list 101 deny icmp any any
17
The above access rules will discard all
Address Mask requests except those that are coming from your ISP, who’s IP
Address is xx.xx.xx.xx.
Remote OS Detection with ICMP
Messages
There is a choice of a variety of
different operating systems that a system administrator can choose from to run
on his systems. After port scanning and getting a list of all open ports and
daemons running on the target system, the next step that a hacker typically
would want to take is to detect the exact Operating System name and version
running on the target system.
Although one can easily get the exact
Operating System name and version running on the remote system by daemon banner
grabbing, HTTP error messages, FTP commands etc even ICMP can be used to get the same
information.
Each operating system responds
differently to a particular kind of a datagram or ICMP message. This means that
a response that we get by sending a particular ICMP message to a Windows system
would be different from the response we get by sending the exact same ICMP
message to a Unix system. Different operating systems respond differently to the
same ICMP message. In other words, the type of response that we get on sending
an ICMP packet to a particular remote system depends on the type of Operating
System running on it. As a result, by studying the response that we get on
sending ICMP messages to a remote system, we can easily differentiate between
the various Operating Systems possibly running on it and deduce the exact OS
name and version, actually running on it.
The key to deducing the exact OS name and
version running on a remote system is to know the differences existing in the
responses made by the various operating systems to the particular ICMP message
that you are using as a differentiating benchmark. Thus to deduce the OS name
and version of a remote host by ICMP messages, simply follow the below
process:
1.
Send
particular ICMP messages to the remote host.
2.
Record the
response that you get by the remote system, when you perform Step
1.
3.
Compare the
response received, to the already known responses shown by the various Operating
Systems so that you can deduce the exact OS name and version running on the
remote host.
NOTE: These differences in the response by
various Operating Systems are also found to be due to improper implementation
and configuration. For a detailed look into these differences read the following
manual: http://www.sys-security.com/archive/papers/ICMP_Scanning_v3.0.zip
There are a number of different ICMP OS
Detection techniques: (This document will provide only any introduction to the
various processes)
ICMP Message
Quoting
Each time an error is encountered in the
data transfer process, the remote host calls upon ICMP and generates an ICMP
error message. Different operating systems quote different amounts of
information in the error message generated, each time such errors are
encountered. On analysis of these errors messages sent by the remote host, we
can deduce (or rather assume) the remote Operating System.
ICMP Error Message
Quenching
RFC 1812 lays down rules according to
which Operating Systems limit the rate at which error messages are sent. One can
easily send UDP packets to a random unused port, so as to make the remote host
generate and send back an ICMP Unreachable error message. If we then count the
number of such Unreachable Error messages sent back from the remote host to our
system in a given amount of time, then we can easily deduce the operating system
running there.
******************
HACKING TRUTH: By Examining the Type of Service (TOS) in
ICMP port Unreachable error messages too, we can determine the Operating System
running on the target system.
******************
ICMP Error Message: Echoing
Integrity
Certain systems are known to alter the IP
Headers of the ICMP error messages sent back by them. If we analyze the extent
and type of alterations made by the remote system in the IP header, we can
deduce to a certain extend the operating system running on the target
system.
Remote Firewall Detection with
ICMP
There may be occasions when you suspect
that a firewall has been installed in the target system’s network, which is
filtering out all your attacks. Does ICMP have a solution for detection of
firewalls too? Yes, it indeed has a solution in the form of the popular Unix
utility traceroute.
Traceroute makes use of ICMP i.e. ‘The
Time Exceeded in Transit error message’, ‘Port Unreachable Error Message’ and
the Time to Live (TTL) field in the IP Header to trace out the route from your
system to the target system.
The typical format of a Time Exceeded In
transit Error Message, which has a type value of 11 and a code value of 0 is as
follows:
0
7 8
15 16
31
____________________________________________________________________
|
|
|
|
| Type =11
|
Code =0
|
16-Bit Checksum
|
|
|
|
|
|_____________
|____________________ |_________________________________ |
|
|
|
|
Identifier
|
sequence number
|
|__________________________________|_________________________________|
|
|
|
|
|
IP Header + first 8 bytes of Original IP Datagram data
|
|
|
|____________________________________________________________________|
To detect a firewall installed or a
router (which discards ICMP TTL expired packets) in your path to the remote
target system, you can use the traceroute utility:
host2 # traceroute
xyz.com
traceroute to xyz.com (202.xx.12.34), 30 hops max, 40 byte
packets
1
isp.net
(202.xy.34.12)
20ms
10ms
10ms
2
xyz.com (202.xx.12.34)
130ms
130ms 130ms
3
*
*
*
The asterix signify that a firewall or a
filtering router has been encountered. Please note that the asterix does not
necessarily mean that the filtering device has been installed in your target
system network, but simply means that a filtering device has been encountered in
the path to the target system. It could also simply signify a filtering device
installed by your own ISP, which discards all ICMP TTL expired
packets.
Since this manual is about the ICMP
protocol, we would not be discussing, but would simply be mentioning the other
methods of detecting a filtering device:
1.
Banner
Grabbing
2.
Using
nmap
3.
Port
Scanning and looking for specific ports on which particular firewalls are known
to run by default.
Countermeasures
You can stop attackers from detecting a
filtering device installed in your network, by adding the following ACL to the
router:
access-list 101 deny ip any any
11
It configures the routers to not respond
to TTL expired messages, when it receives a packet with TTL equal to 0.
Footnote