Nessus Vulnerability Scanner

The results of a Nessus scan, saved as XML, can be collected and parsed with NXLog Enterprise Edition.

Scan sample
<?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.

Example 1. Parsing Nessus logs with Perl

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.

nxlog.conf
<Input perl>
    Module      im_perl
    PerlCode    nessus.pl
</Input>
Event sample
{
  "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"
}
nessus.pl
#!/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);
        }
    }
}
Example 2. Parsing logs with xm_multiline

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.

nxlog.conf
<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>
Event sample
{
  "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."
}
Disclaimer

While we endeavor to keep the information in this topic up to date and correct, NXLog makes no representations or warranties of any kind, express or implied about the completeness, accuracy, reliability, suitability, or availability of the content represented here.

Last revision: 28 March 2019