Reason: hardening, serendipity and curiosity
As you already know, in the past weeks I hardened all of my boxes: while doing it, I flushed all iptables/ipfw rules, changed the default policy to DROP and take it from there to enable every rule as soon as I need it. Whilst Ubuntu uses ufw as a fronted for iptables, Fedora uses firewalld.
After setting up UFW, by looking at
journalctl I can see all rejected connections, like:
Sep 03 11:54:16 -- kernel: [UFW BLOCK] IN=eth0 OUT= MAC=XX SRC=XX DST=XX LEN=60 TOS=0x00 PREC=0x00 TTL=51 ID=24286 DF PROTO=TCP SPT=36864 DPT=23 WINDOW=5808 RES=0x00 SYN URGP=0
As we all know, Internet is a wild place. In this particular case, someone was trying to connect to my box on port 23/tcp (telnetd, is still there someone who uses it?).
My curiosity begin to increase. Let’s have a look on which ports I rejected most of the connections:
/var/log # zgrep -ho "DPT=\w*" syslog* | cut -d "=" -f 2 | sort | uniq -c | sort -nr | head -n 10 # no. of attempts | port 1009 23 969 3128 330 22 248 8080 168 80 158 5060 151 3389 111 1825 94 1433 77 123
(as I am running an httpd-ssl server on this host, connections to 443/tcp port are not showed).
Ok, so mostly of the wild connectors out there try to telnetd to my host (and all other hosts on the Internet). Again, my curiosity prevails: how about a fake telnetd server written in Python with twisted? As I always wanted to have a look with twisted, seems a good idea. The main idea here is to write a simple telnetd server that:
- shows the root prompt and waits for commands
- answers with fake answers to some UNIX commands (like
- answers to all other commands with
Command not foundor with nothing (like that the command was accepted). The choice between answering in the former way rather than the latter is random
- record everything that is written by the attacker
This is a very simple and diminished concept of an Honeypot and leads to the code I published the code on GitHub under telnetd_honeypot.
Just for the sake of increased security, I did not want to run this program as root (not because I do not trust it, just because it’s a bad practice!). But we need to run it as root, because we need superuser powers to open a listening socket on all ports <1024, especially 23/tcp.
Sounds like a dead end? Not at all. Meet rinetd. We set up a bounce redirection from 23/tcp to the port on which our basic honeypot is listening (8023/tcp), launched by an unprivileged user (again: for security. Feel free to spin up a Docker container just to launch the honeypot).
% python telnetd.py &
% telnet localhost 8023
Connected to localhost.
Escape character is '^]'.
/ # uname -a
Linux f001 3.13.3-7-high-octane-fueled #3000-LPG SMPx4 Fri Jun 31 25:24:23 UTC 2200 x86_64 x64_86 x13_37 GNU/Linux
/ # id
uid=0(root) gid=0(root) groups=0(root)
/ # ls
/ # ps auxw
bash: ps: command not found
The results are quite fascinating. By analizing our file produced by our honeypot runned just for 3 days we can see the most typed commands on the other side of the client:
~ % cut -d " " -f 6- telnetd_honeypot.log | sort | uniq -c | sort -nr | head -n 3 921 sh 918 /bin/busybox ZORRO 879 root
We might notice that most of the lines are common passwords guessing, while the
busybox invocation with the parameter
ZORRO is mysterious: even Googling, I have no clues about it. Sounds like a custom firmware? There are also multiple attempt to inject a shellcode (which I am not publishing for obvious reasons).
There are also funny entries:
08/20/2015 12:43:10 AM INFO: 79.x.x.x knock knock neo
Anyone else has seen Neo?
The results are pretty interesting and deserve a further investigation. Upon running just for 3 days, I gather enough results to satisfy my curiosity. The honeypot described here is just a starting point, hoping to gather more contributors to this fascinating problem. With the addition of Docker containers, the future possibilities are quite infinite. Happy investigating!