Features

How Cowrie works

A honeypot is only useful if attackers believe it and you can read what they did. Cowrie is built for both.

  1. 01

    An attacker connects

    Cowrie listens on SSH and Telnet. Any login attempt is recorded; the ones you allow get a shell.

  2. 02

    Cowrie plays the server

    The attacker sees a Debian system with a real-looking filesystem and dozens of working commands.

  3. 03

    Everything becomes an event

    Logins, commands, downloads, TCP forwards and the raw terminal stream are written as JSON and tty logs.

  4. 04

    Events reach your tools

    Output plugins deliver each event to your SIEM, database, chat or threat-sharing platform.

Shell emulation

A Debian box that isn't there

Attackers get a shell inside a fake filesystem that mirrors a Debian install. Common commands are emulated in Python; ls, cat, cd, wget, curl, busybox, uname, ps and many more behave as expected. Nothing they run touches the real host.

The hostname, kernel version, CPU details and file contents are all configurable, so the machine can look like whatever you want attackers to find.

ssh session
root@svr04:~# ls -la /root
drwx------  2 root root 4096 Apr 29  2013 .
drwxr-xr-x 22 root root 4096 Apr 29  2013 ..
-rw-r--r--  1 root root  570 Jan 31  2010 .bashrc
-rw-r--r--  1 root root  140 Nov 19  2007 .profile
root@svr04:~# cat /proc/version
Linux version 3.2.0-4-amd64 ([email protected]) (gcc version 4.6.3 (Debian 4.6.3-14) ) #1 SMP Debian 3.2.68-1+deb7u1
root@svr04:~# busybox
BusyBox v1.20.2 (Debian 1:1.20.0-7) multi-call binary.
root@svr04:~# rm -rf /
root@svr04:~# 
userdb.txt
# user:uid:password  — '!' rejects, '*' accepts anything
root:x:!root
root:x:!123456
root:x:*
admin:x:admin
oracle:x:*
{"eventid": "cowrie.login.failed", "username": "root", "password": "123456", "src_ip": "198.51.100.23"}
{"eventid": "cowrie.login.success", "username": "root", "password": "Passw0rd!", "src_ip": "198.51.100.23"}

Credentials

Decide which logins succeed

A small text file controls which usernames and passwords get in. Reject the obvious ones so scanners keep guessing, accept the rest so you see what they do once inside.

Every attempt, successful or not, is logged with the credentials used. Over time this is a free feed of the passwords currently being sprayed at the internet.

Session recording

Replay what the attacker saw

Cowrie stores the full terminal stream of every session with timing information. The playlog tool replays it in real time, pauses included, so you can watch a session exactly as it happened.

Each command is also logged as its own event, which is what you want for searching and statistics.

bin/playlog
$ bin/playlog var/lib/cowrie/tty/d0c5a9b21e4f.log
— replaying with original timing —
root@svr04:~# w
 09:14:12 up 14 days,  3:02,  1 user,  load average: 0.08, 0.02, 0.01
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    198.51.100.23     09:14    0.00s  0.00s  0.00s w
root@svr04:~# cat /etc/passwd | grep -v nologin
root:x:0:0:root:/root:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
phil:x:1000:1000:Phil California,,,:/home/phil:/bin/bash
{"eventid": "cowrie.command.input", "input": "cat /etc/passwd | grep -v nologin", "session": "d0c5a9b21e4f"}
var/lib/cowrie/downloads
$ ls -l var/lib/cowrie/downloads | head
-rw-r--r-- 1 cowrie cowrie 112640 Sep 11 09:14 3f7a1c9e…b2d4
-rw-r--r-- 1 cowrie cowrie   1823 Sep 11 08:51 8c02e1aa…77f0
-rw-r--r-- 1 cowrie cowrie  60432 Sep 10 23:07 a91d5b3c…04e6
$ file var/lib/cowrie/downloads/3f7a1c9e…b2d4
ELF 32-bit LSB executable, Intel 80386, statically linked, stripped
{"eventid": "cowrie.session.file_upload", "filename": "update.sh", "shasum": "8c02e1aa…77f0", "src_ip": "203.0.113.42"}

Malware collection

Keep what they bring

Files fetched with wget or curl, or pushed in over scp and sftp, are saved to disk and named by their SHA-256 hash. The same payload arriving a thousand times is stored once.

The VirusTotal output plugin can submit each new sample automatically and record the verdict alongside the session.

Logging and outputs

One event stream, many destinations

Every event is a line of JSON with a stable eventid, the session it belongs to, the source address and a timestamp. Grep it, load it into a notebook, or let an output plugin ship it.

Plugins exist for Elasticsearch, Splunk, Microsoft Sentinel, MISP, hpfeeds, MySQL, SQLite, MongoDB, Slack, Discord and more. Enable as many as you like in cowrie.cfg.

All output plugins →
etc/cowrie.cfg
[output_jsonlog]
enabled = true
logfile = ${honeypot:log_path}/cowrie.json

[output_elasticsearch]
enabled = true
host = localhost
port = 9200
index = cowrie

[output_slack]
enabled = true
channel = #honeypot
token = xoxb-…
etc/cowrie.cfg
[ssh]
enabled = true
listen_endpoints = tcp:2222:interface=0.0.0.0

[telnet]
enabled = true
listen_endpoints = tcp:2223:interface=0.0.0.0

[honeypot]
hostname = svr04
# shell = emulated in Python, proxy = a real backend
backend = proxy

[proxy]
backend_ssh_host = 10.0.0.5
backend_ssh_port = 22

Protocols and modes

SSH, Telnet, and a real backend when you need one

Cowrie speaks SSH and Telnet on any ports you choose. The emulated shell is the default and is safe to expose anywhere.

For attackers who need more than an emulation, proxy mode forwards the session to a real system, typically a disposable VM, while Cowrie sits in the middle and records everything.

Deployment

Runs anywhere Python runs

Install from source, or use the official Docker image. A single small VM is enough; many people run a fleet of them and aggregate the JSON centrally.

shell
$ docker run -p 2222:2222 -p 2223:2223 cowrie/cowrie
Installation guide →

Know your attackers.

Deploy Cowrie anywhere and start capturing attacks in minutes

Get Started