#!/usr/bin/perl # # roguegw.pl - Tool to detect rogue gateways in a IP subnet # # v1.0 - xavier@rootshell.be # # Usage: ./roguegw.pl --startip x.x.x.x --endip x.x.x.x --target x.x.x.x # # startip/endip : define the IP range to scan (must be local to the host running the script) # target: external IP address to try to reach (can be an Internet address or another subnet) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with This program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # use Getopt::Long; use Net::Traceroute; use Net::IP; use strict; $SIG{INT} = \&handleBreak; # --------- # Arguments # --------- my $startIP = "10.0.0.1"; # A classic LAN configuration my $endIP = "10.0.0.254"; my $targetIP = "74.125.232.18"; # google.com my $currentIP = ""; my $help; my $randomize; my $options = GetOptions( "help" => \$help, "randomize" => \$randomize, "startip=s" => \$startIP, "endip=s" => \$endIP, "target=s" => \$targetIP); if ($help) { print <<__HELPEND__; Usage: roguegw.pl --startip x.x.x.x --endip x.x.x.x --target x.x.x.x [--randomize] [--help] startip / endip : Define the range of IP addresses to scan. target : Defines the target IP address to reach via the gateway. (Can be a public IP address or another organization subnet. randomize : Randomizes the IP range (usefull to work below the radar). __HELPEND__ exit 1; } if (!validateIP($startIP)) { print "ERROR: IP address " . $startIP . " is invalid!\n"; exit 1; } if (!validateIP($endIP)) { print "ERROR: IP address " . $endIP . " is invalid!\n"; exit 1; } if (!validateIP($targetIP)) { print "ERROR: IP address " . $targetIP . " is invalid!\n"; exit 1; } open(FD, "netstat -rn|") || die "Cannot get system routing table!"; while() { if ($_ =~ m/$targetIP/) { print "ERROR: $targetIP is already present in the routing table. Aborted!\n"; exit 1; } } close(FD); print "Scanning IP range: $startIP - $endIP ...\n"; # --------- # Main Loop # --------- my $ipRange = new Net::IP("$startIP - $endIP") || die "Cannot created Net::IP object!"; my @ipArray; my $i=0; do { $ipArray[$i++] = $ipRange->ip(); } while (++$ipRange); if ($randomize) { print "[IP range randomized]\n"; randomizeArray(\@ipArray); } for ($i = 0; $i < scalar(@ipArray); $i++) { $currentIP = $ipArray[$i]; print "Testing: " . $currentIP . "... "; system "/sbin/route add -host " . $targetIP . " gw " . $currentIP || die "Cannot add static route to $currentIP!"; my $tr = Net::Traceroute->new(host => "$targetIP", max_ttl => "5", query_timeout => "5", debuglvl => "2" ); my $hops = $tr->hops; my $code = $tr->hop_query_stat(1, 0); # If one hop returned + unreachable : host down? if ($hops != 1 && $code != 5) { if ($tr->hop_query_host(1, 0) ne "") { print "Found $hops hops!\n"; my $j; for ($j = 1; $j <= $hops; $j++) { my $host = $tr->hop_query_host($j, 0); if ($host ne "") { print "\t" . $j . ": " . $host . " (" . $tr->hop_query_time($j, 0) . "ms)\n"; } else { print "\t" . $j . ": *\n"; } } system "/sbin/route del -host " . $targetIP . " gw " . $currentIP || die "Cannot remove static route to $currentIP!"; } else { print "Host up but no packet forwarding.\n"; system "/sbin/route del -host " . $targetIP . " gw " . $currentIP || die "Cannot remove static route to $currentIP!"; } } else { print "Host reported unreachable from " . $tr->hop_query_host(1, 0) . "\n"; system "/sbin/route del -host " . $targetIP . " gw " . $currentIP || die "Cannot remove static route to $currentIP!"; } } print "Done.\n"; exit 0; sub validateIP() { my $IP = $_[0]; if ($IP =~ m/^(\d\d?\d?).(\d\d?\d?).(\d\d?\d?).(\d{1,})$/ ) { if ($1 > 255 || $2 > 255 || $3 > 255 || $4 > 255) { return 0; } else { return 1; } } return 0; } # Source: http://docstore.mik.ua/orelly/perl/cookbook/ch04_18.htm sub randomizeArray() { my $array = shift; my $i; for ($i = @$array; --$i; ) { my $j = int rand ($i+1); next if $i == $j; @$array[$i,$j] = @$array[$j,$i]; } } sub handleBreak() { $SIG{INT} = \&handleBreak; print "\n\n*** CTRL-C detected, cleaning up temporary route ***\n\n"; system "/sbin/route del -host " . $targetIP . " gw " . $currentIP; exit 1; }