SCANNING IPS-PROTECTED NETWORKS WITH NESSUS
Jacob Thompson, Independent Security Evaluators
A Nessus vulnerability scan is one component of an overall network-level security assessment. Frequently, networks are protected by an intrusion prevention system (IPS). IPS rules may block traffic when throughput, packet counts, or connection counts cross a predefined threshold, or when packets are sent to blacklisted ports. Nessus provides neither a facility to restrict the scan rate, nor any reliable method to restrict the TCP and UDP ports to which it sends traffic. This paper describes the difficulties encountered in controlling these aspects of Nessus scans and a workaround ISE developed using virtualization, packet filters, and traffic control.
Introduction
An early step in most network security assessments involves reconnaissance probes to identify the hosts and services accessible on the target network. Just as a real attacker would try to avoid detection, for various reasons so should the security analyst performing an assessment. Intrusion Prevention Systems (IPS) with port scan or threshold detection mechanisms, slow or congested networks, and even system administrators who may notice a declining network performance could both detect and block, rate-limit, filter, redirect, or otherwise screw up reconnaissance probes. Inaccurate probes can result in vulnerable services left undiscovered, and an overall inaccurate assessment. To avoid detection and its associated pitfalls, it is useful to limit the scan rate and breadth of hosts and services targetted.
The capabilities to both limit scan rates and to restrict the target destination ports are found in most free and commercial scans. For the most part, these implementations are effective, but Tenable's Nessus and possibly others, despite having the configuration options that appear to limit scan rates and restrict destination ports, do not work reliably. Security analysts who blindly trust these options are performing more intrusive scans than they may realize or intend. In this paper, ISE describes a workaround for controlling scan traffic that extends to any scanner.
Effective Rate Limiting Example
The Nmap scanner, a well-known, freely-available tool for discovering running hosts on networks and enumerating the network services running on them, provides some IPS-evasion functionality. Its documentation1 suggests using the --scan-delay flag to introduce a delay between successive packets. Further, the -p flag restricts the scanned ports to only those listed. Thus, a rate-limited scan of HTTP and HTTPS, with version detection, may be run with the following command:
nmap ‐sV ‐Pn ‐n ‐p 80,443 --scan-delay 0.5s target
The --scan-delay and -p options accomplish the two goals:
- Nmap always waits one-half second between successive probes, and
- since OS fingerprinting is disabled, Nmap restricts its probes to only the ports specified by the -p option.
Nessus, a commercial scanner, uses more powerful and more frequently updated plugins to identify specific service-level vulnerabilities. Unfortunately, in contrast to Nmap, Nessus has no facility to limit the scan rate in the form of "t seconds between probes," and its plugins often ignore the scan policy and generate traffic to ports that were specified to be ignored.
Nessus Limitations
Ideally, Nessus scan policies would support the constraints of adding a delay between successive probes and preventing traffic to all ports except an explicitly allowed white-list. First, we describe the configuration options available in Nessus that control the scan rate and ports to scan, and explain why these settings fail to impose those constraints. As of this writing, version 6.3.3 and plugin set 201503240515 is the latest version and plugin set of the Nessus scanner. This configuration was used to evaluate the limitations.
Issues Rate Limiting Scans
The Performance section of the scan policy contains the following settings:
- Max Checks Per Host, which limits the number of checks that can execute simultaneously against a single host;
- Max Hosts Per Scan which limits the number of hosts that can be scanned simultaneously;
- Network Receive Timeout, which specifies the number of seconds Nessus will wait for a response to a probe unless overridden by a plugin;
- Max Simultaneous TCP Sessions Per Host, which limits the maximum number of established TCP sessions on one host;
- Max Simultaneous TCP Sessions Per Scan, which limits the maximum number of established TCP sessions (not effective when Max Hosts Per Scan is 1);
By setting the Max Checks Per Host, Max Hosts Per Scan, Max Simultaneous TCP Sessions Per Host, and Max Simultaneous TCP Sessions Per Scan options all to 1, Nessus performs the slowest scan possible. However, there is no control over the actual scan rate, and some plugins may be faster than others. Some of these settings, such as Network Receive Timeout, can be overridden and ignored by plugins entirely.
Issues Restricting Scanned Ports
The Nessus documentation2 suggests two scan policy options that might prevent the scanner from sending traffic to any ports other than those specified:
- Port Scan Range; and
- Consider Unscanned Ports as Closed.
The presumptive purpose of combining these options is to prevent the vulnerability scanner from sending traffic to any ports other than those listed under Port Scan Range. However, restricting the port scan range to 80, 443 and enabling Consider Unscanned Ports as Closed still sends traffic to other ports.
Another possibility, suggested in a Tenable forum post3, is to add reject rules to the nessusd.rules file for all ports other than those desired. That also fails.
Figure 1 shows the tcpdump logs traffic generated to ports other than 80 and 443, despite both of these configuration methods used to restrict Nessus's port range.
# sudo tcpdump -i tap0 -p -n -q 'dst 10.0.1.194 and not dst port 80 and not dst port 443' tcpdump: verbose output suppressed, use -v or -vv for full protocol decod listening on tap0, link-type EN10MB (Ethernet), capture size 65535 byte 15:04:16.641700 IP 172.16.0.2.68 > 10.0.1.194.67: UDP, length 341 15:04:19.686034 IP 172.16.0.2.520 > 10.0.1.194.520: UDP, length 2 15:04:19.686249 IP 172.16.0.2.520 > 10.0.1.194.520: UDP, length 2 15:04:19.692011 IP 172.16.0.2 >10.0.1.194: ICMP type-#37, length 15:04:20.706797 IP 172.16.0.2 > 10.0.1.194: ICMP address mask request, length 12 15:04:23.772784 IP 172.16.0.2 > 10.0.1.194: ICMP address mask request, length 1 15:04:26.884169 IP 172.16.0.2 > 10.0.1.194: ICMP address mask request, length 1 15:04:29.949591 IP 172.16.0.2.500 > 10.0.1.194.500: UDP, length 1416 15:04:50.044859 IP 172.16.0.2.500 >10.0.1.194.500: UDP, length 46 15:05:10.124860 IP 172.16.0.2.500 > 10.0.1.194.500: UDP, length 49 15:05:30.209046 IP 172.16.0.2.500 > 10.0.1.194.500: UDP, length 55 15:05:50.294137 IP 172.16.0.2.500 > 10.0.1.194.500: UDP, length 620 15:06:10.383545 IP 172.16.0.2.500 > 10.0.1.194.500: UDP, length 74 15:06:30.475396 IP 172.16.0.2.500 > 10.0.1.194.500: UDP, length 87 15:06:50.571382 IP 172.16.0.2.56923 > 10.0.1.194.69: UDP, length 27 15:06:51.586310 IP 172.16.0.2.56923 > 10.0.1.194.69: UDP, length 2 15:06:52.600532 IP 172.16.0.2.56923 > 10.0.1.194.69: UDP, length 2 15:06:53.615139 IP 172.16.0.2.64052 > 10.0.1.194.69: UDP, length 2 15:06:54.629797 IP 172.16.0.2.64052 > 10.0.1.194.69: UDP, length 24 15:06:55.644433 IP 172.16.0.2.64052 > 10.0.1.194.69: UDP, length 2 15:06:56.660460 IP 172.16.0.2.43722 > 10.0.1.194.6969: UDP, length 1 15:07:11.679232 IP 172.16.0.2.3133 > 10.0.1.194.25771: tcp 15:07:14.722295 IP 172.16.0.2.3133 > 10.0.1.194.25771: tcp 1 15:07:17.773582 IP 172.16.0.2.53448 > 10.0.1.194.0: tcp 15:07:19.801784 IP 172.16.0.2.53448 > 10.0.1.194.0: tcp 15:07:21.830032 IP 172.16.0.2.53448 > 10.0.1.194.0: tcp 15:07:23.864593 IP 172.16.0.2.20 > 10.0.1.194.8888: tcp 0 15:07:23.876154 IP 172.16.0.2.35277 > 10.0.1.194.1900: UDP, length 25 15:07:24.176791 IP 172.16.0.2 > 10.0.1.194: ICMP time stamp query id 1 seq 1, length 3
Issues Employing Local Firewall
Since there is no simple, reliable way to prevent Nessus from generating the unwanted traffic, the alternative is to drop that traffic before it leaves the host using a firewall on the local machine. The operating system should first block all traffic to the target, and then explicitly allow only the desired ports. ISE tested this scenario using an iptables rule blocking the destination host entirely, but the traffic of Figure 1 was still generated. In particular, traffic still reaches other ports, including 67/udp (DHCP), 69/udp (TFTP), 500/tcp (ISAKMP), and 1900/udp (UPnP), as well as various ICMP requests.
The reason for the persistent, unwanted traffic is that Nessus uses the Linux packet socket interface to craft and deliver custom packets directly to the networking device. Packet sockets are created by calling socket with a first argument of PF_PACKET. As documented, "Packet sockets are not subject to the input or output firewall chains." Thus, iptables rules on the host machine are ineffective methods to prevent any Nessus plugins that use packet sockets from sending the unwanted packets.
# strace -f -e socket -p 633 2>&1 | grep PF_PACKET [pid 10972] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10972] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 15 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 15 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 15 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 15 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 15 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 15 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 1 [pid 10939] socket(PF_PACKET, SOCK_RAW, 768) = 15
Virtualization Solution
An easy way to get around the fact that Linux will not filter packet sockets is to run the scanner on a guest virtual machine (VM), and filter and shape the traffic on the VM host. Using qemu, network traffic passes between the guest VM's eth0 interface and the host's tap0 interface, as depicted in Figure 3.
Traffic Control
To achieve the constraint of at least a one-half second delay between probes, we use the Linux Token Bucket Filter queue discipline with the following parameters:
- peakrate of 24000 bits per second, or two 1500-byte packets,
- mtu of 1500 bytes, matching the MTU of the Ethernet interface,
- latency of 5 seconds, so that packets that would be delayed by more than 5 seconds are instead dropped,
- burst of 1500 bytes, to prevent bursts of traffic,
- mpu of 1500 bytes, treating all packets as if they were 1500 bytes, so that the limit is two packets per second, rather than 24000 bits per second, and
- rate of 23999 bits per second, the token creation rate. This must be strictly less than peakrate to be accepted by the kernel.
The resulting rules are shown in Figure 4.
tc qdisc add dev eth0 handle 1:0 root prio priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 tc qdisc add dev eth0 parent 1:1 handle 10:0 pfifo tc qdisc add dev eth0 parent 1:2 handle 20:0 pfifo tc qdisc add dev eth0 parent 1:3 handle 30:0 tbf rate 23999 mpu 1500 burst 1500 latency \ 5s peakrate 24000 minburst 15000 tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip dst target/32 flowid 1:3
Firewall
The host machine operates as a normal Linux-based router. Traffic originating from the guest VM is subject to iptables firewall rules on the VM host -- even if generated by a packet socket. The commands shown in Figure 5 configure the host to forward traffic from the guest (172.16.0.2) if it is destined to TCP ports 80 or 443. UDP traffic, and TCP traffic to other ports, is dropped.
iptables ‐P FORWARD DROP iptables ‐P FORWARD DROP iptables ‐A FORWARD ‐s 172.16.0.2 ‐d target ‐p tcp --dport 80 -j ACCEPT iptables ‐A FORWARD ‐s 172.16.0.2 ‐d target ‐p tcp --dport 443 -j ACCEPT iptables ‐A FORWARD ‐s 172.16.0.2 ‐d target ‐j REJECT iptables ‐A FORWARD ‐s 172.16.0.2 ‐j ACCEPT iptables ‐A FORWARD ‐d 172.16.0.2 ‐j ACCEPT iptables ‐t nat ‐A POSTROUTING ‐s 172.16.0.2 ‐j MASQUERADE sysctl net.ipv4.ip_forward=1
Appendix
Qemu Startup Scirpt
#!/bin/sh DIR=`dirname $0` exec $DIR/qemu-tap-wrapper -hda $DIR/hda.qcow2 -m 1024 -usb -usbdevice tablet -net nic -enable-kvm
Qemu Tap Wrapper Program
<iframe src="qemu-tap-wrapper.c" width="80%"></iframe>
References
[3] Nessusd.rules File Failing to Apply Reject Port Rule Correctly Discussion