Nessus Vulnerability Scanner
The results of a Nessus scan, saved as XML, can be collected and parsed with NXLog Enterprise Edition.
<?xml version="1.0" ?>
<NessusClientData_v2>
<Report xmlns:cm="http://www.nessus.org/cm" name="Scan Testbed">
<ReportHost name="192.168.1.112">
<HostProperties>
<tag name="HOST_END">Wed Jun 18 04:20:45 2014</tag>
<tag name="patch-summary-total-cves">1</tag>
<tag name="traceroute-hop-1">?</tag>
<tag name="traceroute-hop-0">10.10.10.20</tag>
<tag name="operating-system">Linux Kernel</tag>
<tag name="host-ip">192.168.1.112</tag>
<tag name="HOST_START">Wed Jun 18 04:19:21 2014</tag>
</HostProperties>
<ReportItem port="6667" svc_name="irc" protocol="tcp" severity="0" pluginID="22964"
pluginName="Service Detection" pluginFamily="Service detection">
<description>It was possible to identify the remote service by its banner or by looking at the error
message it sends when it receives an HTTP request.
</description>
<fname>find_service.nasl</fname>
<plugin_modification_date>2014/06/03</plugin_modification_date>
<plugin_name>Service Detection</plugin_name>
<plugin_publication_date>2007/08/19</plugin_publication_date>
<plugin_type>remote</plugin_type>
<risk_factor>None</risk_factor>
<script_version>$Revision: 1.137 $</script_version>
<solution>n/a</solution>
<synopsis>The remote service could be identified.</synopsis>
<plugin_output>An IRC server seems to be running on this port is running on this port.</plugin_output>
</ReportItem>
</ReportHost>
</Report>
</NessusClientData_v2>
While the above sample illustrates the correct syntax, it is not a complete Nessus report. For more information refer to the Nessus v2 File Format document on tenable.com. |
The preferred approach for parsing Nessus scans is with im_perl and a Perl script; this provides fine-grained control over the collected information. If Perl is not available, the xm_multiline and xm_xml extension modules can be used instead. Both methods require NXLog Enterprise Edition.
In this example, the im_perl input module executes the nessus.pl
Perl script which reads the Nessus scan. The script generates an event for
each ReportItem
, and includes details from Report
and ReportHost
in each
event. Furthermore, normalized $EventTime
, $Severity
, and $SeverityValue
fields are added to the event record.
<Input perl>
Module im_perl
PerlCode nessus.pl
</Input>
{
"EventTime": "2014-06-18 04:20:45",
"Report": "Scan Testbed",
"ReportHost": "192.168.1.112",
"port": "6667",
"svc_name": "irc",
"protocol": "tcp",
"NessusSeverityValue": 0,
"NessusSeverity": "INFO",
"SeverityValue": 2,
"Severity": "INFO",
"pluginID": "22964",
"pluginName": "Service Detection",
"pluginFamily": "Service detection",
"description": "It was possible to identify the remote service by its banner or by looking at the error\nmessage it sends when it receives an HTTP request.\n",
"fname": "find_service.nasl",
"plugin_modification_date": "2014/06/03",
"plugin_name": "Service Detection",
"plugin_publication_date": "2007/08/19",
"plugin_type": "remote",
"risk_factor": "None",
"script_version": "$Revision: 1.137 $",
"solution": "n/a",
"synopsis": "The remote service could be identified.",
"plugin_output": "An IRC server seems to be running on this port is running on this port.",
"EventReceivedTime": "2017-11-29 20:29:40",
"SourceModuleName": "perl",
"SourceModuleType": "im_perl"
}
#!/usr/bin/perl
use strict;
use warnings;
use FindBin;
use lib $FindBin::Bin;
use Log::Nxlog;
use XML::LibXML;
sub read_data {
my $doc = XML::LibXML->load_xml( location => 'scan.nessus' );
my $report = $doc->findnodes('/NessusClientData_v2/Report');
my @nessus_sev = ("INFO","LOW","MEDIUM","HIGH","CRITICAL");
my @nxlog_sev_val = (2,3,4,5,5);
my @nxlog_sev = ("INFO","WARNING","ERROR","CRITICAL","CRITICAL");
my %mon2num = qw(
Jan 01 Feb 02 Mar 03 Apr 04 May 05 Jun 06
Jul 07 Aug 08 Sep 09 Oct 10 Nov 11 Dec 12
);
my $eventtime;
foreach my $reportHost ( $doc->findnodes('/NessusClientData_v2/Report/ReportHost') )
{
$eventtime = "";
foreach my $properties ( $reportHost->findnodes('./HostProperties/tag') ) {
if ($properties->getAttribute('name') eq "HOST_END") {
my($dow, $m, $d, $t, $y) = $properties->textContent =~
m<^([a-zA-Z]+) ([a-zA-Z]+) (\d+) (\d+:\d+:\d+) (\d+)$> or die "Not a valid date";
$eventtime= $y . "-" . $mon2num{$m} . "-" . $d . " " . $t;
}
}
foreach my $reportItem ( $reportHost->findnodes('./ReportItem') ) {
my $event = Log::Nxlog::logdata_new();
my $raw_event = $reportItem->toString();
Log::Nxlog::set_field_string( $event, 'raw_event', $raw_event );
Log::Nxlog::set_field_string( $event, 'EventTime', $eventtime );
Log::Nxlog::set_field_string( $event, 'Report', $report->get_node(1)->getAttribute('name') );
Log::Nxlog::set_field_string( $event, 'ReportHost', $reportHost->getAttribute('name') );
my @atts = $reportItem->getAttributes();
foreach my $at (@atts) {
my $na = $at->getName();
my $va = "" . $at->getValue();
if ($na eq "severity") {
my $severity = $va + 0;
Log::Nxlog::set_field_integer( $event, "NessusSeverityValue", $severity );
Log::Nxlog::set_field_string( $event, "NessusSeverity", $nessus_sev[$severity] );
Log::Nxlog::set_field_integer( $event, "SeverityValue", $nxlog_sev_val[$severity] );
Log::Nxlog::set_field_string( $event, "Severity", $nxlog_sev[$severity] );
} else {
Log::Nxlog::set_field_string( $event, $na, $va );
}
}
if ( $reportItem->hasChildNodes ) {
my @kids = grep { $_->nodeType == XML_ELEMENT_NODE }
$reportItem->childNodes();
foreach my $kid (@kids) {
my $na = $kid->getName();
my $va = "" . $reportItem->getChildrenByTagName($na);
Log::Nxlog::set_field_string( $event, $na, $va );
}
}
Log::Nxlog::add_input_data($event);
}
}
}
This example depicts an alternative way to collect results from Nessus XML
scan files, recommended only if Perl is not available. This configuration
generates an event for each ReportItem
found in the scan report.
<Extension multiline_parser>
Module xm_multiline
HeaderLine /^<ReportItem/
EndLine /^<\/ReportItem>/
</Extension>
<Extension _xml>
Module xm_xml
ParseAttributes TRUE
</Extension>
<Input in>
Module im_file
File "nessus_report.xml"
InputType multiline_parser
<Exec>
# Discard everything that doesn't seem to be an xml event
if $raw_event !~ /^<ReportItem/ drop();
# Parse the xml event
parse_xml();
</Exec>
</Input>
{
"EventReceivedTime": "2017-11-09 10:22:58",
"SourceModuleName": "in",
"SourceModuleType": "im_file",
"ReportItem.port": "6667",
"ReportItem.svc_name": "irc",
"ReportItem.protocol": "tcp",
"ReportItem.severity": "0",
"ReportItem.pluginID": "22964",
"ReportItem.pluginName": "Service Detection",
"ReportItem.pluginFamily": "Service detection",
"ReportItem.description": "It was possible to identify the remote service by its banner or by looking at the error\nmessage it sends when it receives an HTTP request.\n",
"ReportItem.fname": "find_service.nasl",
"ReportItem.plugin_modification_date": "2014/06/03",
"ReportItem.plugin_name": "Service Detection",
"ReportItem.plugin_publication_date": "2007/08/19",
"ReportItem.plugin_type": "remote",
"ReportItem.risk_factor": "None",
"ReportItem.script_version": "$Revision: 1.137 $",
"ReportItem.solution": "n/a",
"ReportItem.synopsis": "The remote service could be identified.",
"ReportItem.plugin_output": "An IRC server seems to be running on this port is running on this port."
}