IPS Avoidance with Vulnerability Scanners

Monday, May 27, 2013

Nothing impacts a penetration tester's ability to replicate real world threats more than a time restriction. However, time restriction is something that penetration testers almost always have to deal with as most organizations aren't willing to fund open ended black box testing. Sadly, in most cases, the maturity of network defenses is lacking, reducing the impact of time restriction. But in other cases, defenders do stuff right, enhancing the issues brought about by time restrictions through the implementation of time consuming defensive countermeasures. In these cases, penetration testers must find interesting ways to use traditional tools while avoiding detection.

On a recent penetration test, I ran head on into an Intrusion Prevention System (IPS) that was actively preventing port scanning. The IPS was performing temporary blocks on IP addresses that appeared to be scanning the network from external locations. While it was possible to scan slowly to enumerate ports and services, given the size of IP space to be scanned, doing so would have taken all of the time allotted for the test without scratching the surface. Therefore, I came up with a methodology for approaching environments like this in the future.

When anti-port scanning countermeasures are in place, options are limited. Slowing down or getting the information from a third party that was able to bypass the countermeasure are typically the only choices. The aforementioned time restriction usually rules out the possibility of slowing down, so port scan data from a third party resource is preferred.

The first place most people go for third party scan data is Shodan. While a fantastic resource for more than just service availability, Shodan limits the number of ports that it scans, leaving out many critical services. While this is acceptable for raw reconnaissance, thoroughness is critical during discovery.

Another great resource for third party scan data is exfiltrated.com. Exfiltrated.com is a search front end to the Internet Census 2012 which leveraged vulnerable embedded devices to create a distributed port scanner and scan the entire Internet for the most popular 1024 ports as designated by Nmap. Using this search engine, users are able to retrieve port scan results for all public facing version 4 IP addresses on the Internet, as seen in 2012. The accuracy of the results may vary depending on the target, but for most corporate networks, the Census is likely to produce reliable results as external resources typically don't change often and the distributed nature of the Census scanner allowed it remain undetected by port scanning countermeasures.

Once port scan data is had, it is usually safe to begin using Nmap in a very controlled fashion to fingerprint services. In my experience, fingerprinting individual services at T2 ("polite" timing rate option) with Nmap is sufficient to avoid detection. The next natural step is to conduct research on the fingerprinted services to identify vulnerabilities and possible exploit vectors. Once again, time becomes an issue. While manual research and exploitation is the stealthiest way to exploit a target, the process can be sped up by restricting a traditional vulnerability scanner and using it to determine the exploitability of identified services.

Restricting a vulnerability scanner to only assess the security of a few services seems like something all scanners should be equipped to do. This is not the case. Take Nessus for instance. Nessus does not allow explicit port restrictions for the plugin scanner. Nessus allows port scanning to be restricted to specific ports, but when the plugin scanner kicks off, tcpdump shows that Nessus stills generates traffic on ports that are not designated for port scanning. After exchanging emails and tweets with multiple people from Tenable, it appears that while port scanning can be restricted, the Nessus plugin scanner will continue to scan ports and services that are associated with enabled plugins. This does't make much sense to me and seems awfully inefficient. If the Nessus port scanner reports a port as closed, why would the plugin scanner not cross reference the port scan results and launch plugins for only available services? In any case, we have options to enforce this kind of restriction ourselves.

The first option is a technique proposed by my good friend Jake Williams. He recommends setting up a virtual machine, preferably local to the Nessus instance, with port forwarding to remote targets for only the desired ports. Then, scan the port forwarding host with Nessus. While a viable technique, this is difficult to implement using a third party hosted Nessus server. This option is good for local Nessus servers, where it is trivial to establish systems and traffic flow around an existing Nessus server.

The second option is a technique proposed by John Strand. He recommends using iptables to restrict outbound traffic to remote services. This option is good for remote Nessus servers, as everything is self contained and doesn't require control of any additional remote resources.

While using iptables to restrict outbound traffic is a simple idea, it's implementation can be a little tricky, as remote Nessus servers require communication over port 22 for SSH and port 8834 for the Nessus daemon. With a little tinkering, iptables flexes its muscles and provides us with a decent solution. Here is an iptables configuration that works well.

iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 8834 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -p tcp -j REJECT --reject-with tcp-reset
iptables -A OUTPUT -j DROP

Let's look at the configuration line by line. Notice that all of the rules are applied to the OUTPUT chain. This assures that the restrictions apply to the traffic originating on the machine as well.

iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 8834 -m state --state ESTABLISHED,RELATED -j ACCEPT

These two lines ensure that established TCP connections or TCP handshakes originating from remote hosts for services on port 22 and 8834 are allowed to communicate without allowing Nessus to initiate sessions over port 22 or 8834. This is required for continued remote administration of the server and access to the Nessus server web interface.

iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT

This line specifies which remote port traffic is being restricting to. In this example, Nessus is only able to scan remote port 443. Everything else will be restricted by the following lines.

iptables -A OUTPUT -p tcp -j REJECT --reject-with tcp-reset

This line replies to all TCP connection requests not explicitly allowed by the previous rule(s) with a TCP reset. This prevents long waits for TCP timeouts resulting from dropped packets, speeding up the scanner.

iptables -A OUTPUT -j DROP

This line drops all other traffic that was not rejected by the above statement. This typically applies to UDP and ICMP traffic.

Once iptables is configured, the scanner must be set up to use this configuration efficiently. Nessus allows users to establish scan policies under the "Policies" tab. A copy of an original policy should be created and the "Port Scanning" settings under "Policy General Settings" should be set similar to the following. These settings configure Nessus to conduct minimal port scanning of only port 443.

At this point, all that is left is creating a scan, configuring it to use the customized policy, and launching it. Then, rinse and repeat for each interesting service.

Update #1

Carlos Perez proposes another option for surgical scanning with Nessus. He recommends using the nessus.rules file to create rules which restrict Nessus to only certain IP addresses, ports and plug-ins. The nessus.rules file would look something like the following.

# Nessus rules
#

# Syntax: accept|reject address/netmask

# reject 10.42.123.0/24
reject 192.168.0.1
reject 192.168.0.2
# You can also deny/allow certain ports:
# Forbid connecting to port 80 for 10.0.0.1:
reject 10.0.0.1:80
# Forbid connecting to ports 8000 - 10000 for any host in the 192.168.0.0/24 subnet:
reject 192.168.0.0/24:8000-10000

# You can also deny/allow the use of certain plugin IDs:
plugin-reject 10335
plugin-accept 10000-40000

# Accept to test anything:
default accept

Like what you see? Join me for live training! See the Training page for more information.


Please share your thoughts, comments, and suggestions via Twitter.