Kalipot – Part 1: Hardening SSH and Setting Up Cowrie

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.


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


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


$ 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




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:


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:


A user ‘shmoo’ with password ‘moose’ would be


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


A password entry of ‘*’ allows for any password


And ‘/’ allows the use of regular expressions:


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/


etc  proc


group      hostname  inittab motd    resolv.conf

host.conf  hosts     issue    passwd  shadow


cpuinfo  meminfo modules  mounts net version



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=

change it to

listen_endpoints = tcp:22:interface=

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@

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.

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.

Author: TheKilt

Information Security, Cosmic Horror, Gaming, Homebrewing, BBQ

2 thoughts on “Kalipot – Part 1: Hardening SSH and Setting Up Cowrie”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: