Running simple SSH honeypot with Docker

Setting up a honeypot is a very interesting technique to detect and diagnose system vulnerabilities, attack vectors and other things related to computer security. There are many different types of honeypots used in the wild, but the most simple ones are designed to run on systems with intentionally (or not) weakeaned security settings. With a few monitoring tools in place it gives you a good chance of catching bad guys, or most likely automated scripts, red handed.

In the world-wild-web the most common attack vector is targeted for SSH services. Pretty much every server that's not configured to run on private network will have either a standard or tweaked SSH port exposed to public. Accompanied with insecure (short, simple, default) passwords it makes the perfect target for all those bot nets and what not. And what could be possibly worse than a server with a bad root password?

What does it have to do with Docker? Well, one thing that Docker is good at is process and filesystem isolation, which ultimately gives us ability to run more stuff on the same box instead of having to deal with resource hogs like real VMs (VMWare, VBox). One day I was curios what would happen if I just leave a box with a dump root password exposed to internets. More specifically - how long will it take to get infected.

First thing, we'll need a Docker image that has vanilla Ubuntu 14.04 with OpenSSH server running on standard port 22. I made one for example:

FROM ubuntu:14.04

RUN apt-get update && \
    apt-get upgrade -y \
    apt-get install -y openssh-server && \
    mkdir /var/run/sshd

RUN echo root:root | chpasswd
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

Then we just need to build the docker image:

$ docker build -t honeypot .

In order to make docker-based honeypot more effective, we'd need to change SSH server setting on the host system so that honeypot could run on port 22. You can do that by editing /etc/ssh/sshd_server file and change the default port to something like 2222. Make sure to restart SSH service with /etc/init.d/ssh restart.

Now, lets get the party started:

$ docker run -d -p 22:22 honeypot

If you're using any cloud VPS like Digital Ocean there's a big chance that you dont have to wait long. After running a few experiments I found that it takes approximately 10-15 minutes before /var/log/auth.log starts filling up with failed ssh login attempts. Then some "miracle" happens and one of the bruteforcing bots gets in and starts installing software, reconfiguring services, etc and ultimately tries to restart SSH service which will end up with container dying.

It's time to scout. By default Docker uses AUFS filesystem driver and provides ability to see any filesystem changes between container's initial image and it's current state. Simply run diff command:

$ docker diff my-container-id
# C /etc
# C /etc/shadow
# C /etc/ssh
# D /etc/ssh/ssh_config
# A /lib/cpp
# C /root

Where A - additions, D - deletions and C - changes. This is pretty cool because now you dont even have to guess which files were changed in the container. If your system got compromised you can track down every single file that was changed in the process. When I first ran diff command i got the following:

$ docker diff b235c4bdf4be | wc -l
# 6169

Now, how do we get to see the actual file contents? First, if the container is still up and running, you can exec into it:

$ docker exec -it my-container-id bash

In case if container is no longer running, you can copy files from it to the host filesystem using docker cp command, or by jumping directly into container's filesystem diff directory. Obtain container's full ID by running inspect command and then change dir:

$ docker inspect my-container-id
$ cd cd /var/lib/docker/aufs/diff/6c85e7d768b6f405c8cb98b71d21f115ebe317614ae9daf98e822a6978f3301e
$ ls -al
# total 52
# drwxr-xr-x 13 root root 4096 Dec 19 18:10 .
# drwxr-xr-x 31 root root 4096 Dec 19 15:01 ..
# drwxr-xr-x  2 root root 4096 Dec 19 18:10 bin
# drwxr-xr-x 13 root root 4096 Dec 19 18:10 etc
# drwxr-xr-x  3 root root 4096 Dec 19 17:54 lib
# drwx------  7 root root 4096 Dec 19 18:23 root

As an example, dig into compomised root's directory:

$ cd root
$ ls -al
total 4380
# drwxr-xr-x 2 root root    4096 Dec 19 13:28 .
# drwx------ 5 root root    4096 Dec 19 22:22 ..
# -rw-r--r-- 1 root root    2707 Dec  5 20:13 af
# -rw-r--r-- 1 root root     216 May 18  2005 auto
# -rw-r--r-- 1 root root    2205 Dec 19 12:14 get
# -rw-r--r-- 1 root root    2893 Oct 19  2011 mass
# -rw-r--r-- 1 root root   51845 Nov 13 07:33 passfile
# -rw-r--r-- 1 root root     171 Dec 19 07:02 port
# -rw-r--r-- 1 root root  888972 May  8  2015 pscan2
# -rw-r--r-- 1 root root    5843 Dec 14 05:15 pscan2.c
# -rw-r--r-- 1 root root 1246175 Dec 19 08:19 scan.log
# -rw-r--r-- 1 root root  453972 Oct 23  2010 ss

Pretty neat. Keep in mind that all above is a pretty simple (yet entertaining) setup to show you what happens when you don't protect your servers.

P.S. Some other interesting resources related to honeypotting: