Honeypot Open Port Checker
Today was an interesting day. We are setting up a honeypot in the campus and I was asked to check if all the ports in the honeypot VM are accessible from the pubilc internet.
####The Problem
The setup is pretty simple. The honeypot is run in an VM behind the campus NAT. Any IP packet addressed to
the public IP of our VM should be NATed properly, rewritten and sent to the private address of the VM. I
need to make sure that the NATing process is done properly and port forwarding is done for the entire range
of ports 1:65535
. Now, that seems pretty simple.
####Enlightenment
If the VM can receive a SYN datagram addressed to a particular port, port forwarding works fine for that particular port. With this, we can come up with a system to test out all the possible ports if they are available for use.
We are doing this in two phases. The first phase, we are setting up the listener. We will use tcpdump
to
keep track of all the incoming communications to the system.
tcpdump -i eth1 -n src host $IP -vv > dump.pcap
This will
- listen only on interface
eth1
- dump packets only from our own ip
- write all captured data to dump.pcap
Once, this is ready, we move on to phase 2. This is rather simple. We just need a mechanism by which we can
initiate a TCP connection. We will use the swiss-army-knife of networks, netcat
for this. We now, just need
to put this in a loop to continuously try connect to all the available ports. But no, not really that simple.
I initially wrote a naive version of doing this. It goes somewhat like this
for port in `seq 1 65535`
do
echo "Hitting port $port"
netcat -w 10 $TGT_IP $port
done
The -w
flag in netcat is for specifying the timeout duration. This is required because, if netcat connects to a legit service which is listening on a particular port, it will indefinitely be waiting. This is just a
means to terminate those connections.
The script worked. But, it just worked. Did not do anything impressive to see. And also, way too slowly. I estimated it was going to take around 20 minutes to cover all the available ports. Now, that is a real definition of slow.
The problem is, all the processes are spawned sequentially, one after the another as the previous process terminates. So, we need a bit of parallelism magic here. Enter, GNU Parallel. It was love at first sight :)
Slightly modifying the above code, we get
parallel -j 200 "echo port {} && netcat -w 10 $TGT_IP {}" ::: `seq 65535`
Here the -j
flag is to denote how many jobs it needs to spawn in parallel. 200 was a good idea. This
iterated over the entire range of ports in less than five minutes! Now, that’s what I would call an
improvement.
It is now time to check whatever that has been captured by tcpdump
to see if all the ports are
accounted for. A simple grep
with sort
and uniq
to get what are the ports which have been hit.
grep 192.168.1.46.[0-9]* -o dump.pcap | cut -d. -f 5 | sort -n | uniq > openports
seq 1 65535 > availports
diff availports openports
This diff
will show all the ports which are missing in the open ports file. I got a list of ports which I
was not able to listen from the VM.
We can modify this in a slight way and use it to find out which are the outbound ports are being allowed by a corporate firewall to connect to the public internet. I did this by running the listener on my VPS and sadly had to confirm again that only connections to ports 80 and 443 are allowed from students’ systems.
####Alternative Idea
I first had a completely different approach to go about this problem. I was supposed to make sure that a
service can listen to any port in the available range. But, listening to each an every port and making sure
that it can send and receive data, is a tiresome job. So, we can setup port forwarding in the VM using
iptables
, to forward all the ports except one (say 9999), to that particular port(9999).
Something along the lines of
iptables -t nat -A PREROUTING -p tcp --dports 1:9998 -j REDIRECT --to-port 9999
iptables -t nat -A PREROUTING -p tcp --dports 10000:65535 -j REDIRECT --to-port 9999
After the port forwarding is done, all traffic addressed to any of those ports to that particular machine, will be redirected to port 9999. We just need to setup a listener to receive the data (where the intended port is included in the payload) to mark that the particular port is open. We can also send a reply in the TCP connection and outbound connection can be thus checked.
Something along these lines can be implemented if the outbound communication must also be checked. Otherwise, just a quick and dirty approach like the one detailed first, would be enough.