Wednesday, December 19, 2007

Non-Maliciously Scanning For Open Network Ports

Generally, port scanning is looked at as a "Black Hat" activity. This isn't so much stereotyping, as a heavily weighed and considered generalization. Entire industries are built around the fact that most, if not all, networked servers (public and private) are under almost constant attack by some individual or group. It's for that reason that most folks, like myself, take pause before ever engaging in such activity, even if our motives are pure. Depending on your situation, the very fact that you do this might get you flagged.

On the flipside, however, is the obvious "need" to be able to check whether ports are open. Reasons range from making sure that services are up and available, to "White Hat" activity, like making sure that all of the network ports that you think are closed actually are; thus enabling you to detect security risks and eliminate them before someone else can take advantage.

The script I'm putting up today is a port scanner in its purest sense. It doesn't attempt to "investigate" the services running on any of the network ports it finds open, which is usually enough to keep you from getting threatening emails from your security department ;) The little reporting it does do on open network ports is variable, as it gets the information from the /etc/services file on the host from which it's being run (using the standard getservbyport call).

You call the script by whatever name you give it (I'll call it "scanner" because it makes sense and, maybe, I'm not feeling very original right now ;) and supply it with the IP Address of the target server and the highest port on it that you want to scan. The script assumes you want to start at port 1. You can change that very easily by modifying the $port variable. You also need to be root to run this script, as it creates sockets (using standard Berkeley Sockets code) and regular users don't have system permission to do that on Unix and Linux systems. If they do, something is horribly wrong :P

A sample run would look like this:

host # ./scanner 127.0.0.1 1000
Open : 80/tcp :
Open : 111/tcp : sunrpc
Open : 443/tcp :
host #


In the above example, it appears that we've got a regular and secure webserver running, as well as the sunrpc service. The reason that the description field on the left is empty for ports 80 and 443 is that there are no entries in the host's /etc/services file for those ports. Simply adding those entries in that file would make the program produce this on an exactly equal run:

host # ./scanner 127.0.0.1 1000
Open : 80/tcp : http
Open : 111/tcp : sunrpc
Open : 443/tcp : https
host #


Hopefully, you'll find this useful with regards to your completely-above-board administration activities :)

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/perl

#
# scanner - simple port scanner
# 2007 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

if ( $#ARGV != 1 ) {
print "Usage: $0 hostnameOrIP highPort\n";
exit(1);
}

use Socket;

$host = $ARGV[0];
$highport = $ARGV[1];
$port = 1;

OUTERLOOP: while ( $port <= $highport ) {
$| = 1;
$line = " ";
$tcp = 1;
INNERLOOP: while ($tcp >= 0) {
if ( $tcp ) {
$protocol = "tcp";
} else {
$protocol = "udp";
}
#print "${port}/$protocol... ";
if ( $port =~ /\D/) {
$port = getservbyname($port, $protocol);
}
unless ( $port ) {
print "No port : ${port}/$protocol\n";
if ( $tcp ) {
$tcp--;
next INNERLOOP;
} else {
$port++;
next OUTERLOOP;
}
}
$inet_address = inet_aton($host) || die "No host: ${host}!";
$port_address = sockaddr_in($port, $inet_address);
$protocol_num = getprotobyname('$protocol');
socket(SOCKET, PF_INET, SOCK_STREAM, $protocol_num) || die "Socket: $!";
unless ( connect(SOCKET, $port_address) ) {
if ( $tcp ) {
$tcp--;
next INNERLOOP;
} else {
$port++;
$tcp--;
next OUTERLOOP;
}
}
if ( $tcp ) {
send(SOCKET, $line, 'SOCK_STREAM') == length($line) || die "Cannot Send Message!: $!\n";
} else {
send(SOCKET, $line, 'SOCK_DGRAM', $protocol) == length($line) || die "Cannot Send Message!: $!\n";
}
close(SOCKET) || die "Close $!";
$service = getservbyport($port, $protocol);
print "Open : ${port}/$protocol : $service\n";
$port++;
$tcp--;
}
}


, Mike