Multithreaded Perl Portscanner

While learning sockets in Perl (to put it more acurately, while learning the IO::Socket module), I came across a few implementations of Perl portscanners which, even though functional, were far from practical. I know, I know, you can just get Nmap if you’re looking for a good portscanner, but hey, you can build your own scanner and make it decent.

The implementations I often found (there were also some php versions) were too slow because they worked by looping through the port numbers and trying them sequentially. All I did was create some threads to speed things up, and the resulting speed is actually acceptable. The following code loops through the port range specified, creating rounds of 30 threads to test the ports by calling the “testarporta()” sub routine on the current iteration’s port.

On to the code:

#!/usr/bin/perl
use IO::Socket;
use Threads;

#+---------------------------------------------------------+
#|                                                         |
#|               Fanatic Port Scanner v 1.0                |
#|                  coded by guidj0s                       |
#|                                                         |
#+---------------------------------------------------------+

sub testarporta
{
  my $tentar = new IO::Socket::INET (
  	PeerAddr => $_[0],
  	PeerPort => $_[1],
  	Proto => 'tcp',
	Timeout => '1'
  );

  if ($tentar)
  {
  	print "$_[1] ";
  	$portaberta = $_[1];
  	open(logar, '>>fanatic_scanresults.txt');
  	print logar "$portaberta ";
  	close logar;
	close $tentar;
  }

}

if (@ARGV < 3)
{
	die "\n\n\n    Failed. Usage: $0 [ip] [startport] [endport]\n\n\n";
}

my ($ip, $pi, $pf) = @ARGV;

print "\n\n -------------------------------:: Fanatic Port Scanner by guidj0s ::-------\n\n";
print " Working...\n\n\n  Open Ports: ";

open(scanlog, '>>fanatic_scanresults.log');
print scanlog "\n\n\n-----------:: Last Scan Results for $ip ::--------------\n\n";
print scanlog "\nPort Range Selected: $pi-$pf";
print scanlog "\n\n\nOpen Ports: ";
close scanlog;

while ($pi <= $pf)
{
	for my $controle (1..30)
	{
		my $agente = threads->new(\&testarporta, $ip, $pi);
		$pi++;
	}
	foreach (threads->list)
	{
		$_->join;
	}
}

	print "\n\n\t\t\tScan finished.\n\n";

As you can see, the ports found open are logged to fanatic_scanresults.log. If you looked at the code you realized a port is considered “open” only when a connection can be established on it.

The Win32 GUI version
I did make one. I coded it using the Win32::GUI module. I know TK would have been a better option (as I found out quite soon), but that’s what I went with and I really don’t think it’s worth the hassle to migrate (I’m not working on it again any time soon).
As you may know, Win32::GUI isn’t thread safe. In this case, whenever I tried to access a Win32::GUI object from within a child thread, the program crashed. I solved the problem by creating a shared variable ($aberta), which is updated everytime an open port is found. I also created a control variable ($ultima), which is used to check whether the last value printed out/logged was already printed or if the value currently stored in $aberta has already been handled (so I only need to print it when $aberta != $ultima. After doing so, I update $ultima with the current value stored in $aberta), and then access the Win32::GUI element from the main thread.
I added a functionality to the program, which is the option of providing a portlist plain-text file to scan for specific ports only. Enough talking, here’s the code: http://guidjos.justfree.com/fntcgui.txt
Now that I look at my code again, I see there’s a silly mistake. You should never access files like I did here:

open(scanlog, ">>$logto");

But I’ll leave this for another post, as this one’s long enough. The handling of user-input related mistakes isn’t really thorough either, so feel free to improve the code (sharing the new version would be cool, I might give you some space to talk about it and share your code here on the blog ;) ).

  1. No trackbacks yet.