#!/usr/bin/perl -w # ############################################################################# # _____ _ _ _____ _______ ___ A (fast?) banner grabber, written in Perl # |_ _| | | |_ _|_ _\ \ / / | ...and about as subtle as an elephant. # | | | |_| | | | | | \ V /|_| Author : David Ramsden # |_| \___/ |_| |_| |_| (_) Website: http://david.hexstream.co.uk/ # -------------------- Version 0.2 ############################################################################# # ### License (distributed under the zlib license) ### # Copyright (c) 2006 David Ramsden # # This software is provided 'as-is', without any express or implied warranty. # In no event will the authors be held liable for any damages arising from # the use of this software. # # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # # 2. Altered source versions must be plainly marked as such, and must not # be misrepresented as being the original software. # # 3. This notice may not be removed or altered from any source # distribution. ############################################################################# use strict; use POSIX; use IO::Socket; use Fcntl; # Keep an eye on our children! $SIG{CHLD} = \&reaper; # Initialise random seed. srand; # Get command line options. my $victim = shift; my $port_start = shift; my $port_end = shift; # Check all command line options have been specified. if (!defined($victim) || !defined($port_start) || !defined($port_end)) { print "Usage : $0 <victim address> <port start> <port end>\n"; print "Example: $0 127.0.0.1 1 1023\n"; exit 1; } print <<EOF; _____ _ _ _____ _______ ___ *** Starting to grab banners! *** |_ _| | | |_ _|_ _\\ \\ / / | A (fast?) banner grabber, written in Perl | | | |_| | | | | | \\ V /|_| ...and about as subtle as an elephant. |_| \\___/ |_| |_| |_| (_) Author: David Ramsden --------------------- Version 0.2 Website: http://david.hexstream.co.uk/ EOF # Mix up the order of the ports to connect to. my @ports = &randomise_ports(); # Go through each port (now in a random order). foreach my $port (@ports) { print "."; # ./~ Fork bomb, fork bomb. You're my fork bomb. ./~ if (my $pid = fork) { # Don't worry about waiting for the child. # This will create lots of connections which is fast # but we might end up with zombie processes. } elsif (defined $pid) { # Now we're forked, go and connect to the victim's port. &do_grab($victim, $port); } else { die "\n\nforking error: $!\n"; } # Sleep for a very small, random, amount of time. # If we don't, it will only fork one process at a time. select undef, undef, undef, rand(); } print "\n"; print "Note: There are probably still child processes working.\n"; print " Check the process list before viewing results.\n"; exit 0; ## Create a random array of the port numbers. sub randomise_ports() { # Define local variables. my @ports = (); my @new = (); # First get the from and to ports in to an array. # Then shuffle the elements in to random positions. for(my $port = $port_start; $port <= $port_end; $port++) { push @ports, $port }; while(@ports) { push @new, splice(@ports, rand @ports, 1) }; return @new; } ## Connect to victim's port and grab the banner. sub do_grab() { # Keep an eye on our children! $SIG{CHLD} = \&reaper; # Define local variables. my $victim = shift; my $port = shift; open LOG, ">>$victim.log.txt"; # Initiate the connection. my $socket = new IO::Socket::INET (PeerAddr => $victim, PeerPort => $port, Proto => 'tcp', Timeout => 4); # Check if the connection was established. if (!defined($socket)) { print LOG "Port $port: $!\n"; exit 1; } else { print LOG "Port $port connected.\n"; } close LOG; # Set socket to nonblocking. &nonblock($socket); # If this child process is still running after 40 seconds # then "poke" the connection to get some form of response. # We send a HTTP HEAD request, in case it's a web server # waiting for a request. Otherwise we may or may not get # anything back. Hence the second alarm signal that will # kill the connection after another 5 seconds. $SIG{ALRM} = sub { alarm(0); print $socket "HEAD / HTTP/1.0\n\n"; $SIG{ALRM} = sub { close $socket; exit 0; }; alarm(5); }; alarm(40); # Grab the banner. my $rx = 0; my $data = ""; my $banner = ""; while(1) { # Read socket. $socket->recv($data, POSIX::BUFSIZ, 0); # Data was read. if (length($data)) { $rx = 1; $banner .= $data; } elsif (!length($data) && $rx == 1) { # We've recieved data, at some stage and # now we're not getting anything. # So assume we're done reading everything. last; } # Sleep for 500ms before trying a read again. select undef, undef, undef, 0.50; } close $socket; if (defined($banner)) { open BANNERS, ">>$victim.banners.txt"; print BANNERS "Banner grabbed for port $port:\n"; print BANNERS "-"x77 . "\n"; print BANNERS $banner; print BANNERS "-"x77 . "\n\n"; close BANNERS; } # Exit here, to kill the child process we forked. exit 0; } ## Clean up after the child process is stopped or terminated. sub reaper() { wait; } ## Sets a socket in to nonblocking operation. sub nonblock() { # Define local variables. my $socket = shift; # Get the current descriptor flags. my $flags = fcntl($socket, F_GETFL, 0) or die "Can't get flags for socket: $!\n"; # Add the O_NONBLOCK flag to the socket. fcntl($socket, F_SETFL, $flags | O_NONBLOCK) or die "Can't make socket nonblocking: $!\n"; }