Wednesday, January 31, 2024

Knock! Knock!! Anyone There? - Reconnaissance and Defense

In a recent session with our team as part of our MDR Wednesdays program, we were discussing reconnaissance and the usage of port 0. Not surprisingly, quite a few persons were surprised to hear about port 0 and its usage in reconnaissance. This blog post is meant as an additional resource, to aid the understanding. 

One of the first steps, any threat actor will perform in any attack, is reconnaissance. It is the first column in the MITRE ATT&CK Framework and similarly, it is the first task in the Cyber Kill Chain. That is how important this task is.  This post is more around that "active" reconnaissance. To learn more about "passive" reconnaissance, see this link.

Additionally, to make this more realistic, we will use the world's most popular network scanning/mapping tool Nmap. 

Now let's be clear, if you are in an enterprise, I expect you have a security team and firewalls deployed to prevent some of these reconnaissance measures. At the same time, it is quite possible you are in an enterprise but have misconfigured firewalls. Who knows! If you are in a small business with no security team, I would not be surprised if you have not mitigated these reconnaissance measures.

Enough talking and let's get going. Before getting to why a threat actor may target port 0, let's start off with the regular reconnaissance.

 ________________		_______________
| THREAT ACTOR 	|              |     TARGET   |
| 10.0.0.110    | --------->>> |   10.0.0.100 |
|_______________|	       |______________|

Starting with the traditional "ping". Running Nmap with the -PE option, we see from Nmap

┌──(kali㉿securitynik)-[~]
└─$ sudo Nmap --send-ip -n 10.0.0.100 -sn -PE
Starting Nmap 7.94SVN ( https://Nmap.org ) at 2024-01-30 22:30 EST

Nmap scan report for 10.0.0.100
Host is up (0.00091s latency).
MAC Address: 00:0C:29:A2:BB:D7 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 0.26 seconds

How does Nmap knows the host is up? Well if we look at tcpdump, output on the TARGET we see the following.

securitynik@seruritynik-srv:~$ sudo tcpdump -nnti ens33 'host 10.0.0.110 and icmp'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.0.0.110 > 10.0.0.100: ICMP echo request, id 59426, seq 0, length 8
IP 10.0.0.100 > 10.0.0.110: ICMP echo reply, id 59426, seq 0, length 8

As you can see from above, the echo request had an echo reply. Let's now go ahead and block these ICMP echo request on the firewall to prevent this type of reconnaissance.

securitynik@seruritynik-srv:~$ sudo iptables --table filter --append INPUT --proto icmp --in-interface ens33  --icmp-type 8/0 --jump DROP

The command above DROPs the packet. Note this is specific to ICMP Echo Request. Hence, the system will not respond with an ICMP Echo Reply.

Let's run Nmap again.

┌──(kali㉿securitynik)-[~]
└─$ sudo Nmap --send-ip -n 10.0.0.100 -sn -PE
Starting Nmap 7.94SVN ( https://Nmap.org ) at 2024-01-30 22:47 EST
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 2.08 seconds

Now Nmap is reporting 0 host up. Let's see what was seen via tcpdump on the target.

securitynik@seruritynik-srv:~$ sudo tcpdump -nnti ens33 'host 10.0.0.110 and icmp'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.0.0.110 > 10.0.0.100: ICMP echo request, id 55102, seq 0, length 8
IP 10.0.0.110 > 10.0.0.100: ICMP echo request, id 16092, seq 0, length 8

Great, we see that even though the ICMP Echo Request came in, there was no ICMP Echo Reply. Hence the reason why Nmap reported the host is not up.

Confirming the firewall dropped this traffic.

securitynik@seruritynik-srv:~$ sudo iptables --list INPUT --numeric --verbose
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    2    56 DROP       icmp --  ens33  *       0.0.0.0/0            0.0.0.0/0            icmptype 8 code 0

So we confirmed the firewall is now dropping this traffic. Great! But guess what, if you looked at Nmap manpage, you see there are other techniques available to target ICMP. Let's go ahead with another.

This time, we try the Timestamp Request method.

┌──(kali㉿securitynik)-[~]
└─$ sudo Nmap --send-ip -n 10.0.0.100 -sn -PP
Starting Nmap 7.94SVN ( https://Nmap.org ) at 2024-01-30 22:59 EST
Nmap scan report for 10.0.0.100
Host is up (0.00072s latency).
MAC Address: 00:0C:29:A2:BB:D7 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 0.14 seconds

We see that the host is once again reported as up. We can also verify what Nmap received by looking at the target.

securitynik@seruritynik-srv:~$ sudo tcpdump -nnti ens33 'host 10.0.0.110 and icmp'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.0.0.110 > 10.0.0.100: ICMP time stamp query id 7808 seq 0, length 20
IP 10.0.0.100 > 10.0.0.110: ICMP time stamp reply id 7808 seq 0: org 00:00:00.000, recv 03:59:38.965, xmit 03:59:38.965, length 20

Great, so the pings we blocked did not prevent the ICMP reconnaissance so far. Let's now go ahead and block the Timestamp Request.

securitynik@seruritynik-srv:~$ sudo iptables --table filter --append INPUT --proto icmp --in-interface ens33  --icmp-type 13/0 --jump DROP

Trying the Timestamp reconnaissance again. 

┌──(kali㉿securitynik)-[~]
└─$ sudo Nmap --send-ip -n 10.0.0.100 -sn -PP
Starting Nmap 7.94SVN ( https://Nmap.org ) at 2024-01-30 23:03 EST
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 2.08 seconds

Great, we seem to block this one also, as Nmap is once again reporting 0 host up.

Let's confirm at our firewall.

securitynik@seruritynik-srv:~$ sudo iptables --list INPUT --numeric --verbose
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    2    56 DROP       icmp --  ens33  *       0.0.0.0/0            0.0.0.0/0            icmptype 8 code 0
    2    80 DROP       icmp --  ens33  *       0.0.0.0/0            0.0.0.0/0            icmptype 13 code 0

Great we are now blocking the Timestamp request. But Nmap also have the netmask request discovery. Let's try the last of these Nmap methods.

┌──(kali㉿securitynik)-[~]
└─$ sudo Nmap --send-ip -n 10.0.0.100 -sn -PM
Starting Nmap 7.94SVN ( https://Nmap.org ) at 2024-01-30 23:07 EST
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 2.07 seconds

Ooops! Nmap is reporting 0 host up. How could this be? We did not block this traffic. Let us see what the target host sees.

securitynik@seruritynik-srv:~$ sudo tcpdump -nnti ens33 'host 10.0.0.110 and icmp'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.0.0.110 > 10.0.0.100: ICMP address mask request, length 12
IP 10.0.0.110 > 10.0.0.100: ICMP address mask request, length 12

Well the host sees the request but there is no response. Why is this so? Well fortunately, in this case, there is nothing for us to do as this method seems to have been deprecated based on RFC 6918 sections 2.4 and 2.5. 

However, a threat actor can try other mechanisms, such as specifically crafting a packet using scapy. Do keep in mind, there are a lot of these ICMP types and codes that have been deprecated, but depending on the system being targeted (older system?, IoT device?) some of these techniques may still succeed.

Now just to be clear, I only went through blocking those individual types for learning experience. The reality is, we could have done one line to block all ICMP, such as below.

securitynik@seruritynik-srv:~$ sudo iptables --table filter --append INPUT --proto icmp --in-interface ens33 --jump DROP
securitynik@seruritynik-srv:~$ sudo iptables --list INPUT --numeric --verbose
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       icmp --  ens33  *       0.0.0.0/0            0.0.0.0/0

If we run the commands above again all should be blocked. You should then see something such as below in your firewall table.

securitynik@seruritynik-srv:~$ sudo iptables --list INPUT --numeric --verbose
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    6   200 DROP       icmp --  ens33  *       0.0.0.0/0            0.0.0.0/0

Ok. Now we have completed the initial part of understanding why we need to get to port 0.

Here we go! The firewall is blocking all ICMP traffic. However, we are still interested in simply knowing if the host is up. Let's figure that out.

First things first, there should never be any service running on port 0. For example, if we run netstat or in my case below ss, we see on this host:

securitynik@seruritynik-srv:~$ sudo ss --numeric --listening --tcp
State          Recv-Q         Send-Q                 Local Address:Port                    Peer Address:Port         Process
LISTEN         0              4096                         0.0.0.0:27017                        0.0.0.0:*
LISTEN         0              4096                   127.0.0.53%lo:53                           0.0.0.0:*
LISTEN         0              128                          0.0.0.0:22                           0.0.0.0:*
LISTEN         0              244                          0.0.0.0:5432                         0.0.0.0:*
LISTEN         0              128                             [::]:22                              [::]:*
LISTEN         0              244                             [::]:5432                            [::]:*

There is no port 0. So once again, why would an attacker port 0? Let's run Nmap to figure it out.

┌──(kali㉿securitynik)-[~]
└─$ sudo nmap --send-ip -n 10.0.0.100 -Pn -p 0 --reason
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-30 23:27 EST
Nmap scan report for 10.0.0.100

Host is up, received user-set (0.00052s latency).

PORT  STATE  SERVICE REASON
0/tcp closed unknown reset ttl 64
MAC Address: 00:0C:29:A2:BB:D7 (VMware)

Nmap done: 1 IP address (1 host up) scanned in 0.20 seconds

We see above Nmap is reporting 1 host up. We also see the reason it knows the host is up, is because it got a "reset". We can confirm at the target host that it did send a reset message.

securitynik@seruritynik-srv:~$ sudo tcpdump -nnti ens33 'host 10.0.0.110 and port 0'

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode

listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.0.0.110.61475 > 10.0.0.100.0: Flags [S], seq 1785192689, win 1024, options [mss 1460], length 0
IP 10.0.0.100.0 > 10.0.0.110.61475: Flags [R.], seq 0, ack 1785192690, win 0, length 0

So what was the objective above? Even though we block the ICMP messages, from a reconnaissance perspective, the threat actor could target port 0, just to illicit this [R.] message. This confirms the host is online and hence the threat actor would have achieved the same objective as if he or she had pinged the host and got a response.

Let's close this off by blocking traffic coming in to port 0.

securitynik@seruritynik-srv:~$ sudo iptables --table filter --append INPUT --proto tcp --dport 0 --in-interface ens33 --jump DROP

Run the scan again

┌──(kali㉿securitynik)-[~]
└─$ sudo nmap --send-ip -n 10.0.0.100 -Pn -p 0 --reason
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-01-30 23:32 EST
Nmap scan report for 10.0.0.100

Host is up, received user-set.

PORT  STATE    SERVICE REASON
0/tcp filtered unknown no-response

Nmap done: 1 IP address (1 host up) scanned in 2.10 seconds

Now I find it strange above, that the REASON given is no-response but yet still Nmap is reporting 1 host is up. I take it this has to do with ARP. See the reference section for a discussion on this scenario. However, if you have a clearer answer, let me know.

If we look at the host, we can see the SYNs came in but no [R.] was sent.

securitynik@seruritynik-srv:~$ sudo tcpdump -nnti ens33 'host 10.0.0.110 and port 0'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.0.0.110.46295 > 10.0.0.100.0: Flags [S], seq 11534259, win 1024, options [mss 1460], length 0
IP 10.0.0.110.46297 > 10.0.0.100.0: Flags [S], seq 11403185, win 1024, options [mss 1460], length 0
IP 10.0.0.110.39645 > 10.0.0.100.0: Flags [S], seq 465318364, win 1024, options [mss 1460], length 0
IP 10.0.0.110.39647 > 10.0.0.100.0: Flags [S], seq 465449438, win 1024, options [mss 1460], length 0
IP 10.0.0.110.65137 > 10.0.0.100.0: Flags [S], seq 899162038, win 1024, options [mss 1460], length 0
IP 10.0.0.110.65139 > 10.0.0.100.0: Flags [S], seq 899293108, win 1024, options [mss 1460], length 0

We also see the firewall is dropping the Port 0 packets as while the SYN came in, there is no RST ACK.

I decided to try another trick, just in case for some strange reason the RST was being generated and I was not seeing it. This time, I configured the firewall to prevent the RST from leaving the device. 

securitynik@seruritynik-srv:~$ sudo iptables --table filter --append OUTPUT --proto tcp --dport 0 --tcp-flags RST RST --out-interface ens33 --jump DROP

When I rerun the attack, targeting port 0, the output is basically the same. No RST. Which is what I expected because I blocked the port earlier.

securitynik@seruritynik-srv:~$ sudo tcpdump -nnti ens33 'host 10.0.0.110 and port 0'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 10.0.0.110.64965 > 10.0.0.100.0: Flags [S], seq 1541258948, win 1024, options [mss 1460], length 0
IP 10.0.0.110.64967 > 10.0.0.100.0: Flags [S], seq 1541390022, win 1024, options [mss 1460], length 0

Peaking into the firewall to see if any RST was generated and prevented from leaving, we see:

securitynik@seruritynik-srv:~$ sudo iptables --list OUTPUT --numeric --verbose
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 DROP       tcp  --  *      ens33   0.0.0.0/0            0.0.0.0/0            tcp dpt:0 flags:0x04/0x04

Basically, the RST was not even generated and thus no opportunity to even be dropped.

Ok. I think we address the learnings for this example. No need to do anything else with this. 

Main takeaway? Other than pings, threat actors can identify whether a host is live or not by using some seemingly simple reconnaissance techniques. We covered a few in this post. However, there are many more you can try on your own.


References:
Internet Control Message Protocol - Wikipedia
RFC 6918: Formally Deprecating Some ICMPv4 Message Types (rfc-editor.org)
Internet Control Message Protocol (ICMP) Parameters (iana.org)
Why I recived user-set on my Nmap analyze? - Information Security Stack Exchange
Learning by practicing: Stimulus and response revisited (securitynik.com)
MITRE ATT&CK®
Cyber Kill Chain® | Lockheed Martin
Learning by practicing: The importance of reconnaissance to the targeted threat actor (securitynik.com)
nmap(1) - Linux man page (die.net)
Learning by practicing: Building your own TCP 3-way handshake – Packet Crafting – The Scapy Way (securitynik.com)