in reply to Re: processing a module result
in thread processing a module result

Hi GrandFather,

in this case I have tried to understand the documentation but failed so far.

$av_obj_MAS = Masscan::Scanner->new(); $av_obj_MAS->add_host($av_loc_IP); $av_obj_MAS->add_port(@av_arr_PORTS); $av_obj_MAS->sudo(1); $av_obj_MAS->verbose(1); $av_tmp_SCAN = $av_obj_MAS->scan; if ($av_tmp_SCAN) { $av_obj_SCANRESULT = $av_obj_MAS->scan_results; $av_obj_RESULT = %$av_obj_SCANRESULT{scan_results}; @av_arr_SCANRESULT = @{%$av_obj_SCANRESULT{scan_results}}; # print "Test1: " . $%av_obj_RESULT{ip}; }

The first line to get the result from the object obviously works. It is according to the documentation.

It looks like the second line also brings one part of the result to a variable.

But to access the IP (and print it) and the array of port is still not working.

The documentation of the module shows some example data structure provided as result.

{ 'scan_results' => [ { 'timestamp' => '1584816181', 'ip' => '10.0.0.1', 'ports' => [ { 'status' => 'open', 'reason' => 'syn-ack', 'port' => 443, 'proto' => 'tcp', 'ttl' => 60 } ] }, { 'timestamp' => '1584816181', 'ip' => '10.0.0.2', 'ports' => [ { 'reason' => 'syn-ack', 'status' => 'open', 'port' => 443, 'ttl' => 60, 'proto' => 'tcp' } ] }, { 'ports' => [ { 'port' => 80, 'ttl' => 60, 'proto' => 'tcp', 'reason' => 'syn-ack', 'status' => 'open' } ], 'ip' => '10.0.0.1', 'timestamp' => '1584816181' }, { 'ip' => '10.0.0.2', 'timestamp' => '1584816181', 'ports' => [ { 'port' => 80, 'ttl' => 60, 'proto' => 'tcp', 'status' => 'open', 'reason' => 'syn-ack' } ] }, { 'timestamp' => '1584816181', 'ip' => '10.0.0.3', 'ports' => [ { 'reason' => 'syn-ack', 'status' => 'open', 'proto' => 'tcp', 'ttl' => 111, 'port' => 80 } ] }, { 'ports' => [ { 'ttl' => 111, 'proto' => 'tcp', 'port' => 443, 'reason' => 'syn-ack', 'status' => 'open' } ], 'timestamp' => '1584816181', 'ip' => '10.0.0.3' } ], 'masscan' => { 'scan_stats' => { 'total_hosts' => 4, 'up_hosts' => 3 }, 'command_line' => '/usr/bin/masscan --rate 100000 + --banners -p 22,80,443,61222,25 10.0.0.2,10.0.0.1,10.0.0.3,10.0.0.4' } };

with:

$av_obj_SCANRESULT = $av_obj_MAS->scan_results;

I geht the data structure into a scalar - so far so good

now I would like e.g. to print the IP-Address as part of the data structure or move the whole result into an array or just run a foreach ... to process the results list.

but I don't know how

Regards Kallewirsch

Replies are listed 'Best First'.
Re^3: processing a module result
by Discipulus (Canon) on May 18, 2022 at 06:39 UTC
    Hello averlon,

    mainly our goal is to help you in learning, not providing solutions, so I'd start with:

    • use strict; use warnings; always in your program
    this will save a lot of trouble and has not drawbacks, so let perl help you: it is amazing in this

    • Then, regarding your code:
    # doc my $mas = Masscan::Scanner->new(hosts => \@hosts, ports => \@ports, ar +guments => \@arguments); #your code $av_obj_MAS->add_port(@av_arr_PORTS);

    They are sligltly different... where? \@ports is a reference to an array while @av_arr_PORTS is an array. Look carefully at the documentation: arguments are always passed as a single scalar like in $mas->add_port(25) or as array reference like in $mas->ports(['22', '80', '443']); but never as list or array.

    • about accessing the results
    The doc says it: SCAN-RESULTS. I invite you to inspect yourself this result using the core module Data::Dumper or the CPAN one Data::Dump (I prefer the latter, but in some edge case the former is more accurate: get used to both).

    Consider the following oneliner (pay attention to windows double quotes around the code, single quote needed for Linux):

    perl -MData::Dumper -e "$hash{lvl1}[3]{lvl3}[0] = 42; print Dumper \%h +ash" $VAR1 = { 'lvl1' => [ undef, undef, undef, { 'lvl3' => [ 42 ] } ] };

    You are in a similar situation: perldsc is definitevely a good read.

    Modify your program and share your achievements: they will probably bring up new questions

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re^3: processing a module result
by averlon (Sexton) on May 18, 2022 at 08:04 UTC

    Hi

    I guess, I found a solution myself

    I will post it once it is completely working

    Regards Kallewirsch

      Crafting a good question often provides the answer you are looking for without needing to actually ask it. This is a Good Thing!

      You already have a little feedback on your solution: Always use strictures (use strict; use warnings; - see The strictures, according to Seuss). If I get time tomorrow night I'll run through your code and provide what I hope is helpful feedback.

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        Hi,

        the whole code is the following:

        #!/usr/bin/perl # ===== # Author: Karl-Heinz Fischbach # Date: 16.05.2022 # Content: Massscan of IP-Addresses and Ports available # # Copyright (C) 2022 Karl-Heinz Fischbach # 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 3 of the License, or (a +t 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 MERCHANTAB +ILITY 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 al +ong with this program; if not, see <http://www.gnu.org/licenses/>. # # Changelog: # # Ports: 80, 443, 25, 587, 993, 5060, 5080, 7, 9, 21, 22, 23, 37, 49, +53, 69, 79, 88, 107, 115, 119, 137, 138, 139, 143, 161, 162, 194, 199 +, 445, 464, 465, 500, 513, 514, 520, 547, 554, # ===== use strict; use warnings; use utf8; use English; use Net::Domain qw(hostname hostfqdn hostdomain domainname); use Net::Ping; use Masscan::Scanner; use Getopt::Long; use autodie; # die if problem reading or writing a file use Sys::Hostname; use DateTime; use DateTime::Format::Strptime; use DateTime::TimeZone; use File::Spec; use File::Basename; use File::Copy; use File::Touch; use File::ReadBackwards; use IO::All; use Config::IniFiles; use Log::Log4perl qw(get_logger); use Log::Log4perl::Config; use Log::Log4perl::Level; use Log::Dispatch; # _ __ _ _ _ # \ / / (_) | | | | # \ \ / /_ _ _ __ _ __ _| |__ | | ___ # \ \/ / _` | '__| |/ _` | '_ \| |/ _ \ # \ / (_| | | | | (_| | |_) | | __/ # \/ \__,_|_| |_|\__,_|_.__/|_|\___| # # ### variables block our $av_std_ARG=1; my $av_std_BASENAME=basename($0,".pl"); my $av_std_BIN='/usr/local/share/averlon'; my $av_std_DIRNAME=dirname($0); # gibt dann u.U. nur "." wieder my $av_std_EXIT=0; my $av_std_FORCE=0; my $av_std_POSPAR; my $av_std_RETVAL; my $av_std_USER; my $av_std_TMP='/tmp'; my $av_std_VERBOSE=3; # Loglevel = 0; no logging # Loglevel = 1; fatal # Loglevel = 2; error # Loglevel = 3; warn # Loglevel = 4; info # Loglevel = 5; debug # Loglevel = 6; trace our $av_std_CONFIG; our $av_std_LOGFILE='/var/log/' . hostname() . '.log'; our $av_std_LOGGING=0; our $av_std_STORAGE='/mytmp/'; our $av_std_TEST=0; my $av_loc_TESTDATE; my $av_loc_TODAY; my $av_loc_TESTHOUR; our $av_loc_PARAMFILE=''; my $av_loc_NAS="/mytmp"; my $av_loc_mail_CONTENT=''; my $av_loc_STORAGE; my $av_loc_IP; my @av_arr_PORTS; ### ### predefined objects ### my $av_obj_DT=DateTime->today(); my $av_obj_LOGGER=undef; my $av_obj_TMP=undef; my $av_obj_FILE=undef; my $av_obj_INIFILE=undef; my $av_obj_MAIL=undef; my @av_obj_PARTS=undef; my $av_obj_PING=undef; my $av_obj_XMLF=undef; my $av_obj_MAS=undef; my $av_obj_SCANRESULT=undef; my $av_obj_RESULT=undef; my $av_tmp_STRING; my $av_tmp_FN; my $av_tmp_FILE; my $av_tmp_SCAN; my $av_tmp_SCANRESULT; my %av_hash_SCANRESULT; my @av_arr_SCANRESULT; my @av_arr_RESULTPORTS; # ______ _ _ # ____| | | (_) # |__ _ _ _ __ ___| |_ _ ___ _ __ ___ # __| | | | '_ \ / __| __| |/ _ \| '_ \/ __| # | | |_| | | | | (__| |_| | (_) | | | \__ \ # _| \__,_|_| |_|\___|\__|_|\___/|_| |_|___/ # # ### functions commands block sub av_help { print "Benutzung:\n"; print "xxx.pl [-h, --help] [-t, --test] [-v [0-6], --verbose [0-6] +] [-V, --version]\n"; print "Bedeutung der Optionen:\n"; print " -h, --help := diese Information\n"; print " -l, --logging := log all output to file in /var/userlog/\ +n"; print "\tfile is stored in /var/userlog and will have job_ as pref +ix and .log as suffix\n"; print " -v [0-6], --verbose [0-6] := verbose logging, Loglevel is + set to 4\n"; print " -V, --version := Version wird ausgegeben\n"; } # _____ _ _ # __ \ | | (_) # |__) | __ ___ _ __ __ _ _ __ __ _| |_ _ ___ _ __ # ___/ '__/ _ \ '_ \ / _` | '__/ _` | __| |/ _ \| '_ \ # | | | | __/ |_) | (_| | | | (_| | |_| | (_) | | | | # _| |_| \___| .__/ \__,_|_| \__,_|\__|_|\___/|_| |_| # | | # |_| ### preparation commands block print "alle optionen: @ARGV\n"; GetOptions ( "i|ip=s" => \$av_loc_IP, # IP-Address "p|ports=s" => \@av_arr_PORTS, # Ports "h|help" => \&av_help, # help "l|logging" => \$av_std_LOGGING, # logging "t|test" => \$av_std_TEST, # test "v|verbose:4" => \$av_std_VERBOSE, # verbose + loglevel ) or print ("Error in command line arguments: @ARGV"); print "hostname: ", hostname() . "\n"; ( $av_std_VERBOSE > 0 ) && print "debug \$av_std_LOGGING: $av_std_LOGG +ING\n"; ( $av_std_VERBOSE > 0 ) && print "debug \$av_std_VERBOSE: $av_std_VERB +OSE\n"; ( $av_std_VERBOSE > 0 ) && print "debug \$av_std_LOGFILE: $av_std_LOGF +ILE\n"; # # GetOptions Parameter verarbeiten # if ($av_std_LOGGING) { $av_std_LOGFILE="/var/userlog/job_" . basename($0,".pl") . ".log"; $av_obj_FILE = File::Touch->new()->touch("$av_std_LOGFILE"); } if ( not @av_arr_PORTS ) { print "PORTS not defined\n"; @av_arr_PORTS = ('1-1000'); } if ( scalar @av_arr_PORTS == 0 ) { print "no ports given: @av_arr_PORTS\n"; exit (1); } ### ### log4perl ### vorher muss $av_std_LOGFILE gesetzt sein ### my $conf = q( log4perl.rootLogger=TRACE, av_FILE, av_SCREEN log4perl.appender.av_FILE=Log::Log4perl::Appender::File log4perl.appender.av_FILE.filename=sub { return $main::av_std_LOGFIL +E; } log4perl.appender.av_FILE.mode=append log4j.PatternLayout.cspec.U = sub { $ENV{USER} } log4perl.appender.av_FILE.layout=PatternLayout log4perl.appender.av_FILE.layout.ConversionPattern=%-3d{MMM} %d{d} % +d{HH:mm:ss} %-8H %F{1}[%P]: %p %U %m%n log4perl.appender.av_SCREEN=Log::Log4perl::Appender::Screen log4perl.appender.av_SCREEN.stderr=0 log4perl.appender.av_SCREEN.layout=Log::Log4perl::Layout::SimpleLayo +ut log4perl.appender.av_SCREEN.layout.ConversionPattern = %d %m %n ); $_=$conf; if ( $av_std_VERBOSE == 0 ) { s/TRACE/FATAL/; } elsif ( $av_std_VERBOSE == 1 ) { s/TRACE/FATAL/; } elsif ( $av_std_VERBOSE == 2 ) { s/TRACE/ERROR/; } elsif ( $av_std_VERBOSE == 3 ) { s/TRACE/WARN/; } elsif ( $av_std_VERBOSE == 4 ) { s/TRACE/INFO/; } elsif ( $av_std_VERBOSE == 5 ) { s/TRACE/DEBUG/; } elsif ( $av_std_VERBOSE == 6 ) { s/TRACE/TRACE/; } #print $_; #$conf=$_; Log::Log4perl::Config->utf8( 1 ); #Log::Log4perl->init("/usr/local/share/averlon/av_log4perl.conf"); Log::Log4perl->init( \$conf ); $av_obj_LOGGER = get_logger(); # #### #### prepare variables #### ## #$av_obj_LOGGER->trace("..."); # Log a trace message #$av_obj_LOGGER->debug("..."); # Log a debug message #$av_obj_LOGGER->info("..."); # Log a info message #$av_obj_LOGGER->warn("..."); # Log a warn message #$av_obj_LOGGER->error("..."); # Log a error message #$av_obj_LOGGER->fatal("..."); # Log a fatal message # __ __ _ _____ # \/ | (_) | __ \ # \ / | __ _ _ _ __ | |__) | __ ___ ___ # |\/| |/ _` | | '_ \ | ___/ '__/ _ \ / __| # | | | (_| | | | | | | | | | | (_) | (__ _ # _| |_|\__,_|_|_| |_| |_| |_| \___/ \___(_) # # $av_obj_MAS = Masscan::Scanner->new(); # host given by the command line option $av_obj_MAS->add_host($av_loc_IP); # set the ports given by the command line options $av_obj_MAS->ports(\@av_arr_PORTS); $av_obj_MAS->sudo(1); $av_obj_MAS->verbose(1); # now scan $av_tmp_SCAN = $av_obj_MAS->scan; # if result is available if ($av_tmp_SCAN) { # get result from module - this then seems to be an object $av_obj_SCANRESULT = $av_obj_MAS->scan_results; # # # now I need to fetch the part of scan_results from this object # $av_obj_RESULT = %$av_obj_SCANRESULT{scan_results}; # since the scan_result is an array of values, I need to put it in +to an array @av_arr_SCANRESULT = @{%$av_obj_SCANRESULT{scan_results}}; # now to process this array of results # this should contain the e.g. the ip-address of the computer scan +ned and an array of ports found in what status ever foreach $av_tmp_STRING ( @av_arr_SCANRESULT ) { # print simply the ip-address print %$av_tmp_STRING{ip} . "\n"; # now I need to put the array of ports scanned and reported as + an result into an array @av_arr_RESULTPORTS = @{%$av_tmp_STRING{ports}}; # this array may have several entries for each port scanned # now to process the array and print the results foreach $av_tmp_STRING ( @av_arr_RESULTPORTS ) { print "Port: " . %$av_tmp_STRING{port} . "\n"; print "Status: " . %$av_tmp_STRING{status} . "\n"; } } } else { print "scan not successful \n"; } # ______ _ _____ # | ____| | | | __ \ # | |__ _ __ __| | | |__) | __ ___ ___ # | __| | '_ \ / _` | | ___/ '__/ _ \ / __| # | |____| | | | (_| | | | | | | (_) | (__ _ # |______|_| |_|\__,_| |_| |_| \___/ \___(_) # # ### end procedure exit (0);

        anyhow, since I use a standard template for all my scripts there might be some elemtens in not at all used in the script. I will clean up later.

        so far it works - but I need to add some messages if arrays are empty - means - no ports found ....when I have time - it is just for fun

        Regards Kallewirsch

      Hi

      here is my code:

      $av_obj_MAS = Masscan::Scanner->new(); # host given by the command line option $av_obj_MAS->add_host($av_loc_IP); # set the ports given by the command line options $av_obj_MAS->ports(\@av_arr_PORTS); $av_obj_MAS->sudo(1); $av_obj_MAS->verbose(1); # now scan $av_tmp_SCAN = $av_obj_MAS->scan; # if result is available if ($av_tmp_SCAN) { # get result from module - this then seems to be an object $av_obj_SCANRESULT = $av_obj_MAS->scan_results; # # # now I need to fetch the part of scan_results from this object # $av_obj_RESULT = %$av_obj_SCANRESULT{scan_results}; # since the scan_result is an array of values, I need to put it in +to an array @av_arr_SCANRESULT = @{%$av_obj_SCANRESULT{scan_results}}; } # now to process this array of results # this should contain the e.g. the ip-address of the computer scanned +and an array of ports found in what status ever foreach $av_tmp_STRING ( @av_arr_SCANRESULT ) { # print simply the ip-address print %$av_tmp_STRING{ip} . "\n"; # now I need to put the array of ports scanned and reported as an +result into an array @av_arr_RESULTPORTS = @{%$av_tmp_STRING{ports}}; # this array may have several entries for each port scanned # now to process the array and print the results foreach $av_tmp_STRING ( @av_arr_RESULTPORTS ) { print "Port: " . %$av_tmp_STRING{port} . "\n"; print "Status: " . %$av_tmp_STRING{status} . "\n"; } }

      I am sure there is a lot of optimization and shortening of commands possible - but one step after another

      probably it will help also others struggling with this issue - if some

      Regards Kallewirsch
        Hello averlon,

        > I am sure there is a lot of optimization and shortening of commands possible - but one step after another

        You skipped the very first step: use strict and warnings :)

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.