To achieve this, we are going to use the extremely useful scanning tool called nmap. We will call it and parse its output from a Perl script using Nmap::Parser module.
Here goes the script:
#!/usr/bin/perl use strict; use warnings; use Nmap::Parser; die "Usage: $0 host1 [host2 host3 ...]\n" unless @ARGV; listNetServices(@ARGV); =head2 listNetServices( @hosts ) Are we running different versions of network services (ex. SSH) on different hosts? Useful for identifying unpatched (old) versions of network services but we have to include a host with patched services into @hosts. =cut sub listNetServices { my @hosts = @_; my $services; # HoH # Anonymous subroutine my $nmap = sub { my $host = shift; #Nmap::Parser::Host object, just parsed for my $port ( $host->tcp_ports('open') ) { # Nmap::Parser::Host::Service object my $svc = $host->tcp_service($port); my $service = join( ' | ', $svc->name // '', $svc->product // '', $svc->version // '' ); push @{ $services->{$port}{$service} }, $host->hostname . ' (' . $host->addr . ')'; } }; my $np = new Nmap::Parser; $np->callback($nmap); $np->parsescan( '/usr/bin/nmap', '-sV', @hosts ); # Print report for my $port ( sort keys %$services ) { my $n_versions = keys %{ $services->{$port} }; next unless $n_versions > 1; print "$port - $n_versions different versions on this port\n"; for my $version ( sort keys %{ $services->{$port} } ) { print ' ' x 4 . $version . "\n"; for my $host ( sort @{ $services->{$port}{$version} } ) { print ' ' x 8 . $host . "\n"; } } } return; }
(Up-to-date source of the
ListNetServices
function can be found in MyUtils.)And this is a sample output suggesting that host1 is running older versions of both ssh and http daemons:
$ perl script-listed-above host1 host2 22 - 2 different versions on this port ssh | OpenSSH | 5.5p1 Debian 6+squeeze5 host1 (1.2.3.4) ssh | OpenSSH | 6.7 host2 (5.6.7.8) 80 - 2 different versions on this port http | Apache httpd | 2.2.16 host1 (1.2.3.4) http | Apache httpd | 2.4.10 host2 (5.6.7.8)