UDP Scan (-sU
)
While most popular services on the Internet run over the TCP protocol, UDP services are widely deployed. DNS, SNMP, and DHCP (registered ports 53, 161/162, and 67/68) are three of the most common. Because UDP scanning is generally slower and more difficult than TCP, some security auditors ignore these ports. This is a mistake, as exploitable UDP services are quite common and attackers certainly don't ignore the whole protocol. Fortunately, Nmap can help inventory UDP ports.
UDP scan is activated with the -sU
option. It
can be combined with a TCP scan type such as SYN scan
(-sS
) to check both protocols during the same
run.
UDP scan works by sending a UDP packet to every targeted port. For most ports, this packet will be empty (no payload), but for a few of the more common ports a protocol-specific payload will be sent. Based on the response, or lack thereof, the port is assigned to one of four states, as shown in Table 5.3.
Probe Response | Assigned State |
---|---|
Any UDP response from target port (unusual) | open |
No response received (even after retransmissions) | open|filtered |
ICMP port unreachable error (type 3, code 3) | closed |
Other ICMP unreachable errors (type 3, code 1, 2, 9, 10, or 13) | filtered |
The most curious element of this table may be the
open|filtered
state.
It is a symptom of the
biggest challenges with UDP scanning: open ports rarely respond to empty
probes. Those ports for which Nmap has a protocol-specific payload are
more likely to get a response and be marked open
, but
for the rest, the target TCP/IP stack simply passes the empty packet up
to a listening application, which usually discards it
immediately as invalid. If ports in all other states would respond,
then open ports could all be deduced by elimination. Unfortunately,
firewalls and filtering devices are also known to
drop packets without responding. So when Nmap receives no response after
several attempts, it cannot determine whether the port is
open
or filtered
. When Nmap was
released, filtering devices were rare enough that Nmap could (and did)
simply assume that the port was open
. The Internet
is better guarded now, so Nmap changed in 2004 (version
3.70) to report non-responsive UDP ports as
open|filtered
instead. We can see that in Example 5.4, which shows Ereet scanning
a Linux box named Felix.
krad# nmap -sU -v felix
Starting Nmap ( https://nmap.org )
Nmap scan report for felix.nmap.org (192.168.0.42)
(The 997 ports scanned but not shown below are in state: closed)
PORT STATE SERVICE
53/udp open|filtered domain
67/udp open|filtered dhcpserver
111/udp open|filtered rpcbind
MAC Address: 00:02:E3:14:11:02 (Lite-on Communications)
Nmap done: 1 IP address (1 host up) scanned in 999.25 seconds
This scan of Felix demonstrates the
open|filtered
ambiguity issue as well as another
problem: UDP scanning can be slow. Scanning a
thousand ports took almost 17 minutes in this case due to ICMP response rate limiting performed by Felix and most other Linux systems. Nmap provides
ways to work around both problems, as described by the following two sections.
Distinguishing Open from Filtered UDP Ports
In the case of the Felix scan, all but the three
open|filtered
ports were closed
.
So the scan was still successful in narrowing down potentially open
ports to a handful. That is not always the case. Example 5.5 shows a UDP scan against
the heavily filtered site Scanme.
In this case, the scan didn't narrow down the open ports at all.
All 1000 are open|filtered
. A new strategy is
called for.
Table 5.3, “How Nmap interprets responses to a UDP probe” shows
that the open|filtered
state occurs when Nmap fails
to receive any responses from its UDP probes to a particular port.
Yet it also shows that, on rare occasions, the UDP service
listening on a port will respond in kind, proving that the port is
open. The reason these services don't respond often is that the empty
packets Nmap sends are considered invalid. Unfortunately, UDP services
generally define their own packet structure rather than adhering to
some common general format that Nmap could always send. An SNMP
packet looks completely different than a SunRPC, DHCP, or DNS request
packet.
To send the proper packet for every popular UDP service, Nmap
would need a large database defining their probe formats.
Fortunately, Nmap has that in the form of
nmap-service-probes
,
which is part of the service and
version detection subsystem described in Chapter 7, Service and Application Version Detection.
When version scanning is enabled with -sV
(or
-A
), it will send UDP probes to every
open|filtered
port (as well as known
open
ones). If any of the probes elicit a response from an open|filtered
port, the state is
changed to open
. The results of adding
-sV
to the Felix scan are shown in Example 5.6.
krad# nmap -sUV -F felix.nmap.org
Starting Nmap ( https://nmap.org )
Nmap scan report for felix.nmap.org (192.168.0.42)
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
53/udp open domain ISC BIND 9.2.1
67/udp open|filtered dhcpserver
111/udp open rpcbind 2 (rpc #100000)
MAC Address: 00:02:E3:14:11:02 (Lite-on Communications)
Nmap done: 1 IP address (1 host up) scanned in 1037.57 seconds
This new scan shows that port 111 and 53 are definitely open.
The system isn't perfect though—port 67 is still
open|filtered
. In this particular case, the port
is open but Nmap does not have a working version probe for DHCP.
Another tough service is SNMP, which usually only responds when the
correct community string is given. Many devices are configured with
the community string public
, but not all are.
While these results aren't perfect, learning the true state of two out
of three tested ports is still helpful.
After the success in disambiguating Felix results,
Ereet
turns his attention back to Scanme, which listed all ports as open|filtered
last time. He tries again with version detection, as shown in Example 5.7.
Tip | |
---|---|
While Ereet eventually found the open port, he made a mistake in not updating his Nmap version first. Nmap version 5.10BETA1 and newer have a payload system which sends proper service protocol requests to more than three dozen well known UDP ports if they are selected for port scanning or host discovery. While it isn't as comprehensive as version detection, it would have quickly identified the open port 53 in Example 5.5. |
This result took an hour, versus five seconds for the previous Scanme scan, but these results are actually useful. Ereet's smile widens and eyes sparkle at this evidence of an open ISC BIND nameserver on a machine he wants to compromise. That software has a long history of security holes, so perhaps he can find a flaw in this recent version.
Ereet will focus his UDP attacks on port 53 since it is
confirmed open, but he does not forget about the other 999 ports listed as
open|filtered
. As we witnessed with
the dhcpserver port on Felix, certain open UDP services can hide even
from Nmap version detection. He has also only scanned the default ports so
far, there are 64529 others that could possibly be open. For the
record, 53 is the only open UDP port on Scanme.
While this version detection technique is the only way for Nmap
to automatically disambiguate open|filtered
ports,
there are a couple tricks that can be tried manually. Sometimes a
specialized traceroute can help. You could do a traceroute against a
known-open TCP or UDP port with Nmap or a tool such as
Nping.
Then try the same against
the questionable UDP port. Differences in hop counts can
differentiate open from filtered ports. Ereet attempts this against
Scanme in Example 5.8. The first command does a UDP traceroute against
known-open port 53. The second command does the same thing against
presumed-closed port 54. The first few hops have been omitted to save space.
krad#nping --udp --traceroute -c 13 -p 53 scanme.nmap.org
Starting Nping ( https://nmap.org/nping ) SENT (7.0370s) UDP 192.168.0.21:53 > 64.13.134.52:53 ttl=8 id=4826 iplen=28 RCVD (7.1010s) ICMP 4.69.134.222 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=248 id=38454 iplen=56 SENT (8.0400s) UDP 192.168.0.21:53 > 64.13.134.52:53 ttl=9 id=38166 iplen=28 RCVD (8.1050s) ICMP 4.68.18.204 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=247 id=39583 iplen=56 SENT (9.0420s) UDP 192.168.0.21:53 > 64.13.134.52:53 ttl=10 id=6788 iplen=28 RCVD (9.1080s) ICMP 4.59.4.78 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=246 id=59897 iplen=56 SENT (10.0440s) UDP 192.168.0.21:53 > 64.13.134.52:53 ttl=11 id=366 iplen=28 RCVD (10.1100s) ICMP 69.36.239.221 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=243 id=42710 iplen=56 SENT (11.0470s) UDP 192.168.0.21:53 > 64.13.134.52:53 ttl=12 id=63478 iplen=28 SENT (12.0490s) UDP 192.168.0.21:53 > 64.13.134.52:53 ttl=13 id=56653 iplen=28 Max rtt: 73.003ms | Min rtt: 0.540ms | Avg rtt: 48.731ms Raw packets sent: 13 (364B) | Rcvd: 10 (560B) | Lost: 3 (23.08%) Tx time: 12.02836s | Tx bytes/s: 30.26 | Tx pkts/s: 1.08 Rx time: 13.02994s | Rx bytes/s: 42.98 | Rx pkts/s: 0.77 Nping done: 1 IP address pinged in 13.05 seconds krad#nping --udp --traceroute -c 13 -p 54 scanme.nmap.org
Starting Nping ( https://nmap.org/nping ) SENT (7.0370s) UDP 192.168.0.21:53 > 64.13.134.52:54 ttl=8 id=56481 iplen=28 RCVD (7.1130s) ICMP 4.69.134.214 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=248 id=22437 iplen=56 SENT (8.0400s) UDP 192.168.0.21:53 > 64.13.134.52:54 ttl=9 id=23264 iplen=28 RCVD (8.1060s) ICMP 4.68.18.76 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=247 id=50214 iplen=56 SENT (9.0430s) UDP 192.168.0.21:53 > 64.13.134.52:54 ttl=10 id=9101 iplen=28 RCVD (9.1070s) ICMP 4.59.4.78 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=246 id=880 iplen=56 SENT (10.0450s) UDP 192.168.0.21:53 > 64.13.134.52:54 ttl=11 id=35344 iplen=28 RCVD (10.1110s) ICMP 69.36.239.221 > 192.168.0.21 TTL=0 during transit (type=11/code=0) ttl=243 id=44617 iplen=56 SENT (11.0470s) UDP 192.168.0.21:53 > 64.13.134.52:54 ttl=12 id=53857 iplen=28 SENT (12.0490s) UDP 192.168.0.21:53 > 64.13.134.52:54 ttl=13 id=986 iplen=28 Max rtt: 76.488ms | Min rtt: 0.546ms | Avg rtt: 48.480ms Raw packets sent: 13 (364B) | Rcvd: 11 (616B) | Lost: 2 (15.38%) Tx time: 12.02908s | Tx bytes/s: 30.26 | Tx pkts/s: 1.08 Rx time: 13.03165s | Rx bytes/s: 47.27 | Rx pkts/s: 0.84 Nping done: 1 IP address pinged in 13.05 seconds
In this example, Ereet was only able to reach hop eleven of both the open and closed ports. So these results can't be used to distinguish port states against this host. It was worth a try, and does work in a significant number of cases. It is more likely to work in situations where the screening firewall is at least a hop or two before the target host. Scanme, on the other hand, is running its own Linux iptables host-based firewall. So there is no difference in hop count between filtered and open ports.
Another technique is to try application-specific tools against common ports. For example, a brute force SNMP community string cracker could be tried against port 161. As Nmap's version detection probe database grows, the need to augment its results with external specialized tools is reduced. They will still be useful for special cases, such as SNMP devices with a custom community string.
Speeding Up UDP Scans
The other big challenge with UDP scanning is doing it quickly.
Open and filtered ports rarely send any response, leaving Nmap to time
out and then conduct retransmissions just in case the probe or
response were lost. Closed ports are often an even bigger problem.
They usually send back an ICMP port unreachable error. But unlike the
RST packets sent by closed TCP ports in response to a SYN or connect
scan, many hosts rate limit ICMP port unreachable messages by default.
Linux and Solaris are particularly strict about
this.
For example, the
Linux 2.4.20 kernel on Felix limits destination unreachable messages to one per
second (in net/ipv4/icmp.c
). This explains why
the scan in Example 5.4, “UDP scan example” is so slow.
Nmap detects rate limiting and slows down accordingly to avoid flooding the network with useless packets that the target machine will drop. Unfortunately, a Linux-style limit of one packet per second makes a 65,536-port scan take more than 18 hours. Here are some suggestions for improving UDP scan performance. Also read Chapter 6, Optimizing Nmap Performance for more detailed discussion and general advice.
- Increase host parallelism
If Nmap receives just one port unreachable error from a single target host per second, it could receive 100/second just by scanning 100 such hosts at once. Implement this by passing a large value (such as 100) to
--min-hostgroup
.- Scan popular ports first
Very few UDP port numbers are commonly used. A scan of the most common 100 UDP ports (using the
-F
option) will finish quickly. You can then investigate those results while you launch a multi-day 65K-port sweep of the network in the background.-
Add
--version-intensity 0
to version detection scans As mentioned in the previous section, version detection (
-sV
) is often needed to differentiate open from filtered UDP ports. Version detection is relatively slow since it involves sending a large number of application protocol-specific probes to everyopen
oropen|filtered
port found on the target machines. Specifying--version-intensity 0
directs Nmap to try only the probes most likely to be effective against a given port number. It does this by using data from thenmap-service-probes
file. The performance impact of this option is substantial, as will be demonstrated later in this section.- Scan from behind the firewall
As with TCP, packet filters can slow down scans dramatically. Many modern firewalls make setting packet rate limits easy. If you can bypass that problem by launching the scan from behind the firewall rather than across it, do so.
-
Use
--host-timeout
to skip slow hosts ICMP-rate-limited hosts can take orders of magnitude more time to scan than those that respond to every probe with a quick destination unreachable packet. Specifying a maximum scan time (such as
15m
for 15 minutes) causes Nmap to give up on individual hosts if it hasn't completed scanning them in that much time. This allows you to scan all of the responsive hosts quickly. You can then work on the slow hosts in the background.-
Use
-v
and chill out With verbosity (
-v
) enabled, Nmap provides estimated time for scan completion of each host. There is no need to watch it closely. Get some sleep, head to your favorite pub, read a book, finish other work, or otherwise amuse yourself while Nmap tirelessly scans on your behalf.
A perfect example of the need to optimize UDP scans is
Example 5.7, “Improving Scanme's UDP scan results with version detection”. The scan obtained
the desired data, but it took more than an hour to scan this one host!
In Example 5.9,
Ereet runs that scan
again. This time he adds the -F --version-intensity 0
options and the hour long scan is reduced to 13 seconds! Yet the same
key information (an ISC Bind daemon running on port 53) is
detected.
krad# nmap -sUV -T4 -F --version-intensity 0 scanme.nmap.org
Starting Nmap ( https://nmap.org )
Nmap scan report for scanme.nmap.org (64.13.134.52)
Not shown: 99 open|filtered ports
PORT STATE SERVICE VERSION
53/udp open domain ISC BIND 9.3.4
Nmap done: 1 IP address (1 host up) scanned in 12.92 seconds