Cowrie Honeypot


Since summer 2014 I’ve been working on extensions and contributions to the well known Kippo honeypot developed by desaster.

I noticed some SSH attacks against my systems were not logged in complete detail and I started to work on additional logging, from there I’ve added ‘ssh exec commands’ support, SFTP support, SCP support, direct-tcpip (proxying) support and many other features.

To distinguish this from the original software, I have now renamed the system to "Cowrie". All features below are incorporated in my cowrie repository on github.

New Features

SFTP support

Cowrie now supports the SFTP protocol to upload and download files. Uploaded files are placed into the ‘dl/’ directory, like files that were downloaded by ‘wget’. SFTP offers a file system interface to the pickled fs and you can list any file available in there. Downloads are also supported, if the contents are in honeyfs. Programmatically it is based on the Conch code, and uses a UNIX file system like interface to the pickled file system.

Exec support

One way to run remote commands is ‘exec’ commands. Like so:

ssh user@host 'cat /etc/passwd'

Support for this has been merged into the original Kippo repository, so it’s probably already in your version. This includes logging and executing these commands.

I’ve seen other uses as well, where malicious code is uploaded through stdin. Less common now, but I did see this last year:

cat malware | ssh user@host 'cat>./malware;chmod u+x ./malware; ./malware; rm -f ./malware'. 

So I added ‘stdin’ logging whenever standard-in data is encountered in combination with an exec command.

SSH tunnelling (direct-tcpip) support

I added logging initially for additional channels and saw I received some ‘direct-tcpip’ requests. This is the TCP/IP tunneling through SSH. After some more modifications, kippo now pretends to accept these requests so it can log the initial connection data. This is often HTTP, but sometimes SSL, BitTorrent and sometimes something else.

2015-02-09 04:48:08+0000 [SSHService ssh-userauth on HoneyPotTransport,1151,130.211.164.xx] ubnt trying auth password
2015-02-09 04:48:08+0000 [SSHService ssh-userauth on HoneyPotTransport,1151,130.211.164.xx] login attempt [ubnt/ubnt] succeeded
2015-02-09 04:48:08+0000 [SSHService ssh-userauth on HoneyPotTransport,1151,130.211.164.xx] ubnt authenticated with password
2015-02-09 04:48:08+0000 [SSHService ssh-userauth on HoneyPotTransport,1151,130.211.164.xx] starting service ssh-connection
2015-02-09 04:48:08+0000 [SSHService ssh-connection on HoneyPotTransport,1151,130.211.164.xx] got channel direct-tcpip request
2015-02-09 04:48:08+0000 [SSHService ssh-connection on HoneyPotTransport,1151,130.211.164.xx] direct-tcp connection attempt to
2015-02-09 04:48:08+0000 [SSHChannel None (0) on SSHService ssh-connection on HoneyPotTransport,1151,130.211.164.xx] Faking channel open
2015-02-09 04:48:09+0000 [SSHChannel None (0) on SSHService ssh-connection on HoneyPotTransport,1151,130.211.164.xx] received data 'POST HTTP/1.1\r\nHost:\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0\r\nReferer:\r\nX-Requested-With: XMLHttpRequest\r\nConnection: Keep-Alive\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 0\r\n\r\n'

SSH Fingerprint logging

Some adversaries have (accidently?) public keys configured on their attack hosts. The SSH client attempts to login with this public key. Cowrie now accept, logs and then denies public-key authentication. An easy way to fingerprint (sic) attackers.

2014-11-15 00:26:11+0000 [SSHService ssh-userauth on HoneyPotTransport,206,193.104.41.***] Public Key attempt for user admin with fingerprint b4:2b:f0:30:3a:97:04:90:b1:99:47:b4:7b:89:56:xx:

SSH Protocol Updates

I’ve enabled the diffie-hellman-group-exchange-sha1 algorithm. And updated the ciphers to the ones supported by OpenSSH. Als added ‘dss’ keys.

Also I ported code from honssh to stop the Metasploit kippo detection by Andrew Morris. The issue is more with Conch (the Twisted SSH implementation), but there’s a workaround in Cowrie now.

It’s good to realize that Cowrie is a medium interaction honeypot, and there will always be ways to fingerprint the honeypot. Another easy way is to look just at the ciphers offered by the SSH server.

Additional commands

I added additional commmands:

Exit status

SSH has a way to transfer the exit status of the remote command back to the original host. This is called exit status.

$ ssh -p 2222 root@host ls /
bin        boot       dev        etc        home       initrd.img lib
lost+found media      mnt        opt        proc       root       run
sbin       selinux    srv        sys        tmp        usr        var
$ echo $?

Original kippo sends no exit status. Cowrie always sends a ‘0’ exit code signifying succes, regardless of the command that’s executed.

Command line support

Cowrie supports additional emacs keybindings such as ctrl-a (start of line), ctrl-e (end of line), ctrl-p (previous command), ctrl-n (next command), ctrl-b (one character left) and ctrl-f (one character forward)

Ported kippo-extra

I added ‘which’, ‘netstat’, ‘gcc’ from kippo-extra by basilfx.

Usernames and passwords.

I added wildcard support for the password database. Passwords can now be ‘*’ to allow any password. There’s also a ‘!’ operator to deny explicit passwords. The rules are evaluated in order, so the ‘*’ should usually come last. My userdb is now:




I added from threatstream’s repository. It uses sockets and no deferred and should not work all that well with Twisted’s asynchronous system, but in practice people use it.

JSON logging

I’m in the process of converting Cowrie to more structured logging and a new dblog framework that’s more extensible. One result so far is a JSON dblog plugin. This logs the same information as the general dblog modules, but in JSON format, so it can be easily picked up by log analysis tools. It writes timestamps in UTC with microseconds and adds a unique UUID session identifier to each log entry. It also adds argument as their own JSON attributes so text log parsing is no longer necessary.

{"src_ip": "", "timestamp": "2015-02-04T06:40:00.067897Z", "message": "New connection:", "session": "bbc88ffb69564ded87c48b6bc797f78c", "sensor": "helium-cowrie"}

ELK (ElasticSearch, LogStash, Kibana)

Now JSON logging is available, Cowrie includes sample configuration files for logstash and kibana , to display honeypot data in a Kibana dashboard.

The nice thing about logstash is that it can do data enrichment offline. There’s no need to configure GeoIP into Cowrie, just load the IP data in logstash and enrich with GeoIP data such as country and city and ASN number from Maxmind:

{"message":"New connection:","@version":"1","@timestamp":"2015-02-04T20:49:01.717Z","host":"","type":"cowrie","src_ip":"","timestamp":"2015-02-04T20:49:01.717804Z","session":"6196432fa82c452e829f018caf04ba40","sensor":"helium-cowrie","geoip":{"ip":"","country_code2":"CN","country_code3":"CHN","country_name":"China","continent_code":"AS","latitude":35.0,"longitude":105.0,"location":[105.0,35.0],"coordinates":[105.0,35.0],"number":"AS4837","asn":"CNCGROUP China169 Backbone"}}
{"message":"Client version: [SSH-2.0-libssh-0.1]","@version":"1","@timestamp":"2015-02-04T20:49:02.697Z","host":"","type":"cowrie","session":"6196432fa82c452e829f018caf04ba40","timestamp":"2015-02-04T20:49:02.697841Z","client":"SSH-2.0-libssh-0.1","sensor":"helium-cowrie"}

If you then load data in a Kibana dashboard it should look something like this:

Kibana dashboards.


I ported katkad’s SHAsum patches to log binaries, and made some modifications to consolidate the log messages. Malware is now saved as its SHA-256 checksum, and only once per unique sample.

Roadmap & Plans


Most of the current development plans focus on improving the logging. Currently the logging is unstructured text and there is even internal log parsing with regexes to create database entries in some of the dblog modules. I’d like to move to structured output formats to make data easier to parse. The JSON output will improve and contain more data in structured fields.

How to use

To use Cowrie, simply copy from The configuration is almost a drop-in replacement for the original Kippo, with a few small changes to the configuration file.

Keep an eye out for these new options in your cowrie.cfg:

# JSON based logging module
logfile = log/cowrie.json

# Enables passing commands using ssh execCommand
# e.g. ssh root@localhost <command>
# (default: false)
exec_enabled = true

# sftp_enabled enables the sftp subsystem
sftp_enabled = true

If you run into issues, feel free to get on touch on Twitter, check the current issues or create a new one. Patches are also welcome.