#!/usr/bin/perl -w
#
# Copyright (C) 2006 Joshua D. Abraham (jabra@spl0it.org)
#
# 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
# 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
#
# scan.pl - simple port scanner
#
#
use strict;
use Socket;
use Net::hostent;
use IO::Socket::SSL;
use IO::Socket;
use Getopt::Long;
use FileHandle;
use vars qw( $PROG );
( $PROG = $0 ) =~ s/^.*[\/\\]//;    # Truncate calling path from the prog name

my $AUTH    = 'Joshua D. Abraham';  # author
my $VERSION = '1.0';                # version
my %options;
my $raw = 0;
my @targets;                        # list of all targets
my $target;                         # current target
my @ports;                          # list of all ports to scan
my $open_ports = 0;
my $scan_ports = 0;
$options{verbose} = 1;
$options{debug}   = 0;
$options{banner}  = 0;

##############################################################################
#
# help ->
# display help information
# side effect:  exits program
#
##############################################################################
sub help {
    print "Usage: $PROG [Options]
Options:
   -s  --scan <ip-range>     Scan Target ex: 10.0.0.100 or Hostname
   -i  --input <iplist>      Ip List of Adresses to scan
   
   -p  --port <port-list>    TCP ports to scan (ex 22,25,80-139)
   -b  --banner              Perform banner grabbing on open ports
   -V  --verbose             Verbose information
   -v  --version             Display version
   -h  --help                Display this information

Send Comments to Joshua D. Abraham ( jabra\@spl0it.org )\n";

}

##############################################################################
#
# print_version ->
# displays version
# side effect: exits program
#
##############################################################################
sub print_version {
    print "$PROG version $VERSION by $AUTH\n";
    exit;
}

sub scan {
    if ( !defined($target) ) {
        print "no target\n";
        exit;
    }
    foreach (@ports) {
        if ( $_ eq 443 ) {
            my $sslconnect = IO::Socket::SSL->new("$target:https");
            if ( defined($sslconnect) ) {
                print "Open port $_/tcp\n"
                    if ( $options{verbose} > 0 );
                $open_ports += 1;
                if ( $options{banner} > 0 ) {
                    print $sslconnect "GET / HTTP/1.0\r\n\r\n";
                    print <$sslconnect>;
                }
                close $sslconnect;
            }
        }
        else {
            my $connect = IO::Socket::INET->new(
                Proto    => "tcp",
                PeerAddr => $target,
                PeerPort => $_,
                Timeout  => .60,
                Type     => SOCK_STREAM,
            );
            if ( defined($connect) ) {
                print "Open port $_/tcp\n"
                    if ( $options{verbose} > 0 );
                $open_ports += 1;
                if ( $options{banner} > 0 ) {
                    $connect->send("GET \r\n\r\n");
                    print <$connect>;
                    close $connect;

                }
            }
        }
    }
}

if ( @ARGV == 0 ) {
    help;
    exit;
}

GetOptions(
    \%options,
    'scan|s=s', 'ports|p=s', 'iplist|i=s',
    'banner|b' => sub { $options{banner} = 1; },
    'help|h' => sub { help(); },
    'version|v' => sub { print_version(); },
    'verbose|V' => sub { $options{verbose} = 1; },
    )
    or exit 1;
if ( $options{'scan'} and $options{'iplist'} ) {
    help;
    exit;
}
if ( $options{'iplist'} ) {
    if ( -e $options{'iplist'} ) {
        if ( -r $options{'iplist'} ) {
            my $fh = new FileHandle("<$options{'iplist'}");
            die "$options{'iplist'}:$!" unless defined $fh;
            @targets = $fh->getlines();
            chomp @targets;
        }
        else {
            print "File $options{'iplist'} isn't readable\n";
            exit 1;
        }
    }
    else {
        print "File $options{'iplist'} doesn't exist\n";
        exit 1;
    }

}

if ( $options{'scan'} ) {
    my $ipRange;
    if ( $options{'scan'} =~ /[a-zA-Z]/ ) {
        my $name = $options{'scan'};
        my ( $host, @addresses, $hent, $addr_ref );
        if ( $hent = gethostbyname($name) ) {
            $name      = $hent->name();                    # in case different
            $addr_ref  = $hent->addr_list();
            @addresses = map { inet_ntoa($_) } @$addr_ref;
        }
        $ipRange = $addresses[0];
        if ( !defined($ipRange) or $ipRange eq '' ) {
            die "Invalid Ip Address being Resolved\n";
        }
        print "resolved host is $ipRange\n" if ( $options{debug} > 0 );
        push( @targets, $ipRange );
    }
    else {
        if ( $options{'scan'} =~ m/(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/ ) {
            if ( $5 eq 24 ) {
                for ( 1 .. 255 ) {
                    my $tmp = "$1.$2.$3.$_";
                    push( @targets, $tmp );
                }
            }
        }
        elsif ( $options{'scan'} =~ m/(\d+)\.(\d+)\.(\d+)\.\*/ ) {
            for ( 1 .. 255 ) {
                my $tmp = "$1.$2.$3.$_";
                push( @targets, $tmp );
            }
        }
        else {
            my $tmp = $options{'scan'};
            push( @targets, $tmp );
        }
    }
}

if ( $options{'ports'} ) {
    my @tmp = split( ',', $options{'ports'} );
    foreach (@tmp) {
        if ( $_ =~ m/(\d+)\-(\d+)/ ) {
            for ( $1 .. $2 ) {
                push( @ports, $_ );
                $scan_ports += 1;
            }
        }
        else {
            push( @ports, $_ );
            $scan_ports += 1;
        }
    }
}

foreach (@targets) {
    $target     = $_;
    $open_ports = 0;
    print "Target is $target\n";
    if ( $options{debug} > 0 ) {
        print "ports are:\n";
        foreach (@ports) {
            print "$_\n";
        }
    }
    scan;
    if ( $open_ports eq 0 ) {
        print "Found $open_ports open ports while scanning $scan_ports\n";
    }
    print "-------------------------------------------\n";
}
exit;

