Linux auditing using Nessus

Nessus can scan a range of Linux flavours. As of writing these are:
  • CentOS
  • Debian
  • Fedora
  • Gentoo
  • Red Hat
  • Slackware
  • SuSE
  • Ubuntu
There are two types of scans Nessus can run against Linux hosts: 
  • Patch audit
  • Compliance audit

Patch audit - the plugin families are "[distro name] Local Security Checks". Nessus will audit targets and report on missing security patches based on advisories released by respective distributions. Nessus requires credentials in order to preform this type of scan as this are local checks. Tenable recommends that root level  credentials are used, though I have been able to successfully scan Linux hosts with a "standard" account. This however depends on distribution and how hardened it is.

On Red Hat distros Nessus executes the following commands which work with non-root accounts:

$rpm -qa
$uname -a

Nessus then compares its database with versions of kernel and installed packages.
Compliance audit - Tenable provides a number compliance audit files based on various industry best practices or regulations. The audit files can be downloaded from support forums. Compliance scan require elevated permissions as Nessus reads various system files. 

I generally opt for using elevated permissions in both types of scans.

Setting up an account used for scanning

In most cases SSHing directly with root account is disabled (which is a good thing from security standpoint). To confirm if it's disabled we can check /etc/ssh/sshd_confing. We need to look for line reading: "PermiRootLogin". If it's commented out or set to "yes". Root login is possible. 

Nessus can use standard account to connect and then elevate permissions using su, sudo, su + sudo. I generally opt for "sudo" option. In this case Nessus will prepend each command with sudo.

To create a user "auditor"  and add it to sudoers list do the following:

#useradd auditor
#passwd auditor

#vi /etc/sudoers  or simply #visudo

add the following line: 

auditor    ALL=(ALL)    ALL

This will allow user "auditor" to execute all commands including "sudo su" which would let the account to elevate to full root - which may not always be desired. This can be restricted by adding ",! /bin/su" at the end of the line. 

Nessus supports both password and key authentication. For highest level of security and scanning targets out on the internet key auth should be used. This would also apply to blanket scans, when you scan a whole subnet and not specific hosts. There is a risk of someone setting up an SSH server and intercepting the password. We'll use password authentication in our example.

Configuring Linux scanning policy in Nessus:


I like leaving "Netstat SSH Scan" enabled to get a list of listening ports. Output from netstat is most accurate and least intrusive. 

1. Set credentials type to "SSH Settings"
2. Specify the user name
3. Set "Elevate privileges with" to "sudo" (or whatever method you chose)
4. Specify escalation password
5. optionally change ssh port

Plugins - Patch Audit policy:

We need to enable actual local security checks as well as relevant settings. I recommend enabling the whole "Settings" family as it contains a number of useful plugins besides required "SSH Settings" plugin.

1. enable desired local security checks family (for instance "CentOS Local Security Checks"
2. enable whole "settings" family 

Useful plugins in "settings" family:

19506 Nessus Scan Information - info about the scan itself

12634 Authenticated Check: OS Name and Installed Package Enumeration  - this plugin confirms whether supplied credentials worked and if Nessus was able to elevate permissions. If this plugin does not appear in scan output it means Nessus was unable to login to the target.  

21745 Authentication Failure - Local Checks Not Run - If this plugin appears in scan output it means that authentication did not work and Nessus was unable to login to the target. 

In additional to the above the following plugins provide additional information about Linux hosts:

33851 Network daemons not managed by the package system - lists software installed - in most cases - from source. These application will not be updated by the package manager and may indicate compromised host. 

25221 Remote listener enumeration  - show processes listening on ports
33276 Enumerate MAC Addresses via SSH - shows L2 interfaces

22869 Software Enumeration (SSH) - list of installed software
25202 Enumerate IPv6 Interfaces via SSH - shows IPv6 interfaces
25203 Enumerate IPv4 Interfaces via SSH - shows IPv4 interfaces

This is all we need to do to create oatch audit policy. 

Plugins - Compliance Audit policy:

For compliance audit we need to enable "Settings" family and plugin "21157 Unix Compliance Checks"


A desired audit policy file must be uploaded to Nessus server. 

Securing OSPF

There are multiple ways to secure OSPF.  The essential one is authentication. By default there isn't any validation to assure legitimacy of an OSPF topology update. Basically an attacker or a bored employee could install a physical router and become a member of a routing system. Alternately a tool such as LOKI ( could be used. LOKI provides a GUI and is very simple to use, I however found it a bit buggy. More on that can be found in my Attacking OSPF - route injection post.

Other tools that could be used include:
  •  SCAPY - very advanced and fairly complicated packet generation tool, to craft OSPF packets it requires OSPF extension
  • TCPREPLAY - - a legitimate OSPF adjacency set up and database exchange could be captured, modified and replayed (I had limited success with this technique)
On a Cisco router we can use the following to secure our OSPF routing:
  • authentication
  • passive interfaces
  • access control list
  • route filtering
OSPF authentication is part of the protocol standard and should be inter operable between vendors.  We will focus on Cisco specific implementation.

There are three types of authentication supported by OSPF:
  • none (Type 0)
  • clear text (Type 1)
  • MD5 (Type 2)
Sample OSPF hello packets with different types of authentication enabled.
  • none

  • clear text (the key is "testkey")

  • MD5 

Clearly, MD5 is the way to go. When MD5 authentication is enabled, each OSPF packet is hashed using MD5 and configured key (this is called a keyed hash). Neighboring router does the same operation on received packet and if the hash values match packet is accepted and processed. If it doesn't packet is discarded.  

Authentication is enabled on per area and per interface basis. We can have area 1 with authentication, and area 2 without, configured on the same router. What's important to note is that we can have different keys on different interfaces belonging to the same area. This is important in situation when we want to exchange routes with a routing system we don't control. 

In order to enable authentication we need to enable it in router ospf configuration context and on each interface.  

Sample router configuration - enables authentication for area 1:

router ospf 1
 network area 1
 area 1 authentication

Sample interface configuration - enables MD5 authentication on F0/0:


interface FastEthernet0/0

 ip address

 ip ospf authentication message-digest
 ip ospf message-digest-key 1 md5 testkey

On Cisco devices by default, once routing is enabled, routing information is propagated and accepted on all interfaces. In default configuration, Hello packets can be captured on access ports. This gives a potential attacker information about routing protocol in use. What's more important is that hello packets would also be accepted and processed on those ports. So let's suppose there is an OSPF Denial of Service vulnerability in Cisco IOS. At this point an attacker could crash our routers. I assume at this point we have already enabled authentication so our network would be immune to route injection attacks.

To help combat this problem, Cisco IOS implements "passive-interface" feature. Basically, routing information will not be sent out or accepted on an interface marked as passive.

There are two ways to implement this feature :

1. "passive-interface default" - marks all interfaces as passive, interfaces that should be part of routing system must be explicitly configured with "no passive-interface" command.

Sample configuration (sets all interface except f0/0 and f0/1 to passive mode):

router ospf 1
 passive-interface default
 no passive-interface f0/0
 no passive-interface f0/1

2. mark specific interfaces as passive:

router ospf 1
 passive-interface f0/0
 passive-interface f0/1

It is important to note that in both cases the configuration is performed in the OSPF process context and not interface context.

Access Control List (ACL) is another option to accomplish what passive interfaces would. (Though I find passive interface option much more manageable) We can apply ACLs blocking OSPF traffic on access ports or any ports as required. We need to apply them in both directions as we don't want OSPF traffic coming in or going out. 

Sample configuration:

access-list 101 deny ospf any any
interface f0/0
 ip access-group 101 in
 ip access-group 101 out

Route filtering should also be employed to protect routing systems. Filtering works best at topological edges such as WAN aggregation points. For example if we have 3 branch offices using network ranges of, and we can configure a filter  that will prevent any routing updates outside of range. This can generally be done effectively only on Area Border Routers or Autonomous System Border Routers.  OSPF route filtering is a complex and complicated subject which I'll cover some other time. 

Attacking OSPF - route injection

LOKI and author's Black Hat presentation can be downloaded here: 

Falsifying routing information can have disastrous consequences to network stability. For example an attacker could reroute traffic through a monitoring station and capture traffic for later analysis. An attacker could also reroute traffic to a black hole or reroute a 10 Gig transit link traffic towards a 1 GB link causing a Denial of Service (DoS) condition. 

Both network topology and scenario presented in this post are extremely simplistic but should be sufficient to present potential implications.

Our topology:

R1's routing table looks as follows:

R1#show ip route
C is directly connected, FastEthernet1/0 is subnetted, 1 subnets
C is directly connected, FastEthernet0/0
O [110/2] via, 00:00:01, FastEthernet0/0 is subnetted, 1 subnets
C is directly connected, Loopback0
O [110/3] via, 00:00:01, FastEthernet0/0

Its OSPF neighbor table:

R1#show ip ospf neighbor

Neighbor ID     Pri   State                  Dead Time   Address         Interface       1    FULL/BDR        00:00:35      FastEthernet0/0

To launch LOKI in its default directory -  #python /usr/bin/ 

Once we click run, LOKI will by default capture all control plane protocols it supports. In the screenshot below we can see that LOKI captured an OSPF Hello packet from its adjacent router. From the captured packet we can see the following:
  • IP address the hello was sent from is
  • router ID is (by default highest loopback interface address)
  • OSPF Area is 1
  • OSPF authentication is not enabled

From here we can craft our own OSPF packets. 

Firstly we'll send an empty Hello packet and see what happens. To do so we set "area" to "1" and Authentication type to "AUTH_NONE". We start sending packets by clicking "Hello".

In R1's console we confirm that adjacency was set up:

*Mar  1 04:42:46.654: %OSPF-5-ADJCHG: Process 1, Nbr on FastEthernet1/0 from LOADING to FULL, Loading Done

R1#show ip ospf neighbor

Neighbor ID     Pri   State                 Dead Time   Address         Interface              1   FULL/BDR        00:00:38          FastEthernet1/0       1   FULL/BDR        00:00:35      FastEthernet0/0

To get even more details we enable debugging. 

R1#debug ip ospf events

*Mar  1 00:58:49.691: OSPF: Rcv hello from area 1 from FastEthernet1/0
*Mar  1 00:58:49.691: OSPF: 2 Way Communication to on FastEthernet1/0, state 2WAY
*Mar  1 00:58:49.695: OSPF: Neighbor change Event on interface FastEthernet1/0
*Mar  1 00:58:49.695: OSPF: DR/BDR election on FastEthernet1/0
*Mar  1 00:58:49.695: OSPF: Elect BDR
*Mar  1 00:58:49.695: OSPF: Elect DR
*Mar  1 00:58:49.695:        DR: (Id)   BDR: (Id)
*Mar  1 00:58:49.699: OSPF: Send DBD to on FastEthernet1/0 seq 0x24F2 opt 0x52 flag 0x7 len 32
*Mar  1 00:58:49.699: OSPF: Neighbor change Event on interface FastEthernet1/0
*Mar  1 00:58:49.699: OSPF: DR/BDR election on FastEthernet1/0
*Mar  1 00:58:49.699: OSPF: Elect BDR
*Mar  1 00:58:49.703: OSPF: Elect DR
*Mar  1 00:58:49.703:        DR: (Id)   BDR: (Id)
*Mar  1 00:58:49.703: OSPF: Send immediate hello to nbr, src address, on FastEthernet1/0
*Mar  1 00:58:49.703: OSPF: Send hello to area 1 on FastEthernet1/0 from
*Mar  1 00:58:49.707: OSPF: End of hello processing 

At this point we've set ourselves up as an OSPF neighbor and successfully created an adjacency.

Now we'll inject a false route to network

Now R1 believes that it can get to network via F0/0 (real route) and F1/0 (bogus route). Both paths have the same cost.

R1#show ip route

C is directly connected, FastEthernet1/0 is subnetted, 1 subnets
C is directly connected, FastEthernet0/0
O [110/2] via, 00:00:00, FastEthernet0/0
                    [110/2] via, 00:00:00, FastEthernet1/0 is subnetted, 1 subnets
C is directly connected, Loopback0192.
O [110/3] via, 00:00:00, FastEthernet0/0

We didn't do any actual damage in this example, but this type of attack in an enterprise network could cause serious disruptions. 

This attack can be easily defeated in a number of ways. We can use OSPF authentication, passive interfaces, access control lists or route filtering. Actually all of the above should be used together. More on defenses some other time.  

LOKI supports both clear text (though I couldn't get it to work) and MD5 authentication for OSPF. Clear text is not much of security as the key is sent in clear text so it can be sniffed.  In 

LOKI detects type of authentication used and let's us attempt to crack it. We can feed it a word list or use brute force. LOKI cracked my key of "test" (not much of a key) on a slow VM in a couple of seconds. 

Auditing Cisco configuration - startup-config vs running-config

There are two types of config files in Cisco switches and routers. They are "startup" and "running" configs. 

Startup config - is a configuration file stored in NVRAM that a device will use to configure itself upon reload. It can be viewed by running "show startup-config" command. 

Running config - is a currently used configuration stored in volatile memory. It can be viewed by running "show running-config" command.

When an admin logs in to a switch and makes configuration changes they are applied to running config. In order for them to be retained after switch reload, those changes must be committed to startup config by running "copy running-config startup-config" or simply "wr". If changes are not committed they will be lost upon reboot. 

Output of "show running-config" at the very beginning includes information regarding when last changes were made and when they were last committed.

In this example we can see that user "net-admin" made changes and committed them 1 second later:

! Last configuration change at 10:24:49 GMT Thu Mar 15 2012 by net-admin
! NVRAM config last updated at 10:24:50 GMT Thu Mar 15 2012 by net-admin

In this example we see that last configuration change was made in March but  last saved to startup config in February. This could cause unexpected issues upon switch reboot. 

! Last configuration change at 11:50:49 GMT Thu Mar 15 2012 by net-admin
! NVRAM config last updated at 10:24:50 GMT Thu Feb 15 2012 by net-admin

When I audit Cisco configuration I normally get both startup and running config. If I see discrepancy in timestamps I compare both configs. 

We can compare configs using CSDIFF. It is a free source code auditing tool which works great with config files. That way you can asses how important the changes were and what would the potential impact be had the switch been rebooted. 

CSDIF can be downloaded here:

By looking at last changed and last saved times, we can asses change management practices used by our Network Admins. If changes are consistently not committed, it would suggest that there is an issue in change management procedures and they should be reviewed.   

Auditing Cisco configuration - CIS RAT

CIS RAT (Centre for Internet Security - Router Assessment Tool) is a free Perl tool that audits Cisco config files against CIS benchmarks, it creates an HTML report and shows where your config meets or fails CIS benchmark. We can audit against benchmark level 1 and 2.The tool is supported on both Linux and Windows (though getting it to work on Windows required a bit of source code tweaking). 

RAT can audit configuration of the following devices:
  • IOS
  • ASA
  • PIX
  • FWSM
RAT can be downloaded here: 

Installation on Windows requires ActiveState Perl to be installed. Detailed installation instruction can be found in "rat\etc\install.win32.txt" upon extraction. 

Upon installing RAT I had to edit "" and change the following (this shouldn't be required so it may work in your case)

  • line 669: to point to the correct directory
    • use lib 'c:\rat\lib';.
  • lines 746 & 747: again hard coding the paths
    • $ncat_prog        = $PROG_PREFIX . '\bin\';
    • $ncat_report_prog = $PROG_PREFIX . '\bin\'

RAT allows us to customize set of "checks" we want to perform. This step is not required if you want to audit against actual CIS benchmark, in most cases however, we will want to edit it to align it with our Security Policy. 

Run "":

"C:\rat\bin>perl -s customorules.conf"

The script will ask a number of questions and allow you to customize set of checks it'll perform. It'll then save "customrules.conf". For example if you have a separate management network (for VTY access or SNMP) that you already protect with ACLs you may not want to apply additional local ACLs, which is required by the "default" CIS benchmark. Another example is exec timeout. CIS requires that the timeout is set to 10 while your security policy may require 5.  

Running RAT:

By default RAT uses rule set for IOS devices, so we don't need to specify -t. 

c:\>perl  -r customrules.conf "c:\confs\"

To audit PIX, ASA, FWSM we need to use option "-t" to specify config type:

c:\>perl -t cisco-firewall -r customrules.conf "c:\confs\"

I have run into issue where RAT will fail with the following error:

"Nested quantifiers in regex; marked by <-- HERE in m/IOSSNMPCommunity->** <-- "

This happens when "snmp-server community" option is set to asterisks. That would be the case if you copy the IOS config file from CiscoWorks.  Just delete the asterisks and re-run the script.