Nmap Announce mailing list archives

Perl module wrappers for nmap


From: "Max" <musitechman () earthlink net>
Date: Tue, 13 Nov 2001 05:58:59 -0500

Hi,

   Last year I expressed a wish that nmap would be made into a library
that could be accessed through perl via the C XS interface ... had a
few people that said they would like that but no one on the list
(including me) seemed to have the expertise needed to do it ... well ...
I don't (still) have time to learn XS :( .. but ...

I have made some perl class wrappers for nmap.  After doing these I saw on
the nmap web site that rain forest puppy has done some perl code to
wrap nmap but the site was down :( so I could not check it out ...

I will be submitting my module set to CPAN ... barring Fyodor saying
"no way" ...

Because I am not so hot at C but very good at perl, I went the "parse
nmap output into perl-land" route ... and have had fun and come up with
some classes that I think may ispire others to do something really
cool ...

For now I am just writing to announce that I have started this, list
the classes I have done and show a few examples of using them to get
some feedback.

Once I document my work I will submit it to CPAN if there is interest
(maybe even if there is no interest).

The modules/structure I have:

/Nmap/
/Nmap/Nmap/HostList.pm
/Nmap/Nmap/Host.pm
/Nmap/Nmap/PortList.pm
/Nmap/Nmap/Port.pm
/Nmap/Nmap/Util
/Nmap/Nmap/Util/BannerScanner.pm
/Nmap/Nmap/Util/FtpScanner.pm
/Nmap/Nmap/Util/OsGuesser.pm
/Nmap/Nmap/Util/PingScanner.pm
/Nmap/Nmap/Util/SmtpScanner.pm
/Nmap/Nmap/Util/WebScanner.pm
/Nmap/Nmap/Protocol.pm
/Nmap/Nmap/ProtocolList.pm
/Nmap/Nmap/Scanner.pm
/Nmap/Nmap/Util.pm
/Nmap/Nmap.pm

I have not implemented all of the options for nmap or made an attempt to
catch illegal options but I have enough of them for some interesting 
things ....

I have implemented the wrappers in two styles:
1)  Does the complete scan and instantiates objects/lists of objects
returned by the scan (hosts with ports, protocols etc) ... the other
is event driven via callbacks ...

A couple of examples ...

A simple protocol scanner ...

#!/usr/bin/perl

use Nmap;

use strict;

my $scanner = new Nmap::Scanner();

$scanner->nmap('/usr/local/bin/nmap');
$scanner->protocol_scan();
$scanner->add_target($ARGV[0] || 'localhost');
$scanner->register_scan_complete_event(\&scan_done);
$scanner->scan();

#  This will be called once after each host passed in
#  is scanned .. and passed an Nmap::Host reference.

sub scan_done {

    my $host = shift;

    print $host->name()," -- ";

    my $list = $host->getprotocollist();
    while (my $p = $list->getnext()) {
        print join(':',
            $p->number(),$p->name(),$p->state()
        ) . " ";
    }
    print "\n";

}

-- Another simplistic ident_scan scanner ...

#!/usr/bin/perl

use Nmap;
use strict;

my $scanner = new Nmap::Scanner();

$scanner->nmap('/usr/local/bin/nmap');
$scanner->tcp_connect_scan();
$scanner->ident_check();
$scanner->add_scan_port(80);
$scanner->add_scan_port(25);
$scanner->add_scan_port(161);
$scanner->add_scan_port(162);
$scanner->ackicmpping();
$scanner->add_target($ARGV[0] || 'euphrates');
$scanner->max_rtt_timeout(200);
$scanner->register_port_found_event(\&found_port);
$scanner->scan();

sub found_port {

    my $name = shift;
    my $ip   = shift;
    my $port = shift;

    next unless $port->owner();

    print "$name ($ip), port ",$port->number()," owned by ",
          $port->owner(),"\n";

}

-- And finally, a module that is more interesting as it combines 
   nmap with some nice high-level perl socket stuff!

package Nmap::Util::BannerScanner;

use IO::Socket;
use Nmap;

use strict;
use vars qw(@ISA);

@ISA = qw(Nmap::Scanner);

my $REGEX;
my $CALLBACK;
my $SEND;

sub new {
     my $class = shift;
     my $self = $class->SUPER::new();
     return bless $self, $class;
}

sub regex {
    $REGEX = $_[1] || return $REGEX;
}

sub send_on_connect {
    $SEND = $_[1] || return $SEND;
}

sub callback {
    $CALLBACK = $_[1] || return $CALLBACK;
}

sub scan {

    $_[0]->tcp_syn_scan();
    $_[0]->register_scan_complete_event(\&banner);
    $_[0]->SUPER::scan();

}

sub banner {
    my $host = shift;
    my $port = $host->getportlist->getnext();
    my $banner = get_banner($host, $port);
    &{$CALLBACK}($host->name(), $host->ip(), $banner);
}

sub get_banner {

    my $host = shift->ip();
    my $port = shift->number();

    my $server = "";
    local($_);

    my $sock = new IO::Socket::INET(
        PeerAddr => "$host:$port",
        Timeout  => 30
    );

    if (! $sock) {
        print "$host: can't connect: $!\n";
        return "";
    }

    if ($SEND) {
        $sock->print($SEND);
    }

    while (<$sock>) {
        if (/$REGEX/) {
            $server = $1;
            $server =~ s/\r\n//g;
            $sock->close();
            last;
        }
    }

    $sock->close();
    undef $sock;

    return $server;

}

1;

-- And an ftp subclass followed by an ftp scanner

package Nmap::Util::FtpScanner;

use Nmap::Util::BannerScanner;

use strict;
use vars qw(@ISA);

@ISA = qw(Nmap::Util::BannerScanner);

sub new {

    my $class = shift;
    my $self  = $class->SUPER::new();

    $self->regex('^\d+ (.*)$');
    $self->add_scan_port(21);
    $self->add_target($_[0] || die "Need target in constructor!\n");

    return bless $self, $class;
}

1;

--  and a simple ftp scanner script

#!/usr/bin/perl

use lib '/home/snmp/hosts';

use Nmap::Util;

my $ftp = new Nmap::Util::FtpScanner($ARGV[0] || 'localhost');
$ftp->callback(sub { print "$_[0] ($_[1]): $_[2]\n"; });
$ftp->scan();

I have been using the module wrappers at work and it seems to me to
really make nmap easy to use with perl :) ... ideas/comments?

Unless I hear a lot of groans that this is a waste I will continue
with my documenting and publish to CPAN ... and I will welcome input
and be happy to talk to anyone who might be interested in partnering
/contributing to development of this as my time is severly limited.

The big problem with doing things this way is, of course, that if
options change or the default output and messaging changes there
are several methods that will need to be re-written to support the
changes ... that and of course the overhead of having to open a
pipe to nmap in order to capture the output from it.

Regards,
Max

--------------------------------------------------
For help using this (nmap-hackers) mailing list, send a blank email to 
nmap-hackers-help () insecure org . List run by ezmlm-idx (www.ezmlm.org).


Current thread: