Pentesting - Nmap Stealth Scan

Sat 11 April 2020

A stealthy way to scan with nmap. This article shows the TCP Idle Scan in use, and try to explain how it works.

TCP Idle Scan introduction

Continuing from the last article about portscanning we will now implement a technique that is more stealthy. By using the Nmap IPID Idle scanning we can spoof the IP-address of an idle host on the network. We have to locate a idle host on our network before we can attempt to spoof its address for scanning purposes.

Find zombie hosts with metsploit ipidseq scanner

Utilize the metasploit ipidseq to probe for zombie hosts:

msf5 > use auxiliary/scanner/ip/ipidseq
msf5 auxiliary(scanner/ip/ipidseq) > hosts -R

Hosts
=====

address          mac  name  os_name  os_flavor  os_sp  purpose  info  comments
-------          ---  ----  -------  ---------  -----  -------  ----  --------
192.168.219.2               Unknown                    device         
192.168.219.128             Unknown                    device         
192.168.219.130             Unknown                    device         
192.168.219.132             Linux                      server         
192.168.219.145             Unknown                    device         
192.168.219.146             Unknown                    device

RHOSTS => file:/tmp/msf-db-rhosts-20200411-8449-1k9r2ja

msf5 auxiliary(scanner/ip/ipidseq) > run

[*] 192.168.219.2's IPID sequence class: Incremental!
[*] Scanned 1 of 6 hosts (16% complete)
[*] 192.168.219.132's IPID sequence class: All zeros
[*] 192.168.219.128's IPID sequence class: Randomized
[*] Scanned 4 of 6 hosts (66% complete)
[*] Scanned 6 of 6 hosts (100% complete)
[*] Auxiliary module execution completed
msf5 auxiliary(scanner/ip/ipidseq) >

Perform TCP Idle scan with nmap

Scan with nmap options: * -pN: Threat all hosts as online, do not attempt host discovery. * -sI: Idle scan.

msf5 auxiliary(scanner/ip/ipidseq) > nmap -Pn -sI 192.168.219.2 192.168.219.132
[*] exec: nmap -Pn -sI 192.168.219.2 192.168.219.132

Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-11 09:51 CEST
Idle scan using zombie 192.168.219.2 (192.168.219.2:80); Class: Incremental
Nmap scan report for 192.168.219.132
Host is up (0.051s latency).
Not shown: 977 closed|filtered ports
PORT     STATE SERVICE
21/tcp   open  ftp
... a lot of output ...
8180/tcp open  unknown
MAC Address: 00:0C:29:5C:70:61 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 20.79 seconds
msf5 auxiliary(scanner/ip/ipidseq) >

TCP Idle Scan explained

As we can see from the outputs I had at least one zombie host on my network, and I managed to scan my target by spoofing the zombie hosts IP-address.

There are several reasons that spoofing an IP-address is advicable. One obvious is that our real IP-address will never be revealed in the log on the hosts that we are scanning, only the IP-address of the zombie host.

Another reason is that many sysadmins configure trust-relationships based on IP-address, which means if we can manage to spoof a trusted IP-address we might discover more resources than otherwise. When performing a portscanning with a spoofed IP-address the result will be based on what the scanned host offer the zombie host.

Idle scan is based on three properties of TCP/IP:

  • You can probe a port by sending a SYN-packet to the port. If the port is open the host will reply with SYN/ACK, and if the port is closed it will respond with an RST.
  • If the SYN-packet is unsolicited, the reply will be an RST, an unsolicited RST will be ignored.
  • Every IP-packet has a IP ID (fragmentation ID), and many system just increment this ID in a predictable manner.

The first part of the procedure is about finding hosts that increment the IP-ID in a predictable manner. Below is the Wireshark capture of the auxiliary/scanner/ip/ipidseq script we used earlier.

An example of a host with Incremental IP-ID scheme. This is a potential zombie host! An example of a host with All-Zero IP-ID scheme. An example of a host with Random IP-ID scheme.

Revisiting our three properties of TCP/IP we now have every bits of our puzzle.

Idle scan of a open port

  • 1a: Attacker send an SYN/ACK to the zombie host.
  • 1b: Zombie host does not expect a SYN/ACK, replying to attacker with an RST and reveals its IP-ID (31201).
  • 2a: Attacker send an forged (with zombie hosts ip) SYN to the target.
  • 2b: Target sends a SYN/ACK to zombie host, which zombie does not expect.
  • 2c: Zombie host sends RST, and increment its IP-ID (31202) to target host because it did not expected the SYN/ACK.
  • 3a: Attacker probes the zombie host with a new SYN/ACK.
  • 3b: Zombie host does not expect SYN/ACK, replying to attacker with a new RST and incremented IP-ID (31203).

IP-ID incremented by: 2

Idle scan of a closed port

  • 1a: Attacker send an SYN/ACK to the zombie host.
  • 1b: Zombie host does not expect a SYN/ACK, replying to attacker with an RST and reveals its IP-ID (31201).
  • 2a: Attacker send an forged (with zombie hosts ip) SYN to the target.
  • 2b: Target sends a RST to zombie host, which zombie does not expect.
  • 2c: Zombie host ignore the RST, leaving the IP-ID unchanged (31201).
  • 3a: Attacker probes the zombie host with a new SYN/ACK.
  • 3b: Zombie host does not expect SYN/ACK, replying to attacker with a new RST and incremented IP-ID (31202).

IP-ID incremented by: 1

Idle scan of a filtered port

  • 1a: Attacker send an SYN/ACK to the zombie host.
  • 1b: Zombie host does not expect a SYN/ACK, replying to attacker with an RST and reveals its IP-ID (31201).
  • 2a: Attacker send an forged (with zombie hosts ip) SYN to the target.
  • 2b: Target ignore the SYN packet. Does not send anything back to zombie host.
  • 2c: Zombie host does not get anything from target host, thus leaving the IP-ID unchanged (31201).
  • 3a: Attacker probes the zombie host with a new SYN/ACK.
  • 3b: Zombie host does not expect SYN/ACK, replying to attacker with a new RST and incremented IP-ID (31202).

IP-ID incremented by: 1

As we can see, from the attackers view there is no way to differ between an closed or filtered port. Both scenario gives the attacker an IP-ID incremented by '1'. If the port is open, the attacker will see an increase in the IP-ID by '2'.

This scan is based on measuring the difference in IP-ID between probe-start and probe-end. If the zombie host doing any other kind of traffic this will fail since the IP-ID will change/increment outside of the attackers control. In other words, the zombie host has to be idle for this method to work.

The hard part of the TCP Idle scan is to find suitable idle zombie hosts. As soon as we have a zombie host we can run our scan like this:

nmap -Pn -sI 192.168.219.2 192.168.219.132

By default nmap forge probes from port 80 on the zombie host, but you can change that if neccessary (be sure that the choosen port is not filtered by attacker or target):

nmap -Pn -sI 192.168.219.2:445 192.168.219.132

That concludes the TCP Idle scan writeup for now. Happy scanning!