Tips for networks security assesments
This post shows some tips for network security assesments. The topic is very broad and I will not cover overall testing strategies, but will provide small tips that can be useful to know during an assesment.
I’m using two virtual hosts in some of the examples. One is the victim box with IP 192.168.122.38 and another is the attacker box with IP 192.168.122.118. Some tips and examples are relevant only within the same subnet, but some are more meaningful with larger segmented environments and the victim box works as an abstraction for that.
Sneaking through via IPv6
All common hardening guides usually have recommendations for disabling IPv6 unless it’s actually being used.
There can be multiple approaches for disabling IPv6, even within the same operating system. One approach that some companies take is to drop all IPv6 traffic in hardware firewalls and this way prevent any IPv6 traffic in routed connections. The issue with this approach alone is that in common situations layer3 firewall won’t see traffic that happens within the same subnet. What if the attacker is already inside the subnet that contains the hosts they are interested in?
Let’s assume a situation where you have gained access to a network and there are some interesting hosts within the same subnet, but local firewalls are blocking access to interesting services. For example, consider the following iptables rules where INPUT policy is set to DROP and no addittional INPUT rules are set.
root@victim:/home/user# iptables -S
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
root@victim:/home/user# iptables -P INPUT DROP
Let’s scan the victim host’s TCP port 22.
user@attacker:~$ sudo nmap -Pn -p22 192.168.122.38
Starting Nmap 7.80 ( https://nmap.org ) at 2022-12-04 18:30 EET
Nmap scan report for victim (192.168.122.38)
Host is up (0.00041s latency).
PORT STATE SERVICE
22/tcp filtered ssh
MAC Address: 52:54:00:D5:E8:CF (QEMU virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 0.35 seconds
You can see from the output that the port is not open (22/tcp filtered ssh
).
We can also just try an ssh connection to deduce the same thing.
user@attacker:~$ ssh -o ConnectTimeout=5 user@192.168.122.38
ssh: connect to host 192.168.122.38 port 22: Connection timed out
Ssh gives timeout error, so no ssh access.
Now, it’s time to see if we can get ssh access after all using IPv6 link local address. You can read more about this from here, but in practice, this address might allow us to communicate over IPv6 with the hosts in same subnet.
We can use IPv6’s All Nodes multicast address to figure out what hosts will answer over IPv6 link local addresses.
user@attacker:~$ ping -6 -I enp1s0 ff02::1
ping: Warning: source address might be selected on device other than: enp1s0
PING ff02::1(ff02::1) from :: enp1s0: 56 data bytes
64 bytes from fe80::5054:ff:fe3c:345c%enp1s0: icmp_seq=1 ttl=64 time=0.040 ms
64 bytes from fe80::5054:ff:fed5:e8cf%enp1s0: icmp_seq=1 ttl=64 time=0.482 ms
64 bytes from fe80::5054:ff:fe3c:345c%enp1s0: icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from fe80::5054:ff:fed5:e8cf%enp1s0: icmp_seq=2 ttl=64 time=0.597 ms
64 bytes from fe80::5054:ff:fe3c:345c%enp1s0: icmp_seq=3 ttl=64 time=0.065 ms
After pinging for a while we can check what neighbors are reachable.
user@attacker:~$ ip neigh | grep '^fe80'
fe80::5054:ff:fed5:e8cf dev enp1s0 lladdr 52:54:00:d5:e8:cf REACHABLE
There’s one host which is our victim box. Let’s run Nmap to see if port 22 is open. Note the option -6
in Nmap command.
user@attacker:~$ sudo nmap -6 -Pn -p22 fe80::5054:ff:fed5:e8cf%enp1s0
Starting Nmap 7.80 ( https://nmap.org ) at 2022-12-04 18:36 EET
Nmap scan report for fe80::5054:ff:fed5:e8cf
Host is up (0.00069s latency).
PORT STATE SERVICE
22/tcp open ssh
MAC Address: 52:54:00:D5:E8:CF (QEMU virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 13.20 seconds
The port is open (22/tcp open ssh
), so let’s try ssh connection.
user@attacker:~$ ssh -6 fe80::5054:ff:fed5:e8cf%enp1s0
The authenticity of host 'fe80::5054:ff:fed5:e8cf%enp1s0 (fe80::5054:ff:fed5:e8cf%enp1s0)' can't be established.
ECDSA key fingerprint is SHA256:l3aX1uokIZn0STilpU0cKNEBi++k1yPGecB4YEvCxiM.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'fe80::5054:ff:fed5:e8cf%enp1s0' (ECDSA) to the list of known hosts.
user@fe80::5054:ff:fed5:e8cf%enp1s0's password:
Linux victim 5.10.0-19-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Dec 4 18:24:09 2022 from 192.168.122.1
user@victim:~$
We have ssh access!
So, why this works? When you set rules with iptables
command it’s only configuring IPv4 rules. IPv6 rules are set with ip6tables
command.
# IPv6 - Everything allowed
root@victim:~# ip6tables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
# IPv4 - INPUT and FORWARD dropped
root@victim:~# iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
Similar distinction between IPv4 and IPv6 rules management applies to many firewall solutions, so this doesn’t only come up with ip(6)tables
.
This is nothing new, but it still is suprisingly common to find this sort of misconfiguration or lack of hardening with IPv6.
How to prevent this then? The best option is to disable IPv6 at the operating system level. I have wrote about one option for Linux in here. The mentioned method disables IPv6 in a way that you don’t need to set any IPv6 rules in hosts’ firewall (actually you even can’t).
If you can’t disable IPv6 for some reason (e.g. some weird application dependency), but don’t need to allow any traffic using it, then you need to add proper firewall rules in hosts’ firewalls. With Linux systems using iptables you do this with the ip6tables
command.
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT DROP
Just listen
In addition to active probing you should take some time and just listen what happens in the network. You might, for example, notice manufacturer specific layer2 traffic which can tell you what kind of devices are present in the network. One nice example is Cisco DTP (Dynamic Trunking Protocol). If you see DTP packets it means that you may be able to trick an access port of Cisco switch to change its mode to trunk port. One tool you can use to perform layer2 attacks is yersinia.
Where am I?
Consider a situation where you are able to plug your machine into a network. The network has no DHCP server and no layer2 to traffic giving any hints about used addresses. The network is just silent.
One nice tool to figure out what addresses are found inside a local network is netdiscover. It uses ARP requests to figure out available hosts inside the network.
netdiscover -i enp1s0
Currently scanning: 172.26.66.0/16 | Screen View: Unique Hosts
6 Captured ARP Req/Rep packets, from 3 hosts. Total size: 252
_____________________________________________________________________________
IP At MAC Address Count Len MAC Vendor / Hostname
-----------------------------------------------------------------------------
192.168.122.1 52:54:00:85:ab:53 4 168 Unknown vendor
192.168.122.38 52:54:00:d5:e8:cf 1 42 Unknown vendor
Without specifying the -r <range>
option the tool uses autoscan, which will scan for common local networks.
Netdiscover can also do passive (-p
) scan if you don’t want to cause a huge amount of ARP requests. In passive mode netdiscover will listen for ARP requests without sending any packets.
Leaking DNS
Environment’s own DNS server can be a good source for information in many ways and it can give you hints about interesting hosts. For example, let’s say that you have access to some guest network which doesn’t have many interesting things, but it provides its own DNS server for users.
From defenders’ perspective, an ideal situation would be that this DNS server only resolves needed addresses for the guest network. Maybe names for a few guest services and rest of the queries are forwarded to public resolvers.
An ideal situation from attacker’s perspective would be that it’s one big DNS server that holds all records of the environment, and lookups are not restricted based on the source network or some other rule.
The latter situation could provide information for an attacker about hosts that could be found beyond the guest network.
Below is a simple script that loops over two /24
networks and does PTR lookups against each IP to see if any interesting hosts are discovered.
#!/bin/bash
SUBNET_BASE="10.0.0" # .x/24
SUBNET_BASE2="192.168.10" # .x/24
DNS_SERVER="192.168.122.38"
for i in $(seq 1 254)
do
nslookup "$SUBNET_BASE.$i" "$DNS_SERVER" | grep 'name ='
nslookup "$SUBNET_BASE2.$i" "$DNS_SERVER" | grep 'name ='
done
An example output when I run the script in my lab:
user@attacker:~$ ./dns.sh
3.10.168.192.in-addr.arpa name = files.test.local.
10.0.0.10.in-addr.arpa name = secrets.test.local.
18.10.168.192.in-addr.arpa name = www.test.local.
You can start probing for direct access to some new hosts or network segments based on the lookup results. Something unexpected could be routed and open from the guest network.
This kind of lookup technique might not be ideal in all situations or environments.
For example, you might want to avoid sending big amount of requests to upstream resolvers.
Use DNS server without upstream servers to test this technique. For example, Dnsmasq with no-resolv
option and don’t specify upstream servers.
Funny Flags
Scapy is a tool that you can use to craft your own network packets. The below script sends TCP packets with different TCP flag combinations to target host’s port 443. With some luck something could slip by if you are sending data to host through a firewall that is blocking the traffic
Usually modern network stacks are too robust to do anything unexpected, but you can’t be sure without testing different things.
#!/usr/bin/env python
import random
from itertools import combinations
from scapy.all import *
flags = ['S','A','F','R','P', 'U', 'C', 'E']
for r in range(1,8):
for flag_combo in combinations(flags, r):
f = ''.join(list(flag_combo))
print(f"FLAGS: {f}")
ip = IP(src="192.168.122.118", dst="192.168.122.38")
TCP_F = TCP(sport=random.randint(1024,50000), dport=443, flags=f, seq=random.randint(9000,100000))
send(ip/TCP_F)
For testing purposes, you can set up iptables to log each dropped packet by setting up a simple logging rules like the one below.
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [290:96752]
:LOGGING - [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -j LOGGING
-A LOGGING -j LOG --log-prefix "IPTables-Dropped: "
-A LOGGING -j DROP
COMMIT
Then you can extract flags from dropped packets like this. Comparing side by side with sent flag combinations should yield same amount of lines with same flag combinations.
root@victim:/home/user# tail -n0 -f /var/log/kern.log |grep 'IPTables-Dropped' > /tmp/dropped.log
^C
root@victim:/home/user# grep -oP 'RES=[0-9x]+\K.*URGP=' /tmp/dropped.log | awk -F ' URGP=' '{print $1}'
SYN
ACK
FIN
RST
PSH
URG
CWR
ECE
ACK SYN
...
CWR ECE URG ACK PSH SYN FIN
CWR ECE URG ACK PSH RST SYN
Note that this could catch other packets than the ones sent with scapy if other packets happens to be dropped during the tail
command.
You can do many more similar tricks with custom scapy scripts or Nmap. See this Nmap article for examples: https://nmap.org/book/scan-methods-null-fin-xmas-scan.html.
Searching for trunk
If physical environment and its controls are somehow part of the assesment you should glance rooms you have access to for network devices like wireless access points. In some cases connections between switch and access point could be trunks and with poor VLAN allow listing that cable can be a true goldmine. Another examples are connections to IP phones, unused wall sockets, or even switches in open spaces.
Passing through
Sometimes you may have access to two hosts and you want to know what traffic, if any, can pass between those two hosts. One quick way to test this is to start packet capture in one of the hosts and scan its all UDP and TCP ports quickly from the other host. Then you can switch the listening box if you need to figure out this in both directions.
- Run quick TCP scan
sudo nmap -Pn -r -sS --max-retries 0 192.168.122.38 -p-
- Run quick UDP scan
sudo nmap --max-rtt-timeout 10ms -Pn -r -sU --max-retries 0 192.168.122.38 -p-
# Nmap might warn about small round-trip time, but it's OK in this case as we just want to launch UDP packet to each port
Note that at least with Linux hosts and tcpdump you might see traffic that would be dropped in local firewall because tcpdump sees incoming traffic before iptables, but usually idea in this type of test is to see if any of the attempts gets pass inside the network, so seeing traffic in tcpdump is success anyways.
Trust, but verify
This tip is not network assesment specific, but should be kept in mind while doing any sort of security assesment.
If someone assures you that something is not relevant or possible, but verifying it isn’t out of scope, then verify it. This might seem obvious, but when someone is showing you flashy powerpoint presentations with fancy security keywords, you might find youself in a mindset where you have started thinking that everything shown are absolute facts. It’s the opposite mindset you may need to work on if you are not suitably suspicious by nature.
It’s much better that you will point out that something told to be impossible was possible instead of someone figuring it out later and then people will wonder why it was not noticed during the assesment. Administrators can instinctively play down some conserns and potential issues in their environments. In most cases it’s not intentional, but working with the same environment for a long time can give you sort of tunnel vision. One benefit of an external assesment is the possibility to break that tunnel vision and allow people working with the target environment to see things from a different angle.