pbnj-2.04/0000700000175000017500000000000010526514067011304 5ustar jabrajabrapbnj-2.04/t/0000700000175000017500000000000010526513140011536 5ustar jabrajabrapbnj-2.04/t/mysql/0000700000175000017500000000000010523541540012705 5ustar jabrajabrapbnj-2.04/t/mysql/04change2-mysql.t0000700000175000017500000001531410523541540015717 0ustar jabrajabra#!/usr/bin/perl use strict; #use blib; use File::Spec; use Cwd; use DBI; use File::Copy; use Test::DatabaseRow; use Test::More tests => 29; my $test_file = 'change2.xml'; use vars qw($host $np $session $svc $os $FH); is(system("sudo ./scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); #my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); my $dsn = "DBI:mysql:database=pbnjdb;host=localhost;port=3306"; my $dbh = DBI->connect( $dsn, "root" ); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); #system("./04change3.t"); sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } pbnj-2.04/t/mysql/04change3-mysql.t0000700000175000017500000001742210523541540015722 0ustar jabrajabra#!/usr/bin/perl use strict; #use blib; use File::Spec; use Cwd; use DBI; use File::Copy; use Test::DatabaseRow; use Test::More tests => 50; my $test_file = 'change3.xml'; use vars qw($host $np $session $svc $os $FH); is(system("sudo ./scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); #my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); my $dsn = "DBI:mysql:database=pbnjdb;host=localhost;port=3306"; my $dbh = DBI->connect( $dsn, "root" ); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'down', banner => 'Postfix smtpd', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'down', banner => 'CUPS', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); #is(system("rm data.dbl"),0,"Removing Database"); sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } pbnj-2.04/t/mysql/04change-mysql.t0000700000175000017500000000772410523541540015643 0ustar jabrajabra#!/usr/bin/perl use strict; #use blib; use File::Spec; use Cwd; use DBI; use File::Copy; use Test::DatabaseRow; use Test::More tests => 22; my $test_file = 'change1.xml'; use vars qw($host $np $session $svc $os $FH); is(system("sudo ./scanpbnj -x t/$test_file > /dev/null "),0,"Scanpbnj input from $test_file"); #my $dbh = DBI->connect('dbi:mysql:dbname=pbnjdb',"root",""); my $dsn = "DBI:mysql:database=pbnjdb;host=localhost;port=3306"; my $dbh = DBI->connect( $dsn, "root" ,""); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); #system("./04change2.t"); sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } pbnj-2.04/t/postgres/0000700000175000017500000000000010523541545013413 5ustar jabrajabrapbnj-2.04/t/postgres/04change-pg.t0000700000175000017500000000770510523541545015611 0ustar jabrajabra#!/usr/bin/perl use strict; #use blib; use File::Spec; use Cwd; use DBI; use File::Copy; use Test::DatabaseRow; use Test::More tests => 22; my $test_file = 'change1.xml'; use vars qw($host $np $session $svc $os $FH); is(system("./scanpbnj -x t/$test_file"),0,"Scanpbnj input from $test_file"); #my $dbh = DBI->connect('dbi:mysql:dbname=pbnjdb',"root",""); my $dsn = "DBI:Pg:database=pbnjdb;host=localhost;port=5432"; my $dbh = DBI->connect( $dsn, "pbnjdb", "tmp" ); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); #system("./04change2.t"); sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } pbnj-2.04/t/postgres/04change2-pg.t0000700000175000017500000001532210523541545015665 0ustar jabrajabra#!/usr/bin/perl use strict; #use blib; use File::Spec; use Cwd; use DBI; use File::Copy; use Test::DatabaseRow; use Test::More tests => 29; my $test_file = 'change2.xml'; use vars qw($host $np $session $svc $os $FH); is(system("sudo ./scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); #my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); my $dsn = "DBI:Pg:database=pbnjdb;host=localhost;port=5432"; my $dbh = DBI->connect( $dsn, "pbnjdb", "tmp" ); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); #system("./04change3.t"); sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } pbnj-2.04/t/postgres/04change3-pg.t0000700000175000017500000001743010523541545015670 0ustar jabrajabra#!/usr/bin/perl use strict; #use blib; use File::Spec; use Cwd; use DBI; use File::Copy; use Test::DatabaseRow; use Test::More tests => 50; my $test_file = 'change3.xml'; use vars qw($host $np $session $svc $os $FH); is(system("sudo ./scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); #my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); my $dsn = "DBI:Pg:database=pbnjdb;host=localhost;port=5432"; my $dbh = DBI->connect( $dsn, "pbnjdb", "tmp" ); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'down', banner => 'Postfix smtpd', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'down', banner => 'CUPS', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); #is(system("rm data.dbl"),0,"Removing Database"); sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } pbnj-2.04/t/range4.xml0000700000175000017500000001500210523541530013442 0ustar jabrajabra
pbnj-2.04/t/sdump.csv0000700000175000017500000000103710523741025013411 0ustar jabrajabra1,ssh,up,22,tcp,4.2p1 Debian-7ubuntu3,OpenSSH,1148770973,Sat May 27 19:02:53 2006 1,smtp,up,25,tcp,unknown version,Postfix smtpd,1148770973,Sat May 27 19:02:53 2006 1,ipp,up,631,tcp,1.2,CUPS,1148770973,Sat May 27 19:02:53 2006 1,ssh,down,22,tcp,4.2p1 Debian-7ubuntu3,OpenSSH,1148771004,Sat May 27 19:03:24 2006 1,ssh,up,22,tcp,4.2p1 Debian-7ubuntu3,OpenSSH,1148774410,Sat May 27 20:00:10 2006 1,smtp,down,25,tcp,unknown version,Postfix smtpd,1148774410,Sat May 27 20:00:10 2006 1,ipp,down,631,tcp,1.2,CUPS,1148774410,Sat May 27 20:00:10 2006 pbnj-2.04/t/scanpbnj0000700000175000017500000017672310526513134013305 0ustar jabrajabra#!/usr/bin/perl # # Copyright (C) 2005-2006 Joshua D. Abraham (jabra@ccs.neu.edu) # # This program is released under the terms of the GNU General Public License # (GPL), which is distributed with this software in the file "COPYING". # The GPL specifies the terms under which users may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # ScanPBNJ - a program for running Nmap scans and storing the results in # a PBNJ 2.0 database. # use strict; use warnings; use Shell; use DBI; use Nmap::Parser; use Socket; use Net::hostent; use Sys::Hostname; use Getopt::Long; use FileHandle; use YAML; use File::Which; use Term::ANSIColor qw(:constants); use File::HomeDir; use POSIX; $Term::ANSIColor::AUTORESET = 1; use vars qw( $PROG ); ( $PROG = $0 ) =~ s/^.*[\/\\]//; # Truncate calling path from the prog name my $AUTH = 'Joshua D. Abraham'; # author my $VERSION = '2.04'; # version my $np = new Nmap::Parser; # parser object my $type = 'help'; # parse scan or file my @ipRange; # ip Address or ip range to scan my $iplist; # ip list file my $xmlFile; # xml file to parse my $Range = '1-1025'; # port range to scan my $args = "-vv -O -P0 "; # scan args my $scantype = "-sSV"; # default scantype my $cargs = 'no'; # user changed args my $outputdir = '.'; # output database directory my $nmapPath = which('nmap'); # nmap path my $interface = ""; # default interface to perform scan my %options; # getopts hash my $dbh; # database connection my $dbconfig = 'config.yaml'; # database config my $database; # database file my $db; # db backend my $hostname; # db host ip my $port; # db port my $user; # db username my $passwd; # db password my $datadb; # results from the config of the db my $dir = "."; # dir of the config for the db my $colors = 1; # print using colors my $diff = 'version'; $options{test} = 0; # testing flag $options{debug} = 0; # debug flag my $configdir; #chown() that reports errors sub safe_chown { my $uid = shift; my $gid = shift; my $file = shift; if ( chown( $uid, $gid, $file ) != 1 ) { error( 'Unable to change the owner of the file ' . $file . '.' . "\n\n" ); } } if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $colors = 0; require Win32; import Win32; Win32->import(qw(CSIDL_APPDATA)); my $dir = Win32::GetFolderPath( CSIDL_APPDATA() ); # 2.0 $configdir = $dir . "\\" . "pbnj-2.0"; if ( -e $configdir and -d $configdir ) { if ( $options{test} > 2 ) { print "$configdir exists\n"; } } else { mkdir $configdir; print "mkdir $configdir\n"; } if ( !-e $dbconfig ) { $dbconfig = "$configdir\\$dbconfig"; # check if the config exists in ~/.pbnj-2.0/config.yaml if ( !-e $dbconfig ) { open( CONFIG, ">$dbconfig" ); while () { if ( defined($_) ) { print CONFIG $_; } } close(CONFIG); print "$dbconfig generated\n"; } } } else { $configdir = File::HomeDir->my_home; my $tmpuser = $configdir; $configdir .= "/.pbnj-2.0"; $tmpuser =~ s/home//; $tmpuser =~ s/\///g; my $uid = getpwnam($tmpuser); my $gid = id("-g $tmpuser"); if ( !defined($gid) ) { error("gid not defined\n"); } if ( !defined($uid) ) { error("uid not defined\n"); } if ( -e $configdir and -d $configdir ) { if ( $options{test} > 2 ) { print "$configdir exists\n"; } } else { umask 077; mkdir $configdir; print "mkdir $configdir\n"; safe_chown( $uid, $gid, $configdir ); } # check if config exists in the current directory if ( !-e $dbconfig ) { $dbconfig = "$configdir/$dbconfig"; # check if the config exists in ~/.pbnj-2.0/config.yaml if ( !-e $dbconfig ) { umask 077; open( CONFIG, ">$dbconfig" ); while () { if ( defined($_) ) { print CONFIG $_; } } close(CONFIG); safe_chown( $uid, $gid, $dbconfig ); print "$dbconfig generated\n"; } } } ############################################################################## # # createMachinesTable: scalar -> scalar # creates the table for machines in the database # mid INTEGER PRIMARY KEY, # ############################################################################## sub createMachinesTable { my $dbh = shift; my $auto_increment = "AUTO_INCREMENT"; my $mid_type; if ( $db eq "SQLite" ) { $auto_increment = "AUTOINCREMENT"; $mid_type = "INTEGER PRIMARY KEY $auto_increment"; } elsif ( $db eq "mysql" or $db eq "CSV" ) { $mid_type = "INTEGER PRIMARY KEY"; } elsif ( $db eq "Pg" ) { $mid_type = "SERIAL PRIMARY KEY"; } else { print "db not supported\n"; exit 1; } eval { $dbh->do( "CREATE TABLE machines ( mid $mid_type, ip TEXT, host TEXT, localh INTEGER, os TEXT, machine_created TEXT, created_on TEXT)" ); }; if ($@) { return 0; } return 1; } ############################################################################## # # createService: scalar -> scalar # creates the table for services in the database # ############################################################################## sub createServicesTable { my $dbh = shift; #sid INTEGER PRIMARY KEY, eval { $dbh->do( "CREATE TABLE services ( mid INTEGER, service TEXT, state TEXT, port INTEGER, protocol TEXT, version TEXT, banner TEXT, machine_updated TEXT, updated_on TEXT)" ); }; if ($@) { return 0; } return 1; } ############################################################################## # # insertService: anoy hash -> scalar # inserts information about a service into the database # ############################################################################## sub insertService { my ($href) = @_; die "insertService: mid not defined" unless defined $href->{mid}; die "insertService: service not defined" unless defined $href->{service}; die "insertService: state not defined" unless defined $href->{state}; die "insertService: port not defined" unless defined $href->{port}; die "insertService: proto not defined" unless defined $href->{proto}; die "insertService: ver not defined" unless defined $href->{ver}; die "insertService: banner not defined" unless defined $href->{banner}; die "insertService: updated not defined" unless defined $href->{updated}; die "insertService: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $service = $href->{service}; my $state = $href->{state}; my $port = $href->{port}; my $proto = $href->{proto}; my $ver = $href->{ver}; my $banner = $href->{banner}; my $updated = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $insert = $dbh->prepare('INSERT INTO services VALUES (?,?,?,?,?,?,?,?,?)'); my $success = 1; $success &&= $insert->execute( $mid, $service, $state, $port, $proto, $ver, $banner, $machine_updated, $updated ); return $success; } ############################################################################## # # setLocal: anoy hash -> scalar # set the localhost bit # ############################################################################## sub setLocal { my ($href) = @_; die "setLocal: ip not defined" unless defined $href->{ip}; die "setLocal: hostname not defined" unless defined $href->{hostname}; my $ip = $href->{ip}; my $hostname = $href->{hostname}; my $localh = 0; if ( $hostname =~ m/localhost/ and $ip eq "127.0.0.1" ) { if ( $options{test} > 0 or $options{debug} > 1 ) { print "localhost scan\n"; } $localh = 1; } return $localh; } ############################################################################## # # insertMachine: anoy hash -> scalar # inserts information about a machine into the database # ############################################################################## sub insertMachine { my ($href) = @_; die "insertMachine: ip not defined" unless defined $href->{ip}; die "insertMachine: host not defined" unless defined $href->{host}; die "insertMachine: localh not defined" unless defined $href->{localh}; die "insertMachine: os not defined" unless defined $href->{os}; die "insertMachine: created not defined" unless defined $href->{created}; die "insertMachine: machine_created not defined" unless defined $href->{machine_created}; my $ip = $href->{ip}; my $host = $href->{host}; my $localh = $href->{localh}; my $os = $href->{os}; my $created = $href->{created}; my $machine_created = $href->{machine_created}; if ( $db eq "CSV" ) { my $sth = $dbh->selectrow_hashref("select max('mid') from machines"); my $mid = $sth->{mid}; if ( !defined($mid) ) { $mid = 1; } else { $mid++; } my $insert = $dbh->prepare( 'INSERT INTO machines VALUES (?,?,?,?,?,?,?,?,?)'); my $success = 1; $success &&= $insert->execute( $mid, $ip, $host, $localh, $os, $machine_created, $created ); return $mid; } else { $dbh->do( "INSERT INTO machines (ip, host, localh, os, machine_created, created_on) VALUES ( '$ip', '$host', '$localh', '$os', '$machine_created', '$created' ) " ); } my $sth = $dbh->selectrow_hashref( "SELECT mid from machines WHERE ip='$ip' AND host='$host' AND localh='$localh' AND os='$os' AND machine_created='$machine_created' AND created_on='$created'" ); return $sth->{'mid'}; } ############################################################################## # # flushTables: -> # flush the machines and services tables # ############################################################################## sub flushTables { print "flushing tables\n"; $dbh->do("DROP TABLE machines"); $dbh->do("DROP TABLE services"); } ############################################################################## # # addHost: anoy hash -> scalar # insert a host only if it is uniq # ############################################################################## sub addHost { my ($href) = @_; die "addHost: os not defined" unless defined $href->{os}; die "addHost: session not defined" unless defined $href->{session}; die "addHost: host not defined" unless defined $href->{host}; my $os = $href->{os}; my $session = $href->{session}; #a Nmap::Parser::Session object my $host = $href->{host}; my $mid; my $ip = $host->addr; my $machine_created = $session->finish_time(); my $human_time = localtime($machine_created); my $uniqhost = 0; my $hostname = $host->hostname; my $localh = setLocal( { ip => $ip, hostname => $host->hostname } ); my $uniq = $dbh->selectall_arrayref( "select mid from machines WHERE ip='$ip' AND os='$os' AND host='$hostname' AND localh='$localh'" ); if ( $options{test} > 1 ) { print "uniq is $uniq\n"; } foreach my $uniqtmp (@$uniq) { my ($midtmp) = @$uniqtmp; $uniqhost = 1; $mid = $midtmp; if ( $options{test} > 0 or $options{debug} > 1 ) { print "non unique host\n"; print "mid shift is $mid\n"; } } if ( $uniqhost eq 0 ) { if ( $colors eq 1 ) { print BOLD GREEN "Inserting Machine\n"; } else { print "Inserting Machine\n"; } $mid = insertMachine( { ip => $ip, host => $hostname, localh => $localh, os => $os, created => $human_time, machine_created => $machine_created } ); if ( $options{test} > 0 or $options{debug} > 1 ) { ; print "mid is $mid\n"; } } else { print "Machine is already in the database\n"; print "Checking Current Services\n"; } return ( $mid, $uniqhost ); } ############################################################################## # # insertServiceDB: anoy hash -> # take information about a services from the database and insert it as # as being down # ############################################################################## sub insertServiceDB { my ($href) = @_; die "insertServiceDB: mid not defined" unless defined $href->{mid}; die "insertServiceDB: port not defined" unless defined $href->{port}; die "insertServiceDB: state not defined" unless defined $href->{state}; die "insertServiceDB: proto not defined" unless defined $href->{proto}; die "insertSerciceDB: updated not defined" unless defined $href->{updated}; die "insertSerciceDB: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $port = $href->{port}; my $state = $href->{state}; my $proto = $href->{proto}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $uniq_service = $dbh->selectall_arrayref( "SELECT service,version,protocol,banner FROM services WHERE mid='$mid' AND port='$port' AND protocol='$proto' AND state='up' ORDER BY machine_updated DESC" ); my ( $version, $service, $banner, $uniqservice ); foreach my $uniqtmp (@$uniq_service) { ( $service, $version, $proto, $banner ) = @$uniqtmp; #print "service is $service\n"; } if ( $colors eq 1 ) { print BOLD RED "\t! Service $port:$proto $service is down\n"; } else { print "\t! Service $port:$proto $service is down\n"; } insertService( { mid => $mid, service => $service, port => $port, proto => $proto, ver => $version, state => $state, banner => $banner, updated => $human_time, machine_updated => $machine_updated } ); } ############################################################################## # # insertServiceScan: anoy hash -> # take information about a services from the scan and insert it as # as being up # ############################################################################## sub insertServiceScan { my ($href) = @_; die "insertServiceScan: host not defined" unless defined $href->{host}; die "insertServiceScan: mid not defined" unless defined $href->{mid}; die "insertServiceScan: port not defined" unless defined $href->{port}; die "insertServiceScan: state not defined" unless defined $href->{state}; die "insertServiceScan: proto not defined" unless defined $href->{proto}; die "insertServiceScan: change not defined" unless defined $href->{change}; die "insertSerciceScan: updated not defined" unless defined $href->{updated}; die "insertSerciceScan: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $mid = $href->{mid}; my $port = $href->{port}; my $state = $href->{state}; my $proto = $href->{proto}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $change = $href->{change}; my $service; if ( $proto eq "tcp" ) { $service = $host->tcp_service($port); } else { $service = $host->udp_service($port); } my $name = "unknown name"; my $product = "unknown product"; my $version = "unknown version"; if ( defined( $service->name ) ) { $name = $service->name; } if ( defined( $service->version ) ) { $version = $service->version; } if ( defined( $service->product ) ) { $product = $service->product; } if ( $change == 1 ) { if ( $colors == 1 ) { print BOLD GREEN "\tInserting Service on $port:$proto $name\n"; } else { print "\tInserting Service on $port:$proto $name\n"; } } insertService( { mid => $mid, service => $name, port => $port, proto => $proto, ver => $version, state => $state, banner => $product, updated => $human_time, machine_updated => $machine_updated } ); } ############################################################################## # # cmpService: anoy hash -> scalar # compare the service in the database and the service from the scan. # Note: # If the service is up the database & is not in the scan then the state is down. # If the service is not in the database & is in the scan then the state is up. # ############################################################################## sub cmpService { my ($href) = @_; die "cmpService: host not defined" unless defined $href->{host}; die "cmpService: mid not defined" unless defined $href->{mid}; die "cmpService: port not defined" unless defined $href->{port}; die "cmpService: state not defined" unless defined $href->{state}; die "cmpService: proto not defined" unless defined $href->{proto}; die "cmpService: updated not defined" unless defined $href->{updated}; die "cmpService: machine_updated not defined" unless defined $href->{machine_updated}; die "cmpService: db_updated not defined" unless defined $href->{db_updated}; die "cmpService: db_machine_updated not defined" unless defined $href->{db_machine_updated}; my $host = $href->{host}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $state = $href->{state}; my $port = $href->{port}; my $proto = $href->{proto}; my $db_updated = $href->{db_updated}; my $db_machine_updated = $href->{db_machine_updated}; my $service; if ( $proto eq "tcp" ) { $service = $host->tcp_service($port); } elsif ( $proto eq "udp" ) { $service = $host->udp_service($port); } else { print "error in $proto\n"; exit 1; } my $banner_from_scan = "unknown product"; my $version_from_scan = "unknown version"; my $port_from_scan = $service->port; my $service_name_from_scan = "unknown service"; if ( defined( $service->name ) ) { $service_name_from_scan = $service->name; } if ( $options{test} eq 1 ) { print "service name from scan is $service_name_from_scan\n"; } if ( defined( $service->version ) ) { $version_from_scan = $service->version; if ( $options{test} > 2 ) { print "version from scan is $version_from_scan\n"; } } if ( defined( $service->product ) ) { $banner_from_scan = $service->product; if ( $options{test} > 2 ) { print "banner from scan is $banner_from_scan\n"; } } my ( $version_from_db, $service_name_from_db, $banner_from_db ); # note the version banner and service name are the only elements # of the service that we can comparing my $uniq_service = $dbh->selectall_arrayref( "SELECT service,version,banner FROM services WHERE mid='$mid' AND port='$port' AND state='$state' AND protocol='$proto' AND updated_on='$db_updated' AND machine_updated='$db_machine_updated'" ); foreach my $uniqtmp (@$uniq_service) { my ( $nametmp, $vertmp, $bantmp ) = @$uniqtmp; $service_name_from_db = $nametmp; $version_from_db = $vertmp; $banner_from_db = $bantmp; } if ( $options{test} > 1 ) { print "state is $state\n"; print "comparing service $service_name_from_db and $service_name_from_scan\n"; print "comparing version $version_from_db and $version_from_scan\n"; print "comparing banner $banner_from_db and $banner_from_scan\n"; } if ( $diff eq "banner" && $version_from_db eq $version_from_scan && $banner_from_db eq $banner_from_scan && $service_name_from_db eq $service_name_from_scan ) { print "\t= $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; return 1; } elsif ($diff ne "banner" && $version_from_db eq $version_from_scan && $service_name_from_db eq $service_name_from_scan ) { print "\t= $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; return 1; } else { if ( $colors == 1 ) { print BOLD YELLOW "\t! $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; } else { print "\t! $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; } if ( $service_name_from_db ne $service_name_from_scan ) { if ( $colors == 1 ) { print BOLD YELLOW " Service Name was \"$service_name_from_db\" changed to \"$service_name_from_scan\"\n"; } else { print " Service Name was \"$service_name_from_db\" changed to \"$service_name_from_scan\"\n"; } } elsif ( $version_from_db ne $version_from_scan ) { if ( $colors == 1 ) { print BOLD YELLOW " Version was \"$version_from_db\" changed to \"$version_from_scan\"\n"; } else { print " Version was \"$version_from_db\" changed to \"$version_from_scan\"\n"; } } elsif ( $diff eq 'banner' and $banner_from_db ne $banner_from_scan ) { if ( $colors == 1 ) { print BOLD YELLOW " Banner was \"$banner_from_db\" changed to \"$banner_from_scan\"\n"; } else { print " Banner was \"$banner_from_db\" changed to \"$banner_from_scan\"\n"; } } else { print "version or banner difference\n"; } # set time to earlier so insert works after old verison is down $machine_updated = scalar($machine_updated); $machine_updated -= 1; insertService( { mid => $mid, service => $service_name_from_db, port => $port, proto => $proto, ver => $version_from_db, state => 'down', banner => $banner_from_db, updated => $human_time, machine_updated => $machine_updated, } ); return 0; } return 1; } ############################################################################## # # setAndInsertService: anoy hash -> scalar # store all the services in the scan into the database # ############################################################################## sub setAndInsertService { my ($href) = @_; die "setAndInsertService: mid not defined" unless defined $href->{mid}; die "setAndInsertService: proto not defined" unless defined $href->{proto}; die "setAndInsertService: service not defined" unless defined $href->{service}; die "setAndInsertService: updated not defined" unless defined $href->{updated}; die "setAndInsertService: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $service = $href->{service}; my $proto = $href->{proto}; my $state = 'up'; my $product_from_scan = "unknown product"; my $version_from_scan = "unknown version"; my $port_from_scan = $service->port; my $name_from_scan = "unknown service"; if ( defined( $service->name ) ) { $name_from_scan = $service->name; } if ( defined( $service->version ) ) { $version_from_scan = $service->version; } if ( defined( $service->product ) ) { $product_from_scan = $service->product; } print "Inserting Service on $port_from_scan:$proto $name_from_scan\n"; insertService( { mid => $mid, service => $name_from_scan, port => $port_from_scan, proto => $proto, ver => $version_from_scan, state => $state, banner => $product_from_scan, updated => $human_time, machine_updated => $machine_updated } ); } ############################################################################## # # storeEverything: anoy hash -> scalar # store all the services in the scan into the database # ############################################################################## sub storeEverything { my ($href) = @_; die "storeEverything: host not defined" unless defined $href->{host}; die "storeEverything: mid not defined" unless defined $href->{mid}; die "storeEverything: updated not defined" unless defined $href->{updated}; die "storeEverything: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $state; # $port is up in the database # store all the services running on tcp ports foreach ( $host->tcp_ports('open') ) { my $state = $host->tcp_port_state($_); if ( $options{test} eq 1 ) { print "state is $state on port $_\n"; } next if ( $state ne "open" ); my $service = $host->tcp_service($_); next if ( !defined($service) ); #my $uniqservice = 1; setAndInsertService( { proto => 'tcp', service => $service, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); } # store all the services running on tcp ports foreach ( $host->udp_ports('open') ) { my $state = $host->udp_port_state($_); if ( $options{test} eq 1 ) { print "in udp loop\n"; print "state is $state on port $_\n"; } next if ( $state ne "open" ); my $service = $host->udp_service($_); next if ( !defined($service) ); setAndInsertService( { proto => 'udp', service => $service, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); } return 0; } ############################################################################## # # sortDB: anoy hash -> hash # sort the database based on the time # ############################################################################## sub sortDB { my ($href) = @_; die "sortDB: mid not defined" unless defined $href->{mid}; die "sortDB: updated not defined" unless defined $href->{updated}; die "sortDB: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my ( $port, $service, $banner, $state, $state_db ); # determines all ports that are in the database and not in the scan # thus we assume these services went down # may 30 added limit 1 my ( %port_db, %seen_ports, $scan_state, $scan_proto ); my $ports_db_ref = $dbh->selectall_arrayref( "SELECT port,state,protocol,machine_updated,updated_on FROM services WHERE mid='$mid' ORDER BY machine_updated DESC " ); foreach my $key (@$ports_db_ref) { my ( $port, $state, $proto, $machine_updated, $updated ) = @$key; if ( !$port_db{$port}{machine_updated} ) { $port_db{$port}{machine_updated} = $machine_updated; $port_db{$port}{updated} = $updated; $port_db{$port}{port} = $port; $port_db{$port}{state} = $state; $port_db{$port}{proto} = $proto; } else { #print "not less than and exists\n"; } } return %port_db; } ############################################################################## # # setDown: anoy hash -> # remove all services on a given protocol as the host has no ports on # this protocol. # ############################################################################## sub setDown { my ($href) = @_; die "setDown: mid not defined" unless defined $href->{mid}; die "setDown: host not defined" unless defined $href->{host}; die "setDown: proto not defined" unless defined $href->{proto}; die "setDown: portdb not defined" unless defined $href->{portdb}; die "setDown: updated not defined" unless defined $href->{updated}; die "setDown: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $mid = $href->{mid}; my $proto = $href->{proto}; my $db_ref = $href->{portdb}; my %portdb = %{$db_ref}; if ( $options{test} > 0 ) { print "protocol is $proto\n"; } my ( $scan_state, %seen_ports ); foreach my $port ( sort { $a cmp $b } keys %portdb ) { #print "key is $port\n"; if ( $options{test} eq 1 ) { print $portdb{$port}{state} . " and $port\n"; print "port db $port proto $proto\n"; } $scan_state = "down"; if ( $options{test} eq 1 ) { print "scan thinks the status of $port is $scan_state\n"; print "state is " . $portdb{$port}{state} . "\n"; } if ( $scan_state eq "down" && $portdb{$port}{'state'} eq "up" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { insertServiceDB( { mid => $mid, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated } ); if ( $options{test} eq 1 ) { print "pulling data about service from database\n"; } } } } ############################################################################## # # cmpAndInsert: anoy hash -> # add service changes to the database # ############################################################################## sub cmpAndInsert { my ($href) = @_; die "cmpAndInsert: mid not defined" unless defined $href->{mid}; die "cmpAndInsert: host not defined" unless defined $href->{host}; die "cmpAndInsert: proto not defined" unless defined $href->{proto}; die "cmpAndInsert: portdb not defined" unless defined $href->{portdb}; die "cmpAndInsert: updated not defined" unless defined $href->{updated}; die "cmpAndInsert: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $mid = $href->{mid}; my $proto = $href->{proto}; my $db_ref = $href->{portdb}; my %portdb = %{$db_ref}; if ( $options{test} eq 1 or $options{debug} eq 1 ) { print "protocol is $proto\n"; } my ( $scan_state, %seen_ports ); foreach my $port ( sort { $a cmp $b } keys %portdb ) { if ( $options{test} eq 1 ) { print $portdb{$port}{state} . " and $port\n"; print "port db $port proto $proto\n"; } my $tmp; if ( $proto eq "tcp" ) { $tmp = $host->tcp_port_state($port); } elsif ( $proto eq "udp" ) { $tmp = $host->udp_port_state($port); } else { next; } $seen_ports{$port} = "up"; if ($tmp) { $scan_state = "up"; } else { $scan_state = "down"; } if ( $options{test} eq 1 ) { print "scan thinks the status of $port is $scan_state\n"; print "state is " . $portdb{$port}{state} . "\n"; } if ( $portdb{$port}{state} eq "up" && $scan_state eq "up" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { if ( $options{test} eq 1 ) { print "states are both up\n"; print "checking versions and banners\n"; } my $db_updated = $portdb{$port}{updated}; my $db_machine_updated = $portdb{$port}{machine_updated}; my $cmp = cmpService( { mid => $mid, host => $host, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated, db_updated => $db_updated, db_machine_updated => $db_machine_updated, } ); if ( $cmp eq 0 ) { if ( $options{test} > 1 ) { print "port is $port\n"; print "mark 1\n"; } insertServiceScan( { mid => $mid, host => $host, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => $cmp, } ); } else { if ( $options{test} eq 1 ) { print "no difference in name or version or banner\n"; } } } else { #print "scan state is $scan_state\n"; #print "database state is $port_db{$port}{'state'}\n"; if ( $scan_state eq "down" && $portdb{$port}{'state'} eq "up" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { insertServiceDB( { mid => $mid, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated } ); if ( $options{test} eq 1 ) { print "pulling data about service from database\n"; } } elsif ($scan_state eq "up" && $portdb{$port}{'state'} eq "down" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { if ( $options{test} > 1 ) { print "port is $port\n"; print "mark 2\n"; } insertServiceScan( { host => $host, mid => $mid, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => 1, } ); if ( $options{test} eq 1 ) { print "pulling data about service from scan\n"; } } else { if ( $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { if ( $options{test} eq 1 ) { print "states are both down\n"; } } else { if ( $options{test} > 1 ) { print "protocols are different\n"; } } } } chomp( $portdb{$port}{updated} ); #print "\n$port_db{$port}{port} keys is $port\n"; #print "\n$port_db{$port}{state} keys is $port\n"; #print "\n$port_db{$port}{updated} keys is $port\n"; } # bug for seen ports on different protocols if ( $proto eq "tcp" ) { # handles ports that are open in the scan and don't exist in the database foreach ( $host->tcp_ports('open') ) { my $tmptest = $host->tcp_port_state($_); if ( $options{test} eq 1 ) { print "state is $tmptest\n"; } next if ( $tmptest ne "open" ); my $port_tmp = $_; my $state_tmp; if ( $seen_ports{$port_tmp} && $seen_ports{$port_tmp} eq "up" ) { if ( $options{test} eq 1 ) { print "Port is already up\n"; } } else { $state_tmp = "up"; if ( $options{test} > 1 ) { print "inserting scan not in the database on $port_tmp\n"; print "mark 3\n"; } insertServiceScan( { host => $host, mid => $mid, port => $port_tmp, proto => $proto, state => $state_tmp, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => 1, } ); } } } else { # handles ports that are open in the scan and don't exist in the database foreach ( $host->udp_ports('open') ) { my $tmptest = $host->udp_port_state($_); if ( $options{test} eq 1 ) { print "state is $tmptest\n"; } next if ( $tmptest ne "open" ); my $port_tmp = $_; my $state_tmp; if ( $seen_ports{$port_tmp} && $seen_ports{$port_tmp} eq "up" ) { if ( $options{test} eq 1 ) { print "Port is already up\n"; } } else { $state_tmp = "up"; if ( $options{test} > 1 ) { print "inserting scan not in the database on $port_tmp\n"; print "mark 4\n"; } insertServiceScan( { host => $host, mid => $mid, port => $port_tmp, state => $state_tmp, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => 0, } ); } } } } ############################################################################## # # addServices: anoy hash -> # add service changes to the database # ############################################################################## sub addServices { my ($href) = @_; die "addServices: mid not defined" unless defined $href->{mid}; die "addServices: host not defined" unless defined $href->{host}; die "addServices: updated not defined" unless defined $href->{updated}; die "addServices: uniq not defined" unless defined $href->{uniq}; die "addServices: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $mid = $href->{mid}; my $uniq = $href->{uniq}; my ( $port, $service, $banner, $state, $state_db ); my %port_db = sortDB( { host => $host, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); # determines all ports that are in the database and not in the scan # thus we assume these services went down if ( $uniq eq 0 ) { if ( $options{test} > 0 ) { print "store everything from the scan\n"; } storeEverything( { host => $host, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); return 0; } my @tcp_ports = $host->tcp_open_ports(); my @udp_ports = $host->udp_open_ports(); if ( !defined( scalar(@tcp_ports) ) ) { if ( $options{debug} > 0 or $options{test} eq 1 ) { print "no TCP ports found\n"; } setDown( { mid => $mid, host => $host, proto => "tcp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } else { cmpAndInsert( { mid => $mid, host => $host, proto => "tcp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } if ( !defined( scalar(@udp_ports) ) ) { if ( $options{debug} > 0 or $options{test} eq 1 ) { print "no UDP ports found\n"; } setDown( { mid => $mid, host => $host, proto => "udp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } else { cmpAndInsert( { mid => $mid, host => $host, proto => "udp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } } ############################################################################## # # storeData: scalar -> # function to perform scans and insert hosts and services as needed # ############################################################################## sub storeData { my $mTable = createMachinesTable($dbh); if ( $mTable eq 0 ) { print "creating Machines Table\n"; } my $sTable = createServicesTable($dbh); if ( $sTable eq 0 ) { print "creating Services Table\n"; } my $created_on = $np->get_session()->finish_time(); my $human_time = localtime($created_on); for my $host ( $np->all_hosts() ) { my $os = $host->os_sig(); my $os_scan; if ( defined($os) and defined( $os->osfamily ) and defined( $os->osgen ) ) { $os_scan = $os->osfamily . " " . $os->osgen; } else { $os_scan = "unknown os"; } if ( !defined($os_scan) or $os_scan eq "" ) { $os_scan = "unknown os"; } print "\n--------------------------------------\n"; print "Starting Scan of " . $host->addr . "\n"; my ( $mid, $uniq ) = addHost( { os => $os_scan, session => $np->get_session(), host => $host, created_on => $human_time, machine_created => $created_on } ); addServices( { mid => $mid, host => $host, updated => $human_time, machine_updated => $created_on, uniq => $uniq, } ); print "Scan Complete for " . $host->addr . "\n"; print "--------------------------------------\n"; } print "\n"; } ############################################################################## # # verify_windows: array ref -> # verify that the windows machine isn't trying to scanning itself # side effect: calls verify_scan and possibly quits # ############################################################################## sub verify_windows { my $range = shift; foreach (@$range) { if ( $_ =~ m/127\.0\.0\.1/ ) { print "Error: Win32 machines can't scan themselves.\n"; exit 1; } } verify_scan(); } ############################################################################## # # verify_ip: anoy hash -> scalar # determine if ip is in acceptable range # ############################################################################## sub verify_ip { my ($href) = @_; die "verify_ip: oct1 not defined" unless defined $href->{oct1}; die "verify_ip: oct2 not defined" unless defined $href->{oct2}; die "verify_ip: oct3 not defined" unless defined $href->{oct3}; die "verify_ip: oct4 not defined" unless defined $href->{oct4}; my $oct1 = $href->{oct1}; my $oct2 = $href->{oct2}; my $oct3 = $href->{oct3}; my $oct4 = $href->{oct4}; if ( $oct1 < 255 and $oct1 > 0 ) { if ( ( $oct2 eq "*" or $oct2 eq "\* " ) or ( $oct2 == 0 ) or ( $oct2 < 256 and $oct2 > 0 ) ) { if ( ( $oct3 eq "*" or $oct3 eq "\*" ) or ( $oct3 == 0 ) or ( $oct3 < 256 and $oct3 > 0 ) ) { if ( ( $oct4 eq "*" or $oct4 eq "\*" ) or ( $oct4 =~ /0\/\d{1,2}/ ) or ( $oct4 < 256 and $oct4 > 0 ) ) { return 1; } else { print "fourth is $4\n" if ( $options{test} > 2 ); } } else { print "third is $3\n" if ( $options{test} > 2 ); } } else { print "second is $2\n" if ( $options{test} > 3 ); } } return 0; } ############################################################################## # # verify_scan # verifies that the nmap path is set # side effect: quits if the nmap path is not set # ############################################################################## sub verify_scan { if ( !defined($nmapPath) or $nmapPath eq "" ) { print "Error: Nmap was not found in your path.\n"; print "Please download the latest version from\n"; print "http://www.insecure.org/nmap/download.html\n"; exit 1; } } ############################################################################## # # help -> # display help information # side effect: exits program # ############################################################################## sub help { print "Usage: $PROG [Options] {target specification} Target Specification: Can pass hostnames, IP addresses, networks, etc. Ex: microsoft.com, 192.168.0.1, 192.168.1.1/24, 10.0.0.1-254 -i --iplist Scan using a list of IPs from a file -x --xml Parse scan/info from Nmap XML file Scan Options: -a --args Execute Nmap with args (needs quotes) -e --extraargs Add args to the default args (needs quotes) --inter Perform Nmap Scan using non default interface -m --moreports Add ports to scan ex: 8080 or 3306,5900 -n --nmap Path to Nmap executable -p --pingscan Ping Target then scan the host(s) that are alive --udp Add UDP to the scan arguments --rpc Add RPC to the scan arguments -r --range Ports for scan [def 1-1025] --diffbanner Parse changes of the banner Config Options: -d --dbconfig Config for results database [def config.yaml] --configdir Directory for the database config file --data SQLite Database override [def data.dbl] --dir Directory for SQLite or CSV file [def . ] General Options: --nocolors Don't Print Colors --test Testing information --debug Debug information -v --version Display version -h --help Display this information Send Comments to Joshua D. Abraham ( jabra\@ccs.neu.edu )\n"; exit; } ############################################################################## # # print_version -> # displays version # side effect: exits program # ############################################################################## sub print_version { print "$PROG version $VERSION by $AUTH\n"; exit; } ############################################################################## if ( @ARGV == 0 ) { help; exit; } GetOptions( \%options, 'pingscan|p', 'scan|s', 'iplist|i=s', 'xml|x=s', 'range|r=s', 'moreports|m=s', 'nmap|n=s', 'dbconfig|d=s', 'dir=s', 'data=s', 'configdir=s', 'test=s', 'args|a=s', 'extraargs|e=s', 'udp', 'rpc', 'inter=s', 'diffbanner', 'help|h' => sub { help(); }, 'version|v' => sub { print_version(); }, 'nocolors' => sub { $colors = 0; }, 'fruitycolors' => sub { $colors = 2; }, 'debug=s', ) or exit 1; my $dephosts = ""; if ($options{'scan'}){ print "WARNING: --scan is deprecated\n"; print "Please use the following format: $PROG 127.0.0.1 \n"; $dephosts = $options{'scan'}; } if ( ( $options{'iplist'} or $options{'pingscan'} ) and $options{'xml'} ) { print "Invalid type of input\n"; exit 1; } if ( $options{'input'} and $options{'pingscan'} ) { print "Conflicting type of Scan\n"; } if ( $options{'dir'} ) { $dir = $options{'dir'}; } if ( $options{'configdir'} ) { $configdir = $options{'configdir'}; } if ( $options{'dbconfig'} ) { my $tmpconfig; if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $tmpconfig = $configdir . '\\' . $options{'dbconfig'}; } else { $tmpconfig = $configdir . "/" . $options{'dbconfig'}; } if ( -e $tmpconfig && -r $tmpconfig ) { $dbconfig = $tmpconfig; } } chdir($dir) or die "Couldn't change to $dir directory\n"; if ( !defined($dbconfig) or $dbconfig eq "" or ( !-e $dbconfig or !-r $dbconfig ) ) { print "Couldn't open $dbconfig for input\n"; exit; } if ( $options{'inter'} ) { $interface = "-e " . $options{'inter'} . " "; } if ( $options{'nmap'} ) { if ( -X $options{'nmap'} ) { $nmapPath = $options{'nmap'}; } else { print $options{'nmap'} . " isn't executable using $nmapPath\n"; } } if ( $options{'iplist'} ) { if ( -e $options{'iplist'} ) { if ( -r $options{'iplist'} ) { my $fh = new FileHandle("<$options{'iplist'}"); die "$options{'iplist'}:$!" unless defined $fh; @ipRange = $fh->getlines(); chomp @ipRange; $type = 'scan'; } else { print "File $options{'iplist'} isn't readable\n"; exit 1; } } else { print "File $options{'iplist'} doesn't exist\n"; exit 1; } } if ( $options{'xml'} ) { if ( -e $options{'xml'} ) { if ( -r $options{'xml'} ) { $xmlFile = $options{'xml'}; $type = 'file'; } else { print "Input File isn't readable\n"; exit 1; } } else { print "Input File doesn't exist\n"; exit 1; } } if ( $options{'udp'} ) { $scantype = $scantype . "U"; } if ( $options{'rpc'} ) { $scantype = $scantype . "R"; } if ( $options{'args'} ) { $args = ""; $scantype = ""; $args = $options{'args'}; $cargs = 'yes'; } if ( $options{'extraargs'} ) { $args = $args . $options{'extraargs'} . " "; } if ( $options{'dir'} ) { $outputdir = $options{'dir'}; } if ( $options{'range'} ) { my (@ports) = split ',', $options{'range'}; foreach (@ports) { chomp; if ( $_ !~ /\d/ ) { print "$_ not digit\n"; } } $Range = ""; for ( my $i = 0; $i < scalar(@ports); $i++ ) { $Range .= $ports[$i]; if ( $i < scalar(@ports) - 1 ) { $Range .= ","; } } } #@ports = @ports - 1; if ( $options{'moreports'} ) { my @morePorts = split ',', $options{'moreports'}; foreach (@morePorts) { if (/(\d+)/) { chomp; if ( $_ =~ /\d/ ) { $Range .= ",$_"; } else { print "MorePorts: Port $_ isn't between 1 and 65535\n"; exit 1; } } else { print "MorePorts: Port $_ isn't a number\n"; exit 1; } } } if ( $options{'diffbanner'} ) { $diff = "banner"; } my $tmp = scalar(@ARGV); my @targets; if ( $type ne 'file' ) { foreach (@ARGV) { s/\ //g; my @args = split(',', $_); foreach(@args){ push( @targets, $_ ); } } my @args = split(',', $dephosts); foreach(@args){ push( @targets, $_ ); } } foreach my $host (@targets) { if ($host) { my $ipRange; if ( $host =~ /[a-zA-Z]/ ) { my $name = $host; if ( $name eq 'localhost' ) { $ipRange = '127.0.0.1'; } else { 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 '' ) { print "Invalid Ip Address being Resolved\n"; exit 1; } } print "Resolved $host to $ipRange\n" if ( $options{debug} > 3 ); $type = 'scan'; push( @ipRange, $ipRange ); } elsif ( $host =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\-(\d{1,3}|\*|'*')/ ) { my $max; if ( $5 =~ m/\*/ ) { $max = 255; } elsif ( $5 < 256 ) { $max = $5; } else { print "IP Address not in proper range\n"; exit 1; } if ( $4 < $5 ) { for ( $4 .. $max ) { if (verify_ip( { oct1 => $1, oct2 => $2, oct3 => $3, oct4 => $_ } ) == 1 ) { my $ip = join( ".", $1, $2, $3, $_ ); push( @ipRange, $ip ); $type = 'scan'; } } } } elsif ( $host =~ /(\d{1,3})\.(\d{1,3}|\*)\.(\d{1,3}|\*)\.(0\/\d{1,2}|\d{1,3}|\*|'*')/ ) { if ( $options{test} > 3 ) { print "first is $1\n"; print "second is $2\n"; print "third is $3\n"; print "fourth is $4\n"; } my $valid = verify_ip( { oct1 => $1, oct2 => $2, oct3 => $3, oct4 => $4 } ); if ( $valid == 1 ) { $type = 'scan'; push( @ipRange, $host ); } } if ( !defined($host) ) { print "IP Address not in proper range\n"; exit 1; } } else { print "Invalid IP Address\n"; exit 1; print "scan is $host" if ( $options{debug} eq 1 ); } } if ( $options{'pingscan'} ) { if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $nmapPath = "\"$nmapPath\""; verify_windows( \@ipRange ); } else { verify_scan(); } $np->parsescan( $nmapPath, "-R -sP", @ipRange ); my $livehosts = ""; for my $host ( $np->get_ips('up') ) { if ( $livehosts eq "" ) { $livehosts = $host; } else { $livehosts = join( " ", $livehosts, $host ); } } if ( $livehosts eq "" ) { print "Scanned @ipRange\n"; print "No Hosts Responding to Ping Scan\n"; exit; } else { print "Live Hosts Found: $livehosts\n"; @ipRange = $livehosts; } } # make sure something is passed help() if ( $type ne 'file' and $type ne 'scan' ); if ( $type eq 'file' ) { $np->parsefile($xmlFile); } elsif ( $type eq 'scan' ) { $args = $args . $interface; if ( $cargs eq 'no' ) { $args = $args . $scantype . " -p $Range"; } if ( $options{debug} > 2 or $options{test} > 0 ) { print "nmap path is $nmapPath\n"; } if ( $args =~ /-o(?:X|N|G)/ ) { warn "$PROG Cannot pass option '-oX', '-oN' or '-oG'\n"; warn "Removing option\n"; $args =~ s/-o(?:X|N|G)//g; print "args is now $args\n"; } if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $nmapPath = "\"$nmapPath\""; verify_windows( \@ipRange ); } else { verify_scan(); if ( $> ne 0 ) { print "PBNJ Scans requires root privileges.\n"; exit 1; } } if ( $options{debug} > 0 or $options{test} > 0 ) { print "Scan Args are $args\n"; print "Scanning "; foreach (@ipRange) { print "- $_ "; } print "\n"; } $np->parsescan( $nmapPath, $args, @ipRange ); } else { print "type error $type\n"; exit 1; } # only connect to the database when we need too. if ( $type eq "scan" or $type eq "file" ) { if ( $options{data} ) { $db = "SQLite"; $database = $options{data}; } else { $datadb = YAML::LoadFile($dbconfig); foreach my $tmp ( keys %$datadb ) { $passwd = $$datadb{$tmp} if ( $tmp eq 'passwd' ); $user = $$datadb{$tmp} if ( $tmp eq 'user' ); $db = $$datadb{$tmp} if ( $tmp eq 'db' ); $database = $$datadb{$tmp} if ( $tmp eq 'database' ); $hostname = $$datadb{$tmp} if ( $tmp eq 'host' ); $port = $$datadb{$tmp} if ( $tmp eq 'port' ); } } # connection to database if ( $db eq 'SQLite' or $db eq 'CSV' ) { $dbh = DBI->connect( "dbi:$db:$database", $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1 } ) || die "Cannot connect: $DBI::errstr"; } elsif ( $db eq 'mysql' ) { my $dsn = "DBI:$db:database=$database;host=$hostname;port=$port"; $dbh = DBI->connect( $dsn, $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1 } ) || die "Cannot connect: $DBI::errstr"; } elsif ( $db eq 'Pg' ) { my $dsn = "DBI:$db:database=$database;host=$hostname;port=$port"; $dbh = DBI->connect( $dsn, $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1, PrintWarn => 0 } ) || die "Cannot connect: $DBI::errstr"; } else { print "$db isn't supported\n"; } } storeData($dbh); $dbh->disconnect; __DATA__ # Config.yaml # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # Configuration file for PBNJ 2.0 # YAML:1.0 # # Config for connecting to a DBI database # SQLite, mysql etc db: SQLite # for SQLite the name of the file. For mysql the name of the database database: data.dbl # Username for the database. For SQLite no username is needed. user: "" # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: "" # Port for the database. For SQLite no port is needed. port: "" pbnj-2.04/t/range.xml0000700000175000017500000001525310523541530013366 0ustar jabrajabra
pbnj-2.04/t/test1.xml0000700000175000017500000000536410523541530013334 0ustar jabrajabra
pbnj-2.04/t/nmap_results.xml0000700000175000017500000001565610523541530015015 0ustar jabrajabra
pbnj-2.04/t/02parser.t0000700000175000017500000002610610523541530013372 0ustar jabrajabra#!/usr/bin/perl use strict; use Nmap::Parser; use File::Spec; use Cwd; use Test::More tests => 141; use constant HOST1 => '127.0.0.1'; use constant HOST2 => '127.0.0.2'; use constant HOST3 => '127.0.0.3'; use constant HOST4 => '127.0.0.4'; my @UP_HOSTS = (HOST1, HOST3, HOST4); my @DOWN_HOSTS = (HOST2); use constant TOTAL_HOSTS => 4; use constant TEST_FILE =>'nmap_results.xml'; use vars qw($host $np $session $svc $os $FH); $FH = File::Spec->catfile(cwd(),'t',TEST_FILE); $FH = File::Spec->catfile(cwd(), TEST_FILE) unless(-e $FH); my $np = new Nmap::Parser; parser_test(); session_test(); host_1(); host_2(); host_3(); host_4(); sub parser_test { ok($np->parsefile($FH),"Parsing nmap data: $FH"); #TESTING GET_IPS() is_deeply([$np->get_ips()],[HOST1, HOST2, HOST3, HOST4], 'Testing get_ips for correct number of hosts'); is_deeply([$np->get_ips('up')],[HOST1,HOST3, HOST4], 'Testing get_ips for correct hosts with status = up'); is_deeply([$np->get_ips('down')],[HOST2], 'Testing get_ips for correct hosts for with status = down'); #TESTING IPV4_SORT my @hosts = (HOST3, HOST1, HOST4, HOST2); is_deeply([$np->ipv4_sort(@hosts)],[HOST1, HOST2, HOST3, HOST4], 'Testing ipv4_sort'); #TESTING ALL_HOSTS() my $total_hosts = 0; for my $h ($np->all_hosts()){ isa_ok($h, 'Nmap::Parser::Host'); isnt($h->status,undef,'Testing host object '.$h->addr.' in all_hosts()'); $total_hosts++; } is($total_hosts, TOTAL_HOSTS, "Testing correct number of hosts with all_hosts()"); #TESTING ALL_HOSTS(UP) my $total_uphosts = 0; for my $h ($np->all_hosts('up')){ isnt($h->addr,HOST2,'Testing host '.$h->addr.' in all_hosts(up)'); $total_uphosts++; } is($total_uphosts, scalar(@UP_HOSTS), "Testing correct number of UP hosts with all_hosts(up)"); #TESTING ALL_HOSTS(DOWN) my $total_downhosts = 0; for my $h ($np->all_hosts('down')){ is($h->addr,HOST2,'Testing host '.$h->addr.' in all_hosts(up)'); $total_downhosts++; } is($total_downhosts, scalar(@DOWN_HOSTS), "Testing correct number of DOWN hosts with all_hosts(down)"); } sub session_test { isa_ok($session = $np->get_session(), 'Nmap::Parser::Session'); is($session->numservices(),1023+1023,'Session: total number of services'); is($session->numservices('connect'),1023,'Session: numservices type = connect'); is($session->numservices('udp'),1023,'Session: numservices type = udp'); is($session->start_time(),1057088883,'Session: start_time'); is($session->start_str(),'Tue Jul 1 14:48:03 2003','Session: start_str'); is($session->finish_time(),1057088900,'Session: finish_time'); is($session->time_str(),'Tue Jul 1 14:48:20 2003','Session: time_str'); is($session->nmap_version(),'3.80','Session: nmap_version'); is($session->xml_version(),'1.01','Session: xml_version'); is($session->scan_args(),'nmap -v -v -v -oX test.xml -O -sTUR -p 1-1023 127.0.0.[1-4]','Session: scan_args'); is($session->scan_type_proto(),undef,'Session: scan_type_proto()'); is($session->scan_type_proto('connect'),'tcp','Session: scan_type_proto(connect)'); is($session->scan_type_proto('udp'),'udp','Session: scan_type_proto(udp)'); } sub host_1 { isa_ok($host = $np->get_host(HOST1), 'Nmap::Parser::Host','GET '.HOST1); is($host->status,'up','Host1: status'); is($host->addr,HOST1,'Host1: addr'); is($host->addrtype,'ipv4','Host1: addrtype'); is($host->ipv4_addr,HOST1,'Host1: ipv4_addr'); is($host->mac_addr,'00:09:5B:3F:7D:5E','Host1: mac_addr'); is($host->mac_vendor, 'Netgear','Host1: mac_vendor'); is($host->hostname,'host1','Host1: hostname()'); is($host->hostname(0),$host->hostname, 'Host1: hostname(0)'); is($host->hostname(1),'host1_2', 'Host1: hostname(1)'); is_deeply([$host->all_hostnames()],['host1','host1_2'],'Host1: all_hostnames'); is($host->extraports_state(),'closed','Host1: extraports_state'); is($host->extraports_count(),2038,'Host1: extraports_count'); is($host->tcp_port_count(),8,'Host1: tcp_port_count'); is($host->udp_port_count(),2,'Host1: udp_port_count'); is_deeply([$host->tcp_ports()],[qw(22 25 80 111 443 555 631 4903)],'Host1: tcp_ports()'); is_deeply([$host->tcp_ports('open')],[qw(80 111 443 555 631)],'Host1: tcp_ports(open)'); is_deeply([$host->tcp_ports('closed')], [qw(4903)],'Host1: tcp_ports(closed)'); is_deeply([$host->tcp_ports('filtered')], [qw(22 25 555)],'Host1: tcp_ports(filtered)'); is_deeply([$host->tcp_ports('open|filtered')],[qw(555)],'Host1: tcp_ports(open|filtered)'); is_deeply([$host->udp_ports()], [qw(111 937)],'Host1: udp_ports()'); is_deeply([$host->udp_ports('open')], [qw(111)],'Host1: udp_ports(open)'); is_deeply([$host->udp_ports('filtered')], [qw(937)],'Host1: udp_ports(filtered)'); is_deeply([$host->udp_ports('closed')], [qw()],'Host1: udp_ports(closed)'); is($host->tcp_ports('open'), $host->tcp_open_ports(), 'Host1: tcp_open_ports'); is($host->tcp_ports('filtered'),$host->tcp_filtered_ports(),'Host1: tcp_filtered_ports'); is($host->tcp_ports('closed'), $host->tcp_closed_ports(), 'Host1: tcp_closed_ports'); is($host->udp_ports('open'), $host->udp_open_ports(), 'Host1: udp_open_ports'); is($host->udp_ports('filtered'),$host->udp_filtered_ports(),'Host1: udp_filtered_ports'); is($host->udp_ports('closed'), $host->udp_closed_ports(), 'Host1: udp_closed_ports'); is($host->uptime_seconds(), '1973', 'Host1: uptime_seconds'); is($host->uptime_lastboot(),'Tue Jul 1 14:15:27 2003','Host1: uptime_lastboot'); is($host->tcpsequence_index(), 4336320, 'Host1: tcpsequence_index'); is($host->tcpsequence_class(),'random positive increments','Host1: tcpsequence_class'); is($host->tcpsequence_values(), 'B742FEAF,B673A3F0,B6B42D41,B6C710A1,B6F23FC4,B72FA3A8', 'Host1: tcpsequence_values'); is($host->ipidsequence_class(),'All zeros','Host1: ipidsequence_class'); is($host->ipidsequence_values(), '0,0,0,0,0,0', 'Host1: ipidsequence_values'); is($host->tcptssequence_class(),'100HZ','Host1: tcptssequence_class'); is($host->tcptssequence_values(), '30299,302A5,302B1,302BD,302C9,302D5', 'Host1: tcptssequence_values'); isa_ok($np->del_host(HOST1), 'Nmap::Parser::Host','DEL '.HOST1); is($np->get_host(HOST1),undef, 'Testing deletion of '.HOST1); #TESTING SERVICE OBJECT FOR HOST 1 my $svc; isa_ok($svc = $host->tcp_service(22),'Nmap::Parser::Host::Service','TCP port 22'); is($svc->name, 'ssh','Service: name'); is($svc->method, 'table','Service: method'); is($svc->confidence, 3, 'Service: confidence'); isa_ok($svc = $host->udp_service(111),'Nmap::Parser::Host::Service','UDP port 111'); is($svc->name, 'rpcbind','Service: name'); is($svc->proto, 'rpc','Service: proto'); is($svc->rpcnum, '100000','Service: rpcnum'); #TESTING OS OBJECT FOR HOST 1 my $os; isa_ok($os = $host->os_sig(),'Nmap::Parser::Host::OS','os_sig()'); } sub host_2 { isa_ok($host = $np->get_host(HOST2), 'Nmap::Parser::Host','GET '.HOST2); is($host->addr,HOST2, 'Host2: addr'); is($host->status,'down', 'Host2: status = down'); isa_ok($np->del_host(HOST2), 'Nmap::Parser::Host','DEL '.HOST2); is($np->get_host(HOST2),undef, 'Testing deletion of '.HOST2); } sub host_3 { isa_ok($host = $np->get_host(HOST3), 'Nmap::Parser::Host','GET '.HOST3); #TESTING SERVICE OBJECTS my $svc; isa_ok($svc = $host->tcp_service(22),'Nmap::Parser::Host::Service','tcp_service(22) for '.HOST3); is($svc->owner,'root', 'TCP Service: owner'); is($svc->name, 'ssh', 'TCP Service: name'); is($svc->product,'OpenSSH','TCP Service: product'); is($svc->version,'3.4p1','TCP Service: version'); is($svc->extrainfo,'protocol 1.99', 'TCP Service: extrainfo'); isa_ok($svc = $host->udp_service(80),'Nmap::Parser::Host::Service','udp_service(780) for '.HOST3); is($svc->owner,'www-data', 'UDP Service: owner'); is($svc->name, 'http', 'UDP Service: name'); is($svc->product,'Apache httpd','UDP Service: product'); is($svc->version,'1.3.26','UDP Service: version'); is($svc->extrainfo,'(Unix) Debian GNU/Linux', 'UDP Service: extrainfo'); isa_ok($svc = $host->tcp_service(500),'Nmap::Parser::Host::Service','TCP port 500'); isa_ok($np->del_host(HOST3), 'Nmap::Parser::Host','DEL '.HOST3); is($np->get_host(HOST3),undef, 'Testing deletion of '.HOST3); } sub host_4 { isa_ok($host = $np->get_host(HOST4), 'Nmap::Parser::Host','GET '.HOST4); my $os; #TESTING OS OBJECTS isa_ok($os = $host->os_sig, 'Nmap::Parser::Host::OS','os_sig for '.HOST4); is($os->portused_open,22,'OS: portused open'); is($os->portused_closed,1,'OS: portused closed'); is($os->name_count,2,'OS: name count'); is($os->name,'Linux Kernel 2.4.0 - 2.5.20','OS: name()'); is($os->name(0),$os->name,'OS: name(0)'); is($os->name(1),'Solaris 9','OS: name(1)'); is_deeply([$os->all_names],['Linux Kernel 2.4.0 - 2.5.20','Solaris 9'],'OS: all_names'); is($os->name_accuracy(),100,'OS: name_accuracy()'); is($os->name_accuracy(0),$os->name_accuracy(),'OS: name_accuracy(0)'); is($os->name_accuracy(1),99,'OS: name_accuracy(1)'); my $count = 11; is($os->class_count(),$count,'OS: class_count MAX = '.$count); is($os->osfamily(),'AOS','OS: osfamily()'); is($os->osfamily(0),$os->osfamily(),'OS: osfamily(0)'); is($os->osfamily($count),'Linux','OS: osfamily(MAX)'); is($os->osfamily(15),$os->osfamily($count),'OS: osfamily(15) = osfamily(MAX)'); is($os->vendor(),'Redback','OS: vendor()'); is($os->vendor(0),$os->vendor(),'OS: vendor(0)'); is($os->vendor($count),'Linux','OS: vendor(MAX)'); is($os->vendor(15),$os->vendor($count),'OS: vendor(15) = vendor(MAX)'); is($os->osgen(),undef,'OS: osgen()'); is($os->osgen(0),$os->osgen(),'OS: osgen(0)'); is($os->osgen($count),'2.4.x','OS: osgen(MAX)'); is($os->osgen(15),$os->osgen($count),'OS: osgen(15) = osgen(MAX)'); is($os->type(),'router','OS: type()'); is($os->type(0),$os->type(),'OS: type(0)'); is($os->type($count),'general purpose','OS: type(MAX)'); is($os->type(15),$os->type($count),'OS: type(15) = type(MAX)'); is($os->class_accuracy(),97,'OS: class_accuracy()'); is($os->class_accuracy(0),$os->class_accuracy(),'OS: class_accuracy(0)'); is($os->class_accuracy($count),50,'OS: class_accuracy(MAX)'); is($os->class_accuracy(15),$os->class_accuracy($count),'OS: class_accuracy(15) = type(MAX)'); is($host->tcptssequence_values,undef,'HOST4: tcptssequence_values = undef'); isa_ok($np->del_host(HOST4), 'Nmap::Parser::Host','DEL '.HOST4); is($np->get_host(HOST4),undef, 'Testing deletion of '.HOST4); } pbnj-2.04/t/02callback.t0000700000175000017500000000267010523541530013632 0ustar jabrajabra#!/usr/bin/perl use strict; use File::Spec; use Cwd; use Test::More tests => 15; use Nmap::Parser; use constant TEST_FILE =>'nmap_results.xml'; use constant HOST1 => '127.0.0.1'; use constant HOST2 => '127.0.0.2'; use constant HOST3 => '127.0.0.3'; use constant HOST4 => '127.0.0.4'; use constant TOTAL_ADDRS => 4; use vars qw($FH $TOTAL @UP_HOSTS @DOWN_HOSTS); $FH = File::Spec->catfile(cwd(),'t',TEST_FILE); $FH = File::Spec->catfile(cwd(), TEST_FILE) unless(-e $FH); my $np = new Nmap::Parser; isa_ok($np, 'Nmap::Parser'); ok($np->callback(\&my_callback),'Registering callback function'); is($np->callback(),0,'Unregistering callback function'); ok($np->callback(\&my_callback),'re-registering callback function'); $TOTAL = 0; $np->parsefile($FH); is($TOTAL, TOTAL_ADDRS, 'Making sure all hosts were parsed in callback'); ok(eq_set([@UP_HOSTS], [HOST1,HOST3,HOST4]), 'Testing for correct UP hosts'); ok(eq_set([@DOWN_HOSTS], [HOST2]), 'Testing for correct DOWN hosts'); for my $host (HOST1, HOST2, HOST3, HOST4){ is($np->get_host($host) , undef, 'Making sure '.$host.' does not exists'); } sub my_callback { my $host = shift; my $addr = $host->addr; if($addr =~ /^127\.0\.0/){ $TOTAL++; } isa_ok($host,'Nmap::Parser::Host',$host->addr); if( $host->status eq 'up'){push @UP_HOSTS, $addr;} elsif($host->status eq 'down'){push @DOWN_HOSTS, $addr;} } pbnj-2.04/t/test2.xml0000700000175000017500000001017410523541530013330 0ustar jabrajabra
pbnj-2.04/t/03parser.t0000700000175000017500000001027510523541530013373 0ustar jabrajabra#!/usr/bin/perl use strict; use Nmap::Parser; use File::Spec; use Cwd; use Test::More 'no_plan'; use constant HOST1 => '127.0.0.1'; my @UP_HOSTS = (HOST1); use constant TOTAL_HOSTS => 1; use constant TEST_FILE =>'test1.xml'; use vars qw($host $np $session $svc $os $FH); $FH = File::Spec->catfile(cwd(),'t',TEST_FILE); $FH = File::Spec->catfile(cwd(), TEST_FILE) unless(-e $FH); my $np = new Nmap::Parser; parser_test(); session_test(); host_1(); sub parser_test { ok($np->parsefile($FH),"Parsing nmap data: $FH"); #TESTING GET_IPS() is_deeply([$np->get_ips()],[HOST1], 'Testing get_ips for correct number of hosts'); is_deeply([$np->get_ips('up')],[HOST1], 'Testing get_ips for correct hosts with status = up'); #is_deeply([$np->get_ips('down')],[HOST2], 'Testing get_ips for correct hosts for with status = down'); } sub session_test { isa_ok($session = $np->get_session(), 'Nmap::Parser::Session'); print $session->nmap_version() . "\n";; is($session->numservices(),1670,'Session: total number of services'); is($session->numservices('syn'),1670,'Session: numservices type = connect'); is($session->numservices('udp'),undef,'Session: numservices type = udp'); is($session->start_time(),1144909629,'Session: start_time'); is($session->start_str(),'Thu Apr 13 02:27:09 2006','Session: start_str'); is($session->finish_time(),1144909633,'Session: finish_time'); is($session->time_str(),'Thu Apr 13 02:27:13 2006','Session: time_str'); is($session->nmap_version(),'3.95','Session: nmap_version'); is($session->xml_version(),'1.01','Session: xml_version'); is($session->scan_args(),'nmap -A -vv -O -oX test1 127.0.0.1','Session: scan_args'); is($session->scan_type_proto(),undef,'Session: scan_type_proto()'); is($session->scan_type_proto('syn'),'tcp','Session: scan_type_proto(syn)'); } sub host_1 { isa_ok($host = $np->get_host(HOST1), 'Nmap::Parser::Host','GET '.HOST1); is($host->status,'up','Host1: status'); is($host->addr,HOST1,'Host1: addr'); is($host->addrtype,'ipv4','Host1: addrtype'); is($host->ipv4_addr,HOST1,'Host1: ipv4_addr'); is($host->hostname,'localhost.localdomain','Host1: hostname()'); is($host->hostname(0),$host->hostname, 'Host1: hostname(0)'); is($host->hostname(1),'localhost.localdomain', 'Host1: hostname(1)'); is($host->extraports_state(),'closed','Host1: extraports_state'); is($host->extraports_count(),1670,'Host1: extraports_count'); is($host->tcp_port_count(),0,'Host1: tcp_port_count'); is($host->udp_port_count(),0,'Host1: udp_port_count'); is_deeply([$host->tcp_ports()],[qw()],'Host1: tcp_ports()'); is_deeply([$host->tcp_ports('open')],[qw()],'Host1: tcp_ports(open)'); is_deeply([$host->tcp_ports('closed')], [qw()],'Host1: tcp_ports(closed)'); is_deeply([$host->tcp_ports('filtered')],[qw()],'Host1: tcp_ports(filtered)'); is_deeply([$host->tcp_ports('open|filtered')],[qw()],'Host1: tcp_ports(open|filtered)'); is_deeply([$host->udp_ports()], [qw()],'Host1: udp_ports()'); is_deeply([$host->udp_ports('open')],[qw()],'Host1: udp_ports(open)'); is_deeply([$host->udp_ports('filtered')], [qw()],'Host1: udp_ports(filtered)'); is_deeply([$host->udp_ports('closed')], [qw()],'Host1: udp_ports(closed)'); is($host->tcp_ports('open'), $host->tcp_open_ports(), 'Host1: tcp_open_ports'); is($host->tcp_ports('filtered'),$host->tcp_filtered_ports(),'Host1: tcp_filtered_ports'); is($host->tcp_ports('closed'), $host->tcp_closed_ports(), 'Host1: tcp_closed_ports'); is($host->udp_ports('open'), $host->udp_open_ports(), 'Host1: udp_open_ports'); is($host->udp_ports('filtered'),$host->udp_filtered_ports(),'Host1: udp_filtered_ports'); is($host->udp_ports('closed'), $host->udp_closed_ports(), 'Host1: udp_closed_ports'); isa_ok($np->del_host(HOST1), 'Nmap::Parser::Host','DEL '.HOST1); is($np->get_host(HOST1),undef, 'Testing deletion of '.HOST1); #TESTING OS OBJECT FOR HOST 1 my $os; isa_ok($os = $host->os_sig(),'Nmap::Parser::Host::OS','os_sig()'); } pbnj-2.04/t/test3.xml0000700000175000017500000000775610523541530013345 0ustar jabrajabra
pbnj-2.04/t/instance.xml0000700000175000017500000000513410523541530014073 0ustar jabrajabra
pbnj-2.04/t/change1.xml0000700000175000017500000001032710523541530013575 0ustar jabrajabra
pbnj-2.04/t/change2.xml0000700000175000017500000001014110523541530013570 0ustar jabrajabra
pbnj-2.04/t/change3.xml0000700000175000017500000000776710523541530013615 0ustar jabrajabra
pbnj-2.04/t/01modules.t0000700000175000017500000000043310523541530013540 0ustar jabrajabra#!/usr/bin/perl # Test the loadability of our modules use Test::More qw(no_plan); my @modules = qw(File::HomeDir FileHandle Getopt::Long Sys::Hostname Net::hostent Text::CSV_XS DBI DBD::SQLite YAML XML::Twig Nmap::Parser File::Which); for my $m (@modules){ use_ok($m); } pbnj-2.04/t/sdump.tab0000600000175000017500000000103710523741026013364 0ustar jabrajabra1 ssh up 22 tcp 4.2p1 Debian-7ubuntu3 OpenSSH 1148770973 Sat May 27 19:02:53 2006 1 smtp up 25 tcp unknown version Postfix smtpd 1148770973 Sat May 27 19:02:53 2006 1 ipp up 631 tcp 1.2 CUPS 1148770973 Sat May 27 19:02:53 2006 1 ssh down 22 tcp 4.2p1 Debian-7ubuntu3 OpenSSH 1148771004 Sat May 27 19:03:24 2006 1 ssh up 22 tcp 4.2p1 Debian-7ubuntu3 OpenSSH 1148774410 Sat May 27 20:00:10 2006 1 smtp down 25 tcp unknown version Postfix smtpd 1148774410 Sat May 27 20:00:10 2006 1 ipp down 631 tcp 1.2 CUPS 1148774410 Sat May 27 20:00:10 2006 pbnj-2.04/t/query.yaml0000700000175000017500000001300610526513137013600 0ustar jabrajabra# Query.yaml # # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # the file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # # Configuration file for PBNJ 2.0 # # Contains all the names, descriptions and queries for PBNJ 2.0 # # If you would like to submit a new query. please submit it to the link # below. The summary should start with QUERY: description # # http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774490 # --- #YAML:1.0 - name: possiblevuln desc: list all of the services that possibly, should not be running sql: select * from services where service!='ssh' and state='up' # example of verion checking #- name: vulnssh # desc: list all of the services that have old ssh running # sql: |- # select S.updated_on,M.ip,S.service,S.port,S.version from services as S, # machines as M where service='ssh' and state='up' and version!='4.1p1' - name: sshmachines desc: all the machines that have run ssh sql: |- select S.updated_on,M.host,S.service,S.state,S.version from services as S, machines as M where port='22' and M.mid = S.mid - name: allservices desc: all services that have ever been up sql: select * from services where state='up' - name: services desc: basic dump of the services table sql: select updated_on,service,version,banner,state from services - name: unknown_version_up desc: services that have run a unknown version sql: |- select updated_on,service,banner from services where version='unknown version' and state='up' - name: unknown_banner_up desc: services that have run a unknown banner sql: |- select updated_on,service,version from services where banner='unknown banner' and state='up' - name: machines desc: basic dump of the machines table sql: select created_on,ip,host,localh,os from machines - name: sdump desc: dump of the services table sql: select * from services - name: mdump desc: dump of the machines table sql: select * from machines - name: servicesup desc: services running on machines with a given ip or range sql: |- select M.host, S.service,S.version,S.banner from services as S,machines as M where state='up' and M.mid = S.mid - name: unknownversion desc: all instances of services running with an unknown version sql: select * from services where version='unknown version' - name: unknownbanner desc: all instances of services running with an unknown banner sql: select * from services where banner='unknown banner' - name: machine_audit desc: machine audit query sql: select ip,host,os from machines - name: service_audit desc: serice audit query sql: |- select s.port,s.protocol,s.service,s.banner,s.version from services s join machines m join (select mid,service,max(machine_updated)'muo' from services group by mid,service)r where s.mid=r.mid and s.service=r.service and s.state='up' AND s.machine_updated=r.muo and m.mid=s.mid ORDER BY s.port; - name: latestinfo_audit desc: latest host and services info sql: |- select S.port,S.protocol,S.service,S.state,S.banner,S.version from services as S where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) ORDER BY s.port; - name: latestinfo desc: latest host and services info sql: |- select S.updated_on,M.host, S.service,S.state,S.version,S.protocol from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid - name: latestchange desc: latest host and services info sql: |- select S.updated_on,M.ip, S.service,S.state,S.version,S.protocol from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid - name: servicestate desc: |- most recent state for all services whether they have or have not changed sql: |- select s.updated_on,m.host,r.service,state from services s join machines m join (select mid,service,max(machine_updated)'muo' from services group by mid,service)r where s.mid=r.mid and s.service=r.service and s.machine_updated=r.muo and m.mid=s.mid; - name: uptimeratio desc: |- ratio for each service for each machine of the uptime of all the services in the database. This is based on our scans. Therefore, if you can scan once a day or once every hour the ratio is more or less accurate depending. sql: |- select a.mid,a.service,upCount,scanCount,1.0*upCount/scanCount'ratio' from (select mid,service,state,count(*)'upCount' from services where state='up' group by mid,service,state) a join (select mid,service,count(*)'scanCount' from services group by mid,service) b where a.mid=b.mid and a.service=b.service ; - name: monthlyreport desc: |- report of services ip addresses and versions that are currntly running sql: |- select M.ip, S.port,S.service,S.version,S.banner from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid pbnj-2.04/t/range2.xml0000700000175000017500000001606310523541530013450 0ustar jabrajabra
pbnj-2.04/t/range3.xml0000700000175000017500000001606410523541530013452 0ustar jabrajabra
pbnj-2.04/t/config.yaml0000700000175000017500000000174310526513137013705 0ustar jabrajabra# Config.yaml # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # the file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # Configuration file for PBNJ 2.0 # YAML:1.0 # # Config for connecting to a DBI database # SQLite, mysql etc db: SQLite # for SQLite the name of the file. For mysql the name of the database database: data.dbl # Username for the database. For SQLite no username is needed. user: "" # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: "" # Port for the database. For SQLite no port is needed. port: "" pbnj-2.04/t/todo/0000700000175000017500000000000010525442273012512 5ustar jabrajabrapbnj-2.04/t/todo/01distribution.t0000700000175000017500000000025210523541554015561 0ustar jabrajabra#!/usr/bin/perl use Test::More; eval 'require Test::Distribution'; plan (skip_all => 'Test::Distribution not isntalled' ) if $@; Test::Distribution->import ( ); pbnj-2.04/t/todo/05output.t0000700000175000017500000000313510523541554014411 0ustar jabrajabra#!/usr/bin/perl use strict; use warnings; use blib; use File::Compare; use File::Copy; use Test::More; use Shell; version_test(); sub version_test { my $version = nmap(-V); chomp($version); $version =~ s/\n//; if ($version !~ /3\.\d{2}/ and $version !~ /4\.0\d{1}/ and $version !~ /4\.1\d{1}/){ plan ( tests => 1); is (1,1,"Nmap version is too new for these Tests"); exit; } } plan ( tests => no_plan ); my $db = "data.dbl"; #chdir("t") or die "couldn't change directory"; #copy("../outputpbnj", "."); #copy("../config.yaml", "."); #copy("../data.dbl", "."); #copy("../query.yaml", "."); #tests is(system("perl outputpbnj -q latestinfo -t csv -f test1.csv"),0,"latestinfo CSV Output input from $db"); is(system("perl outputpbnj -q latestinfo -t tab -f test1.tab"),0,"latestinfo Tab Output input from $db"); is(system("perl outputpbnj -q sdump -t csv -f test2.csv"),0,"sdump Tab Output input from $db"); is(system("perl outputpbnj -q sdump -t tab -f test2.tab"),0,"sdump Tab Output input from $db"); is(compare("test1.csv", "output.csv"),1,"CSV test latestinfo"); is(compare("test1.tab", "output.tab"),1,"TAB test latestinfo"); is(compare("test2.csv", "output2.csv"),1,"CSV test dumpservices"); is(compare("test2.tab", "output2.tab"),1,"TAB test dumpservices"); #is(unlink("test1.csv"),1,"Remove Test1.csv"); #is(unlink("test1.tab"),1,"Remove Test1.tab"); #is(unlink("test2.tab"),1,"Remove Test2.tab"); #is(unlink("test2.csv"),1,"Remove Test2.tab"); #is(unlink("outputpbnj"),1,"Remove Test2.tab"); #is(unlink($db),1,"Remove DB"); pbnj-2.04/t/todo/04change.t0000700000175000017500000003052210523541554014275 0ustar jabrajabra#!/usr/bin/perl use strict; use warnings; use blib; use Test::More; use File::Spec; use Cwd; use DBI; use File::Copy; use Shell; version_test(); sub version_test { my $version = nmap(-V); chomp($version); $version =~ s/\n//; $version = $& if ($version =~ /\d\.\d\d/); if ($version =~ /3\.\d{2}/ or $version =~ /4\.0\d/ or $version =~ /4\.1\d/){ print "version is $version\n"; print "Nmap version is too new for these Tests"; } else{ exit 1; } } BEGIN { eval { require Test::DatabaseRow; Test::DatabaseRow->import }; if ($@) { print "1..0 # Skipped no Test::DatabaseRow\n"; plan ( tests => 3); if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\change1.xml\" "),0,"Scanpbnj input from change1.xml"); is(system("perl scanpbnj -x \"t\\change2.xml\" "),0,"Scanpbnj input from change2.xml"); is(system("perl scanpbnj -x \"t\\change3.xml\"" ),0,"Scanpbnj input from change3.xml"); } else{ is(system("./scanpbnj -x t/change1.xml > /dev/null"),0,"Scanpbnj input from change1.xml"); is(system("./scanpbnj -x t/change2.xml > /dev/null"),0,"Scanpbnj input from change2.xml"); is(system("./scanpbnj -x t/change3.xml > /dev/null"),0,"Scanpbnj input from change3.xml"); } exit; } } use Test::DatabaseRow; plan ( tests => 101 ); my $test_file = 'change1.xml'; use vars qw($host $np $session $svc $os $FH); if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change1.xml"); } else{ is(system("./scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } ### 04change2 sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); ############################################################################## # # 04change2 # ############################################################################## $test_file = 'change2.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change2.xml"); } else{ is(system("perl scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); ############################################################################## # # 04change3 # ############################################################################## $test_file = 'change3.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change3.xml"); } else { is(system("perl scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'down', banner => 'Postfix smtpd', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'down', banner => 'CUPS', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); #is(system("rm data.dbl"),0,"Removing Database"); pbnj-2.04/t/todo/04change.t-backup0000700000175000017500000003053610523541554015545 0ustar jabrajabra#!/usr/bin/perl use strict; use warnings; use blib; use Test::More; use File::Spec; use Cwd; use DBI; use File::Copy; use Shell; version_test(); sub version_test { my $version = nmap("-V"); chomp($version); $version =~ s/\n//; $version = $& if ($version =~ /\d\.\d\d/); if ($version =~ /3\.\d{2}/ or $version =~ /4\.0\d/ or $version =~ /4\.1\d/){ print "version is $version\n"; print "Nmap version is too new for these Tests"; } else{ exit 1; } } BEGIN { eval { require Test::DatabaseRow; Test::DatabaseRow->import }; if ($@) { print "1..0 # Skipped no Test::DatabaseRow\n"; plan ( tests => 3); if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\change1.xml\" "),0,"Scanpbnj input from change1.xml"); is(system("perl scanpbnj -x \"t\\change2.xml\" "),0,"Scanpbnj input from change2.xml"); is(system("perl scanpbnj -x \"t\\change3.xml\"" ),0,"Scanpbnj input from change3.xml"); } else{ is(system("./scanpbnj -x t/change1.xml > /dev/null"),0,"Scanpbnj input from change1.xml"); is(system("./scanpbnj -x t/change2.xml > /dev/null"),0,"Scanpbnj input from change2.xml"); is(system("./scanpbnj -x t/change3.xml > /dev/null"),0,"Scanpbnj input from change3.xml"); } exit; } } use Test::DatabaseRow; plan ( tests => 51); my $test_file = 'change1.xml'; use vars qw($host $np $session $svc $os $FH); if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change1.xml"); } else{ is(system("./scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } ### 04change2 sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing table:service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing table:service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing table:service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing table:service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing table:service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing table:service element:updated_on"); } # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); ############################################################################## # # 04change2 # ############################################################################## $test_file = 'change2.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change2.xml"); } else{ is(system("perl scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); ############################################################################## # # 04change3 # ############################################################################## =begin $test_file = 'change3.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change3.xml"); } else { is(system("perl scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'down', banner => 'Postfix smtpd', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'down', banner => 'CUPS', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); =end =cut #is(system("rm data.dbl"),0,"Removing Database"); pbnj-2.04/t/todo/06scan.t0000700000175000017500000000176010525441473014001 0ustar jabrajabra#!/usr/bin/perl use strict; use blib; use File::Spec; use Cwd; use Test::More tests => 2; use Nmap::Parser; my $np = new Nmap::Parser; can_ok($np,'parsescan'); my $nmap_path = find_nmap(); SKIP: { skip '[Nmap-Parser] Could not find nmap executable in path',2 if($nmap_path eq ''); ok($nmap_path,"Exe Path: $nmap_path"); } sub find_nmap { my $exe_to_find = 'nmap'; $exe_to_find =~ s/\.exe//; local($_); local(*DIR); for my $dir (File::Spec->path()) { opendir(DIR,$dir) || next; my @files = (readdir(DIR)); closedir(DIR); my $path; for my $file (@files) { $file =~ s/\.exe$//; next unless($file eq $exe_to_find); $path = File::Spec->catfile($dir,$file); # Should symbolic link be considered? Helps me on cygwin but ... next unless -r $path && (-x _ || -l _); return $path; last DIR; } } } pbnj-2.04/t/04change.t0000700000175000017500000002625110525440074013331 0ustar jabrajabra#!/usr/bin/perl use strict; use warnings; use blib; use Test::More; use File::Spec; use Cwd; use DBI; use File::Copy; use Shell; BEGIN { eval { require Test::DatabaseRow; Test::DatabaseRow->import }; if ($@) { print "1..0 # Skipped no Test::DatabaseRow\n"; plan ( tests => 3); chdir("t") or die "can't change to t directory\n"; copy("../scanpbnj", "."); copy("../config.yaml", "."); if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"change1.xml\" "),0,"Scanpbnj input from change1.xml"); is(system("perl scanpbnj -x \"change2.xml\" "),0,"Scanpbnj input from change2.xml"); is(system("perl scanpbnj -x \"change3.xml\"" ),0,"Scanpbnj input from change3.xml"); } else { is(system("./scanpbnj -x change1.xml > /dev/null"),0,"Scanpbnj input from change1.xml"); is(system("./scanpbnj -x change2.xml > /dev/null"),0,"Scanpbnj input from change2.xml"); is(system("./scanpbnj -x change3.xml > /dev/null"),0,"Scanpbnj input from change3.xml"); } exit; } } use Test::DatabaseRow; plan ( tests => 115); my $test_file = 'change1.xml'; use vars qw($host $np $session $svc $os $FH); chdir("t") or die "can't change to t directory\n"; copy("../scanpbnj", "."); copy("../config.yaml", "."); if ($^O ne 'MSWin32'){ system("chmod 700 scanpbnj"); } if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"$test_file\" "),0,"Scanpbnj input from change1.xml"); } else{ is(system("./scanpbnj -x $test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; is(row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing $service port $port element:service"), 1); is(row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing $service element:port") ,1); is(row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing $service element:protocol") ,1); is(row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing $service element:state") ,1); is(row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing $service element:protocol") ,1); is(row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing $service element:machine_updated") ,1); is(row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing $service element:updated_on") ,1); } ### 04change2 sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing $service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing $service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing $service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing $service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing $service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing $service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing $service element:updated_on"); } print "Testing insert into new database from $test_file\n"; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); ############################################################################## # # 04change2 # ############################################################################## $test_file = 'change2.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"$test_file\" "),0,"Scanpbnj input from change2.xml"); } else{ is(system("perl scanpbnj -x $test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } print "Testing insert of services into database from $test_file\n"; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); print "Testing SSH service down in database from $test_file\n"; testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); ############################################################################## # # 04change3 # ############################################################################## $test_file = 'change3.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"$test_file\" "),0,"Scanpbnj input from change3.xml"); } else { is(system("perl scanpbnj -x $test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } print "Testing SSH service up and SMTP and IPP down in database from $test_file\n"; testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'down', banner => 'Postfix smtpd', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'down', banner => 'CUPS', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); #is(system("rm data.dbl"),0,"remove database"); pbnj-2.04/t/05output.t0000700000175000017500000000300010525441104013423 0ustar jabrajabra#!/usr/bin/perl use strict; use warnings; use blib; use File::Compare; use File::Copy; use Test::More; use Shell; SKIP: { if ($^O eq 'MSWin32' || $^O =~ /cygwin/){ print "1..0 # Skipped not UNIX\n"; exit; } } plan ( tests => 14 ); my $db = "data.dbl"; chdir("t") or die "couldn't change directory"; copy("../outputpbnj", "."); copy("../config.yaml", "."); copy("../data.dbl", "."); copy("../query.yaml", "."); #tests is(system("perl outputpbnj -q latestinfo -t csv -f 05test1.csv"),0,"latestinfo CSV 05test1.csv from $db"); is(system("perl outputpbnj -q latestinfo -t tab -f 05test1.tab"),0,"latestinfo Tab 05test1.tab from $db"); is(system("perl outputpbnj -q sdump -t csv -f 05test2.csv"),0,"sdump Tab Output input from $db"); is(system("perl outputpbnj -q sdump -t tab -f 05test2.tab"),0,"sdump Tab Output input from $db"); is(compare("05test1.csv", "latestinfo.csv"),0,"latestinfo CSV cmp 05test1.csv latestinfo.csv"); is(compare("05test1.tab", "latestinfo.tab"),0,"latestinfo CSV cmp 05test1.tab latestinfo.tab"); is(compare("05test2.csv", "sdump.csv"),0,"sdump CSV cmp 05test2.csv sdump.csv"); is(compare("05test2.tab", "sdump.tab"),0,"sdump TAB cmp 05test2.tab sdump.tab"); is(unlink("05test1.csv"),1,"Remove test1.csv"); is(unlink("05test1.tab"),1,"Remove test1.tab"); is(unlink("05test2.tab"),1,"Remove test2.tab"); is(unlink("05test2.csv"),1,"Remove test2.tab"); is(unlink("outputpbnj"),1,"Remove outputpbnj"); is(unlink("$db"),1,"Remove DB $db"); pbnj-2.04/t/long/0000700000175000017500000000000010523541534012502 5ustar jabrajabrapbnj-2.04/t/long/04change.t0000700000175000017500000002701110523541534014264 0ustar jabrajabra#!/usr/bin/perl use strict; use warnings; use blib; use Test::More; use File::Spec; use Cwd; use DBI; use File::Copy; use Shell; version_test(); sub version_test { my $version = nmap("-V"); chomp($version); $version =~ s/\n//; $version = $& if ($version =~ /\d\.\d\d/); if ($version =~ /3\.\d{2}/ or $version =~ /4\.0\d/ or $version =~ /4\.1\d/){ if ($version > 4.11){ #print "nmap old version"; exit; } else{ #print "nmap new version\n"; return "ok"; } #print "version is $version\n"; #print "Nmap version is too new for these Tests"; #exit; } else{ exit 1; } } BEGIN { eval { require Test::DatabaseRow; Test::DatabaseRow->import }; if ($@) { print "1..0 # Skipped no Test::DatabaseRow\n"; plan ( tests => 3); if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\change1.xml\" "),0,"Scanpbnj input from change1.xml"); is(system("perl scanpbnj -x \"t\\change2.xml\" "),0,"Scanpbnj input from change2.xml"); is(system("perl scanpbnj -x \"t\\change3.xml\"" ),0,"Scanpbnj input from change3.xml"); } else{ is(system("./scanpbnj -x t/change1.xml > /dev/null"),0,"Scanpbnj input from change1.xml"); is(system("./scanpbnj -x t/change2.xml > /dev/null"),0,"Scanpbnj input from change2.xml"); is(system("./scanpbnj -x t/change3.xml > /dev/null"),0,"Scanpbnj input from change3.xml"); } exit; } } use Test::DatabaseRow; plan ( tests => 116); my $test_file = 'change1.xml'; use vars qw($host $np $session $svc $os $FH); if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change1.xml"); } else{ is(system("./scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } my $dbh = DBI->connect('dbi:SQLite:dbname=data.dbl'); # set the default database handle local $Test::DatabaseRow::dbh = $dbh; sub testService{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; is(row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing $service port $port element:service"), 1); is(row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing $service element:port") ,1); is(row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing $service element:protocol") ,1); is(row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port", tests => [ state => $state ], label => "Testing $service element:state") ,1); is(row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing $service element:protocol") ,1); is(row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port", tests => [ machine_updated => $machine_updated ], label => "Testing $service element:machine_updated") ,1); is(row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port", tests => [ updated_on => $updated ], label => "Testing $service element:updated_on") ,1); } ### 04change2 sub testServiceChange{ my ($href) = @_; die "testService: port not defined" unless defined $href->{port}; die "testService: service not defined" unless defined $href->{service}; die "testService: version not defined" unless defined $href->{version}; die "testService: proto not defined" unless defined $href->{proto}; die "testService: state not defined" unless defined $href->{state}; die "testService: updated_on not defined" unless defined $href->{updated_on}; die "testService: machine_updated not defined" unless defined $href->{machine_updated}; my $service = $href->{service}; my $port = $href->{port}; my $version = $href->{version}; my $proto = $href->{proto}; my $state = $href->{state}; my $updated = $href->{updated_on}; my $machine_updated = $href->{machine_updated}; row_ok( sql => "SELECT service FROM services WHERE mid = '1' and port=$port", tests => [ service => $service ], label => "Testing $service port $port element:service"); row_ok( sql => "SELECT port FROM services WHERE mid = '1' and port=$port", tests => [ port => $port ], label => "Testing $service element:port"); row_ok( sql => "SELECT protocol FROM services WHERE mid = '1' and port=$port", tests => [ protocol => $proto ], label => "Testing $service element:protocol"); row_ok( sql => "SELECT state FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ state => $state ], label => "Testing $service element:state"); row_ok( sql => "SELECT version FROM services WHERE mid = '1' and port=$port", tests => [ version => $version ], label => "Testing $service element:protocol"); row_ok( sql => "SELECT machine_updated FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ machine_updated => $machine_updated ], label => "Testing $service element:machine_updated"); row_ok( sql => "SELECT updated_on FROM services WHERE mid = '1' and port=$port and machine_updated=$machine_updated", tests => [ updated_on => $updated ], label => "Testing $service element:updated_on"); } print "Testing insert into new database from $test_file\n"; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); ############################################################################## # # 04change2 # ############################################################################## $test_file = 'change2.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change2.xml"); } else{ is(system("perl scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } print "Testing insert of services into database from $test_file\n"; # service 25 testService( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'up', banner => 'CUPS', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); testService( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'up', banner => 'Postfix smtpd', updated_on => 'Sat May 27 19:02:53 2006', machine_updated => '1148770973' }); print "Testing SSH service down in database from $test_file\n"; testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'down', banner => 'OpenSSH', updated_on => 'Sat May 27 19:03:24 2006', machine_updated => '1148771004' }); ############################################################################## # # 04change3 # ############################################################################## $test_file = 'change3.xml'; if ($^O eq 'MSWin32'){ is(system("perl scanpbnj -x \"t\\$test_file\" "),0,"Scanpbnj input from change3.xml"); } else { is(system("perl scanpbnj -x t/$test_file > /dev/null"),0,"Scanpbnj input from $test_file"); } print "Testing SSH service up and SMTP and IPP down in database from $test_file\n"; testServiceChange( { service => 'ssh', port => 22, proto => 'tcp', version => '4.2p1 Debian-7ubuntu3', state => 'up', banner => 'OpenSSH', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'smtp', port => 25, proto => 'tcp', version => 'unknown version', state => 'down', banner => 'Postfix smtpd', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); testServiceChange( { service => 'ipp', port => 631, proto => 'tcp', version => '1.2', state => 'down', banner => 'CUPS', updated_on => 'Sat May 27 20:00:10 2006', machine_updated => '1148774410' }); is(system("rm data.dbl"),0,"remove database"); pbnj-2.04/t/01pod.t0000700000175000017500000000027510523541530012656 0ustar jabrajabra#!/usr/bin/perl use strict; use warnings; use Test::More; eval 'use Test::Pod 1.00'; plan( skip_all => 'Test::Pod 1.00 required for testing POD' ) if $@; all_pod_files_ok( ); pbnj-2.04/t/latestinfo.csv0000700000175000017500000000027210523741021014425 0ustar jabrajabraSat May 27 20:00:10 2006,localhost,ssh,up,4.2p1 Debian-7ubuntu3,tcp Sat May 27 20:00:10 2006,localhost,smtp,down,unknown version,tcp Sat May 27 20:00:10 2006,localhost,ipp,down,1.2,tcp pbnj-2.04/t/latestinfo.tab0000700000175000017500000000027210523741021014400 0ustar jabrajabraSat May 27 20:00:10 2006 localhost ssh up 4.2p1 Debian-7ubuntu3 tcp Sat May 27 20:00:10 2006 localhost smtp down unknown version tcp Sat May 27 20:00:10 2006 localhost ipp down 1.2 tcp pbnj-2.04/query.yaml0000600000175000017500000001300610526513057013335 0ustar jabrajabra# Query.yaml # # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # the file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # # Configuration file for PBNJ 2.0 # # Contains all the names, descriptions and queries for PBNJ 2.0 # # If you would like to submit a new query. please submit it to the link # below. The summary should start with QUERY: description # # http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774490 # --- #YAML:1.0 - name: possiblevuln desc: list all of the services that possibly, should not be running sql: select * from services where service!='ssh' and state='up' # example of verion checking #- name: vulnssh # desc: list all of the services that have old ssh running # sql: |- # select S.updated_on,M.ip,S.service,S.port,S.version from services as S, # machines as M where service='ssh' and state='up' and version!='4.1p1' - name: sshmachines desc: all the machines that have run ssh sql: |- select S.updated_on,M.host,S.service,S.state,S.version from services as S, machines as M where port='22' and M.mid = S.mid - name: allservices desc: all services that have ever been up sql: select * from services where state='up' - name: services desc: basic dump of the services table sql: select updated_on,service,version,banner,state from services - name: unknown_version_up desc: services that have run a unknown version sql: |- select updated_on,service,banner from services where version='unknown version' and state='up' - name: unknown_banner_up desc: services that have run a unknown banner sql: |- select updated_on,service,version from services where banner='unknown banner' and state='up' - name: machines desc: basic dump of the machines table sql: select created_on,ip,host,localh,os from machines - name: sdump desc: dump of the services table sql: select * from services - name: mdump desc: dump of the machines table sql: select * from machines - name: servicesup desc: services running on machines with a given ip or range sql: |- select M.host, S.service,S.version,S.banner from services as S,machines as M where state='up' and M.mid = S.mid - name: unknownversion desc: all instances of services running with an unknown version sql: select * from services where version='unknown version' - name: unknownbanner desc: all instances of services running with an unknown banner sql: select * from services where banner='unknown banner' - name: machine_audit desc: machine audit query sql: select ip,host,os from machines - name: service_audit desc: serice audit query sql: |- select s.port,s.protocol,s.service,s.banner,s.version from services s join machines m join (select mid,service,max(machine_updated)'muo' from services group by mid,service)r where s.mid=r.mid and s.service=r.service and s.state='up' AND s.machine_updated=r.muo and m.mid=s.mid ORDER BY s.port; - name: latestinfo_audit desc: latest host and services info sql: |- select S.port,S.protocol,S.service,S.state,S.banner,S.version from services as S where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) ORDER BY s.port; - name: latestinfo desc: latest host and services info sql: |- select S.updated_on,M.host, S.service,S.state,S.version,S.protocol from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid - name: latestchange desc: latest host and services info sql: |- select S.updated_on,M.ip, S.service,S.state,S.version,S.protocol from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid - name: servicestate desc: |- most recent state for all services whether they have or have not changed sql: |- select s.updated_on,m.host,r.service,state from services s join machines m join (select mid,service,max(machine_updated)'muo' from services group by mid,service)r where s.mid=r.mid and s.service=r.service and s.machine_updated=r.muo and m.mid=s.mid; - name: uptimeratio desc: |- ratio for each service for each machine of the uptime of all the services in the database. This is based on our scans. Therefore, if you can scan once a day or once every hour the ratio is more or less accurate depending. sql: |- select a.mid,a.service,upCount,scanCount,1.0*upCount/scanCount'ratio' from (select mid,service,state,count(*)'upCount' from services where state='up' group by mid,service,state) a join (select mid,service,count(*)'scanCount' from services group by mid,service) b where a.mid=b.mid and a.service=b.service ; - name: monthlyreport desc: |- report of services ip addresses and versions that are currntly running sql: |- select M.ip, S.port,S.service,S.version,S.banner from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid pbnj-2.04/config.yaml0000600000175000017500000000174310526516245013444 0ustar jabrajabra# Config.yaml # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # the file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # Configuration file for PBNJ 2.0 # YAML:1.0 # # Config for connecting to a DBI database # SQLite, mysql etc db: SQLite # for SQLite the name of the file. For mysql the name of the database database: data.dbl # Username for the database. For SQLite no username is needed. user: "" # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: "" # Port for the database. For SQLite no port is needed. port: "" pbnj-2.04/iplist0000600000175000017500000000003410523541634012527 0ustar jabrajabra192.168.1.1 192.168.1.100 pbnj-2.04/outputpbnj.man.10000600000175000017500000002461110523741736014362 0ustar jabrajabra#!/usr/bin/perl # # pod2man outputpbnj.man.1 | gzip -c > outputpbnj.1p.gz && gunzip outputpbnj.1p.gz # # Copyright (C) 2005-2006 Joshua D. Abraham (jabra@ccs.neu.edu) # # This manpage is released under the terms of the GNU General Public # License (GPL), which is distributed with this software in the file # "COPYING". The GPL specifies the terms under which users may copy # and use this software. # =pod =begin man =head1 NAME OutputPBNJ - a program to query a PBNJ 2.0 database. =head1 SYNOPSIS outputpbnj [Query Options] [Database Options] [General Options] =cut =begin man =head1 DESCRIPTION OutputPBNJ uses a query yaml config file to execute queries against the PBNJ 2.0 database. OutputPBNJ returns the result in various output types (csv, tab and html). Apart of PBNJ 2.0 suite of tools to monitor changes on a network. =head1 OPTIONS Usage: outputpbnj [Query Options] [Config Options] [General Options] Query Options: -q --query Perform sql query -t --type Output Type [csv,tab,html] -f --file Store the result in file otherwise stdout --both Print results and store them in a file --dir Store the result in this directory [def .] -l --lookup Lookup description based on name --list List of names and descriptions -n --name Lookup all the names -d --desc Lookup all the descriptions -s --sql Lookup all the sql queries Config Options: --qconfig Config of sql queries [def query.yaml] --dbconfig Config for accessing database [def config.yaml] --dbdir Directory for Config file [def .] --data SQLite Database override [def data.dbl] General Options: --test Test Level --debug Verbose information -v --version Display version -h --help Display this information Send Comments to Joshua D. Abraham ( jabra@ccs.neu.edu ) =end man =cut __END__ =begin man =head1 THINGS TO NOTE * OutputPBNJ requires root privileges to query a database that is owned by root. Thus, if you are scanning with ScanPBNJ you will need to run OutputPBNJ with root privileges to access the database. * If there are configs in the current directory, they are used instead of those in the user's config directory. =head1 Query Options =head2 -q --query Perform sql query This option is where the actual query is specified. Therefore, once you know the query you wish to use simply pass it as an argument to this option. =head2 -t --type Output Type [csv,tab,html] This options is used to specify which output format you wish to use. For example, if you would like to have output that you can show someone else the CSV format is useful because you can simply pull the file into OpenOffice Calc or Excel as it is a comma delimited file. =head2 -f --file This option is used to specifiy output to a file rather than standard output. This is useful if you want to grow the results of queries as the result will be added onto the end of the file. =head2 --both This option is used when you want both output to standard output, as well as to a file. This will save the result to a file if you are having the result sent to the screen or piped to your email which you may or may not disregard. =head2 --dir Store the result in this directory [default .] This option is used with the writing to a file. This option will store the file in a alternative directory than the current directory. =head2 -l --lookup This options is used to lookup the description of a specific query. This will return the description of the query. =head2 --list List of names and descriptions This option is used to return a list of all the queries with the names and descriptions. This is very useful when you are starting to use OutputPBNJ or using a new query config. =head2 -n --name This option is used to print the all the query names. =head2 -d --desc This option is used to print the all the query descriptions. This is useful to find out all the queries do. =head2 -s --sql This option is used to print the all the queries. This is useful for developing new queries based on other queries. =head1 Config Options =head2 --qconfig Config of sql queries [default query.yaml] This option is used to specify an alternative query.yaml file. =head2 --dbconfig Config for accessing results database [default config.yaml] This option is used to specify an alternative config.yaml file. =head2 --dbdir Directory for Config file [default .] This option is used to specify an alternative directory for the config.yaml file. =head1 GENERAL OPTIONS =head2 --test Increases the Test level, causing OutputPBNJ to print testing information about the Query. Using the Test level is mostly only using for testing. This will also print the debugging information so it can get rather lengthy. The greater the Test level the more output will be given. This option is also used for reporting bugs. All bug reports should be submitted using --test 1 and an additional report may be needed depending on the issue =head2 --debug Increases the Debug level, causing OutputPBNJ to print more information about the query in progress. The higher the debug leve the more output the user will receive. =head2 -v --version Prints the OutputPBNJ version number and exits. =head2 -h --help Display this information Prints a help screen with the command flags. Running OutputPBNJ without any arguments does the same thing. =head1 FILES PBNJ's data files are stored in ScanPBNJ and OutputPBNJ. When either of these programs is run the configuration files will be generated for the user if they do not already exists and placed in the $HOME/.pbnj-2.0 directory. Again, if there is a configuration file in the current directory it is used instead of the version in the configuration directory. $HOME/.pbnj-2.0/config.yaml - holds settings for connecting to the database which store the information from PBNJ scans. $HOME/.pbnj-2.0/query.yaml - lists all queries that can be used to retrieve information from the database. Also, includes the name and description for each query. This is only generated when you executed OutputPBNJ. For Windows, the pbnj-2.0 config directory is in the APPDATA directory, which contains both config.yaml and query.yaml. Depending on your environment, the APPDATA directory may be a different location from other environments. Therefore, when the configs are executed for the first time they will display the path where the configs were generated. =head1 QUERY The query.yaml file contains the list of various names, descriptions and sql queries that can be executed by OutputPBNJ. Here is one example: - name: vulnssh desc: list all of the services that have old ssh running sql: |- select S.updated_on,M.ip,S.service,S.port,S.version from services as S, machines as M where service='ssh' and state='up' and version!='4.1p1' This examples shows how the name, description and sql are layed out in the yaml format. Therefore, we know the name of the query is vulnssh and it's purpose is to list SSH servers which are not running a version 4.1p1. It is very easy to create another script that would check for the latest version of a given service and therefore the user would be able to verify that that particular service needed to be updated on the machine that was scanned. =head1 FEATURE REQUESTS Any feature requests should be reported to the online feature-request-tracking system available on the web at: http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774489 Before requesting a feature, please check to see if the features has already been requested. =head1 BUG REPORTS Any bugs found should be reported to the online bug-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488. Before reporting bugs, please check to see if the bug has already been reported. When reporting PBNJ bugs, it is important to include a reliable way to reproduce the bug, version number of PBNJ and Nmap, OS name and version, and any relevant hardware specs. And of course, patches to rectify the bug are even better. =head1 SUPPORTED DATABASES The following databases are supported: * SQLite [default] * MySQL * Postgres * CSV =head1 DATABASE SCHEMA The following is the SQLite version of the database schema: CREATE TABLE machines ( mid INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT, host TEXT, localh INTEGER, os TEXT, machine_created TEXT, created_on TEXT); CREATE TABLE services ( mid INTEGER, service TEXT, state TEXT, port INTEGER, protocol TEXT, version TEXT, banner TEXT, machine_updated TEXT, updated_on TEXT); =head1 SEE ALSO scanpbnj(1), genlist(1), nmap(1) =head1 AUTHORS Joshua D. Abraham ( jabra@ccs.neu.edu ) =head1 LEGAL NOTICES 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 at http://www.gnu.org/copyleft/gpl.html, or in the COPYING file included with PBNJ. It should also be noted that PBNJ has occasionally been known to crash poorly written applications, TCP/IP stacks, and even operating systems. While this is extremely rare, it is important to keep in mind. PBNJ should never be run against mission critical systems unless you are prepared to suffer downtime. We acknowledge here that PBNJ may crash your systems or networks and we disclaim all liability for any damage or problems PBNJ could cause. =end man pbnj-2.04/Makefile.PL0000700000175000017500000000211010526512217013246 0ustar jabrajabrause ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'pbnj', 'AUTHOR' => 'Joshua D. Abraham', 'VERSION' => '2.04', 'EXE_FILES' => [ 'scanpbnj', 'outputpbnj', 'genlist' ], 'INSTALLDIRS' => 'site', 'MAN1PODS' => { 'scanpbnj.man.1' => 'blib/man1/scanpbnj.1p', 'outputpbnj.man.1' => 'blib/man1/outputpbnj.1p', 'genlist.man.1' => 'blib/man1/genlist.1p', }, 'PREREQ_PM' => { 'XML::Twig' => '3.22', 'Nmap::Parser' => '1.01', 'DBI' => '1.50', 'YAML' => '0.39', 'DBD::SQLite' => '1.11', 'Text::CSV_XS' => '0.23', 'File::Which' => '0.05', 'File::HomeDir' => '0.06', }, 'dist' => { 'SUFFIX' => ".gz", 'DIST_DEFAULT' => 'all tardist', 'COMPRESS' => "gzip -9f" }, 'realclean' => { 'FILES' => '' }, 'clean' => { 'FILES' => '' }, ); pbnj-2.04/COPYING0000600000175000017500000004363110523541634012345 0ustar jabrajabra GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. pbnj-2.04/BUGS0000600000175000017500000000127510526515053011772 0ustar jabrajabraBUGS * ScanPBNJ doesn't probably scan a ipv6 machine. The current work-around is it perform the scan with Nmap storing the results in XML and use ScanPBNJ to parse the XML. SUBMITTING NEW BUGS Any bugs found should be reported to the online bug-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488. Before reporting bugs, please check to see if the bug has already been reported. When reporting PBNJ bugs, it is important to include a reliable way to reproduce the bug, version number of PBNJ and Nmap, OS name and version, and any relevant hardware specs. And of course, patches to rectify the bug are even better. pbnj-2.04/scanpbnj0000700000175000017500000017672310526513017013042 0ustar jabrajabra#!/usr/bin/perl # # Copyright (C) 2005-2006 Joshua D. Abraham (jabra@ccs.neu.edu) # # This program is released under the terms of the GNU General Public License # (GPL), which is distributed with this software in the file "COPYING". # The GPL specifies the terms under which users may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # ScanPBNJ - a program for running Nmap scans and storing the results in # a PBNJ 2.0 database. # use strict; use warnings; use Shell; use DBI; use Nmap::Parser; use Socket; use Net::hostent; use Sys::Hostname; use Getopt::Long; use FileHandle; use YAML; use File::Which; use Term::ANSIColor qw(:constants); use File::HomeDir; use POSIX; $Term::ANSIColor::AUTORESET = 1; use vars qw( $PROG ); ( $PROG = $0 ) =~ s/^.*[\/\\]//; # Truncate calling path from the prog name my $AUTH = 'Joshua D. Abraham'; # author my $VERSION = '2.04'; # version my $np = new Nmap::Parser; # parser object my $type = 'help'; # parse scan or file my @ipRange; # ip Address or ip range to scan my $iplist; # ip list file my $xmlFile; # xml file to parse my $Range = '1-1025'; # port range to scan my $args = "-vv -O -P0 "; # scan args my $scantype = "-sSV"; # default scantype my $cargs = 'no'; # user changed args my $outputdir = '.'; # output database directory my $nmapPath = which('nmap'); # nmap path my $interface = ""; # default interface to perform scan my %options; # getopts hash my $dbh; # database connection my $dbconfig = 'config.yaml'; # database config my $database; # database file my $db; # db backend my $hostname; # db host ip my $port; # db port my $user; # db username my $passwd; # db password my $datadb; # results from the config of the db my $dir = "."; # dir of the config for the db my $colors = 1; # print using colors my $diff = 'version'; $options{test} = 0; # testing flag $options{debug} = 0; # debug flag my $configdir; #chown() that reports errors sub safe_chown { my $uid = shift; my $gid = shift; my $file = shift; if ( chown( $uid, $gid, $file ) != 1 ) { error( 'Unable to change the owner of the file ' . $file . '.' . "\n\n" ); } } if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $colors = 0; require Win32; import Win32; Win32->import(qw(CSIDL_APPDATA)); my $dir = Win32::GetFolderPath( CSIDL_APPDATA() ); # 2.0 $configdir = $dir . "\\" . "pbnj-2.0"; if ( -e $configdir and -d $configdir ) { if ( $options{test} > 2 ) { print "$configdir exists\n"; } } else { mkdir $configdir; print "mkdir $configdir\n"; } if ( !-e $dbconfig ) { $dbconfig = "$configdir\\$dbconfig"; # check if the config exists in ~/.pbnj-2.0/config.yaml if ( !-e $dbconfig ) { open( CONFIG, ">$dbconfig" ); while () { if ( defined($_) ) { print CONFIG $_; } } close(CONFIG); print "$dbconfig generated\n"; } } } else { $configdir = File::HomeDir->my_home; my $tmpuser = $configdir; $configdir .= "/.pbnj-2.0"; $tmpuser =~ s/home//; $tmpuser =~ s/\///g; my $uid = getpwnam($tmpuser); my $gid = id("-g $tmpuser"); if ( !defined($gid) ) { error("gid not defined\n"); } if ( !defined($uid) ) { error("uid not defined\n"); } if ( -e $configdir and -d $configdir ) { if ( $options{test} > 2 ) { print "$configdir exists\n"; } } else { umask 077; mkdir $configdir; print "mkdir $configdir\n"; safe_chown( $uid, $gid, $configdir ); } # check if config exists in the current directory if ( !-e $dbconfig ) { $dbconfig = "$configdir/$dbconfig"; # check if the config exists in ~/.pbnj-2.0/config.yaml if ( !-e $dbconfig ) { umask 077; open( CONFIG, ">$dbconfig" ); while () { if ( defined($_) ) { print CONFIG $_; } } close(CONFIG); safe_chown( $uid, $gid, $dbconfig ); print "$dbconfig generated\n"; } } } ############################################################################## # # createMachinesTable: scalar -> scalar # creates the table for machines in the database # mid INTEGER PRIMARY KEY, # ############################################################################## sub createMachinesTable { my $dbh = shift; my $auto_increment = "AUTO_INCREMENT"; my $mid_type; if ( $db eq "SQLite" ) { $auto_increment = "AUTOINCREMENT"; $mid_type = "INTEGER PRIMARY KEY $auto_increment"; } elsif ( $db eq "mysql" or $db eq "CSV" ) { $mid_type = "INTEGER PRIMARY KEY"; } elsif ( $db eq "Pg" ) { $mid_type = "SERIAL PRIMARY KEY"; } else { print "db not supported\n"; exit 1; } eval { $dbh->do( "CREATE TABLE machines ( mid $mid_type, ip TEXT, host TEXT, localh INTEGER, os TEXT, machine_created TEXT, created_on TEXT)" ); }; if ($@) { return 0; } return 1; } ############################################################################## # # createService: scalar -> scalar # creates the table for services in the database # ############################################################################## sub createServicesTable { my $dbh = shift; #sid INTEGER PRIMARY KEY, eval { $dbh->do( "CREATE TABLE services ( mid INTEGER, service TEXT, state TEXT, port INTEGER, protocol TEXT, version TEXT, banner TEXT, machine_updated TEXT, updated_on TEXT)" ); }; if ($@) { return 0; } return 1; } ############################################################################## # # insertService: anoy hash -> scalar # inserts information about a service into the database # ############################################################################## sub insertService { my ($href) = @_; die "insertService: mid not defined" unless defined $href->{mid}; die "insertService: service not defined" unless defined $href->{service}; die "insertService: state not defined" unless defined $href->{state}; die "insertService: port not defined" unless defined $href->{port}; die "insertService: proto not defined" unless defined $href->{proto}; die "insertService: ver not defined" unless defined $href->{ver}; die "insertService: banner not defined" unless defined $href->{banner}; die "insertService: updated not defined" unless defined $href->{updated}; die "insertService: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $service = $href->{service}; my $state = $href->{state}; my $port = $href->{port}; my $proto = $href->{proto}; my $ver = $href->{ver}; my $banner = $href->{banner}; my $updated = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $insert = $dbh->prepare('INSERT INTO services VALUES (?,?,?,?,?,?,?,?,?)'); my $success = 1; $success &&= $insert->execute( $mid, $service, $state, $port, $proto, $ver, $banner, $machine_updated, $updated ); return $success; } ############################################################################## # # setLocal: anoy hash -> scalar # set the localhost bit # ############################################################################## sub setLocal { my ($href) = @_; die "setLocal: ip not defined" unless defined $href->{ip}; die "setLocal: hostname not defined" unless defined $href->{hostname}; my $ip = $href->{ip}; my $hostname = $href->{hostname}; my $localh = 0; if ( $hostname =~ m/localhost/ and $ip eq "127.0.0.1" ) { if ( $options{test} > 0 or $options{debug} > 1 ) { print "localhost scan\n"; } $localh = 1; } return $localh; } ############################################################################## # # insertMachine: anoy hash -> scalar # inserts information about a machine into the database # ############################################################################## sub insertMachine { my ($href) = @_; die "insertMachine: ip not defined" unless defined $href->{ip}; die "insertMachine: host not defined" unless defined $href->{host}; die "insertMachine: localh not defined" unless defined $href->{localh}; die "insertMachine: os not defined" unless defined $href->{os}; die "insertMachine: created not defined" unless defined $href->{created}; die "insertMachine: machine_created not defined" unless defined $href->{machine_created}; my $ip = $href->{ip}; my $host = $href->{host}; my $localh = $href->{localh}; my $os = $href->{os}; my $created = $href->{created}; my $machine_created = $href->{machine_created}; if ( $db eq "CSV" ) { my $sth = $dbh->selectrow_hashref("select max('mid') from machines"); my $mid = $sth->{mid}; if ( !defined($mid) ) { $mid = 1; } else { $mid++; } my $insert = $dbh->prepare( 'INSERT INTO machines VALUES (?,?,?,?,?,?,?,?,?)'); my $success = 1; $success &&= $insert->execute( $mid, $ip, $host, $localh, $os, $machine_created, $created ); return $mid; } else { $dbh->do( "INSERT INTO machines (ip, host, localh, os, machine_created, created_on) VALUES ( '$ip', '$host', '$localh', '$os', '$machine_created', '$created' ) " ); } my $sth = $dbh->selectrow_hashref( "SELECT mid from machines WHERE ip='$ip' AND host='$host' AND localh='$localh' AND os='$os' AND machine_created='$machine_created' AND created_on='$created'" ); return $sth->{'mid'}; } ############################################################################## # # flushTables: -> # flush the machines and services tables # ############################################################################## sub flushTables { print "flushing tables\n"; $dbh->do("DROP TABLE machines"); $dbh->do("DROP TABLE services"); } ############################################################################## # # addHost: anoy hash -> scalar # insert a host only if it is uniq # ############################################################################## sub addHost { my ($href) = @_; die "addHost: os not defined" unless defined $href->{os}; die "addHost: session not defined" unless defined $href->{session}; die "addHost: host not defined" unless defined $href->{host}; my $os = $href->{os}; my $session = $href->{session}; #a Nmap::Parser::Session object my $host = $href->{host}; my $mid; my $ip = $host->addr; my $machine_created = $session->finish_time(); my $human_time = localtime($machine_created); my $uniqhost = 0; my $hostname = $host->hostname; my $localh = setLocal( { ip => $ip, hostname => $host->hostname } ); my $uniq = $dbh->selectall_arrayref( "select mid from machines WHERE ip='$ip' AND os='$os' AND host='$hostname' AND localh='$localh'" ); if ( $options{test} > 1 ) { print "uniq is $uniq\n"; } foreach my $uniqtmp (@$uniq) { my ($midtmp) = @$uniqtmp; $uniqhost = 1; $mid = $midtmp; if ( $options{test} > 0 or $options{debug} > 1 ) { print "non unique host\n"; print "mid shift is $mid\n"; } } if ( $uniqhost eq 0 ) { if ( $colors eq 1 ) { print BOLD GREEN "Inserting Machine\n"; } else { print "Inserting Machine\n"; } $mid = insertMachine( { ip => $ip, host => $hostname, localh => $localh, os => $os, created => $human_time, machine_created => $machine_created } ); if ( $options{test} > 0 or $options{debug} > 1 ) { ; print "mid is $mid\n"; } } else { print "Machine is already in the database\n"; print "Checking Current Services\n"; } return ( $mid, $uniqhost ); } ############################################################################## # # insertServiceDB: anoy hash -> # take information about a services from the database and insert it as # as being down # ############################################################################## sub insertServiceDB { my ($href) = @_; die "insertServiceDB: mid not defined" unless defined $href->{mid}; die "insertServiceDB: port not defined" unless defined $href->{port}; die "insertServiceDB: state not defined" unless defined $href->{state}; die "insertServiceDB: proto not defined" unless defined $href->{proto}; die "insertSerciceDB: updated not defined" unless defined $href->{updated}; die "insertSerciceDB: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $port = $href->{port}; my $state = $href->{state}; my $proto = $href->{proto}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $uniq_service = $dbh->selectall_arrayref( "SELECT service,version,protocol,banner FROM services WHERE mid='$mid' AND port='$port' AND protocol='$proto' AND state='up' ORDER BY machine_updated DESC" ); my ( $version, $service, $banner, $uniqservice ); foreach my $uniqtmp (@$uniq_service) { ( $service, $version, $proto, $banner ) = @$uniqtmp; #print "service is $service\n"; } if ( $colors eq 1 ) { print BOLD RED "\t! Service $port:$proto $service is down\n"; } else { print "\t! Service $port:$proto $service is down\n"; } insertService( { mid => $mid, service => $service, port => $port, proto => $proto, ver => $version, state => $state, banner => $banner, updated => $human_time, machine_updated => $machine_updated } ); } ############################################################################## # # insertServiceScan: anoy hash -> # take information about a services from the scan and insert it as # as being up # ############################################################################## sub insertServiceScan { my ($href) = @_; die "insertServiceScan: host not defined" unless defined $href->{host}; die "insertServiceScan: mid not defined" unless defined $href->{mid}; die "insertServiceScan: port not defined" unless defined $href->{port}; die "insertServiceScan: state not defined" unless defined $href->{state}; die "insertServiceScan: proto not defined" unless defined $href->{proto}; die "insertServiceScan: change not defined" unless defined $href->{change}; die "insertSerciceScan: updated not defined" unless defined $href->{updated}; die "insertSerciceScan: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $mid = $href->{mid}; my $port = $href->{port}; my $state = $href->{state}; my $proto = $href->{proto}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $change = $href->{change}; my $service; if ( $proto eq "tcp" ) { $service = $host->tcp_service($port); } else { $service = $host->udp_service($port); } my $name = "unknown name"; my $product = "unknown product"; my $version = "unknown version"; if ( defined( $service->name ) ) { $name = $service->name; } if ( defined( $service->version ) ) { $version = $service->version; } if ( defined( $service->product ) ) { $product = $service->product; } if ( $change == 1 ) { if ( $colors == 1 ) { print BOLD GREEN "\tInserting Service on $port:$proto $name\n"; } else { print "\tInserting Service on $port:$proto $name\n"; } } insertService( { mid => $mid, service => $name, port => $port, proto => $proto, ver => $version, state => $state, banner => $product, updated => $human_time, machine_updated => $machine_updated } ); } ############################################################################## # # cmpService: anoy hash -> scalar # compare the service in the database and the service from the scan. # Note: # If the service is up the database & is not in the scan then the state is down. # If the service is not in the database & is in the scan then the state is up. # ############################################################################## sub cmpService { my ($href) = @_; die "cmpService: host not defined" unless defined $href->{host}; die "cmpService: mid not defined" unless defined $href->{mid}; die "cmpService: port not defined" unless defined $href->{port}; die "cmpService: state not defined" unless defined $href->{state}; die "cmpService: proto not defined" unless defined $href->{proto}; die "cmpService: updated not defined" unless defined $href->{updated}; die "cmpService: machine_updated not defined" unless defined $href->{machine_updated}; die "cmpService: db_updated not defined" unless defined $href->{db_updated}; die "cmpService: db_machine_updated not defined" unless defined $href->{db_machine_updated}; my $host = $href->{host}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $state = $href->{state}; my $port = $href->{port}; my $proto = $href->{proto}; my $db_updated = $href->{db_updated}; my $db_machine_updated = $href->{db_machine_updated}; my $service; if ( $proto eq "tcp" ) { $service = $host->tcp_service($port); } elsif ( $proto eq "udp" ) { $service = $host->udp_service($port); } else { print "error in $proto\n"; exit 1; } my $banner_from_scan = "unknown product"; my $version_from_scan = "unknown version"; my $port_from_scan = $service->port; my $service_name_from_scan = "unknown service"; if ( defined( $service->name ) ) { $service_name_from_scan = $service->name; } if ( $options{test} eq 1 ) { print "service name from scan is $service_name_from_scan\n"; } if ( defined( $service->version ) ) { $version_from_scan = $service->version; if ( $options{test} > 2 ) { print "version from scan is $version_from_scan\n"; } } if ( defined( $service->product ) ) { $banner_from_scan = $service->product; if ( $options{test} > 2 ) { print "banner from scan is $banner_from_scan\n"; } } my ( $version_from_db, $service_name_from_db, $banner_from_db ); # note the version banner and service name are the only elements # of the service that we can comparing my $uniq_service = $dbh->selectall_arrayref( "SELECT service,version,banner FROM services WHERE mid='$mid' AND port='$port' AND state='$state' AND protocol='$proto' AND updated_on='$db_updated' AND machine_updated='$db_machine_updated'" ); foreach my $uniqtmp (@$uniq_service) { my ( $nametmp, $vertmp, $bantmp ) = @$uniqtmp; $service_name_from_db = $nametmp; $version_from_db = $vertmp; $banner_from_db = $bantmp; } if ( $options{test} > 1 ) { print "state is $state\n"; print "comparing service $service_name_from_db and $service_name_from_scan\n"; print "comparing version $version_from_db and $version_from_scan\n"; print "comparing banner $banner_from_db and $banner_from_scan\n"; } if ( $diff eq "banner" && $version_from_db eq $version_from_scan && $banner_from_db eq $banner_from_scan && $service_name_from_db eq $service_name_from_scan ) { print "\t= $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; return 1; } elsif ($diff ne "banner" && $version_from_db eq $version_from_scan && $service_name_from_db eq $service_name_from_scan ) { print "\t= $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; return 1; } else { if ( $colors == 1 ) { print BOLD YELLOW "\t! $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; } else { print "\t! $service_name_from_db:$port is ($version_from_db) $banner_from_db\n"; } if ( $service_name_from_db ne $service_name_from_scan ) { if ( $colors == 1 ) { print BOLD YELLOW " Service Name was \"$service_name_from_db\" changed to \"$service_name_from_scan\"\n"; } else { print " Service Name was \"$service_name_from_db\" changed to \"$service_name_from_scan\"\n"; } } elsif ( $version_from_db ne $version_from_scan ) { if ( $colors == 1 ) { print BOLD YELLOW " Version was \"$version_from_db\" changed to \"$version_from_scan\"\n"; } else { print " Version was \"$version_from_db\" changed to \"$version_from_scan\"\n"; } } elsif ( $diff eq 'banner' and $banner_from_db ne $banner_from_scan ) { if ( $colors == 1 ) { print BOLD YELLOW " Banner was \"$banner_from_db\" changed to \"$banner_from_scan\"\n"; } else { print " Banner was \"$banner_from_db\" changed to \"$banner_from_scan\"\n"; } } else { print "version or banner difference\n"; } # set time to earlier so insert works after old verison is down $machine_updated = scalar($machine_updated); $machine_updated -= 1; insertService( { mid => $mid, service => $service_name_from_db, port => $port, proto => $proto, ver => $version_from_db, state => 'down', banner => $banner_from_db, updated => $human_time, machine_updated => $machine_updated, } ); return 0; } return 1; } ############################################################################## # # setAndInsertService: anoy hash -> scalar # store all the services in the scan into the database # ############################################################################## sub setAndInsertService { my ($href) = @_; die "setAndInsertService: mid not defined" unless defined $href->{mid}; die "setAndInsertService: proto not defined" unless defined $href->{proto}; die "setAndInsertService: service not defined" unless defined $href->{service}; die "setAndInsertService: updated not defined" unless defined $href->{updated}; die "setAndInsertService: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $service = $href->{service}; my $proto = $href->{proto}; my $state = 'up'; my $product_from_scan = "unknown product"; my $version_from_scan = "unknown version"; my $port_from_scan = $service->port; my $name_from_scan = "unknown service"; if ( defined( $service->name ) ) { $name_from_scan = $service->name; } if ( defined( $service->version ) ) { $version_from_scan = $service->version; } if ( defined( $service->product ) ) { $product_from_scan = $service->product; } print "Inserting Service on $port_from_scan:$proto $name_from_scan\n"; insertService( { mid => $mid, service => $name_from_scan, port => $port_from_scan, proto => $proto, ver => $version_from_scan, state => $state, banner => $product_from_scan, updated => $human_time, machine_updated => $machine_updated } ); } ############################################################################## # # storeEverything: anoy hash -> scalar # store all the services in the scan into the database # ############################################################################## sub storeEverything { my ($href) = @_; die "storeEverything: host not defined" unless defined $href->{host}; die "storeEverything: mid not defined" unless defined $href->{mid}; die "storeEverything: updated not defined" unless defined $href->{updated}; die "storeEverything: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $state; # $port is up in the database # store all the services running on tcp ports foreach ( $host->tcp_ports('open') ) { my $state = $host->tcp_port_state($_); if ( $options{test} eq 1 ) { print "state is $state on port $_\n"; } next if ( $state ne "open" ); my $service = $host->tcp_service($_); next if ( !defined($service) ); #my $uniqservice = 1; setAndInsertService( { proto => 'tcp', service => $service, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); } # store all the services running on tcp ports foreach ( $host->udp_ports('open') ) { my $state = $host->udp_port_state($_); if ( $options{test} eq 1 ) { print "in udp loop\n"; print "state is $state on port $_\n"; } next if ( $state ne "open" ); my $service = $host->udp_service($_); next if ( !defined($service) ); setAndInsertService( { proto => 'udp', service => $service, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); } return 0; } ############################################################################## # # sortDB: anoy hash -> hash # sort the database based on the time # ############################################################################## sub sortDB { my ($href) = @_; die "sortDB: mid not defined" unless defined $href->{mid}; die "sortDB: updated not defined" unless defined $href->{updated}; die "sortDB: machine_updated not defined" unless defined $href->{machine_updated}; my $mid = $href->{mid}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my ( $port, $service, $banner, $state, $state_db ); # determines all ports that are in the database and not in the scan # thus we assume these services went down # may 30 added limit 1 my ( %port_db, %seen_ports, $scan_state, $scan_proto ); my $ports_db_ref = $dbh->selectall_arrayref( "SELECT port,state,protocol,machine_updated,updated_on FROM services WHERE mid='$mid' ORDER BY machine_updated DESC " ); foreach my $key (@$ports_db_ref) { my ( $port, $state, $proto, $machine_updated, $updated ) = @$key; if ( !$port_db{$port}{machine_updated} ) { $port_db{$port}{machine_updated} = $machine_updated; $port_db{$port}{updated} = $updated; $port_db{$port}{port} = $port; $port_db{$port}{state} = $state; $port_db{$port}{proto} = $proto; } else { #print "not less than and exists\n"; } } return %port_db; } ############################################################################## # # setDown: anoy hash -> # remove all services on a given protocol as the host has no ports on # this protocol. # ############################################################################## sub setDown { my ($href) = @_; die "setDown: mid not defined" unless defined $href->{mid}; die "setDown: host not defined" unless defined $href->{host}; die "setDown: proto not defined" unless defined $href->{proto}; die "setDown: portdb not defined" unless defined $href->{portdb}; die "setDown: updated not defined" unless defined $href->{updated}; die "setDown: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $mid = $href->{mid}; my $proto = $href->{proto}; my $db_ref = $href->{portdb}; my %portdb = %{$db_ref}; if ( $options{test} > 0 ) { print "protocol is $proto\n"; } my ( $scan_state, %seen_ports ); foreach my $port ( sort { $a cmp $b } keys %portdb ) { #print "key is $port\n"; if ( $options{test} eq 1 ) { print $portdb{$port}{state} . " and $port\n"; print "port db $port proto $proto\n"; } $scan_state = "down"; if ( $options{test} eq 1 ) { print "scan thinks the status of $port is $scan_state\n"; print "state is " . $portdb{$port}{state} . "\n"; } if ( $scan_state eq "down" && $portdb{$port}{'state'} eq "up" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { insertServiceDB( { mid => $mid, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated } ); if ( $options{test} eq 1 ) { print "pulling data about service from database\n"; } } } } ############################################################################## # # cmpAndInsert: anoy hash -> # add service changes to the database # ############################################################################## sub cmpAndInsert { my ($href) = @_; die "cmpAndInsert: mid not defined" unless defined $href->{mid}; die "cmpAndInsert: host not defined" unless defined $href->{host}; die "cmpAndInsert: proto not defined" unless defined $href->{proto}; die "cmpAndInsert: portdb not defined" unless defined $href->{portdb}; die "cmpAndInsert: updated not defined" unless defined $href->{updated}; die "cmpAndInsert: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $mid = $href->{mid}; my $proto = $href->{proto}; my $db_ref = $href->{portdb}; my %portdb = %{$db_ref}; if ( $options{test} eq 1 or $options{debug} eq 1 ) { print "protocol is $proto\n"; } my ( $scan_state, %seen_ports ); foreach my $port ( sort { $a cmp $b } keys %portdb ) { if ( $options{test} eq 1 ) { print $portdb{$port}{state} . " and $port\n"; print "port db $port proto $proto\n"; } my $tmp; if ( $proto eq "tcp" ) { $tmp = $host->tcp_port_state($port); } elsif ( $proto eq "udp" ) { $tmp = $host->udp_port_state($port); } else { next; } $seen_ports{$port} = "up"; if ($tmp) { $scan_state = "up"; } else { $scan_state = "down"; } if ( $options{test} eq 1 ) { print "scan thinks the status of $port is $scan_state\n"; print "state is " . $portdb{$port}{state} . "\n"; } if ( $portdb{$port}{state} eq "up" && $scan_state eq "up" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { if ( $options{test} eq 1 ) { print "states are both up\n"; print "checking versions and banners\n"; } my $db_updated = $portdb{$port}{updated}; my $db_machine_updated = $portdb{$port}{machine_updated}; my $cmp = cmpService( { mid => $mid, host => $host, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated, db_updated => $db_updated, db_machine_updated => $db_machine_updated, } ); if ( $cmp eq 0 ) { if ( $options{test} > 1 ) { print "port is $port\n"; print "mark 1\n"; } insertServiceScan( { mid => $mid, host => $host, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => $cmp, } ); } else { if ( $options{test} eq 1 ) { print "no difference in name or version or banner\n"; } } } else { #print "scan state is $scan_state\n"; #print "database state is $port_db{$port}{'state'}\n"; if ( $scan_state eq "down" && $portdb{$port}{'state'} eq "up" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { insertServiceDB( { mid => $mid, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated } ); if ( $options{test} eq 1 ) { print "pulling data about service from database\n"; } } elsif ($scan_state eq "up" && $portdb{$port}{'state'} eq "down" && $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { if ( $options{test} > 1 ) { print "port is $port\n"; print "mark 2\n"; } insertServiceScan( { host => $host, mid => $mid, port => $port, state => $scan_state, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => 1, } ); if ( $options{test} eq 1 ) { print "pulling data about service from scan\n"; } } else { if ( $portdb{$port}{proto} && $portdb{$port}{proto} eq $proto ) { if ( $options{test} eq 1 ) { print "states are both down\n"; } } else { if ( $options{test} > 1 ) { print "protocols are different\n"; } } } } chomp( $portdb{$port}{updated} ); #print "\n$port_db{$port}{port} keys is $port\n"; #print "\n$port_db{$port}{state} keys is $port\n"; #print "\n$port_db{$port}{updated} keys is $port\n"; } # bug for seen ports on different protocols if ( $proto eq "tcp" ) { # handles ports that are open in the scan and don't exist in the database foreach ( $host->tcp_ports('open') ) { my $tmptest = $host->tcp_port_state($_); if ( $options{test} eq 1 ) { print "state is $tmptest\n"; } next if ( $tmptest ne "open" ); my $port_tmp = $_; my $state_tmp; if ( $seen_ports{$port_tmp} && $seen_ports{$port_tmp} eq "up" ) { if ( $options{test} eq 1 ) { print "Port is already up\n"; } } else { $state_tmp = "up"; if ( $options{test} > 1 ) { print "inserting scan not in the database on $port_tmp\n"; print "mark 3\n"; } insertServiceScan( { host => $host, mid => $mid, port => $port_tmp, proto => $proto, state => $state_tmp, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => 1, } ); } } } else { # handles ports that are open in the scan and don't exist in the database foreach ( $host->udp_ports('open') ) { my $tmptest = $host->udp_port_state($_); if ( $options{test} eq 1 ) { print "state is $tmptest\n"; } next if ( $tmptest ne "open" ); my $port_tmp = $_; my $state_tmp; if ( $seen_ports{$port_tmp} && $seen_ports{$port_tmp} eq "up" ) { if ( $options{test} eq 1 ) { print "Port is already up\n"; } } else { $state_tmp = "up"; if ( $options{test} > 1 ) { print "inserting scan not in the database on $port_tmp\n"; print "mark 4\n"; } insertServiceScan( { host => $host, mid => $mid, port => $port_tmp, state => $state_tmp, proto => $proto, updated => $human_time, machine_updated => $machine_updated, change => 0, } ); } } } } ############################################################################## # # addServices: anoy hash -> # add service changes to the database # ############################################################################## sub addServices { my ($href) = @_; die "addServices: mid not defined" unless defined $href->{mid}; die "addServices: host not defined" unless defined $href->{host}; die "addServices: updated not defined" unless defined $href->{updated}; die "addServices: uniq not defined" unless defined $href->{uniq}; die "addServices: machine_updated not defined" unless defined $href->{machine_updated}; my $host = $href->{host}; my $human_time = $href->{updated}; my $machine_updated = $href->{machine_updated}; my $mid = $href->{mid}; my $uniq = $href->{uniq}; my ( $port, $service, $banner, $state, $state_db ); my %port_db = sortDB( { host => $host, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); # determines all ports that are in the database and not in the scan # thus we assume these services went down if ( $uniq eq 0 ) { if ( $options{test} > 0 ) { print "store everything from the scan\n"; } storeEverything( { host => $host, mid => $mid, updated => $human_time, machine_updated => $machine_updated } ); return 0; } my @tcp_ports = $host->tcp_open_ports(); my @udp_ports = $host->udp_open_ports(); if ( !defined( scalar(@tcp_ports) ) ) { if ( $options{debug} > 0 or $options{test} eq 1 ) { print "no TCP ports found\n"; } setDown( { mid => $mid, host => $host, proto => "tcp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } else { cmpAndInsert( { mid => $mid, host => $host, proto => "tcp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } if ( !defined( scalar(@udp_ports) ) ) { if ( $options{debug} > 0 or $options{test} eq 1 ) { print "no UDP ports found\n"; } setDown( { mid => $mid, host => $host, proto => "udp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } else { cmpAndInsert( { mid => $mid, host => $host, proto => "udp", portdb => \%port_db, updated => $human_time, machine_updated => $machine_updated } ); } } ############################################################################## # # storeData: scalar -> # function to perform scans and insert hosts and services as needed # ############################################################################## sub storeData { my $mTable = createMachinesTable($dbh); if ( $mTable eq 0 ) { print "creating Machines Table\n"; } my $sTable = createServicesTable($dbh); if ( $sTable eq 0 ) { print "creating Services Table\n"; } my $created_on = $np->get_session()->finish_time(); my $human_time = localtime($created_on); for my $host ( $np->all_hosts() ) { my $os = $host->os_sig(); my $os_scan; if ( defined($os) and defined( $os->osfamily ) and defined( $os->osgen ) ) { $os_scan = $os->osfamily . " " . $os->osgen; } else { $os_scan = "unknown os"; } if ( !defined($os_scan) or $os_scan eq "" ) { $os_scan = "unknown os"; } print "\n--------------------------------------\n"; print "Starting Scan of " . $host->addr . "\n"; my ( $mid, $uniq ) = addHost( { os => $os_scan, session => $np->get_session(), host => $host, created_on => $human_time, machine_created => $created_on } ); addServices( { mid => $mid, host => $host, updated => $human_time, machine_updated => $created_on, uniq => $uniq, } ); print "Scan Complete for " . $host->addr . "\n"; print "--------------------------------------\n"; } print "\n"; } ############################################################################## # # verify_windows: array ref -> # verify that the windows machine isn't trying to scanning itself # side effect: calls verify_scan and possibly quits # ############################################################################## sub verify_windows { my $range = shift; foreach (@$range) { if ( $_ =~ m/127\.0\.0\.1/ ) { print "Error: Win32 machines can't scan themselves.\n"; exit 1; } } verify_scan(); } ############################################################################## # # verify_ip: anoy hash -> scalar # determine if ip is in acceptable range # ############################################################################## sub verify_ip { my ($href) = @_; die "verify_ip: oct1 not defined" unless defined $href->{oct1}; die "verify_ip: oct2 not defined" unless defined $href->{oct2}; die "verify_ip: oct3 not defined" unless defined $href->{oct3}; die "verify_ip: oct4 not defined" unless defined $href->{oct4}; my $oct1 = $href->{oct1}; my $oct2 = $href->{oct2}; my $oct3 = $href->{oct3}; my $oct4 = $href->{oct4}; if ( $oct1 < 255 and $oct1 > 0 ) { if ( ( $oct2 eq "*" or $oct2 eq "\* " ) or ( $oct2 == 0 ) or ( $oct2 < 256 and $oct2 > 0 ) ) { if ( ( $oct3 eq "*" or $oct3 eq "\*" ) or ( $oct3 == 0 ) or ( $oct3 < 256 and $oct3 > 0 ) ) { if ( ( $oct4 eq "*" or $oct4 eq "\*" ) or ( $oct4 =~ /0\/\d{1,2}/ ) or ( $oct4 < 256 and $oct4 > 0 ) ) { return 1; } else { print "fourth is $4\n" if ( $options{test} > 2 ); } } else { print "third is $3\n" if ( $options{test} > 2 ); } } else { print "second is $2\n" if ( $options{test} > 3 ); } } return 0; } ############################################################################## # # verify_scan # verifies that the nmap path is set # side effect: quits if the nmap path is not set # ############################################################################## sub verify_scan { if ( !defined($nmapPath) or $nmapPath eq "" ) { print "Error: Nmap was not found in your path.\n"; print "Please download the latest version from\n"; print "http://www.insecure.org/nmap/download.html\n"; exit 1; } } ############################################################################## # # help -> # display help information # side effect: exits program # ############################################################################## sub help { print "Usage: $PROG [Options] {target specification} Target Specification: Can pass hostnames, IP addresses, networks, etc. Ex: microsoft.com, 192.168.0.1, 192.168.1.1/24, 10.0.0.1-254 -i --iplist Scan using a list of IPs from a file -x --xml Parse scan/info from Nmap XML file Scan Options: -a --args Execute Nmap with args (needs quotes) -e --extraargs Add args to the default args (needs quotes) --inter Perform Nmap Scan using non default interface -m --moreports Add ports to scan ex: 8080 or 3306,5900 -n --nmap Path to Nmap executable -p --pingscan Ping Target then scan the host(s) that are alive --udp Add UDP to the scan arguments --rpc Add RPC to the scan arguments -r --range Ports for scan [def 1-1025] --diffbanner Parse changes of the banner Config Options: -d --dbconfig Config for results database [def config.yaml] --configdir Directory for the database config file --data SQLite Database override [def data.dbl] --dir Directory for SQLite or CSV file [def . ] General Options: --nocolors Don't Print Colors --test Testing information --debug Debug information -v --version Display version -h --help Display this information Send Comments to Joshua D. Abraham ( jabra\@ccs.neu.edu )\n"; exit; } ############################################################################## # # print_version -> # displays version # side effect: exits program # ############################################################################## sub print_version { print "$PROG version $VERSION by $AUTH\n"; exit; } ############################################################################## if ( @ARGV == 0 ) { help; exit; } GetOptions( \%options, 'pingscan|p', 'scan|s', 'iplist|i=s', 'xml|x=s', 'range|r=s', 'moreports|m=s', 'nmap|n=s', 'dbconfig|d=s', 'dir=s', 'data=s', 'configdir=s', 'test=s', 'args|a=s', 'extraargs|e=s', 'udp', 'rpc', 'inter=s', 'diffbanner', 'help|h' => sub { help(); }, 'version|v' => sub { print_version(); }, 'nocolors' => sub { $colors = 0; }, 'fruitycolors' => sub { $colors = 2; }, 'debug=s', ) or exit 1; my $dephosts = ""; if ($options{'scan'}){ print "WARNING: --scan is deprecated\n"; print "Please use the following format: $PROG 127.0.0.1 \n"; $dephosts = $options{'scan'}; } if ( ( $options{'iplist'} or $options{'pingscan'} ) and $options{'xml'} ) { print "Invalid type of input\n"; exit 1; } if ( $options{'input'} and $options{'pingscan'} ) { print "Conflicting type of Scan\n"; } if ( $options{'dir'} ) { $dir = $options{'dir'}; } if ( $options{'configdir'} ) { $configdir = $options{'configdir'}; } if ( $options{'dbconfig'} ) { my $tmpconfig; if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $tmpconfig = $configdir . '\\' . $options{'dbconfig'}; } else { $tmpconfig = $configdir . "/" . $options{'dbconfig'}; } if ( -e $tmpconfig && -r $tmpconfig ) { $dbconfig = $tmpconfig; } } chdir($dir) or die "Couldn't change to $dir directory\n"; if ( !defined($dbconfig) or $dbconfig eq "" or ( !-e $dbconfig or !-r $dbconfig ) ) { print "Couldn't open $dbconfig for input\n"; exit; } if ( $options{'inter'} ) { $interface = "-e " . $options{'inter'} . " "; } if ( $options{'nmap'} ) { if ( -X $options{'nmap'} ) { $nmapPath = $options{'nmap'}; } else { print $options{'nmap'} . " isn't executable using $nmapPath\n"; } } if ( $options{'iplist'} ) { if ( -e $options{'iplist'} ) { if ( -r $options{'iplist'} ) { my $fh = new FileHandle("<$options{'iplist'}"); die "$options{'iplist'}:$!" unless defined $fh; @ipRange = $fh->getlines(); chomp @ipRange; $type = 'scan'; } else { print "File $options{'iplist'} isn't readable\n"; exit 1; } } else { print "File $options{'iplist'} doesn't exist\n"; exit 1; } } if ( $options{'xml'} ) { if ( -e $options{'xml'} ) { if ( -r $options{'xml'} ) { $xmlFile = $options{'xml'}; $type = 'file'; } else { print "Input File isn't readable\n"; exit 1; } } else { print "Input File doesn't exist\n"; exit 1; } } if ( $options{'udp'} ) { $scantype = $scantype . "U"; } if ( $options{'rpc'} ) { $scantype = $scantype . "R"; } if ( $options{'args'} ) { $args = ""; $scantype = ""; $args = $options{'args'}; $cargs = 'yes'; } if ( $options{'extraargs'} ) { $args = $args . $options{'extraargs'} . " "; } if ( $options{'dir'} ) { $outputdir = $options{'dir'}; } if ( $options{'range'} ) { my (@ports) = split ',', $options{'range'}; foreach (@ports) { chomp; if ( $_ !~ /\d/ ) { print "$_ not digit\n"; } } $Range = ""; for ( my $i = 0; $i < scalar(@ports); $i++ ) { $Range .= $ports[$i]; if ( $i < scalar(@ports) - 1 ) { $Range .= ","; } } } #@ports = @ports - 1; if ( $options{'moreports'} ) { my @morePorts = split ',', $options{'moreports'}; foreach (@morePorts) { if (/(\d+)/) { chomp; if ( $_ =~ /\d/ ) { $Range .= ",$_"; } else { print "MorePorts: Port $_ isn't between 1 and 65535\n"; exit 1; } } else { print "MorePorts: Port $_ isn't a number\n"; exit 1; } } } if ( $options{'diffbanner'} ) { $diff = "banner"; } my $tmp = scalar(@ARGV); my @targets; if ( $type ne 'file' ) { foreach (@ARGV) { s/\ //g; my @args = split(',', $_); foreach(@args){ push( @targets, $_ ); } } my @args = split(',', $dephosts); foreach(@args){ push( @targets, $_ ); } } foreach my $host (@targets) { if ($host) { my $ipRange; if ( $host =~ /[a-zA-Z]/ ) { my $name = $host; if ( $name eq 'localhost' ) { $ipRange = '127.0.0.1'; } else { 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 '' ) { print "Invalid Ip Address being Resolved\n"; exit 1; } } print "Resolved $host to $ipRange\n" if ( $options{debug} > 3 ); $type = 'scan'; push( @ipRange, $ipRange ); } elsif ( $host =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\-(\d{1,3}|\*|'*')/ ) { my $max; if ( $5 =~ m/\*/ ) { $max = 255; } elsif ( $5 < 256 ) { $max = $5; } else { print "IP Address not in proper range\n"; exit 1; } if ( $4 < $5 ) { for ( $4 .. $max ) { if (verify_ip( { oct1 => $1, oct2 => $2, oct3 => $3, oct4 => $_ } ) == 1 ) { my $ip = join( ".", $1, $2, $3, $_ ); push( @ipRange, $ip ); $type = 'scan'; } } } } elsif ( $host =~ /(\d{1,3})\.(\d{1,3}|\*)\.(\d{1,3}|\*)\.(0\/\d{1,2}|\d{1,3}|\*|'*')/ ) { if ( $options{test} > 3 ) { print "first is $1\n"; print "second is $2\n"; print "third is $3\n"; print "fourth is $4\n"; } my $valid = verify_ip( { oct1 => $1, oct2 => $2, oct3 => $3, oct4 => $4 } ); if ( $valid == 1 ) { $type = 'scan'; push( @ipRange, $host ); } } if ( !defined($host) ) { print "IP Address not in proper range\n"; exit 1; } } else { print "Invalid IP Address\n"; exit 1; print "scan is $host" if ( $options{debug} eq 1 ); } } if ( $options{'pingscan'} ) { if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $nmapPath = "\"$nmapPath\""; verify_windows( \@ipRange ); } else { verify_scan(); } $np->parsescan( $nmapPath, "-R -sP", @ipRange ); my $livehosts = ""; for my $host ( $np->get_ips('up') ) { if ( $livehosts eq "" ) { $livehosts = $host; } else { $livehosts = join( " ", $livehosts, $host ); } } if ( $livehosts eq "" ) { print "Scanned @ipRange\n"; print "No Hosts Responding to Ping Scan\n"; exit; } else { print "Live Hosts Found: $livehosts\n"; @ipRange = $livehosts; } } # make sure something is passed help() if ( $type ne 'file' and $type ne 'scan' ); if ( $type eq 'file' ) { $np->parsefile($xmlFile); } elsif ( $type eq 'scan' ) { $args = $args . $interface; if ( $cargs eq 'no' ) { $args = $args . $scantype . " -p $Range"; } if ( $options{debug} > 2 or $options{test} > 0 ) { print "nmap path is $nmapPath\n"; } if ( $args =~ /-o(?:X|N|G)/ ) { warn "$PROG Cannot pass option '-oX', '-oN' or '-oG'\n"; warn "Removing option\n"; $args =~ s/-o(?:X|N|G)//g; print "args is now $args\n"; } if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $nmapPath = "\"$nmapPath\""; verify_windows( \@ipRange ); } else { verify_scan(); if ( $> ne 0 ) { print "PBNJ Scans requires root privileges.\n"; exit 1; } } if ( $options{debug} > 0 or $options{test} > 0 ) { print "Scan Args are $args\n"; print "Scanning "; foreach (@ipRange) { print "- $_ "; } print "\n"; } $np->parsescan( $nmapPath, $args, @ipRange ); } else { print "type error $type\n"; exit 1; } # only connect to the database when we need too. if ( $type eq "scan" or $type eq "file" ) { if ( $options{data} ) { $db = "SQLite"; $database = $options{data}; } else { $datadb = YAML::LoadFile($dbconfig); foreach my $tmp ( keys %$datadb ) { $passwd = $$datadb{$tmp} if ( $tmp eq 'passwd' ); $user = $$datadb{$tmp} if ( $tmp eq 'user' ); $db = $$datadb{$tmp} if ( $tmp eq 'db' ); $database = $$datadb{$tmp} if ( $tmp eq 'database' ); $hostname = $$datadb{$tmp} if ( $tmp eq 'host' ); $port = $$datadb{$tmp} if ( $tmp eq 'port' ); } } # connection to database if ( $db eq 'SQLite' or $db eq 'CSV' ) { $dbh = DBI->connect( "dbi:$db:$database", $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1 } ) || die "Cannot connect: $DBI::errstr"; } elsif ( $db eq 'mysql' ) { my $dsn = "DBI:$db:database=$database;host=$hostname;port=$port"; $dbh = DBI->connect( $dsn, $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1 } ) || die "Cannot connect: $DBI::errstr"; } elsif ( $db eq 'Pg' ) { my $dsn = "DBI:$db:database=$database;host=$hostname;port=$port"; $dbh = DBI->connect( $dsn, $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1, PrintWarn => 0 } ) || die "Cannot connect: $DBI::errstr"; } else { print "$db isn't supported\n"; } } storeData($dbh); $dbh->disconnect; __DATA__ # Config.yaml # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # Configuration file for PBNJ 2.0 # YAML:1.0 # # Config for connecting to a DBI database # SQLite, mysql etc db: SQLite # for SQLite the name of the file. For mysql the name of the database database: data.dbl # Username for the database. For SQLite no username is needed. user: "" # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: "" # Port for the database. For SQLite no port is needed. port: "" pbnj-2.04/ChangeLog0000600000175000017500000001072710526523176013070 0ustar jabrajabraCHANGELOG 2.04 --- * converted text files files from unix to dos format * added backwards compatibility for --scan * update man pages to reflect removal of --scan * fixed ip parsing bug for certain ip's * removed -s ( default is to scan all ip's ) * fixed help and manpages to reflect changes * -p doesn't require arguments. Therefore, to perform ping scan use the following: scanpbnj -p 192.168.1.1/24 * fixed bug when inserting a service with an unknown name. * added more tests * small Makefile.PL change of manpages CHANGELOG 2.02 --- * added testing for scanpbnj - 04change.t * fix small typos CHANGLOG 2.0BETA2 ----------------- * added more error checking to outputpbnj * various random fixes CHANGLOG 2.0BETA1 ----------------- * Set Directory fir Windows User. In APPDATA directory is where the pbnj-2.0 directory will be created and the config files will be stored there. * small bug with group id. * Started Final Testing before the 2.0 Release * -r can now pass args like 22,25,80-90 * --inter bug where interface wasn't being added properly * fixed up the documentation a bit CHANGLOG 1.5.10 ----------------- * fixed bug in outputPBNJ where tab wouldn't line up properly * update the manpages. * fixed bug where when doing a scan with sudo privs the config dir was being created and owned by root. * added configs to outputpbnj and scanpbnj thus the config files will be generated if they don't already exists. Thus it can now be packaged for debian. * fixed bug where inserting services were not being displayed CHANGELOG 1.5.9 ----------------- * set default scan to not compare changes in the banner * added --diffbanner that will parse changes in the banner * fixed banner/version/service changes by setting the state of the old service to down, which needed to be done before inserting the new version * fixed bug where range wasn't changing * fixed validation for scanning a range using x.x.x.0/24 * fixed bug in pingscan when the range would be scanned as well as the live hosts. * fixed windows path error * updated quickinstall script for the modules not in Ubuntu CHANGELOG 1.5.8 ----------------- * fixed bug with uniq hosts and services that are down being removed twice * added better checking for ip addresses that are real * fixed hostname setting bug where the localhost would be set to the external hostname when scanning localhost. * fixed Makefile.PL on unix to copy the needed files * moved 04 and 05 tests into todo for a future release CHANGELOG 1.5.7 ----------------- * fixed bug in print list * fixed --qconfig which uses an alternative query config file * removed useless yaml configs * removed diff from tests to work on windows * Added COLOR output * Added --nocolors, for those who don't like colors * Nmap-4.20-ALPHA2 fixed issue with machine being identified even when a port isn't open. Therefore, the scanner is able to set all ports that were running to down. CHANGELOG 1.5.6 ----------------- * fixed running scanner without privs exits with perl error * added --header to outputpbnj that prints the header of the sql results * added --list to outputpbnj that prints the name - description for each query in the query.yaml config file * added --interface so that the use can pass a specific interface to use for the nmap scan * added -U --udp to perform a udp scan * added -R --rpc to perfrom a rpc scan * fixed output to be less wordy * finished Windows Install Documentation(thanks ANDY) * Displays error with url to download nmap when it is not in the user's path. CHANGELOG 1.5.5 ----------------- * fixed bug in the scanner when parsing xml files CHANGELOG 1.5.4 ----------------- * add MySQL support * added MySQL tests * added Postgres support * added Postgres tests * added CSV support * fixed bug in tests that has make test fail when Test::DatabaseRow is not installed CHANGELOG 1.5.3 ----------------- * more testing for scanning ranges (store everything and afterwards) * error if nmap isn't in path. Displays url to download it. * fixed env variables * find nmap using File::Which and updated the tests. * tested scanner outputpbnj and genlist on cygwin CHANGELOG 1.5 ----------------- * added tests for changes that occur on localhost. * need tests for a network scan * udp port scan testing seems like it is working but more testing is still needed * fixed various testing bugs CHANGELOG 1.4.2.0 ----------------- * Preliminary udp port scan added pbnj-2.04/genlist0000700000175000017500000000647110526512755012711 0ustar jabrajabra#!/usr/bin/perl # # Copyright (C) 2005-2006 Joshua D. Abraham (jabra@ccs.neu.edu) # # This program is released under the terms of the GNU General Public License # (GPL), which is distributed with this software in the file "COPYING". # The GPL specifies the terms under which users may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # # Genlist - ping scanner # use strict; use warnings; use FileHandle; use Nmap::Parser; use Getopt::Long; use File::Which; use vars qw( $PROG ); ( $PROG = $0 ) =~ s/^.*[\/\\]//; # Truncate calling path from the prog name my $AUTH = 'Joshua D. Abraham'; # author my $VERSION = '2.04'; # version my $np = new Nmap::Parser; # parser object my $list; # output list of live hosts; my @output_files; my $ipfound; my $type = 'help'; my $outputdir = '.'; # output database directory my $nmapPath = which('nmap'); # nmap path my $args = "-sP"; my $interface = ""; # default interface to perform scan my @ipRange; my %options; # getopts hash ############################################################################## # scan -> # performs a ping scan and prints the list of machines that are up # side effects: exits program ############################################################################## sub scan { $np->parsescan( $nmapPath, $args, @ipRange ); for my $host ( $np->get_ips('up') ) { print "$host\n"; } exit; } ############################################################################## # # help -> # display help information # side effect: exits program # ############################################################################## sub help { print "Usage: $PROG [Input Type] [General Options] Input Type: -s --scan Ping Target Range ex: 10.0.0.\\* Scan Options: -n --nmap Path to Nmap executable --inter Perform Nmap Scan using non default interface General Options: -v --version Display version -h --help Display this information Send Comments to Joshua D. Abraham ( jabra\@ccs.neu.edu )\n"; exit; } sub print_version { print "$PROG version $VERSION by $AUTH\n"; exit; } ############################################################################## GetOptions( \%options, 'scan|s=s', 'nmap|n=s', 'inter=s', 'help|h' => sub { help(); }, 'version|v' => sub { print_version(); }, ) or exit 1; if ( $options{'nmap'} ) { if ( -X $options{'nmap'} ) { $nmapPath = $options{'nmap'}; } else { print $options{'nmap'} . " isn't executable using $nmapPath\n"; } } if ( $options{'scan'} ) { my $ipRange; if ( $options{'scan'} =~ /(\d{1,3})\.(\d{1,3}|\*)\.(\d{1,3}|\*)\.(0\/\d{1,2}|\d{1,3}|\*|'*')/ ) { $ipRange = $options{'scan'}; $type = 'scan'; } else { print "scan is $options{'scan'}"; } push( @ipRange, $ipRange ); } if ( $options{'inter'} ) { $interface = "-e " . $options{'interface'} . " "; $args = $args . $interface; } # make sure something is passed help() if ( $type ne 'scan' ); scan(); pbnj-2.04/AUTHORS0000600000175000017500000000007110523541634012351 0ustar jabrajabraAuthor of PBNJ Joshua D. Abraham - jabra@ccs.neu.edu pbnj-2.04/README0000600000175000017500000001300110526514535012161 0ustar jabrajabraPBNJ Version 2.04 by Joshua D. Abraham ( http://pbnj.sf.net ) ******************************************************************** COPYRIGHT Copyright(C) 2005 - 2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ******************************************************************** PBNJ - a suite of tools to monitor changes on a network. OVERVIEW PBNJ is a network suite to monitor changes that occur on a network over time. It does this by checking for changes on the target machine(s), which includes the details about the services running on them as well as the service state. PBNJ parses the data from a scan and stores it in a database. PBNJ uses Nmap to perform scans. It should be noted that when performing a scan using PBNJ will be detected by an IDS, which will alert the Network Admin that a scan is being performed. WHAT IS NEW IN VERSION 2.0 The PBNJ 2.0 is completely different from PBNJ 1.0. The most drastic change is that PBNJ 2.0 stores the information from a scan in database. It also has queries that can extract the information that is most useful to the user. When the user wants to extract information, PBNJ extracts the information into a Perl data structure, so there can be multiple output methods such as tab, csv and html. PBNJ 2.0 can also accept input from Nmap in XML format. This allows PBNJ to be more flexbile than version 1.0. PROGRAMS PBNJ include 2 main programs, ScanPBNJ and OutputPBNJ. It also includes a program called Genlist. ScanPBNJ - a program for running Nmap scans and storing the results in a PBNJ 2.0 database. OutputPBNJ - a program to query a PBNJ 2.0 database. Genlist - ping scanner FILES PBNJ's data files are stored in ScanPBNJ and OutputPBNJ. When either of these programs is run the configuration files will be generated for the user if they don't already exists and placed in the $HOME/.pbnj-2.0 directory. Again, if there is a configuration file in the current directory it is used instead of the version in the configuration directory. $HOME/.pbnj-2.0/config.yaml - holds settings for connecting to the database which store the information from PBNJ scans. $HOME/.pbnj-2.0/query.yaml - lists all queries that can be used to retrieve information from the database. Also, includes the name and description for each query. This is only generated when you executed OutputPBNJ. For Windows, the pbnj-2.0 config directory is in the APPDATA directory, which contains both config.yaml and query.yaml. Depending on your environment, the APPDATA directory may be a different location from other environments. Therefore, when the configs are executed for the first time they will display the path where the configs were generated. FEATURE REQUESTS Any feature requests should be reported to the online feature-request-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774489 Before requesting a feature, please check to see if the features has already been requested. BUG REPORTS Any bugs found should be reported to the online bug-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488. Before reporting bugs, please check to see if the bug has already been reported. When reporting PBNJ bugs, it is important to include a reliable way to reproduce the bug, version number of PBNJ and Nmap, OS name and version, and any relevant hardware specs. And of course, patches to rectify the bug are even better. SUPPORTED DATABASES The following databases are supported: * SQLite [default] * MySQL * Postgres * CSV To use any of the alternative database simply change the config.yaml to the configuration that you want. DATABASE SCHEMA The following is the SQLite database schema: CREATE TABLE machines ( mid INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT, host TEXT, localh INTEGER, os TEXT, machine_created TEXT, created_on TEXT); CREATE TABLE services ( mid INTEGER, service TEXT, state TEXT, port INTEGER, protocol TEXT, version TEXT, banner TEXT, machine_updated TEXT, updated_on TEXT); MAN PAGES Man pages are available for each program. Also, there are versions in html in the docs directory. Let me know what you think. Joshua D. Abraham (jabra@ccs.neu.edu) pbnj-2.04/docs/0000700000175000017500000000000010523541605012227 5ustar jabrajabrapbnj-2.04/docs/outputpbnj-man.html0000700000175000017500000003522710526513742016120 0ustar jabrajabraContent-type: text/html Man page of OUTPUTPBNJ.MAN.1

OUTPUTPBNJ.MAN.1

Section: User Contributed Perl Documentation (1)
Updated: 2006-11-06
Index Return to Main Contents
 

NAME

 OutputPBNJ - a program to query a PBNJ 2.0 database.

 

SYNOPSIS

 outputpbnj [Query Options] [Database Options] [General Options]

 

DESCRIPTION

 OutputPBNJ uses a query yaml config file to execute queries against 
 the PBNJ 2.0 database. OutputPBNJ returns the result in various 
 output types (csv, tab and html).

 Apart of PBNJ 2.0 suite of tools to monitor changes on a network.

 

OPTIONS

 Usage: outputpbnj [Query Options] [Config Options] [General Options]
 Query Options:
   -q  --query <name>     Perform sql query
   -t  --type <type>      Output Type [csv,tab,html]
   -f  --file <file>      Store the result in file otherwise stdout
       --both             Print results and store them in a file
       --dir <dir>        Store the result in this directory [def .]

   -l  --lookup <name>    Lookup description based on name
       --list             List of names and descriptions
   -n  --name             Lookup all the names
   -d  --desc             Lookup all the descriptions
   -s  --sql              Lookup all the sql queries

 Config Options:
        --qconfig <file>  Config of sql queries [def query.yaml]
        --dbconfig <file> Config for accessing database [def config.yaml]        
        --dbdir <dir>     Directory for Config file [def .]

        --data <file>     SQLite Database override [def data.dbl]

 General Options:
       --test <level>     Test Level
       --debug <level>    Verbose information
   -v  --version          Display version
   -h  --help             Display this information

 Send Comments to Joshua D. Abraham ( jabra@ccs.neu.edu )

 

THINGS TO NOTE

 * OutputPBNJ requires root privileges to query a database that is
 owned by root. Thus, if you are scanning with ScanPBNJ you will need
 to run OutputPBNJ with root privileges to access the database.

 * If there are configs in the current directory, they are used
 instead of those in the user's config directory.

 

Query Options

 

-q --query <name> Perform sql query

 This option is where the actual query is specified. Therefore, once
 you know the query you wish to use simply pass it as an argument to
 this option.

 

-t --type <type> Output Type [csv,tab,html]

 This options is used to specify which output format you wish to use.
 For example, if you would like to have output that you can show
 someone else the CSV format is useful because you can simply pull the
 file into OpenOffice Calc or Excel as it is a comma delimited file.

 

-f --file <file>

 This option is used to specifiy output to a file rather than standard
 output. This is useful if you want to grow the results of queries as
 the result will be added onto the end of the file.

 

--both

 This option is used when you want both output to standard output, as
 well as to a file. This will save the result to a file if you are
 having the result sent to the screen or piped to your email which you
 may or may not disregard.

 

--dir <dir> Store the result in this directory [default .]

 This option is used with the writing to a file. This option will
 store the file in a alternative directory than the current directory.

 

-l --lookup <name>

 This options is used to lookup the description of a specific query.
 This will return the description of the query.

 

--list List of names and descriptions

 This option is used to return a list of all the queries with the
 names and descriptions. This is very useful when you are starting to
 use OutputPBNJ or using a new query config.

 

-n --name

 This option is used to print the all the query names.

 

-d --desc

 This option is used to print the all the query descriptions. This is 
 useful to find out all the queries do.

 

-s --sql

 This option is used to print the all the queries. This is useful for 
 developing new queries based on other queries.

 

Config Options

 

--qconfig <file>

 Config of sql queries [default query.yaml]

 This option is used to specify an alternative query.yaml file.

 

--dbconfig <file>

 Config for accessing results database [default config.yaml]

 This option is used to specify an alternative config.yaml file.

 

--dbdir <dir>

 Directory for Config file [default .]

 This option is used to specify an alternative directory for the
 config.yaml file.

 

GENERAL OPTIONS

 

--test <level>

 Increases the Test level, causing OutputPBNJ to print testing
 information about the Query. Using the Test level is mostly only
 using for testing. This will also print the debugging information so
 it can get rather lengthy. The greater the Test level the more output
 will be given.

 This option is also used for reporting bugs. All bug reports should
 be submitted using --test 1 and an additional report may be needed
 depending on the issue

 

--debug <level>

 Increases the Debug level, causing OutputPBNJ to print more
 information about the query in progress. The higher the debug leve
 the more output the user will receive.

 

-v --version

 Prints the OutputPBNJ version number and exits.

 

-h --help Display this information

 Prints a help screen with the command flags.
 Running OutputPBNJ without any arguments does the same thing.

 

FILES

 PBNJ's data files are stored in ScanPBNJ and OutputPBNJ. When either
 of these programs is run the configuration files will be generated
 for the user if they do not already exists and placed in the
 $HOME/.pbnj-2.0 directory. Again, if there is a configuration file in
 the current directory it is used instead of the version in the
 configuration directory.

 $HOME/.pbnj-2.0/config.yaml - holds settings for connecting to the
 database which store the information from PBNJ scans.

 $HOME/.pbnj-2.0/query.yaml - lists all queries that can be used to
 retrieve information from the database. Also, includes the name and
 description for each query. This is only generated when you executed
 OutputPBNJ.

 For Windows, the pbnj-2.0 config directory is in the APPDATA
 directory, which contains both config.yaml and query.yaml. Depending
 on your environment, the APPDATA directory may be a different location
 from other environments. Therefore, when the configs are executed for
 the first time they will display the path where the configs were 
 generated.

 

QUERY

 The query.yaml file contains the list of various names, descriptions
 and sql queries that can be executed by OutputPBNJ.

 Here is one example:

 - name: vulnssh
   desc: list all of the services that have old ssh running
   sql: |-
    select S.updated_on,M.ip,S.service,S.port,S.version from services
    as S, machines as M where service='ssh' and state='up' and
    version!='4.1p1'

 This examples shows how the name, description and sql are layed out in
 the yaml format. Therefore, we know the name of the query is vulnssh
 and it's purpose is to list SSH servers which are not running
 a version 4.1p1. It is very easy to create another script that would
 check for the latest version of a given service and therefore the
 user would be able to verify that that particular service needed to
 be updated on the machine that was scanned.

 

FEATURE REQUESTS

 Any feature requests should be reported to the online
 feature-request-tracking system available on the web at: 
 http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774489
 Before requesting a feature, please check to see if the features has
 already been requested.

 

BUG REPORTS

 Any bugs found should be reported to the online bug-tracking system 
 available on the web at :  
 http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488.  
 Before reporting bugs, please check to see if the bug has already been
 reported.

 When reporting PBNJ bugs, it is important to include a reliable way
 to reproduce the bug, version number of PBNJ and Nmap, OS
 name and version, and any relevant hardware specs. And of course,
 patches to rectify the bug are even better.

 

SUPPORTED DATABASES

 The following databases are supported:

 * SQLite [default]
 * MySQL
 * Postgres
 * CSV

 

DATABASE SCHEMA

 The following is the SQLite version of the database schema:

 CREATE TABLE machines (
            mid INTEGER PRIMARY KEY AUTOINCREMENT,
            ip TEXT,
            host TEXT,
            localh INTEGER,
            os TEXT,
            machine_created TEXT,
            created_on TEXT);
 CREATE TABLE services (
            mid INTEGER,
            service TEXT,
            state TEXT,
            port INTEGER,
            protocol TEXT,
            version TEXT,
            banner TEXT,
            machine_updated TEXT,
            updated_on TEXT);

 

SEE ALSO

 scanpbnj(1), genlist(1), nmap(1)

 

AUTHORS

 Joshua D. Abraham ( jabra@ccs.neu.edu )

 

LEGAL NOTICES

 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 at
 http://www.gnu.org/copyleft/gpl.html, or in the COPYING file included
 with PBNJ.

 It should also be noted that PBNJ has occasionally been known to crash
 poorly written applications, TCP/IP stacks, and even operating systems.
 While this is extremely rare, it is important to keep in mind.  PBNJ
 should never be run against mission critical systems unless you are
 prepared to suffer downtime. We acknowledge here that PBNJ may crash
 your systems or networks and we disclaim all liability for any damage
 or problems PBNJ could cause.


 

Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
THINGS TO NOTE
Query Options
-q --query <name> Perform sql query
-t --type <type> Output Type [csv,tab,html]
-f --file <file>
--both
--dir <dir> Store the result in this directory [default .]
-l --lookup <name>
--list List of names and descriptions
-n --name
-d --desc
-s --sql
Config Options
--qconfig <file>
--dbconfig <file>
--dbdir <dir>
GENERAL OPTIONS
--test <level>
--debug <level>
-v --version
-h --help Display this information
FILES
QUERY
FEATURE REQUESTS
BUG REPORTS
SUPPORTED DATABASES
DATABASE SCHEMA
SEE ALSO
AUTHORS
LEGAL NOTICES

This document was created by man2html, using the manual pages.
Time: 04:30:26 GMT, November 15, 2006 pbnj-2.04/docs/scanpbnj-man.html0000700000175000017500000005322110526514016015471 0ustar jabrajabraContent-type: text/html Man page of SCANPBNJ.MAN.1

SCANPBNJ.MAN.1

Section: User Contributed Perl Documentation (1)
Updated: 2006-11-14
Index Return to Main Contents
 

NAME

 ScanPBNJ - a program for running Nmap scans and storing the results in 
 a PBNJ 2.0 database.

 

SYNOPSIS

 scanpbnj [Options] {target specification}

 

DESCRIPTION

 ScanPBNJ performs an Nmap scan and then stores the results in
 a database. The ScanPBNJ stores information about the machine that has
 been scanned. ScanPBNJ stores the IP Address, Operating System,
 Hostname and a localhost bit. The localhost bit, is simply a single
 bit which is 1 when the target machine is localhost, otherwise it is
 0. It also stores two timestamps for the machine table. The first is
 a human readable version and the second is the unix time. Both of
 these timestamp correspond to the first time that the machine was
 scanned.

 ScanPBNJ stores information about the services that are found to be
 running on the target machine. ScanPBNJ stores typical information
 about the service, by storing the port and protocol. Also, ScanPBNJ
 stores version, product and service state information about each
 service. The service state can either be up or down. Two timestamps 
 are also inserted for each instance of every service. The first is a 
 human readable version and the second is the unix time. Both of 
 these timestamp correspond to the time that the service was scanned.

 This tool can give an admin a clear network layout with of
 all the machines with all the services they are running.

 Apart of PBNJ 2.0 suite of tools to monitor changes on a network.

 

OPTIONS

 Usage: scanpbnj [Options] {target specification}

 Target Specification:
   Can be a IP Address, hostname, network etc.
   Ex: microsoft.com, 10.0.0.0/24, 192.168.1.1, 10.0.0.0-100
   -i  --iplist <iplist>    Scan using a list of IPs from a file
   -x  --xml <xml-file>     Parse scan/info from Nmap XML file

 Scan Options:
   -a  --args <args>        Execute Nmap with args (needs quotes)
   -e  --extraargs <args>   Add args to the default args (needs quotes)
       --inter <interface>  Perform scan with non default interface
   -m  --moreports <ports>  Add ports to scan ex: 8080 or 3306,5900-5910
   -n  --nmap <path>        Path to Nmap executable 
   -p  --pingscan           Ping Target then scan the alive host(s)
       --udp                Add UDP to the scan arguments
       --rpc                Add RPC to the scan arguments
   -r  --range <range>      Ports for scan [def 1-1025]

        --diffbanner        Parse changes of the banner

 Config Options:
  -d    --dbconfig <config> Config for results database [def config.yaml]
        --configdir <dir>   Directory for the database config file

        --data <file>       SQLite Database override [def data.dbl]
        --dir <dir>         Directory for SQLite or CSV files [def .]

 General Options:
       --nocolors           Don't Print Colors
       --test <level>       Testing information
       --debug <level>      Debug information 
   -v  --version            Display version
   -h  --help               Display this information

 Send Comments to Joshua D. Abraham ( jabra@ccs.neu.edu )

 

THINGS TO NOTE

 * ScanPBNJ requires root privileges to perform a scan.

 * If you do not pass a specific ports range, 1-1025 is used.

 * If there are configs in the current directory, they are used 
 instead of those in the user's config directory.

 * ScanPBNJ does not modify previous database entries. It simply
 inserts new information when a change is found.

 * One thing that should be done when performing scans is to make
 sure to use the same ports or you will get false positives.

 

EXAMPLE SINGLE SCAN

 1) Scan a class B network on ports 1-9000

     sudo ./scanpbnj -r 1-9000 10.0.0.0/16

 2) Scan an IP Address on ports 1-9000

     sudo ./scanpbnj -r 1-9000 10.0.0.100

 

EXAMPLE AUTOMATED SCANS

 The following examples can be added to /etc/crontab

 1) Scan a Class C network every 2 hours

 30 */2 * * *   root scanpbnj 10.0.0.\*

 2) Scan a Class C network everyday at 2:30

 30 2 * * *     root scanpbnj 10.0.0.\*

 

TARGET SPECIFICATION

 The target specified is a typical method of probing the network. 
 Therefore, any of the following can be used:
 (e.g. 10.0.0.1, 10.0.0.1-254, 10.0.0.0/24 or 10.0.0.\* ). 
 The first example is simply an IP address. The second example is 
 the scanning of a range. The third is a range in CIDR notation. 
 The fourth example is the IP with the star which specifies to scan 
 255 hosts. This is the same format that Nmap uses with the only 
 exception being the \* on the last octet. This is needed because it 
 needs to not interpret the star when it is being executed.

 Another option, is to use a hostname or domain name. ScanPBNJ will 
 then resolve the name to the correct IP address. If you pass a 
 debug flag with level 1 or greater, ScanPBNJ will display what IP 
 address, the hostname resolved too.

 

-i <iplist> Scan using a list of IPs from a file

 The iplist option is useful when you have a specific list of IPs to
 scan. This will perform a full scan of the IPs that are specified. 
 This option is similar to using -sL with Nmap. The results of
 the scan are inserted into the database.

 

-x <xml-file> Parse scan/info from Nmap XML file

 This option is useful when you can't perform the scan yourself or 
 you don't want ScanPBNJ to perform the scan. Another situation where 
 this is useful, is if you have an XML file that was done in the past 
 and you want to extract information from it, possibly to compare 
 with what is currently being run on the target. ScanPBNJ parses the 
 Nmap XML file and extracts the information about the host(s) and 
 service(s) then inserts the results into the database.

 

SCAN OPTIONS

 

-a --args <args>

 ** NOTE ** This option needs quotes around the passed arguments

 This option will bypass the default arguments that are used in
 scanning with Nmap. This can be used to do a particular type of scan
 that is not possible by simply adding extra arguments. For example,
 if you want to only scan UDP ports and still do version
 identification and OS detection, you would do so using the following
 notation:

  sudo scapbnj -a "-A -O -sU"  localhost

 

-e --extraargs <args>

 ** NOTE ** This option needs quotes around the passed arguments

 This option will add additional arguments onto the default scan 
 arguments. This is most useful in doing scans where time optimization 
 is needed. Therefore, these arguments will be added and then used in 
 the scan.

 

--inter <intface>

 This option sets an alternative interface for performing the scan. 
 This is useful when you have multiple interfaces on a machine 
 with restrictions on which devices can access certain IP or IP ranges.

 

-m --moreports <ports>

 This options adds additional ports to the range of ports to scan.
 Individual port numbers are OK, as are ranges separated by a
 hyphen (e.g. 1-1023,5800,5900,8080).

 For example:

  sudo scanpbnj -m 7000-7500,8080  localhost

 This scan would scan the default range as well 7000-7500 and 8080.

 

-n --nmap <alternative-nmap-path>

 Use an alternative Nmap rather than Nmap located in the your path.  
 This is useful if you have multiple version of Nmap installed on
 a system or if you are testing a new version of Nmap. Remember that if
 you are using a newly compiled version of Nmap that you need to 
 export NMAPDIR to the location that Nmap was compiled in. Thus, if
 you have compiled Nmap in your homedir, use the following notation:

  export NMAPDIR=$HOME/nmap-VERSION/

  sudo scanpbnj -n $HOME/nmap-VERISON/ localhost

 

-p Ping Target then scan the host(s) that are alive

 The ping scan is a useful method of only scanning the host that are
 responding to ICMP echo requests. This scan basically takes the host
 that respond to ICMP echo requests and then performs a scan only on
 those hosts. Therefore, no time is wasted in scanning hosts that do
 not respond. The results of the scan are then inserted into the 
 database.

 

--udp Add UDP to the scan arguments

 Perform a UDP scan, in addition to the default scan.

  sudo scanpbnj --udp localhost

 If you want to only perform a UDP scan you need to set the specific
 arguments for the scan.

  sudo scanpbnj -a "-vv -O -P0 1-1025 -sVU" localhost

 

--rpc Add RPC to the scan arguments

 Perform a RPC scan in addition to the default scan.

  sudo scanpbnj --udp localhost

 If you want to only perform a RPC scan you need to set the specific
 arguments for the scan.

  sudo scanpbnj -a "-vv -O -P0 1-1025 -sVR" localhost

 

-r --range <ports>

 Ports for scan [default 1-1025]

 This option specifies which ports you want to scan and overrides the
 default. Individual port numbers are OK, as are ranges separated by a
 hyphen (e.g. 1-1023,5800,5900,8080 ).

 Thus, a scan like this is ok.

  sudo scanpbnj -r 22,25,80,100-200  localhost

 Also, if you have leave off the number after the hyphen it will scan
 all from the start port to 65535.

 For example:

  sudo scanpbnj -r 22,25- localhost

 

--diffbanner

 Parse changes of the banner

 This options enables ScanPBNJ to do comparisons on the banner. The
 reason this is not on by default is that it could show changes in
 services that are not are important to the user. However, this option
 is useful to a security professional who is looking for any changes
 that occur so that they can be verified.

 

DATABASE OPTIONS

 

-d --dbconfig <file>

 Config for results database [default config.yaml]

 This option is used to specify an alternative config.yaml file.

 

--configdir <dir>

 Directory for Config file [default . ]

 This option is used to specify an alternative directory for the 
 config.yaml file.

 

--data <file>

 SQLite Database override [default data.dbl ]

 This option is used when you want to change the name of the SQLite
 database file that is generated.

 

--dir <dir>

 Directory for SQLite or CSV files [default . ]

 This option is used when you want the database to be generated in a
 different directory.

 

GENERAL OPTIONS

 

--nocolors

 The default results from ScanPBNJ print the useful changes with colors 
 This options will simply not print the colors.

 

--test <level>

 Increases the Test level, causing ScanPBNJ to print testing information 
 about the scan in progress. Using the Test level is mostly only using 
 for testing. This will also print the debugging information so it can 
 get rather lengthy. The greater the Test level the more output will be 
 given.

 This option is also used for reporting bugs. All bug reports should
 be submitted using --test 1 and an additional report may be needed 
 depending on the issue.

 

--debug <level>

 Increases the Debug level, causing ScanPBNJ to print more information 
 about the scan in progress. Nmap scanning arguments are shown as well 
 as the ip address if you are scanning a domain name. This option is 
 used to give the user more information about what the scanner is doing. 
 The higher the debug level the more output the user will receive.

 

-v --version

 Prints the ScanPBNJ version number and exits.

 

-h --help

 Prints a short help screen with the command flags.  Running ScanPBNJ
 without any arguments does the same thing.

 

DEFAULT SCAN

 Here are the default arguments that are used during a default scan:

 -vv -O -P0 -sSV -p 1-1025

 

FILES

 PBNJ's data files are stored in ScanPBNJ and OutputPBNJ. When either
 of these programs is run the configuration files will be generated
 for the user if they don't already exists and placed in the
 $HOME/.pbnj-2.0 directory. Again, if there is a configuration file 
 in the current directory it is used instead of the version in the
 configuration directory.

 $HOME/.pbnj-2.0/config.yaml - holds settings for connecting to
 the database which store the information from PBNJ scans.

 $HOME/.pbnj-2.0/query.yaml - lists all queries that can be used to
 retrieve information from the database. Also, includes the name and
 description for each query. This is only generated when you executed
 OutputPBNJ.

 For Windows, the pbnj-2.0 config directory is in the APPDATA
 directory, which contains both config.yaml and query.yaml. Depending
 on your environment, the APPDATA directory may be a different location
 from other environments. Therefore, when the configs are executed for
 the first time they will display the path where the configs were 
 generated.

 

FEATURE REQUESTS

 Any feature requests should be reported to the online 
 feature-request-tracking system available on the web at :  
 http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774489
 Before requesting a feature, please check to see if the features has 
 already been requested.

 

BUG REPORTS

 Any bugs found should be reported to the online bug-tracking system
 available on the web at : 
 http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488.  
 Before reporting a bug, please check to see if the bug has already been
 reported.

 When reporting PBNJ bugs, it is important to include a reliable way to
 reproduce the bug, version number of PBNJ and Nmap, OS  
 name and version, and any relevant hardware specs. And of course, 
 patches to rectify the bug are even better.

 

SUPPORTED DATABASES

 The following databases are supported:

 * SQLite [default]
 * MySQL 
 * Postgres
 * CSV

 

DATABASE SCHEMA

 The following is the SQLite version of the database schema:

 CREATE TABLE machines (
            mid INTEGER PRIMARY KEY AUTOINCREMENT,
            ip TEXT,
            host TEXT,
            localh INTEGER,
            os TEXT,
            machine_created TEXT,
            created_on TEXT);
 CREATE TABLE services (
            mid INTEGER,
            service TEXT,
            state TEXT,
            port INTEGER,
            protocol TEXT,
            version TEXT,
            banner TEXT,
            machine_updated TEXT,
            updated_on TEXT);

 

SEE ALSO

 outputpbnj(1), genlist(1), nmap(1)

 

AUTHORS

 Joshua D. Abraham ( jabra@ccs.neu.edu )

 

LEGAL NOTICES

 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 at
 http://www.gnu.org/copyleft/gpl.html, or in the COPYING file included
 with PBNJ.

 It should also be noted that PBNJ has occasionally been known to
 crash poorly written applications, TCP/IP stacks, and even operating
 systems.  While this is extremely rare, it is important to keep in
 mind.  PBNJ should never be run against mission critical systems
 unless you are prepared to suffer downtime. We acknowledge here that
 PBNJ may crash your systems or networks and we disclaim all liability
 for any damage or problems PBNJ could cause.


 

Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
THINGS TO NOTE
EXAMPLE SINGLE SCAN
EXAMPLE AUTOMATED SCANS
TARGET SPECIFICATION
-i <iplist> Scan using a list of IPs from a file
-x <xml-file> Parse scan/info from Nmap XML file
SCAN OPTIONS
-a --args <args>
-e --extraargs <args>
--inter <intface>
-m --moreports <ports>
-n --nmap <alternative-nmap-path>
-p Ping Target then scan the host(s) that are alive
--udp Add UDP to the scan arguments
--rpc Add RPC to the scan arguments
-r --range <ports>
--diffbanner
DATABASE OPTIONS
-d --dbconfig <file>
--configdir <dir>
--data <file>
--dir <dir>
GENERAL OPTIONS
--nocolors
--test <level>
--debug <level>
-v --version
-h --help
DEFAULT SCAN
FILES
FEATURE REQUESTS
BUG REPORTS
SUPPORTED DATABASES
DATABASE SCHEMA
SEE ALSO
AUTHORS
LEGAL NOTICES

This document was created by man2html, using the manual pages.
Time: 04:31:10 GMT, November 15, 2006 pbnj-2.04/docs/genlist-man.html0000700000175000017500000001653110526514042015342 0ustar jabrajabraContent-type: text/html Man page of GENLIST.MAN.1

GENLIST.MAN.1

Section: User Contributed Perl Documentation (1)
Updated: 2006-11-06
Index Return to Main Contents
 

NAME

 Genlist - ping scanner

 

SYNOPSIS

 genlist [Input Type] [Scan Options] [General Options]

 

DESCRIPTION

 Genlist is a program that returns a list of hosts that responding 
 to ping probes. Thus, this list can be used to perform an scan of 
 these machines using PBNJ or Nmap.

 Apart of PBNJ 2.0 suite of tools to monitor changes on a network.

 

OPTIONS

 Usage: genlist [Input Type] [General Options]
 Input Type:
   -s  --scan <target>      Ping Target Range ex: 10.0.0.\*

 Scan Options:
   -n  --nmap <path>        Path to Nmap executable 
       --inter <interface>  Perform scan using non default interface

 General Options:
   -v  --version            Display version
   -h  --help               Display this information

 Send Comments to Joshua D. Abraham ( jabra@ccs.neu.edu )

 

EXAMPLE OF GENLIST USED WITH PBNJ

 $ ./genlist -s 10.0.0.\* > iplist

 $ sudo ./scanpbnj -i iplist

 

EXAMPLE OF GENLIST USED WITH NMAP

 $ ./genlist -s 10.0.0.\* > iplist

 $ sudo ./nmap -iL iplist

 

INPUT TYPE

 

-s <target> Ping Target Range ex: 10.0.0.*

 The ping scan is a useful method of only scanning the host that are 
 responding to ICMP echo requests. This scan basically takes the host 
 that respond to ping and prints them. This is useful in combining 
 the result with a PBNJ or Nmap scan because no time is wasted in 
 scanning hosts that do not respond.

 

SCAN OPTIONS

 

--interface <intface>

 This option sets an alternative interface for performing the scan.
 This is useful when you have multiple interfaces on a machine
 with restrictions on which devices can access certain IP ranges.

 

-n --nmap <path>

 Use an alternative Nmap rather than Nmap located in the your  path. 
 This is useful if you have multiple version of Nmap installed on
 a system or if you are testing a new version of Nmap. Remember that if
 you are using a newly compiled version of Nmap that you need to 
 export NMAPDIR to the location that Nmap was compiled in. Thus, if
 you have compiled Nmap in your homedir, use the following notation to
 run it with Genlist:

 $ export NMAPDIR=$HOME/nmap-VERSION/

 $ sudo genlist -s 10.0.0.\* --nmap $HOME/nmap-VERISON/

 

General Options:

 

-v --version

 Prints the Genlist version number and exits.

 

-h --help Display this information

 Prints a short help screen with the most common command flags.
 Running Genlist without any arguments does the same thing.

 

FEATURE REQUESTS

 Any feature requests should be reported to the online
 feature-request-tracking system available on the web at :
 http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774489
 Before requesting a feature, please check to see if the features has
 already been requested.

 

BUG REPORTS

 Any bugs found should be reported to the online bug-tracking system
 available on the web at :
 http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488.
 Before reporting bugs, please check to see if the bug has already been
 reported.

 When reporting PBNJ bugs, it is important to include a reliable way to
 reproduce the bug, version number of PBNJ and Nmap, OS
 name and version, and any relevant hardware specs. And of course,
 patches to rectify the bug are even better.

 

SEE ALSO

 scanpbnj(1) outputpbnj(1), nmap(1)

 

AUTHORS

 Joshua D. Abraham ( jabra@ccs.neu.edu )

 

LEGAL NOTICES

 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 at
 http://www.gnu.org/copyleft/gpl.html, or in the COPYING file included
 with PBNJ.

 It should also be noted that PBNJ has occasionally been known to crash
 poorly written applications, TCP/IP stacks, and even operating systems.
 While this is extremely rare, it is important to keep in mind.  PBNJ
 should never be run against mission critical systems unless you are
 prepared to suffer downtime. We acknowledge here that PBNJ may crash
 your systems or networks and we disclaim all liability for any damage
 or problems PBNJ could cause.


 

Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
EXAMPLE OF GENLIST USED WITH PBNJ
EXAMPLE OF GENLIST USED WITH NMAP
INPUT TYPE
-s <target> Ping Target Range ex: 10.0.0.*
SCAN OPTIONS
--interface <intface>
-n --nmap <path>
General Options:
-v --version
-h --help Display this information
FEATURE REQUESTS
BUG REPORTS
SEE ALSO
AUTHORS
LEGAL NOTICES

This document was created by man2html, using the manual pages.
Time: 04:31:30 GMT, November 15, 2006 pbnj-2.04/outputpbnj0000700000175000017500000010262610526513046013447 0ustar jabrajabra#!/usr/bin/perl # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This program is released under the terms of the GNU General Public License # (GPL), which is distributed with this software in the file "COPYING". # The GPL specifies the terms under which users may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # # OutputPBNJ - a program to query a PBNJ 2.0 database. # use strict; use warnings; use Shell; use YAML; use DBI; use Getopt::Long; use Text::CSV_XS; use FileHandle; use File::HomeDir; use vars qw( $PROG ); ( $PROG = $0 ) =~ s/^.*[\/\\]//; # Truncate calling path from the prog name my $AUTH = 'Joshua D. Abraham'; # author my $VERSION = '2.04'; # version my $type = 'tab'; # default output format my $output = 'stdout'; # default output my $bothOutput = 0; # use both output methods my $query = 'query.yaml'; # yaml configureation file my $data; # store the contents of yaml config my $result; # result of sql query my %options; # getopts hash my $header = 0; # print column headers my $dbh; # database connection my $dbconfig = 'config.yaml'; # database config my $database; # database file my $db; # db backend my $hostname; # db host ip my $port; # db port my $user; # db username my $passwd; # db password my $dbdir = "."; # output database directory my $dir = "."; # output database directory my $datadb; # db $options{test} = 0; # testing flag $options{debug} = 0; # debug flag my $configdir; #chown() that reports errors sub safe_chown { my $uid = shift; my $gid = shift; my $file = shift; if ( chown( $uid, $gid, $file ) != 1 ) { error( 'Unable to change the owner of the file ' . $file . '.' . "\n\n" ); } } if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { require Win32; import Win32; Win32->import(qw(CSIDL_APPDATA)); my $dir = Win32::GetFolderPath( CSIDL_APPDATA() ); $configdir = $dir . "\\" . "pbnj-2.0"; if ( -e $configdir and -d $configdir ) { #print "$configdir exists\n"; } else { mkdir $configdir; print "mkdir $configdir\n"; } # check if config exists in the current directory if ( !-e $dbconfig ) { $dbconfig = "$configdir\\$dbconfig"; } my ( $read_config, $read_query ); # check if the config exists in ~/.pbnj-2.0/config.yaml if ( !-e $dbconfig ) { $read_config = 0; } else { # print "config exists\n"; $read_config = 2; } if ( !-e $query ) { $query = "$configdir\\$query"; } if ( !-e $query ) { $read_query = 0; } else { # print "query exists\n"; $read_query = 2; } my @array; while () { push( @array, $_ ); } #print "query is $read_query and config is $read_config\n"; if ( $read_query != 2 or $read_config != 2 ) { if ( $read_config == 0 ) { open( CONFIG, ">$dbconfig" ); foreach (@array) { last if (/Query.yaml/); if ( defined($_) ) { print CONFIG $_; } } close(CONFIG); print "$dbconfig generated\n"; } if ( $read_query == 0 ) { open( QUERY, ">$query" ); my $config = 2; foreach (@array) { $config = 0 if (/Query.yaml/); if ( defined($_) and $config == 0 ) { print QUERY $_; } } close(QUERY); print "$query generated\n"; } } } else { $configdir = File::HomeDir->my_home; my $tmpuser = $configdir; $tmpuser =~ s/home//; $tmpuser =~ s/\///g; my $uid = getpwnam($tmpuser); my $gid = id("-g $tmpuser"); if ( !defined($gid) ) { error("gid not defined\n"); } if ( !defined($uid) ) { error("uid not defined\n"); } $configdir .= "/.pbnj-2.0"; if ( -e $configdir and -d $configdir ) { #print "$configdir exists\n"; } else { umask 077; mkdir $configdir; print "mkdir $configdir\n"; safe_chown( $uid, $gid, $configdir ); } # check if config exists in the current directory if ( !-e $dbconfig ) { $dbconfig = "$configdir/$dbconfig"; } my ( $read_config, $read_query ); # check if the config exists in ~/.pbnj-2.0/config.yaml if ( !-e $dbconfig ) { $read_config = 0; } else { # print "config exists\n"; $read_config = 2; } if ( !-e $query ) { $query = "$configdir/$query"; } if ( !-e $query ) { $read_query = 0; } else { # print "query exists\n"; $read_query = 2; } my @array; while () { push( @array, $_ ); } #print "query is $read_query and config is $read_config\n"; if ( $read_query != 2 or $read_config != 2 ) { if ( $read_config == 0 ) { umask 077; open( CONFIG, ">$dbconfig" ); foreach (@array) { last if (/Query.yaml/); if ( defined($_) ) { print CONFIG $_; } } close(CONFIG); safe_chown( $uid, $gid, $dbconfig ); print "$dbconfig generated\n"; } if ( $read_query == 0 ) { umask 077; open( QUERY, ">$query" ); my $config = 2; foreach (@array) { $config = 0 if (/Query.yaml/); if ( defined($_) and $config == 0 ) { print QUERY $_; } } close(QUERY); safe_chown( $uid, $gid, $query ); print "$query generated\n"; } } } ############################################################################## # # help -> # display help information # side effect: exits program # ############################################################################## sub help { print "Usage: $PROG [Query Options] [Config Options] [General Options] Query Options: -q --query Perform sql query -t --type Output Type [csv,tab,html] -f --file Store the result in file otherwise stdout --both Print results and store them in a file --dir Store the result in this directory [def .] -l --lookup Lookup descrition based on name --list List of names and descriptions -n --name Lookup all the names -d --desc Lookup all the descriptions -s --sql Lookup all the sql queries Config Options: --qconfig Config of sql queries [def query.yaml] --dbconfig Config for accessing database [def config.yaml] --configdir Directory for the database config file --data SQLite Database override [def data.dbl] General Options: --test Testing information --debug Debug information -v --version Display version -h --help Display this information Send Comments to Joshua D. Abraham ( jabra\@ccs.neu.edu )\n"; exit; } ############################################################################## # # print_version -> # displays version # side effect: exits program # ############################################################################## sub print_version { print "$PROG version $VERSION by $AUTH\n"; exit; } ############################################################################## # # printName: array -> # print the names of the queries # side effect: exits program # # data yaml config contents # ############################################################################## sub printName { my $data = shift || die "printName data not defined"; print "Name of the Queries\n"; print "* * * * * * * * * * * * * * * * * * * * * * * * * * * \n"; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { if ( $key eq 'name' ) { print "- " . $$tmp{$key} . "\n"; } } } exit; } ############################################################################## # # printDesc # print the descriptions of the queries # side effect: exits program # # data yaml config contents # ############################################################################## sub printDesc { my $data = shift || die "printDesc: data not defined"; print "Description of the Queries\n"; print "* * * * * * * * * * * * * * * * * * * * * * * * * * * \n"; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { if ( $key eq 'desc' ) { print "- " . $$tmp{$key} . "\n"; } } } exit; } ############################################################################## # # printList # print the list of the queries name followed by description # side effect: exits program # # data yaml config contents # ############################################################################## sub printList { my $data = shift || die "printList: data not defined"; print "List of Name - Description of the Queries\n"; print "* * * * * * * * * * * * * * * * * * * * * * * * * * * \n"; my %line; my $i = 0; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { next if ( !defined( $$tmp{$key} ) ); $line{ $i++ }{name} = $$tmp{$key} if ( $key eq "name" ); $line{$i}{desc} = $$tmp{$key} if ( $key eq "desc" ); } } $i--; foreach ( 0 .. $i ) { next if ( !defined( $line{$_}{name} or !defined( $line{$_}{desc} ) ) ); print $line{$_}{name} . " - " . $line{$_}{desc} . "\n"; } exit; } ############################################################################## # # printSql # print the Sql of the queries # side effect: exits program # # data yaml config contents # ############################################################################## sub printSql { my $data = shift || die "printSql: data not defined"; print "Sql of the Queries\n"; print "* * * * * * * * * * * * * * * * * * * * * * * * * * * \n"; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { if ( $key eq 'sql' ) { print "- " . $$tmp{$key} . "\n"; } } } exit; } ############################################################################## # # lookupDescByName: anon hash # lookup description of the query based on the name # side effect: exits program # # data yaml config contents # name name of the query to lookup # ############################################################################## sub lookupDescByName { my ($href) = @_; die "lookupByName: data not defined" unless defined $href->{data}; die "lookupByName: name not defined" unless defined $href->{name}; my $data = $href->{data}; my $name = $href->{name}; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { if ( $key eq 'name' and $$tmp{$key} eq $name ) { print "Description for $name\n"; print "$$tmp{desc}\n"; exit; } } } print "Didn't find any descrition with the name $name\n"; exit 1; } ############################################################################## # lookupByDesc : anon hash -> # lookup description of query based on the decription # side effect: exits program # # data yaml config contents # desc descrition of the query to lookup # ############################################################################## sub lookupNameByDesc { my ($href) = @_; die "lookupByDesc: data not defined" unless defined $href->{data}; die "lookupByDesc: desc not defined" unless defined $href->{desc}; my $data = $href->{data}; my $desc = $href->{desc}; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { if ( $key eq 'desc' and $$tmp{$key} eq $desc ) { print "Name is $$tmp{name}\n"; exit; } } } print "didn't find any descrition with the name $desc\n"; exit 1; } ############################################################################## # # lookupSql: anon hash -> scalar # lookup sql based on the name # # data data from the yaml config file # name name of the query to lookup # ############################################################################## sub lookupSql { my ($href) = @_; die "lookupSqlByName: data not defined" unless defined $href->{data}; die "lookupSqlByName: name not defined" unless defined $href->{name}; my $data = $href->{data}; my $name = $href->{name}; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { if ( $key eq 'name' and $$tmp{$key} eq $name ) { my $sql = $$tmp{sql}; return $sql; } } } } ############################################################################## # # realName: anon hash -> scalar # determines if the name exists # # data data from the yaml config file # name name of the query to lookup # ############################################################################## sub realName { my ($href) = @_; die "realName: data not defined" unless defined $href->{data}; die "realName: name not defined" unless defined $href->{data}; my $data = $href->{data}; my $name = $href->{name}; foreach (@$data) { my $tmp = $_; foreach my $key ( keys %$tmp ) { if ( $key eq 'name' and $$tmp{$key} eq $name ) { return 1; } } } return 0; } ############################################################################## # # runSql: anon hash -> array ref # execute sql and return arrayref to the result # # data data for output # name name of sql query # db sqlite3 database file # # ############################################################################ sub runSql { my ($href) = @_; die "runSql: data not defined" unless defined $href->{data}; die "runSql: name not defined" unless defined $href->{name}; die "runSql: db not defined" unless defined $href->{db}; my $data = $href->{data}; my $name = $href->{name}; my $dbh = $href->{db}; my ( $exist, $sql ); $exist = realName( { data => $data, name => $name } ); if ( $exist eq 1 ) { $sql = lookupSql( { data => $data, name => $name } ); print "sql is $sql\n" if ( $options{debug} eq 1 or $options{test} eq 1 ); } else { print "Query $name does not exist the Query Config File\n"; exit 1; } my $sth = $dbh->prepare($sql); if (defined($sth)){ my $tmp = $sth->execute; return $sth; } else { print "Broken SQL Query\n"; exit 1; } exit; } # html output sub htmlOutput { my $output = shift; foreach (@$output) { foreach (@$_) { print "$_ "; } print "\n"; } print "\n"; } # tab output sub tabOutput { my $output = shift; foreach (@$output) { foreach (@$_) { print "$_\t"; } print "\n"; } print "\n"; } # csv output sub csvOutput { my $output = shift; foreach (@$output) { foreach (@$_) { print "$_,"; } print "\n"; } print "\n"; } ############################################################################## # # delimOutput: anon hash -> # output the results of a sql query using a delminatator # side effect: # # results the data for output # fileName contains the filename of the output or stdout # delim Delminator for the file (csv, tab, space) # # ############################################################################## sub delimOutput { my ($href) = @_; my ( $fh, @fields, $elements ); die "output: results not defined" unless defined $href->{results}; die "output: fileName not defined" unless defined $href->{fileName}; die "output: delim not defined" unless defined $href->{delim}; my $sth = $href->{results}; my $fileName = $href->{fileName}; my $delim = $href->{delim}; my $csv = Text::CSV_XS->new( { binary => 1 } ); my $row = $sth->fetchall_arrayref; if ( $fileName ne 'stdout' ) { $fh = new FileHandle(">>$fileName"); die "'$fileName': $!" unless defined $fh; } my $num_fields = $sth->{NUM_OF_FIELDS}; if (scalar(@$row) eq 0){ print "No Results from Query\n"; exit; } print "num of fields is $num_fields\n" if ( $options{test} eq 1 ); if ( ( $type eq 'csv' or $type eq 'html' ) and ( $header eq 1 ) ) { for ( 0 .. $num_fields ) { print "before column extraction\n" if ( $options{test} eq 1 ); my $column = $sth->{NAME_lc}->[$_]; print "after column extraction\n" if ( $options{test} eq 1 ); if ( defined($column) ) { print "column is $column\n" if ( $options{debug} eq 1 or $options{debug} eq 1 ); print $fh "$column" if ( $fileName ne 'stdout' ); print $fh "$delim" if ( $fileName ne 'stdout' && $_ < $num_fields - 1 ); print "$column" if ( $fileName eq 'stdout' or $bothOutput eq 1 ); print "$delim" if ( ( $fileName eq 'stdout' or $bothOutput eq 1 ) && $_ < ( $num_fields - 1 ) ); } else { print "column not defined" if ( $options{test} eq 1 ); } } print "\n" if ( $fileName eq 'stdout' ); print $fh "\n" if ( $fileName ne 'stdout' ); } my $rownum = 0; foreach (@$row) { my $result; foreach my $line (@$_) { if ( defined $result ) { $result = join( ',', $result, $line ); } else { $result = join( ',', $line ); } } if ( $csv->parse($result) ) { @fields = $csv->fields(); $elements = @fields; } if ( $type eq "tab" and $rownum eq 0 and $header eq 1 ) { for ( my $x = 0; $x < $elements; $x++ ) { print "before column extraction\n" if ( $options{test} eq 1 ); my $col = $sth->{NAME_lc}->[$x]; print "after column extraction\n" if ( $options{test} eq 1 ); if ( defined($col) ) { print "column is $col\n" if ( $options{test} eq 1 ); my $len = "%" . length( $fields[$x] ); my $tmp; if ( $fields[$x] =~ /\w/ ) { $tmp = 's'; } elsif ( $fields[$x] =~ /\d/ ) { $tmp = 'd'; } else { print "field is $fields[$x]" if ( $options{test} eq 1 ); } printf "$len$tmp", $col if ( $type eq 'tab' and ( $fileName eq 'stdout' or $bothOutput eq 1 ) ); printf "\t" if ( $type eq 'tab' and ( $fileName eq 'stdout' or $bothOutput eq 1 ) ); printf $fh "$len$tmp", $col if ( $type eq 'tab' && $fileName ne 'stdout' ); printf $fh "\t" if ( $type eq 'tab' && $fileName ne 'stdout' ); } } $rownum++; } for ( my $x = 0; $x < $elements; $x++ ) { my $len; my $tmp; #print "x is $x \t\n"; #print "element is $elements \t\n"; $len = "%" . length( $fields[$x] ); if ( $fields[$x] =~ /\w/ ) { $tmp = 's'; } elsif ( $fields[$x] =~ /\d/ ) { $tmp = 'd'; } else { $tmp = 's'; } printf $fh "$fields[$x]" if ( $fileName ne 'stdout' ); printf $fh "$delim" if ( $fileName ne 'stdout' && $x < $elements - 1 ); printf "$len$tmp", $fields[$x] if ( $fileName eq 'stdout' or $bothOutput eq 1 ); printf "$delim" if ( ( $fileName eq 'stdout' or $bothOutput eq 1 ) && $x < $elements - 1 ); } printf "\n" if ( $fileName eq 'stdout' or $bothOutput eq 1 ); printf $fh "\n" if ( $fileName ne 'stdout' ); } print "\n" if ( $fileName eq 'stdout' or $bothOutput eq 1 ); print "\n" if ( $fileName ne 'stdout' ); printf $fh "\n" if ( $fileName ne 'stdout' ); } ############################################################################# # # GetOpts # ############################################################################# if ( @ARGV == 0 ) { help; exit; } GetOptions( \%options, 'type|t=s', 'file|f=s', 'lookup|l=s', 'both|b', 'query|q=s', 'names|n', 'desc|d', 'sql|s', 'list', 'dbconfig=s', 'configdir=s', 'dir=s', 'data=s', 'qconfig=s', 'test|=s', 'debug|=s', 'help|h' => sub { help(); }, 'version|v' => sub { print_version(); }, 'both' => sub { $bothOutput = 1 }, ) or exit 1; if ( $options{'configdir'} ) { $configdir = $options{'configdir'}; } if ( $options{'dir'} ) { $dir = $options{'dir'}; } if ( $options{'dbconfig'} ) { my $tmpconfig; if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $tmpconfig = $configdir . '\\' . $options{'dbconfig'}; } else { $tmpconfig = $configdir . "/" . $options{'dbconfig'}; } if ( -e $tmpconfig && -r $tmpconfig ) { $dbconfig = $tmpconfig; } } if ( $options{'qconfig'} ) { my $tmpconfig; if ( $^O eq 'MSWin32' || $^O =~ /cygwin/ ) { $tmpconfig = $configdir . '\\' . $options{'qconfig'}; } else { $tmpconfig = $configdir . "/" . $options{'qconfig'}; } if ( -e $tmpconfig && -r $tmpconfig ) { $query = $tmpconfig; } } if ( -e $query && -r $query ) { $data = YAML::LoadFile($query); } else { print "configuration file $query not readable\n"; exit 1; } chdir($dir) or die "Couldn't change to directory $dir\n"; if ( $options{'query'} ) { if ( $options{data} ) { $db = "SQLite"; $database = $options{data}; } else { if ( -e $dbconfig && -r $dbconfig ) { $datadb = YAML::LoadFile($dbconfig); foreach my $tmp ( keys %$datadb ) { $passwd = $$datadb{$tmp} if ( $tmp eq 'passwd' ); $user = $$datadb{$tmp} if ( $tmp eq 'user' ); $db = $$datadb{$tmp} if ( $tmp eq 'db' ); $database = $$datadb{$tmp} if ( $tmp eq 'database' ); $hostname = $$datadb{$tmp} if ( $tmp eq 'host' ); $port = $$datadb{$tmp} if ( $tmp eq 'port' ); } } else { print "Configuration file $dbconfig not readable\n"; exit 1; } } # connection to database if ( $db eq 'SQLite' ) { if ( !-e $database ) { print "SQLite database $database doesn't exist\n"; exit 1; } if ( !-r $database ) { print "SQLite database $database can't be read\n"; print "Might need root privileges to access it\n"; exit 1; } $dbh = DBI->connect( "dbi:$db:$database", $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1 } ) || die "Cannot connect: $DBI::errstr"; } elsif ( $db eq 'mysql' ) { my $dsn = "DBI:$db:database=$database;host=$hostname;port=$port"; $dbh = DBI->connect( $dsn, $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1 } ) || die "Cannot connect: $DBI::errstr"; } elsif ( $db eq 'Pg' ) { my $dsn = "DBI:$db:database=$database;host=$hostname;port=$port"; $dbh = DBI->connect( $dsn, $user, $passwd, { PrintError => 0, RaiseError => 0, AutoCommit => 1, PrintWarn => 0 } ) || die "Cannot connect: $DBI::errstr"; #$dbh = DBI->connect("dbi:$db:dbname=$dbname", "", "", {AutoCommit => 0}); } elsif ( $db eq 'CSV' ) { print "output queries not supported for CSV format\n"; exit; } else { print "$db isn't supported\n"; } } if ( $options{'list'} ) { printList($data); } if ( $options{'names'} ) { printName($data); } if ( $options{'desc'} ) { printDesc($data); } if ( $options{'sql'} ) { printSql($data); } if ( $options{'type'} ) { if ( $options{'type'} eq 'tab' ) { $type = 'tab'; } elsif ( $options{'type'} eq 'html' ) { $type = 'html'; } elsif ( $options{'type'} eq 'csv' ) { $type = 'csv'; } else { print $options{'type'}; die "type not supported\n"; } } if ( $options{'file'} ) { chdir($dir) or die "Couldn't change to $dir directory\n"; if ( -e $options{'file'} ) { if ( -w $options{'file'} ) { $output = $options{'file'}; } } elsif ( !-w $options{'file'} ) { $output = $options{'file'}; } else { print "file not writable\n"; exit 1; } } if ( $options{'lookup'} ) { lookupDescByName( { data => $data, name => $options{'lookup'} } ); exit; } if ( $options{'query'} ) { $result = runSql( { data => $data, name => $options{'query'}, db => $dbh } ); } &help if ( not defined $result ); ############################################################################# # # Main # ############################################################################# if ( $type eq 'html' ) { #htmlOutput( $result, $output ); delimOutput( { results => $result, fileName => $output, delim => " " } ); } elsif ( $type eq 'tab' ) { delimOutput( { results => $result, fileName => $output, delim => "\t" } ); } elsif ( $type eq 'csv' ) { delimOutput( { results => $result, fileName => $output, delim => "," } ); } else { print "output not defined\n"; } $dbh->disconnect; __DATA__ # Config.yaml # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # Configuration file for PBNJ 2.0 # YAML:1.0 # # Config for connecting to a DBI database # SQLite, mysql etc db: SQLite # for SQLite the name of the file. For mysql the name of the database database: data.dbl # Username for the database. For SQLite no username is needed. user: "" # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: "" # Port for the database. For SQLite no port is needed. port: "" # Query.yaml # # # Copyright (C) 2005-2006 Joshua D. Abraham ( jabra@ccs.neu.edu ) # # This config file is released under the terms of the GNU General # Public License (GPL), which is distributed with this software in the # file "COPYING". The GPL specifies the terms under which users # may copy and use this software. # # # PBNJ 2.0 # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2006 # Updated: November 15, 2006 # Version: 2.04 # # Configuration file for PBNJ 2.0 # # Contains all the names, descriptions and queries for PBNJ 2.0 # # If you would like to submit a new query, please submit it to the link # below. The summary should start with QUERY: description # # http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774490 # # --- #YAML:1.0 - name: possiblevuln desc: list all of the services that possibly, should not be running sql: select * from services where service!='ssh' and state='up' # example of verion checking #- name: vulnssh # desc: all of the services that have old ssh running # sql: |- # select S.updated_on,M.ip,S.service,S.port,S.version from services as S, # machines as M where service='ssh' and state='up' and version!='4.1p1' - name: sshmachines desc: all the machines that have run ssh sql: |- select S.updated_on,M.host,S.service,S.state,S.version from services as S, machines as M where port='22' and M.mid = S.mid - name: allservices desc: all services that have ever been up sql: select * from services where state='up' - name: services desc: basic dump of the services table sql: select updated_on,service,version,banner,state from services - name: unknown_version_up desc: services that have run a unknown version sql: |- select updated_on,service,banner from services where version='unknown version' and state='up' - name: unknown_banner_up desc: services that have run a unknown banner sql: |- select updated_on,service,version from services where banner='unknown banner' and state='up' - name: machines desc: basic dump of the machines table sql: select created_on,ip,host,localh,os from machines - name: sdump desc: dump of the services table sql: select * from services - name: mdump desc: dump of the machines table sql: select * from machines - name: servicesup desc: services running on machines with a given ip or range sql: |- select M.host, S.service,S.version,S.banner from services as S,machines as M where state='up' and M.mid = S.mid - name: unknownversion desc: all instances of services running with an unknown version sql: select * from services where version='unknown version' - name: unknownbanner desc: all instances of services running with an unknown banner sql: select * from services where banner='unknown banner' - name: machine_audit desc: machine audit query sql: select ip,host,os from machines - name: service_audit desc: serice audit query sql: |- select s.port,s.protocol,s.service,s.banner,s.version from services s join machines m join (select mid,service,max(machine_updated)'muo' from services group by mid,service)r where s.mid=r.mid and s.service=r.service and s.state='up' AND s.machine_updated=r.muo and m.mid=s.mid ORDER BY s.port; - name: latestinfo_audit desc: latest host and services info sql: |- select S.port,S.protocol,S.service,S.state,S.banner,S.version from services as S where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) ORDER BY s.port; - name: latestinfo desc: latest host and services info (by hostname) sql: |- select S.updated_on,M.host, S.service,S.state,S.version,S.protocol from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid - name: latestchange desc: latest host and services info (by ip) sql: |- select S.updated_on,M.ip, S.service,S.state,S.version,S.protocol from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid - name: servicestate desc: |- most recent state for all services whether they have or have not changed sql: |- select s.updated_on,m.host,r.service,state from services s join machines m join (select mid,service,max(machine_updated)'muo' from services group by mid,service)r where s.mid=r.mid and s.service=r.service and s.machine_updated=r.muo and m.mid=s.mid; - name: uptimeratio desc: |- ratio for each service for each machine of the uptime of all the services in the database. This is based on our scans. Therefore, if you can scan once a day or once every hour the ratio is more or less accurate depending. sql: |- select a.mid,a.service,upCount,scanCount,1.0*upCount/scanCount'ratio' from (select mid,service,state,count(*)'upCount' from services where state='up' group by mid,service,state) a join (select mid,service,count(*)'scanCount' from services group by mid,service) b where a.mid=b.mid and a.service=b.service ; - name: monthlyreport desc: |- report of services ip addresses and versions that are currntly running sql: |- select M.ip, S.port,S.service,S.version,S.banner from services as S,machines as M where updated_on = (select updated_on from services ORDER BY updated_on DESC limit 1) and M.mid = S.mid pbnj-2.04/quickinstall.sh0000700000175000017500000001002410523541634014340 0ustar jabrajabra#!/bin/sh # # Copyright (C) 2005-2006 Joshua D. Abraham (jabra@ccs.neu.edu) # # This program is released under the terms of the GNU General Public License # (GPL), which is distributed with this software in the the file "COPYING". # The GPL specifies the terms under which users may copy and use this software. # # pbnj # (P)orts (B)anners N' (J)unk # # Author: Joshua D. Abraham # Date: March 15, 2005 # Updated: July 19, 2006 # Version: 2.0 # # This program is a simple install script for for PBNJ 2.0 # install(){ echo "Building Makefile [ perl Makefile.PL ] ..." perl Makefile.PL if test $? -ne 0 ; then echo "Makefile error" error else echo "ok" fi echo "Preparing PBNJ for Install [ make ] ..." make if test $? -ne 0 ; then echo "make didn't pass" error else echo "ok" fi echo "Testing PBNJ for Install [ make test ] ..." make test if test $? -ne 0 ; then echo "All the tests didn't pass" error else echo "ok" fi echo "Installing PBNJ [ sudo make install ] ..." sudo make install if test $? -ne 0 ; then echo "Install Failed" error else echo "ok" echo "PBNJ installed" echo "Run man pbnj for details"; fi echo "Cleaning up dir [ make realclean ]..." make realclean if test $? -ne 0 ; then echo "Cleanup Failed" error else echo "ok" echo "Installation is now Complete" fi } ubuntuInstall() { if test `uname -s` == "Linux" -a -e /etc/lsb-release; then source /etc/lsb-release if test "$DISTRIB_ID" == "Ubuntu" ; then echo "Installing the modules needed for PBNJ 2.0" sudo apt-get install libdbi-perl \ libdbd-sqlite3-perl libyaml-perl libxml-twig-perl \ libfile-which-perl libtext-csv-perl if test $? -ne 0 ; then echo "Couldn't find one of the module packages in apt" nonUbuntuInstall fi echo "Here are the modules that are not provided by APT:" echo " - Nmap::Parser" echo " - File::HomeDir" echo "Do you have all the modules installed? [y/n]" read MOD if test "$MOD" == "y" -o "$MOD" == "yes" ; then install else echo "Use the directions in the INSTALL file." fi else nonUbuntuInstall fi elif test `uname -s` == "FreeBSD"; then echo "Here are the modules required for PBNJ" echo " - YAML /usr/ports/databases/p5-DBI/ " echo " - DBI /usr/ports/textproc/p5-YAML/ " echo " - DBD::SQLite /usr/ports/databases/p5-DBD-SQLite" echo " - XML::Twig /usr/ports/textproc/p5-XML-Twig/" echo " - Text-CSV_XS /usr/ports/textproc/p5-Text-CSV_XS " echo " - Nmap::Parser /usr/ports/security/p5-Nmap-Parser" echo " - File::Which /usr/ports/sysutils/p5-File-Which" echo " - File::HomeDir /usr/port/devel/p5-File-HomeDir" echo " " echo "Do you have all the modules installed? [y/n]" read MOD if test "$MOD" == "y" -o "$MOD" == "yes" ; then install else echo "Use the directions in the INSTALL file." fi fi } nonUbuntuInstall(){ echo "Here are the modules required for PBNJ" echo " - YAML" echo " - DBI" echo " - DBD::SQLite" echo " - XML::Twig" echo " - Nmap::Parser" echo " - File::Which" echo " - File::HomeDir" echo "Do you have all the modules installed? [y/n]" read MOD if test "$MOD" == "y" -o "$MOD" == "yes" ; then install elif test "$MOD" == "n" -o "$MOD" == "no" ; then echo "Use the directions in the INSTALL file." fi } # start with Ubuntu Install echo "Install script for PBNJ 2.0" ubuntuInstall pbnj-2.04/INSTALL0000600000175000017500000000346110523541634012340 0ustar jabrajabra#################################### PBNJ 2.0 UNIX Install Directions #################################### Quick Install - simply run from this directory To Install PBNJ Properly ( make sure you have the needed deps) perl Makefile.PL make make test ** Then as root ** make install You will need to install the following modules for PBNJ 2.0 to work YAML DBI DBD::SQLite XML::Twig Nmap::Parser File::Which Text::CSV_XS File::HomeDir Also, you will need Nmap (any version will do) If you are running Ubuntu, I suggest you use the packages whenever possible. NOTE * you will need to add the universe repo Also, Nmap::Parser and File::HomeDir are not packaged yet. sudo apt-get install \ libyaml-perl \ libdbi-perl \ libdbd-sqlite3-perl \ libxml-twig-perl \ libtext-csv-perl \ libfile-which-perl If you are running FreeBSD here are the packages: pkg_add -r p5-DBI ( /usr/ports/databases/p5-DBI/ ) pkg_add -r p5-YAML ( /usr/ports/textproc/p5-YAML/ ) pkg_add -r p5-DBD-SQLite ( /usr/ports/databases/p5-DBD-SQLite ) pkg_add -r p5-XML-Twig ( /usr/ports/textproc/p5-XML-Twig/ ) pkg_add -r p5-Text-CSV_XS ( /usr/ports/textproc/p5-Text-CSV_XS ) pkg_add -r p5-File-Which ( /usr/ports/sysutils/p5-File-Which ) pkg_add -r p5-Nmap-Parser ( /usr/ports/security/p5-Nmap-Parser ) pkg_add -r p5-File-HomeDir ( /usr/port/devel/p5-File-HomeDir ) To install a module using CPAN $ sudo cpan # make sure you have the latest version of CPAN installed cpan> install CPAN cpan> install Bundle::CPAN # then when you see the cpan> prompt type install and the name of # the module cpan> install Nmap::Parser cpan> install File::HomeDir pbnj-2.04/NOTES-ON-NMAP-VERSION0000600000175000017500000000132410523541634014304 0ustar jabrajabraThe version of Nmap you have installed will affect the performance of PBNJ 2.0. If you are running a version older than Nmap-4.20ALPHA3, then Nmap won't be able to properly identify the OS when no services are running. Thus, if you scan a machine that is running services, then scan it when all the services are off, PBNJ 2.0 will consider the operating system to different as the OS for the 2nd scan is unknown. This is because there is nothing for Nmap to connect to, so Nmap is not able to return a proper fingerprint. Therefore, this would cause the machine from scan 1 to show all services as still running and the machine from the 2nd scan to be inserted as a new machine with no running services. pbnj-2.04/genlist.man.10000600000175000017500000001142710523741754013616 0ustar jabrajabra#!/usr/bin/perl # # pod2man genlist.man.1 | gzip -c > genlist.1p.gz && gunzip genlist.1p.gz # # Copyright (C) 2005-2006 Joshua D. Abraham (jabra@ccs.neu.edu) # # This manpage is released under the terms of the GNU General Public # License (GPL), which is distributed with this software in the file # "COPYING". The GPL specifies the terms under which users may copy # and use this software. # =pod =begin man =head1 NAME Genlist - ping scanner =head1 SYNOPSIS genlist [Input Type] [Scan Options] [General Options] =cut =begin man =head1 DESCRIPTION Genlist is a program that returns a list of hosts that responding to ping probes. Thus, this list can be used to perform an scan of these machines using PBNJ or Nmap. Apart of PBNJ 2.0 suite of tools to monitor changes on a network. =head1 OPTIONS Usage: genlist [Input Type] [General Options] Input Type: -s --scan Ping Target Range ex: 10.0.0.\* Scan Options: -n --nmap Path to Nmap executable --inter Perform scan using non default interface General Options: -v --version Display version -h --help Display this information Send Comments to Joshua D. Abraham ( jabra@ccs.neu.edu ) =end man =cut __END__ =begin man =head1 EXAMPLE OF GENLIST USED WITH PBNJ $ ./genlist -s 10.0.0.\* > iplist $ sudo ./scanpbnj -i iplist =head1 EXAMPLE OF GENLIST USED WITH NMAP $ ./genlist -s 10.0.0.\* > iplist $ sudo ./nmap -iL iplist =head1 INPUT TYPE =head2 -s Ping Target Range ex: 10.0.0.* The ping scan is a useful method of only scanning the host that are responding to ICMP echo requests. This scan basically takes the host that respond to ping and prints them. This is useful in combining the result with a PBNJ or Nmap scan because no time is wasted in scanning hosts that do not respond. =head1 SCAN OPTIONS =head2 --interface This option sets an alternative interface for performing the scan. This is useful when you have multiple interfaces on a machine with restrictions on which devices can access certain IP ranges. =head2 -n --nmap Use an alternative Nmap rather than Nmap located in the your path. This is useful if you have multiple version of Nmap installed on a system or if you are testing a new version of Nmap. Remember that if you are using a newly compiled version of Nmap that you need to export NMAPDIR to the location that Nmap was compiled in. Thus, if you have compiled Nmap in your homedir, use the following notation to run it with Genlist: $ export NMAPDIR=$HOME/nmap-VERSION/ $ sudo genlist -s 10.0.0.\* --nmap $HOME/nmap-VERISON/ =head1 General Options: =head2 -v --version Prints the Genlist version number and exits. =head2 -h --help Display this information Prints a short help screen with the most common command flags. Running Genlist without any arguments does the same thing. =head1 FEATURE REQUESTS Any feature requests should be reported to the online feature-request-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774489 Before requesting a feature, please check to see if the features has already been requested. =head1 BUG REPORTS Any bugs found should be reported to the online bug-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488. Before reporting bugs, please check to see if the bug has already been reported. When reporting PBNJ bugs, it is important to include a reliable way to reproduce the bug, version number of PBNJ and Nmap, OS name and version, and any relevant hardware specs. And of course, patches to rectify the bug are even better. =head1 SEE ALSO scanpbnj(1) outputpbnj(1), nmap(1) =head1 AUTHORS Joshua D. Abraham ( jabra@ccs.neu.edu ) =head1 LEGAL NOTICES 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 at http://www.gnu.org/copyleft/gpl.html, or in the COPYING file included with PBNJ. It should also be noted that PBNJ has occasionally been known to crash poorly written applications, TCP/IP stacks, and even operating systems. While this is extremely rare, it is important to keep in mind. PBNJ should never be run against mission critical systems unless you are prepared to suffer downtime. We acknowledge here that PBNJ may crash your systems or networks and we disclaim all liability for any damage or problems PBNJ could cause. =end man pbnj-2.04/scanpbnj.man.10000600000175000017500000003723210526513551013744 0ustar jabrajabra#!/usr/bin/perl # # pod2man scanpbnj.man.1 | gzip -c > scanpbnj.1p.gz && gunzip scanpbnj.1p.gz # # Copyright (C) 2005-2006 Joshua D. Abraham (jabra@ccs.neu.edu) # # This manpage is released under the terms of the GNU General Public # License (GPL), which is distributed with this software in the file # "COPYING". The GPL specifies the terms under which users may copy # and use this software. # =pod =begin man =head1 NAME ScanPBNJ - a program for running Nmap scans and storing the results in a PBNJ 2.0 database. =head1 SYNOPSIS scanpbnj [Options] {target specification} =cut =begin man =head1 DESCRIPTION ScanPBNJ performs an Nmap scan and then stores the results in a database. The ScanPBNJ stores information about the machine that has been scanned. ScanPBNJ stores the IP Address, Operating System, Hostname and a localhost bit. The localhost bit, is simply a single bit which is 1 when the target machine is localhost, otherwise it is 0. It also stores two timestamps for the machine table. The first is a human readable version and the second is the unix time. Both of these timestamp correspond to the first time that the machine was scanned. ScanPBNJ stores information about the services that are found to be running on the target machine. ScanPBNJ stores typical information about the service, by storing the port and protocol. Also, ScanPBNJ stores version, product and service state information about each service. The service state can either be up or down. Two timestamps are also inserted for each instance of every service. The first is a human readable version and the second is the unix time. Both of these timestamp correspond to the time that the service was scanned. This tool can give an admin a clear network layout with of all the machines with all the services they are running. Apart of PBNJ 2.0 suite of tools to monitor changes on a network. =head1 OPTIONS Usage: scanpbnj [Options] {target specification} Target Specification: Can be a IP Address, hostname, network etc. Ex: microsoft.com, 10.0.0.0/24, 192.168.1.1, 10.0.0.0-100 -i --iplist Scan using a list of IPs from a file -x --xml Parse scan/info from Nmap XML file Scan Options: -a --args Execute Nmap with args (needs quotes) -e --extraargs Add args to the default args (needs quotes) --inter Perform scan with non default interface -m --moreports Add ports to scan ex: 8080 or 3306,5900-5910 -n --nmap Path to Nmap executable -p --pingscan Ping Target then scan the alive host(s) --udp Add UDP to the scan arguments --rpc Add RPC to the scan arguments -r --range Ports for scan [def 1-1025] --diffbanner Parse changes of the banner Config Options: -d --dbconfig Config for results database [def config.yaml] --configdir Directory for the database config file --data SQLite Database override [def data.dbl] --dir Directory for SQLite or CSV files [def .] General Options: --nocolors Don't Print Colors --test Testing information --debug Debug information -v --version Display version -h --help Display this information Send Comments to Joshua D. Abraham ( jabra@ccs.neu.edu ) =end man =cut __END__ =begin man =head1 THINGS TO NOTE * ScanPBNJ requires root privileges to perform a scan. * If you do not pass a specific ports range, 1-1025 is used. * If there are configs in the current directory, they are used instead of those in the user's config directory. * ScanPBNJ does not modify previous database entries. It simply inserts new information when a change is found. * One thing that should be done when performing scans is to make sure to use the same ports or you will get false positives. =head1 EXAMPLE SINGLE SCAN 1) Scan a class B network on ports 1-9000 sudo ./scanpbnj -r 1-9000 10.0.0.0/16 2) Scan an IP Address on ports 1-9000 sudo ./scanpbnj -r 1-9000 10.0.0.100 =head1 EXAMPLE AUTOMATED SCANS The following examples can be added to /etc/crontab 1) Scan a Class C network every 2 hours 30 */2 * * * root scanpbnj 10.0.0.\* 2) Scan a Class C network everyday at 2:30 30 2 * * * root scanpbnj 10.0.0.\* =head1 TARGET SPECIFICATION The target specified is a typical method of probing the network. Therefore, any of the following can be used: (e.g. 10.0.0.1, 10.0.0.1-254, 10.0.0.0/24 or 10.0.0.\* ). The first example is simply an IP address. The second example is the scanning of a range. The third is a range in CIDR notation. The fourth example is the IP with the star which specifies to scan 255 hosts. This is the same format that Nmap uses with the only exception being the \* on the last octet. This is needed because it needs to not interpret the star when it is being executed. Another option, is to use a hostname or domain name. ScanPBNJ will then resolve the name to the correct IP address. If you pass a debug flag with level 1 or greater, ScanPBNJ will display what IP address, the hostname resolved too. =head2 -i Scan using a list of IPs from a file The iplist option is useful when you have a specific list of IPs to scan. This will perform a full scan of the IPs that are specified. This option is similar to using -sL with Nmap. The results of the scan are inserted into the database. =head2 -x Parse scan/info from Nmap XML file This option is useful when you can't perform the scan yourself or you don't want ScanPBNJ to perform the scan. Another situation where this is useful, is if you have an XML file that was done in the past and you want to extract information from it, possibly to compare with what is currently being run on the target. ScanPBNJ parses the Nmap XML file and extracts the information about the host(s) and service(s) then inserts the results into the database. =head1 SCAN OPTIONS =head2 -a --args ** NOTE ** This option needs quotes around the passed arguments This option will bypass the default arguments that are used in scanning with Nmap. This can be used to do a particular type of scan that is not possible by simply adding extra arguments. For example, if you want to only scan UDP ports and still do version identification and OS detection, you would do so using the following notation: sudo scapbnj -a "-A -O -sU" localhost =head2 -e --extraargs ** NOTE ** This option needs quotes around the passed arguments This option will add additional arguments onto the default scan arguments. This is most useful in doing scans where time optimization is needed. Therefore, these arguments will be added and then used in the scan. =head2 --inter This option sets an alternative interface for performing the scan. This is useful when you have multiple interfaces on a machine with restrictions on which devices can access certain IP or IP ranges. =head2 -m --moreports This options adds additional ports to the range of ports to scan. Individual port numbers are OK, as are ranges separated by a hyphen (e.g. 1-1023,5800,5900,8080). For example: sudo scanpbnj -m 7000-7500,8080 localhost This scan would scan the default range as well 7000-7500 and 8080. =head2 -n --nmap Use an alternative Nmap rather than Nmap located in the your path. This is useful if you have multiple version of Nmap installed on a system or if you are testing a new version of Nmap. Remember that if you are using a newly compiled version of Nmap that you need to export NMAPDIR to the location that Nmap was compiled in. Thus, if you have compiled Nmap in your homedir, use the following notation: export NMAPDIR=$HOME/nmap-VERSION/ sudo scanpbnj -n $HOME/nmap-VERISON/ localhost =head2 -p Ping Target then scan the host(s) that are alive The ping scan is a useful method of only scanning the host that are responding to ICMP echo requests. This scan basically takes the host that respond to ICMP echo requests and then performs a scan only on those hosts. Therefore, no time is wasted in scanning hosts that do not respond. The results of the scan are then inserted into the database. =head2 --udp Add UDP to the scan arguments Perform a UDP scan, in addition to the default scan. sudo scanpbnj --udp localhost If you want to only perform a UDP scan you need to set the specific arguments for the scan. sudo scanpbnj -a "-vv -O -P0 1-1025 -sVU" localhost =head2 --rpc Add RPC to the scan arguments Perform a RPC scan in addition to the default scan. sudo scanpbnj --udp localhost If you want to only perform a RPC scan you need to set the specific arguments for the scan. sudo scanpbnj -a "-vv -O -P0 1-1025 -sVR" localhost =head2 -r --range Ports for scan [default 1-1025] This option specifies which ports you want to scan and overrides the default. Individual port numbers are OK, as are ranges separated by a hyphen (e.g. 1-1023,5800,5900,8080 ). Thus, a scan like this is ok. sudo scanpbnj -r 22,25,80,100-200 localhost Also, if you have leave off the number after the hyphen it will scan all from the start port to 65535. For example: sudo scanpbnj -r 22,25- localhost =head2 --diffbanner Parse changes of the banner This options enables ScanPBNJ to do comparisons on the banner. The reason this is not on by default is that it could show changes in services that are not are important to the user. However, this option is useful to a security professional who is looking for any changes that occur so that they can be verified. =head1 DATABASE OPTIONS =head2 -d --dbconfig Config for results database [default config.yaml] This option is used to specify an alternative config.yaml file. =head2 --configdir Directory for Config file [default . ] This option is used to specify an alternative directory for the config.yaml file. =head2 --data SQLite Database override [default data.dbl ] This option is used when you want to change the name of the SQLite database file that is generated. =head2 --dir Directory for SQLite or CSV files [default . ] This option is used when you want the database to be generated in a different directory. =head1 GENERAL OPTIONS =head2 --nocolors The default results from ScanPBNJ print the useful changes with colors This options will simply not print the colors. =head2 --test Increases the Test level, causing ScanPBNJ to print testing information about the scan in progress. Using the Test level is mostly only using for testing. This will also print the debugging information so it can get rather lengthy. The greater the Test level the more output will be given. This option is also used for reporting bugs. All bug reports should be submitted using --test 1 and an additional report may be needed depending on the issue. =head2 --debug Increases the Debug level, causing ScanPBNJ to print more information about the scan in progress. Nmap scanning arguments are shown as well as the ip address if you are scanning a domain name. This option is used to give the user more information about what the scanner is doing. The higher the debug level the more output the user will receive. =head2 -v --version Prints the ScanPBNJ version number and exits. =head2 -h --help Prints a short help screen with the command flags. Running ScanPBNJ without any arguments does the same thing. =head1 DEFAULT SCAN Here are the default arguments that are used during a default scan: -vv -O -P0 -sSV -p 1-1025 =head1 FILES PBNJ's data files are stored in ScanPBNJ and OutputPBNJ. When either of these programs is run the configuration files will be generated for the user if they don't already exists and placed in the $HOME/.pbnj-2.0 directory. Again, if there is a configuration file in the current directory it is used instead of the version in the configuration directory. $HOME/.pbnj-2.0/config.yaml - holds settings for connecting to the database which store the information from PBNJ scans. $HOME/.pbnj-2.0/query.yaml - lists all queries that can be used to retrieve information from the database. Also, includes the name and description for each query. This is only generated when you executed OutputPBNJ. For Windows, the pbnj-2.0 config directory is in the APPDATA directory, which contains both config.yaml and query.yaml. Depending on your environment, the APPDATA directory may be a different location from other environments. Therefore, when the configs are executed for the first time they will display the path where the configs were generated. =head1 FEATURE REQUESTS Any feature requests should be reported to the online feature-request-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774489 Before requesting a feature, please check to see if the features has already been requested. =head1 BUG REPORTS Any bugs found should be reported to the online bug-tracking system available on the web at : http://sourceforge.net/tracker/?func=add&group_id=149390&atid=774488. Before reporting a bug, please check to see if the bug has already been reported. When reporting PBNJ bugs, it is important to include a reliable way to reproduce the bug, version number of PBNJ and Nmap, OS name and version, and any relevant hardware specs. And of course, patches to rectify the bug are even better. =head1 SUPPORTED DATABASES The following databases are supported: * SQLite [default] * MySQL * Postgres * CSV =head1 DATABASE SCHEMA The following is the SQLite version of the database schema: CREATE TABLE machines ( mid INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT, host TEXT, localh INTEGER, os TEXT, machine_created TEXT, created_on TEXT); CREATE TABLE services ( mid INTEGER, service TEXT, state TEXT, port INTEGER, protocol TEXT, version TEXT, banner TEXT, machine_updated TEXT, updated_on TEXT); =head1 SEE ALSO outputpbnj(1), genlist(1), nmap(1) =head1 AUTHORS Joshua D. Abraham ( jabra@ccs.neu.edu ) =head1 LEGAL NOTICES 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 at http://www.gnu.org/copyleft/gpl.html, or in the COPYING file included with PBNJ. It should also be noted that PBNJ has occasionally been known to crash poorly written applications, TCP/IP stacks, and even operating systems. While this is extremely rare, it is important to keep in mind. PBNJ should never be run against mission critical systems unless you are prepared to suffer downtime. We acknowledge here that PBNJ may crash your systems or networks and we disclaim all liability for any damage or problems PBNJ could cause. =end man pbnj-2.04/INSTALL-WIN32.txt0000600000175000017500000000211410523541634013750 0ustar jabrajabra#################################### PBNJ 2.0 Windows Install Directions #################################### Download the nmap installer for windows which can be found on Nmap's download page. http://www.insecure.org/nmap/download.html ------------------------------------------ Download ActiveState Perl http://www.activestate.com/Products/Download/Download.plex?id=ActivePerl Then to install the module you should use ActiveState's ppm (Programmer's Package Manager). Start Menu -> run -> cmd c:>ppm ppm>install YAML ppm>install DBI ppm>install DBD-SQLite ppm>install XML-Twig ppm>install Nmap-Parser ppm>install Text-CSV_XS ppm>install File-Which ppm>install File-HomeDir ------------------------------------------ Download nmake ftp://ftp.microsoft.com/softlib/mslfiles/nmake15.exe Then use the standard Perl Make Install Directions. C:\pbnj-2.0>nmake15.exe C:\pbnj-2.0>perl Makefile.PL C:\pbnj-2.0>nmake install Then you should be able to run the programs. There is documentation about each tools in the docs directory. pbnj-2.04/MANIFEST0000600000175000017500000000075410525442316012441 0ustar jabrajabraREADME INSTALL MANIFEST Makefile.PL scanpbnj outputpbnj ChangeLog scanpbnj.man.1 outputpbnj.man.1 genlist.man.1 quickinstall.sh INSTALL-WIN32.txt EXAMPLES AUTHORS BUGS NOTES-ON-NMAP-VERSION genlist query.yaml config.yaml docs/scanpbnj-man.html docs/outputpbnj-man.html docs/genlist-man.html databases/pg.yaml databases/mysql.yaml databases/csv.yaml databases/sqlite3.yaml t/01modules.t t/02callback.t t/02parser.t t/03parser.t t/test1.xml t/nmap_results.xml pbnj-2.04/EXAMPLES0000600000175000017500000000165510523541634012453 0ustar jabrajabraSINGLE SCAN Scan Localhost sudo ./scanpbnj 127.0.0.1 Mail latest changes in csv format to user bill sudo ./outputpbnj -q latestinfo -t csv |mail -s "PBNJ Latest Info" bill AUTOMATED SCANS WITH CRONJOBS Copy the following into your /etc/crontab # scan of 10 net every 2 hours and email the latest changes to root 16 */2 * * * root /root/bin/scan # monthly report of class c and email to root 59 1 1 * * root /root/bin/monthly-report Scan Every 2 Hours: /root/bin/scan contains the following: #!/bin/sh scanpbnj 192.168.10.\* outputpbnj -q latestinfo -t csv | mail -s "PBNJ LatestInfo `date`" root Monthly Report: /root/bin/monthly-report contains the following: #!/bin/sh MONTHYEAR=`date +%B-%Y` cd /root/ mkdir report-$MONTHYEAR cd report-$MONTHYEAR scanpbnj 192.168.10.\* outputpbnj -q monthlyreport -t csv | mail -s "PBNJ Month Report `date +%B+%r`" root pbnj-2.04/databases/0000700000175000017500000000000010523541575013234 5ustar jabrajabrapbnj-2.04/databases/csv.yaml0000600000175000017500000000071710523541575014722 0ustar jabrajabra# YAML:1.0 # Config for connecting to a DBI database # SQLite, mysql etc db: CSV # for SQLite the name of the file. For mysql the name of the database database: data.csv # Username for the database. For SQLite no username is needed. user: "" # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: "" # Port for the database. For SQLite no port is needed. port: "" pbnj-2.04/databases/mysql.yaml0000600000175000017500000000073610523541575015275 0ustar jabrajabra# YAML:1.0 # Config for connecting to a DBI database # SQLite, mysql etc db: mysql # for SQLite the name of the file. For mysql the name of the database database: pbnjdb # Username for the database. For SQLite no username is needed. user: pbnjuser # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: localhost # Port for the database. For SQLite no port is needed. port: 3306 pbnj-2.04/databases/pg.yaml0000600000175000017500000000073610523541575014536 0ustar jabrajabra# YAML:1.0 # Config for connecting to a DBI database # SQLite, mysql etc db: Pg # for SQLite the name of the file. For mysql the name of the database database: pbnjdb # Username for the database. For SQLite no username is needed. user: pbnjuser # Password for the database. For SQLite no password is needed. passwd: "tmp" # Password for the database. For SQLite no host is needed. host: localhost # Port for the database. For SQLite no port is needed. port: 5432 pbnj-2.04/databases/sqlite3.yaml0000600000175000017500000000072210523541575015507 0ustar jabrajabra# YAML:1.0 # Config for connecting to a DBI database # SQLite, mysql etc db: SQLite # for SQLite the name of the file. For mysql the name of the database database: data.dbl # Username for the database. For SQLite no username is needed. user: "" # Password for the database. For SQLite no password is needed. passwd: "" # Password for the database. For SQLite no host is needed. host: "" # Port for the database. For SQLite no port is needed. port: ""