For the past year, I’ve been setting up honeypots and network sensors on the wifi network at local security conferences, watching to see what other people are doing on the network. For the most part, the answer has been ‘not much’. But I wanted to write this up to capture the howto knowledge.
Cowrie
The Cowrie honeypot is a python application that simulates a ssh or telnet server, and will serve up a fake shell environment which can be tailored to resemble any kind of Linux distribution you like, with a fake directory tree and hosted files an attacker could examine or pillage. It supports logging in several formats, including syslog-like logs, JSON, Cuckoo, ELK and several different SQL databases.
The install doc is a pretty good guide to getting Cowrie up and running, so we’ll lean heavily on that.
Step zero, left as an exercise for the reader, is to get a Raspberry Pi and install Raspbian on it. For hardware, I recommend a Pi 3B, as in my experience, something like a Pi Zero W doesn’t have enough horsepower to handle the simulated file system cowrie serves up, though it works fine as a network scan sensor as described in part 2. For the OS, I use the full version of Raspbian, rather than the lite version, as many public wifi networks rely on captive portals to sign in, and I’ve yet to find a reliable way to connect to a captive portal with a text-based browser. If you know of one, please let me know.
Remember to change the password on the default ‘pi’ account.
Harden and relocate your actual SSH server
Assuming you’re going to want to have some sort of remote access and management capability on your Pi, we need to have SSH on your honeypot. However, given that we’re intentionally putting out a device for people to attempt to hack, we should a) harden the actual ssh server and b) move it to a different port so when someone comes looking for ssh, they’ll find our honeypot instead. What I have below is cribbed substantially from https://medium.com/@jasonrigden/hardening-ssh-1bcb99cd4cef, which goes a lot further than what I’m putting here. There shouldn’t be anything sensitive on your honeypot, so I’m going to stick to the basics here. If you want to lock down everything, please take a look at Jason’s post.
First, back-up your ssh config
$ cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
Next open up the config file in your favorite text editor. My preference is vi or vim, but you can use whatever you’re comfortable with.
$ sudo vi /etc/ssh/sshd_config
Disable root logins by finding the line that reads
PermitRootLogin yes
or
PermitRootLogin prohibit-password
And change it to
PermitRootLogin no
You should also set your ssh server to disconnect idle sessions both to save system resources and to ensure you don’t leave a session running indefinitely where someone could find it if you leave your laptop unlocked. ClientAliveInterval tells the ssh server to check in on the client after a set number of seconds of inactivity, and ClientAliveCountMax tells the server how many times to do that before disconnecting. Here, we’ll set our server to check in after 5 minutes, twice, so that it’ll kill the connection after 10 minutes.
ClientAliveInterval 300 ClientAliveCountMax 2
I would recommend creating a second account on the honeypot other than the pi user (such as pot_mngr), then whitelisting only that other account to login via SSH. You can then ‘su’ to the pi account to do actual management tasks. Add a line that reads:
AllowUsers pot_mngr
I would also recommend creating and using ssh keys rather than passwords. Again, Jason’s post has the details.
As previously mentioned, we also need to change the port our real ssh server is running on so we can put Cowrie on port 22, which is where people expect to find ssh. Find the ‘Port’ line and change
Port 22
to another value of your choosing that doesn’t conflict with any other service on your device.
Port 32232
You can close your text editor now, and then test your config file to make sure it’s good by running:
sshd -t
If everything checks out, restart ssh. Your existing session should continue, but you’ll need to use the new port for any future connections.
service ssh restart
Installing Cowrie
Again, the basic Cowrie install doc is pretty good, so we’re going to crib from that.
First, log in to your honeypot, and download the prerequisites. Raspbian supports both python 2 and python 3, and cowrie gives us the apt commands for both, pick one. I tried both in January 2019, and they both worked.
Python 2
$ sudo apt-get install git python-virtualenv libssl-dev libffi-dev build-essential libpython-dev python2.7-minimal authbind
Python 3
$ sudo apt-get install git python-virtualenv libssl-dev libffi-dev build-essential libpython3-dev python3-minimal authbind
Cowrie also makes some disclaimers that they ‘think’ cowrie is secure, but… Caveat Emptor. So, they also recommend creating a standard (non-root, non-sudo-capable) user to run cowrie
$ sudo adduser --disabled-password cowrie Adding user 'cowrie' ... Adding new group 'cowrie' (1002) ... Adding new user 'cowrie' (1002) with group 'cowrie' ... Changing the user information for cowrie Enter the new value, or press ENTER for the default Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] $ sudo su - cowrie
Next, cd to your cowrie user’s home directory and get the cowrie files from git
$ git clone http://github.com/cowrie/cowrie
Cd into the cowrie directory you just created (cd ~cowrie/cowrie), and create a virtual environment. Again, this is for either python 2 or python 3, pick the same one you picked back up in step 1
$ virtualenv --python=python3 cowrie-env
-or-
$ virtualenv --python=python2 cowrie-env
Then install the python requirements. This is the same for either python 2 or python 3
$ source cowrie-env/bin/activate (cowrie-env) $ pip install --upgrade pip (cowrie-env) $ pip install --upgrade -r requirements.txt
Here’s where we’re going to start deviating from the default cowrie install, as we’re going to skip a couple of steps and then do some custom configuration.
We’re going to jump ahead to configure cowrie to run on port 22 using authbind, which we downloaded back in step one. Get a sudo-capable shell (such as your ‘pi’ user), and tell authbind that cowrie can run on port 22:
$ sudo touch /etc/authbind/byport/22 $ sudo chown cowrie:cowrie /etc/authbind/byport/22 $ sudo chmod 770 /etc/authbind/byport/22
Then, back as your cowrie user, edit the main cowrie script
$vi /home/cowrie/cowrie/bin/cowrie
And change
AUTHBIND_ENABLED no
To
AUTHBIND_ENABLED yes
Configuring Cowrie
Cowrie is very customizable – you can give it custom users and passwords, create a fake filesystem and fake files, and set it up to output to a variety of data repositories/analytics tools.
The default filesystem is configured to resemble a Debian 5.0 install. Since my plan was to run this on the network at security conferences, I reconfigured mine to look like a fresh Kali install with default credentials.
Configuring ‘users’
Cowrie uses a simple flat text file, cowrie/etc/userdb.txt for simulating users, with the format:
<username>:x:<password>
Per the documentation, the second field (the ‘x’) is not currently used for anything. So, if you want a root user to be able to log in with the password ‘toor’, your stanza would be:
root:x:toor
A user ‘shmoo’ with password ‘moose’ would be
shmoo:x:moose
You can also use negation (‘!’) to permit a user to login with any password except the specified one. So, if you wanted to make it look like you’d done the bare minimum to secure your Kali install, you could permit an attacker to login with any password other than ‘toor’ by specifying
root:x:!toor
A password entry of ‘*’ allows for any password
root:x:*
And ‘/’ allows the use of regular expressions:
root:x:/honeypot/i
Faking the filesystem
Cowrie uses a packed data structure (a ‘pickle’) to hold its simulated file structure. It also includes a tool called ‘createfs’ which allows you to clone an existing filestructure into a new pickle. Now, all this will give you is directory listings; we will populate selected actual files in the next step. If you don’t want the createfs and the pickle to show up trivially in the pickle, you can create a dot directory in /tmp/ or the like and put them there
$ /tmp/.h/createfs --help Usage: createfs [-h] [-v] [-p] [-l dir] [-d maxdepth] [-o file] -v verbose -p include /proc -l <dir> local root directory (default is current working directory) -d <depth> maximum depth (default is full depth) -o <file> write output to file instead of stdout -h display this help
Using it is pretty simple. For my project, I logged into a fresh Kali install, copied over the createfs script, and ran it from ‘/’. Depending on how beefy your honeypot is, you may want to be judicious with the -d parameter, as the pickle needs to be unpacked into memory every time someone logs in. I found that on a Pi Zero W, ‘-d 6’ or above would render the honeypot unusable, as the connection would timeout before the pickle unpacked. Using ‘-d 5’ would cause some lag on login, but be reasonable once the attacker connected, and ‘-d 4’ would be pretty responsive, but the filesystem wouldn’t stand up to much scrutiny. A Pi 3B can handle a ‘-d 5’ or ‘-d 6’ pretty easily.
# /tmp/.h/createfs -d 6 -o /tmp/.h/kali.fs
Once you’ve created the pickle, use sftp to copy it over to your honeypot and put it in ~cowrie/cowrie/share/cowrie/.
To make your honeypot look more realistic to an attacker (if they log in and poke around), you can also put actual files and the output of fake text commands into your fake filesystem for the attacker to look at. For this to work, you need to build an actual fake directory structure (i.e., in addition to the pickle) and populate it with the relevant files. You can see the default files in cowrie/honeyfs/
$ ls -R honeyfs/ honeyfs/: etc proc honeyfs/etc: group hostname inittab motd resolv.conf host.conf hosts issue passwd shadow honeyfs/proc: cpuinfo meminfo modules mounts net version honeyfs/proc/net: arp
You can see you need to build out the directory structure and put the files you want to make available to attackers in their proper places. You can make this as complicated or as simple as you like. For my kalipot, I copied the same files out of /etc/ on my default Kali box, and dropped them in place in the cowrie honeyfs/etc directory, but left the rest the same. If you want to, you can add files in the user directories for the attacker to try and pillage.
You can also simulate the output of text commands by building a directory tree under cowrie/share/txtcmds, and putting the desired output in a text file named for the command, in the proper directory. Cowrie comes with several commands pre-loaded in this way, including emacs, vi, vim, nano, make, killall and top (all under usr/bin). Most of these are preloaded with error messages providing plausible reasons for why these commands aren’t actually available. Some commands with static outputs, such as bin/mount, or bin/df, have realistic-looking outputs. For my kalipot, I just went with the defaults.
Now we need a cowrie config file. Find the default config in cowrie/etc/cowrie.cfg.dist and make a copy to edit
cd ~/cowrie/etc/ cp cowrie.cfg.dist cowrie.cfg
Open the file for editing and search for the ‘hostname’ directive which defaults to
hostname = srv04
and change it to
hostname =kali
This will ensure the right hostname shows up at the prompt in the honeypot shell.
Next, find the listen_endpoints line. This controls the port cowrie is listening on. Above, we set up authbind so cowrie could listen on port 22 (the default ssh port), now we need to tell cowrie to go there. The default line is:
listen_endpoints = tcp:2222:interface=0.0.0.0
change it to
listen_endpoints = tcp:22:interface=0.0.0.0
Last we need to tell cowrie to use the kali filesystem pickle we created. Find the filesystem stanza:
filesystem = ${honeypot:share_path}/kali.fs
and change it to
filesystem = ${honeypot:share_path}/fs.pickle
That’s it, now you have a working Cowrie honeypot. You can start it by su’ing to your cowrie account and running:
$ sudo su - cowrie $ cd ~/ $ cd cowrie $ bin/cowrie start Join the Cowrie community at: http://bit.ly/cowrieslack Using activated Python virtual environment "/home/cowrie/cowrie/cowrie-env" Starting cowrie: [twistd --umask=0022 --pidfile=var/run/cowrie.pid --logger cowrie.python.logfile.logger cowrie ]... By default, logs will be written to ~/cowrie/var/log/cowrie/cowrie.log and cowrie.json.
Now, you can attempt to log in to your kalipot:
$ ssh root@192.168.1.174 Password: The programs included with the Kali GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Kali GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. root@kali:~#
In part 2 of this series, we’ll set up iptables rules and logging to monitor for nmap scans and attempts to connect to other ports than ssh.
In part 3, I’ll show how to set up p a Splunk universal forwarder to forward your honeypot’s logs to a Splunk server for monitoring.
2 thoughts on “Kalipot – Part 1: Hardening SSH and Setting Up Cowrie”