Firewall Intelligence Gathering It is very common for routers and firewalls to be set up to protect machines and / or subnets from outside traffic. However, because of the way these firewalls work it is possible to gain information about holes in the firewalls (unrestricted IPs) and information about the firewall itself by using the way firewalls reply to ICMP ECHO_REQUEST (ping) packets. When trying to ping an IP address that is behind such a firewall, it often seems if ping packet is simply blocked by the router / firewall and ignored. In fact they return a packet, not from the IP that you targeted with a ping, but from the router itself. So by pinging a restricted IP, you can get the IP address of the firewall protecting it. This works regardless of whether the target IP is active or not. This means you can find unprotected IPs, regardless of whether the machine attached to such an unprotected address is on or not. You could ping a protected IP and if you got a reply from the router then you would know the IP was protected, if you got no reply (if the target machine is off) or a proper ECHO_REPLY from the target itself, you know you have found an unrestricted IP. If you know a time when such machines are likely to be off (for example office machines on people's desks rather than servers), you can scan the subnet and determine unrestricted IPs by a lack of reply (similar in method to the way port scanning with FIN packets works) and not trigger any logs / defences on the target machine. By default however, ping will not pick up on replies to pings that originate from a different IP than the one you targetted. You can of course watch the packet stream using a packet sniffer such as tcpdump or sniffit, but it would be easier it ping simply reported such packets. To this end I have created a patch for ping included in linux and OpenBSD which will display when a returned ICMP packet is not from the target. OpenBSD patch for Ping Either download from here http://www.abel.net.uk/~dms/archive/ping.bsd.patch Or cut and paste the text below into a file called ping.bsd.patch Get the source for OpenBSD ping (also works for NetBSD, probably for FreeBSD and other BSD unixes, except SunOS) http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/ping/ping.c?rev=1.36 Put the source and the patch into the same directory. Type patch < ping.bsd.patch compile ping with gcc -o ping ping.c and voila, you have a version of ping which can recognise replies from firewalls. Ping must be run as root or have SUID permissions to work as it uses raw sockets. Linux patch for Ping Either download from here http://www.abel.net.uk/~dms/archive/ping.linux.patch Or cut and paste the text below into a file called ping.linux.patch The source for linux ping is available in the netkit-base-0.10.tar.gz package available from ftp://sunsite.unc.edu/pub/Linux/system/network/ Unpack this archive, go into the ping directory. Copy the file ping.linux.patch into this directory and type patch < ping.linux.patch compile ping with gcc -o ping ping.c Again ping must be run as root or have SUID permissions. Test Drive At the time of writing www.icq.com has exactly this type of firewall. Using your newly patched warez, ping www.icq.com. It should reply with 'Reply not from target' and the IP address of the firewall. Bingo, you have docs. OpenBSD Patch Code --- bsdping.c.orig Thu Nov 26 10:08:06 1998 +++ ping.c Thu Nov 26 10:04:31 1998 @@ -69,6 +69,14 @@ * This program has to run SUID to ROOT to access the ICMP socket. */ +/* + * BSD patch by Harl to pick up ECHO_REPLY from firewalls that is otherwise + * not reported. + * + * Anti-copyright (1998) Steal what the fuck you want. + * + */ + #include #include #include @@ -149,6 +157,7 @@ char DOT = '.'; char *hostname; int ident; /* process id to identify our packets */ +static struct in_addr dest_addr_store; /* counters */ long npackets; /* max packets to transmit */ @@ -334,6 +343,8 @@ hostname = hnamebuf; } + dest_addr_store = to->sin_addr; + if (options & F_FLOOD && options & F_INTERVAL) errx(1, "-f and -i options are incompatible"); @@ -640,8 +651,18 @@ (void)gettimeofday(&tv, (struct timezone *)NULL); + /* Check the IP header */ ip = (struct ip *)buf; + + /* Check reply is from pinged host */ + if (memcmp(&dest_addr_store, &ip->ip_src.s_addr, sizeof(struct in_addr))) { + printf("Reply not from target. Source %s",inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); + (void)printf(" ttl=%d", ip->ip_ttl); + if (timing) + (void)printf(" time=%ld.%ld ms\n", triptime/10, triptime%10); + } + hlen = ip->ip_hl << 2; if (cc < hlen + ICMP_MINLEN) { if (options & F_VERBOSE) @@ -1280,3 +1301,5 @@ " [-w maxwait] host\n"); exit(1); } + + Linux Patch Code --- ping.c Tue May 19 11:16:15 1998 +++ newping.c Tue Nov 24 09:42:39 1998 @@ -180,6 +180,7 @@ char DOT = '.'; static char *hostname; static int ident; /* process id to identify our packets */ +static struct in_addr dest_addr_store; /* counters */ static long npackets; /* max packets to transmit */ @@ -393,6 +394,8 @@ hostname = hnamebuf; } + dest_addr_store = to->sin_addr; + if (options & F_FLOOD && options & F_INTERVAL) { (void)fprintf(stderr, "ping: -f and -i incompatible options.\n"); @@ -716,6 +719,14 @@ if (options & F_QUIET) return; + /* Check reply is from pinged host */ + if (memcmp(&dest_addr_store, &ip->saddr, sizeof(struct in_addr))) { + printf("Reply not from target. Source %s",inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); + (void)printf(" ttl=%d", ip->ip_ttl); + if (timing) + (void)printf(" time=%ld.%ld ms", triptime/10, triptime%10); + } + else if (options & F_FLOOD) (void)write(STDOUT_FILENO, &BSPACE, 1); else {