A honeypot is only useful if attackers believe it and you can read what they did. Cowrie is built for both.
Cowrie listens on SSH and Telnet. Any login attempt is recorded; the ones you allow get a shell.
The attacker sees a Debian system with a real-looking filesystem and dozens of working commands.
Logins, commands, downloads, TCP forwards and the raw terminal stream are written as JSON and tty logs.
Output plugins deliver each event to your SIEM, database, chat or threat-sharing platform.
Shell emulation
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.
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:~#
# 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
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
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 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"}$ 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
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
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 →[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-…
[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
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
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.
$ docker run -p 2222:2222 -p 2223:2223 cowrie/cowrie