Vulnerability
Assessments with Nmap and Nessus
Wyman Miles
The need for network vulnerability assessments is a fact of life
for systems administrators. It is often necessary to discover new
applications that have been installed, verify adherence to policy,
and look for unpatched systems. In the event of a compromise, comparing
the operating system's view of services to that of the network is
a simple way to verify the presence of a rootkit. Two excellent
tools exist for this purpose, Nmap and Nessus.
Nmap is a command-line port scanner that can rapidly inventory
the open ports on a series of machines, verify firewall configurations,
gather service banners, and identify operating systems by observing
different TCP settings.
Nessus is a rich vulnerability scanner built around plug-ins written
in the Nessus Attack Scripting Language (NASL), which makes it very
extensible and powerful. NASL is a full-featured language that allows
for simple automation of vulnerabilities assessments. Protocol-specific
packets can be crafted and sent to a host, the results analyzed,
and a severity of risk passed back to the Nessus client. Thousands
of plug-ins currently exist that are designed to test for incorrectly
configured services, detect software vulnerabilities, gather operating
system and application versions, look for missing patches, and the
like. As new vulnerabilities are discovered, new plug-ins are added.
Nessus is built around a client-server model. The client GUI communicates
with the server to authenticate the current user, get a list of
available plug-ins, and request an attack. The server process itself
carries out the attack, applying plug-ins as requested, and returning
the results.
Both tools are quite powerful, but they don't lend themselves
well to automated scripting. Recently, a common approach to compromising
Unix hosts or suitable Windows PCs has been the venerable "xhost
+" vulnerability. A rapid test of a small network for incorrectly
configured X servers requires starting the Nessus client, authenticating,
searching through a list of plug-in families for the right one,
then waiting for the scan results. Simply looking for X servers
with Nmap is a straightforward process, but it can't test for proper
configuration.
Perl modules exist to wrapper Nmap port scans and request Nessus
vulnerability scans. By combining these two processes, it's possible
to build a simple, extensible tool that can rapidly audit a network
for a small number of services and apply Nessus where needed. Perl
gives us to ability to combine the speed of Nmap with the detail
of Nessus.
A Visit to CPAN
To show the basics of scripting around Nmap and Nessus, we'll
develop a script called getbanner.pl. This script allows a systems
administrator to rapidly inventory a network for hosts listening
on a certain port or range of ports, then scrutinize those machines
by performing Nessus scans, additional Nmap scans, and an inventory
of running services.
I'll assume you have both Nmap and Nessus in your infrastructure
and have used both. To wrapper Nmap scans, you'll need the Nmap::Parser
Perl module. To communicate with Nessus, you'll need the Net::Nessus::ScanLite
module. Both modules have a number of prerequisites, necessary to
parse Nmap's XML output and properly communicate with Nessus. You'll
need:
- Nmap::Parser
- Net::Nessus
- Net::Nessus::ScanLite
- Config::IniFiles
- XML::SAX
- XML::SAX::Base
- XML:Twig
Because most Nessus installations use SSL to communicate with
the server, you might also need:
A handy feature of the getbanner.pl script is its ability to pull
service banners from unknown ports, in a way similar to Nmap's "-sV"
option. For this, you'll need:
Perl makes it easy to install modules directly from CPAN:
perl -MCPAN -e shell
cpan> install XML::Twig
CPAN: Storable loaded ok
Going to read /build/perl-5.8.1/src/CPAN/Metadata
Database was generated on Wed, 08 Sep 2004 13:05:09 GMT
CPAN: LWP::UserAgent loaded ok
Fetching with LWP:
http://cpan.develooper.com/authors/01mailrc.txt.gz
Going to read /build/perl-5.8.1/src/CPAN/sources/authors/01mailrc.txt.gz
Fetching with LWP:
http://cpan.develooper.com/modules/02packages.details.txt.gz
Going to read \
/build/perl-5.8.1/src/CPAN/sources/modules/02packages.details.txt.gz
Database was generated on Sun, 17 Apr 2005 15:04:18 GMT
Fetching with LWP:
http://cpan.develooper.com/modules/03modlist.data.gz
Going to read \
/build/perl-5.8.1/src/CPAN/sources/modules/03modlist.data.gz
Going to write /build/perl-5.8.1/src/CPAN/Metadata
Running install for module XML::Twig
Running make for M/MI/MIROD/XML-Twig-3.17.tar.gz
Fetching with LWP:
file:///build/perl-5.8.1/src/CPAN/sources/authors/id/M/MI/ \
MIROD/XML-Twig-3.17.tar.gz
LWP failed with code[404] message[File \
'/build/perl-5.8.1/src/CPAN/sources/authors/id/M/MI/ \
MIROD/XML-Twig-3.17.tar.gz' does not exist]
Fetching with LWP:
http://cpan.develooper.com/authors/id/M/MI/MIROD/XML-Twig-3.17.tar.gz
CPAN: Digest::MD5 loaded ok
Fetching with LWP:
file:///build/perl-5.8.1/src/CPAN/sources/authors/id/M/MI/ \
MIROD/CHECKSUMS
Fetching with LWP:
file:///build/perl-5.8.1/src/CPAN/sources/authors/id/M/MI/ \
MIROD/CHECKSUMS.gz
Fetching with LWP:
http://cpan.develooper.com/authors/id/M/MI/MIROD/CHECKSUMS
Checksum for /build/perl-5.8.1/src/CPAN/sources/authors/id/M/MI/ \
MIROD/XML-Twig-3.17.tar.gz ok
CPAN: Archive::Tar loaded ok
Perl then unpacks and installs the module. Some modules, like IO::Socket::SSL,
require that you have OpenSSL installed.
Your First Scan
The Nmap::Parser module simply calls the Nmap executable, passing
it whatever arguments you specify (while adding a few of its own
to ensure XML output), then parses the results of the scan. The
code in Listing 1 shows how to do this.
To begin, we'll set the arguments to pass to the Nmap process.
We're calling Nmap with the -sT option, which gives a basic
connect() scan. As scans go, this is fairly slow, because it requires
the remote host to complete the TCP handshake before Nmap can move
on. But it doesn't require root privileges, as a SYN scan would,
and is less likely to crash hosts with unreliable network stacks
like printers and network electronics. Note that the Nmap::Parser
module seems to have trouble parsing simple ping scans (-sP).
A method that will achieve similar results is to simply look for
TCP port 0 (-sT -p 0).
The call to parsescan starts the Nmap process:
$np -> parsescan($NMAP_EXE, $NMAP_ARGS, $target_net);
Here's an example of how to use this basic script:
./basic.pl 10.0.1.0/24
Hostname: test1.cornell.edu
Address: 10.0.1.1
Open ports: 22 ,23 ,514
Hostname: test2.cornell.edu
Address: 10.0.1.2
Open ports: 135 ,139 ,445
Hostname: test3.cornell.edu
Address: 10.0.1.3
Open ports: 135 ,139 ,445
You'll notice the module returns, for each host discovered by Nmap,
its DNS hostname (if available), its IP address, and a list of ports.
We're only interested in open ports for now, but the tcp_ports method
can also return ports in state "closed" or "filtered". The latter
is of particular interest because it lets us infer which router access
lists, firewall rules, or host-based filtering may be in place that
could block our scan. This can be of great help in diagnosing service
connectivity issues and verifying network security policies. To do
this, simply change the tcp_ports method from "open" to "filtered".
Because Nmap rarely collects useful information from hosts that
are down or otherwise unresponsive, we'll also limit our results
somewhat. The module allows us to do that as well:
$np -> parse_filters({only_active => 1});
This will limit the results to those hosts that are detected as up
and responsive.
What we've done here is create a verbose Nmap. Suppose we want
to detect hosts listening on a particular port and perform some
action on them. The Nmap::Parser module allows the programmer to
register a callback function that will be run each time a host is
found:
$np -> register_host_callback(\&new_host);
This will run the new_host function whenever an active host is found.
The module will pass the current parser object to the function. Listing
2 shows a way of using this method in conjunction with the Net::Telnet
module to grab service banners from every port on our router:
./banners.pl 10.0.1.1
Attempting to connect to 10.0.1.1:22
SSH-1.99-Cisco-1.25
Attempting to connect to 10.0.1.1:23
User Access Verification
Username:
Attempting to connect to 10.0.1.1:514
Whenever the scan finds a machine with a port open, the Net::Telnet
module will attempt to connect, send a few carriage returns to the
service, then record the first five lines of the response. This is
similar to the behavior of Nmap's own -sV switch.
Vulnerability Scanning with Nessus
The Net::Nessus::ScanLite module, as its name implies, allows
us to perform lightweight vulnerability scans of a host. It's not
intended to replace the full functionality of the Nessus client
interface, but it does present some useful opportunities for rapid
network auditing, CGI scripting to test machines as they visit a
Web page, etc. It was originally written to accompany an Ethernet
address registration system and perform some simple checks for missing
Windows patches and absent administrator passwords and to open shares
before permitting the target machine full access to the network.
It's quite useful for rapid, automated, small-scale vulnerability
scans.
The module needs to know where your Nessus scan host lives, whether
it requires SSL, the port on which it listens, and a valid Nessus
username and password. Initializing a scan object is simple:
my $nessus = Net::Nessus::ScanLite -> new(host => 'localhost',
port => 1241,
ssl => 1);
The scanner object will accept any option that is valid in a Nessus
configuration file, because it simply passes those along when negotiating
the NTP (in this case, Nessus Transfer Protocol) session.
The Perl module expects a list of Nessus plug-ins, separated by
semicolons. All plug-ins have a five-digit number assigned to them,
more or less in the order they're written and submitted. Public
plug-ins start at 10000 and generally accepted practice is to number
site-specific plug-ins at 90000. The Nessus site has several search
tools available to find plug-ins by name, category, type, or keyword.
It is important to note that Nessus classifies plug-ins into two
broad groups: those that are unlikely to cause harm to the remote
system, and those that might. The latter category includes plug-ins
that perform SYN scans, plug-ins that attempt a login session, as
well as considerably more dangerous plug-ins that will cause a crash
or denial of service. The unfortunate reality is, as some tests
require dangerous plug-ins, disallowing their use severely limits
the potential scope of a test.
For example, a very common and important vulnerability assessment
is a simple check for a password on all local accounts. It may seem
obvious, but weak or absent passwords are still a major method of
compromise. Nessus considers testing a Windows machine for an absent
administrator password as the use of a dangerous plug-in, and it
is disabled by default.
Furthermore, Nessus plug-ins are interdependent. To perform some
basic service tests to determine which application is running, its
version, and any possible vulnerabilities, Nessus must run the check
that actually determines whether a port is open. Without enabling
such dependencies, a script can fail simply because its prerequisite
tests have not been performed.
Before automating scans, it's important to test your scanning
methodology with the Nessus client and understand what checks it
performs and by what method. Some checks don't require enabling
dependencies or enabling the dangerous checks, but some do. Test
in advance against systems you carefully control and when the scan
behavior gives the results you need at the level of safety you require,
automate it.
To set the most open Nessus options:
$nessus -> preferences( { host_expansion => 'none',
safe_checks => 'no',
auto_enable_dependencies => 'yes',
checks_read_timeout => 1 });
Be aware that this may cause the vulnerability scanner to attempt
more than just the plug-ins you specify.
Listing 3 shows a simple script to test a single host for the
"xhost +" configuration problem, using plug-in 10407:
./nessus.pl 192.168.1.15
Total info = 1
Info:
ID: 10407
Port: 6000
Description: This X server does *not* allow any client to connect
to it, however, it is recommended that you filter incoming
connections to this port as attacker may send garbage data and
slow down your X session or even kill the server.
Here is the server version : 11.0
Here is the message we received : Client is not authorized
Solution : filter incoming connections to ports 6000-6009
Risk factor : Low
Total holes = 0
Putting It All Together
Now that we have a basic framework that will perform Nmap scans,
take actions based on the results, and scan machines with Nessus,
let's put it all together. The result, in Listing 4, is getbanner.
It will scan a host or network for machines listening on a specific
port, inventory their services, and return service banners. Alternatively,
it will take a list of Nessus plug-ins and apply them to any host
matching the initial scan criteria.
The script takes a few simple arguments:
-P [TCP port specification]
-n [nessus plugin or list]
-t [target machine or network]
As the port and target specifications are passed directly to Nmap,
the script will accept the same syntax for port or address ranges
that Nmap would accept if called directly.
For example, find all probable Windows machines and determine
which services are running:
getbanner.pl -P "135,139,445" -t 192.168.0.0/24
Find X servers and test them for promiscuous xhost permissions:
getbanner.pl -P 6000 -n 10407 -t 192.168.0.0/24
Find all your SSH servers and test them for various vulnerabilities:
getbanner.pl -P 22 -n 11195 -t 192.168.0.0/24
Look for Web servers running the recently vulnerable awstats CGI.
Note the need to quote the plug-in list so its delimiters aren't interpreted
by the shell:
getbanner.pl -P "80,443" -n "11347;16456;16189;" -t 192.168.0.0/24
Grab every banner off every host that responds:
getbanner.pl -P 0 -t 192.168.0.0/16
Conclusion
This is been a quick introduction to the Perl programming interfaces
for Nmap and Nessus. I hope this article will help you use these
tools for your own projects.
References
Nmap -- http://www.insecure.org/nmap
Nessus -- http://www.nessus.org
Nessus plug-ins search -- http://www.nessus.org/plugins
CPAN, the Comprehensive Perl Archive Network -- http://www.cpan.org
Wyman Miles is a Senior Security Engineer at Cornell University.
Previously, he was Manager of Infrastructure at Rice University.
He has worked as a Unix systems administrator in various roles in
higher education for 14 years, supporting electronic mail, DNS,
DHCP, Web infrastructure, and large NAS systems. Outside of work,
he spends time biking, hiking, and snowboarding in the Finger Lakes
region of New York. He can be reached at: wm63@cornell.edu. |