CreationP has asked for the wisdom of the Perl Monks concerning the following question:

Hello Perl Monks. I'm trying to make a portscanner that will take values from a MySQL database. I was able to make it without SQL support with this code:

%h; $h{'Echo [Returns what is sent to server]'} = {service => ['7']}; $h{'Discard [A sink, like /dev/null]'} = {service => ['9']}; foreach $key(keys %h) {foreach $service (@{$h{$key}{'service'}}) {if($khost=~/^$service/) {chop($service) if ($service =~/\.$/); print "\n[!] Port: [$start_port] Service: $key"; print O "[!] Port: [$start_port] Service: $key\n"; $start_port++}}}}}

Now I'm trying to do the same thing but with DBI. I have a table called "vulnerabilities" and I want to create a hash in perl, populated by the 'port', 'name', 'comment' that can be found on the vulnerabilities table. Untill now my code is something like this:

$sql = "select * from scanner.vulnerabilities"; $sth = $dbh->prepare($sql); $sth->execute or die "SQL Error: $DBI::errstr\n"; my %ref; while (my $row = $sth ->fetchrow_hashref() ){ $ref{ $row ->{'port'}} = $row ->{'Name'} } foreach $key(keys %ref) {foreach $port (@{$ref{$key}{'port'}}) {if($khost=~/^$port/) {chop($port) if ($port =~/\.$/); print "\n[!] Port: [$start_port] Service: $key"; print O "[!] Port: [$start_port] Service: $key\n"; $start_port++}}}}}

The way it is does not working as it does not log the results. In small, I want to create a hash from MySQL that can do what the original program does. Although I have read a hell lot of resources it seems that I miss something. This program is for a college project and I cannot seem to be able to find the answer anywhere. Thank you in advance.

Replies are listed 'Best First'.
Re: Hash from mySQL
by NetWallah (Canon) on May 14, 2012 at 13:44 UTC
    From the way you have populated %ref, it looks like a simple hash whose key is $port and value is a (host)name.

    In that case, the following code:

    {foreach $port (@{$ref{$key}{'port'}})
    is trying to treat %ref as a HOH. IMHO, the outer loop should look like:
    for my $port (keys %ref){ my $host = $ref{$port}; # Process the $host/$port combo ...

                 I hope life isn't a big joke, because I don't get it.
                       -SNL

Re: Hash from mySQL
by RichardK (Parson) on May 14, 2012 at 13:49 UTC

    well you didn't say how it's failing, so it's difficult to offer any useful advice. What error messages are you getting ?

    You could try using Data::Dumper to see what's in %ref and that might help you understand why it's not doing what you expect.

    say Dumper(\%ref);

      In order for the monks to have a better picture of what I'm trying to do I will quote my whole programs. The first one is the original I created at the start:

      print "Host: "; chop ($host = <STDIN>); print "Port to start (1-66535): "; chop ($start_port = <STDIN>); print "Port to finish(1-66535): "; chop ($last_port = <STDIN>); if ($start_port > $last_port) { print "Error! Start port cannot be bigger then end port. \n Pl +ease re-enter start and end ports. \n\n"; exit 1; } if ($start_port < 1) { print "[?] Start port cannot be less than 1. Try entering a di +fferent number."; exit 1; } if ($last_port > 66535) { print "The maximun end port number is 66535 [..you gave $last_ +port]. \n\n"; exit 1; } $serverip= inet_ntoa((gethostbyname($host))[4]); print "[*] Server's IP: [$serverip]\n"; print "[*] Scan Results: "; open(O, ">>ScanLog.txt"); print O "\nYour target host was $host, at ",scalar(localtime), ":\n\n" +; while ($start_port <= $last_port) { $con = new IO::Socket::INET (PeerAddr => $host,PeerPort => $start_ +port,Timeout => 1, Proto => 'tcp'); if (!($con)) { $start_port++; } else { $khost = $start_port; chomp($khost); %h; $h{'Echo [Returns what is sent to server]'} = {service => ['7' +]}; $h{'Discard [A sink, like /dev/null]'} = {service => ['9']}; $h{'Systat [May be connected to system, w, or ps]'} = {service + => ['11']}; $h{'Daytime [Sends time-of-day (date)]'} = {service => ['11']} +; $h{'Netstat [Similar to systat]'} = {service => ['15']}; $h{'ftpdata [Data connection from FTP server]'} = {service => +['20']}; $h{'ftp [Control connection from FTP client (use SSH;)]'} = {s +ervice => ['21']}; $h{'telnet [Server port for Telnet (use SSH)]'} = {service => +['23']}; $h{'smtp [Server port for SMTP (sendmail)]'} = {service => ['2 +5']}; $h{'wins [WINS server often found here (not 1512)]'} = {servic +e => ['42']}; $h{'whois [whois server (rs.internic.net)]'} = {service => ['4 +3']}; $h{'tacacs [TACACS authentication service]'} = {service => ['4 +9']}; $h{'domain [Domain Name Service]'} = {service => ['53']}; $h{'bootp [Usefull for probing networks (NIS name)]'} = {servi +ce => ['67']}; $h{'tftp [Unauthenticated file tranfer]'} = {service => ['69'] +}; $h{'gopher [Safer if controlled using proxy servers]'} = {serv +ice => ['70']}; $h{'finger [Colecting usernames/passwords cracking information +]'} = {service => ['79']}; $h{'http [WWW, safer if controlled using proxy servers]'} = {s +ervice => ['80']}; foreach $key(keys %h) {foreach $service (@{$h{$key}{'service'}}) {if($khost=~/^$service/) {chop($service) if ($service =~/\.$/); print "\n[!] Port: [$start_port] Service: $key"; print O "[!] Port: [$start_port] Service: $key\n"; $start_port++}}}}} print O "\n ---------------------E-O-F------------------------\n"; close(O); }

      Now the program I want to create using the MySQL database.

      print "Host: "; chop ($host = <STDIN>); print "Port to start (1-66535): "; chop ($start_port = <STDIN>); print "Port to finish(1-66535): "; chop ($last_port = <STDIN>); if ($start_port > $last_port) { print "Error! Start port cannot be bigger then end port. \n Pl +ease re-enter start and end ports. \n\n"; exit 1; } if ($start_port < 1) { print "[?] Start port cannot be less than 1. Try entering a di +fferent number."; exit 1; } if ($last_port > 66535) { print "The maximun end port number is 66535 [..you gave $last_ +port]. \n\n"; exit 1; } $serverip= inet_ntoa((gethostbyname($host))[4]); print "[*] Server's IP: [$serverip]\n"; print "[*] Scan Results: "; open(O, ">>ScanLog.txt"); print O "\nYour target host was $host, at ",scalar(localtime), ":\n\n" +; while ($start_port <= $last_port) { $con = new IO::Socket::INET (PeerAddr => $host,PeerPort => $start_ +port,Timeout => 1, Proto => 'tcp'); if (!($con)) { $start_port++; } else { $khost = $start_port; chomp($khost); $sql = "select * from scanner.vulnerabilities"; $sth = $dbh->prepare($sql); $sth->execute or die "SQL Error: $DBI::errstr\n"; my %ref; while (my $row = $sth ->fetchrow_hashref() ){ $ref{ $row ->{'port'}} = $row ->{'Name'} } foreach $key(keys %ref) {foreach $port (@{$ref{$key}{'port'}}) {if($khost=~/^$port/) {chop($po rt) if ($port =~/\.$/); print "\n[!] Port: [$start_port] Service: $key"; print O "[!] Port: [$start_port] Service: $key\n"; $start_port++}}}}} print O "\n ---------------------E-O-F------------------------\n"; close(O);

      There isn't any problems with the execution of the file but I do not think that the hash I'm trying to create is populated. If it is then the foreach loop isn't doing what is supposed to do. In other words, I'm trying to do what the first program does but by populating the hash from the database. I'm new to perl and although I think I'm going well I just can't figure out the hash from database and manipulating it. If any monk can help me out by giving me the correct code at the hash loop and explaining me a bit about it would be very very helpfull and awsome. I have read everything about hashes and hashrefs but still I lack the general perl knowledge to understand them. Thank you in advance.