← Back to list

Homelab — Cowrie

Cowrie SSH Honeypot Cloud-to-SIEM Threat Intelligence Lab

ipzen · 2026-04-21 07:29 · 6 claps · 4.9 min read
#cowrie #homelab #soc-home-lab
Open on Medium ↗
Wiki topics: 🔒 · Cybersecurity

Homelab — Cowrie

Cowrie SSH Honeypot Cloud-to-SIEM Threat Intelligence Lab

Medium-interaction SSH honeypot deployed on AWS EC2, streaming live attacker telemetry through Tailscale mesh VPN to a hybrid SIEM stack (Splunk Enterprise + Wazuh) running on-premise. Built to capture, analyze, and visualize real-world brute-force attacks against exposed infrastructure.

Project Goals

This lab was built as part of my Cybersecurity Officer studies at Technigo to demonstrate hands-on capability in:

  • Deception technology Deploy a honeypot that survives internet exposure
  • Cloud security Secure a public-facing service while keeping admin access private. Learn about cloud hosting.
  • SIEM integration Manage logs input to SIEM on homelab from VPS.
  • Threat intelligence Analyze real attacker behavior on my honeypot to gather information.
  • Blue-team practice Custom detection rules, dashboards, and incident triage

The result is a live threat intel source capturing SSH brute-force attacks in real time, with all findings queryable in Splunk and Wazuh.

Architecture

┌─────────────────────────────────────┐
                    │          Internet (port 22)         │
                    └────────────────┬────────────────────┘
                                     │
                                     ▼
          ┌────────────────────────────────────────────────┐
          │          AWS EC2 (Ubuntu 22.04, t2.micro)      │
          │  ┌─────────────────────────────────────────┐   │
          │  │  Cowrie 2.9.12  (port 22, via authbind) │   │
          │  │  └─→ /opt/cowrie/var/log/cowrie.json    │   │
          │  └────────────────────┬────────────────────┘   │
          │                       │                        │
          │  ┌────────────────────┴────────────────────┐   │
          │  │  Splunk UF 10.2.2  │  Wazuh Agent 4.x   │   │
          │  └────────┬─────────────────────┬──────────┘   │
          └───────────┼─────────────────────┼──────────────┘
                      │                     │
                      ▼                     ▼
         ┌────────────────────────────────────────┐
         │       Tailscale Mesh VPN (100.x.x.x)   │
         └────────────────────┬───────────────────┘
                              │
                              ▼
          ┌────────────────────────────────────────────────┐
          │     Home Lab (Proxmox on HP EliteDesk G3)      │
          │                                                │
          │   ┌──────────────────┐   ┌──────────────────┐  │
          │   │ Splunk Enterprise│   │ Wazuh Manager    │  │
          │   │   (LXC 103)      │   │   (VM 201)       │  │
          │   │   port 9997 / 8k │   │  ports 1514/1515 │  │
          │   └──────────────────┘   └──────────────────┘  │
          │                                                │
          │   Dashboards │ Alerts │ Rules │ Forensics      │
          └────────────────────────────────────────────────┘

Admin SSH (port 2222) is locked to a single IP via AWS Security Group. Port 22 is deliberately exposed to attract attackers. Authbind allows the unprivileged cowrie user to bind port 22 without root minimizing blast radius if the honeypot is compromised.

Tech Stack

Layer Technology Cloud compute AWS EC2 (Ubuntu 22.04 LTS, t2.micro) Honeypot Cowrie 2.9.12 (Python/Twisted) Privilege separation authbind (non-root bind to port 22) Splunk Universal Forwarder 10.2.2 Wazuh Agent Transport Tailscale WireGuard mesh VPN SIEM 1 Splunk Enterprise (on-prem LXC) SIEM 2 Wazuh 4.x Manager (on-prem VM) Home hypervisor Proxmox VE

Deployment Walkthrough

1. AWS EC2

Spun up a t2.micro Ubuntu 22.04 instance in EC2. Two security group rules:

Port Source Purpose 22 TCP 0.0.0.0/0 Honeypot deliberately exposed 2222 TCP Admin IP Real SSH IP-restricted

Moved the real OpenSSH to port 2222 via /etc/ssh/sshd_config so port 22 is free for Cowrie.

2. Cowrie Install (git clone method)

sudo apt install -y git python3-venv libssl-dev libffi-dev build-essential \\
  libpython3-dev python3-minimal authbind
sudo adduser --disabled-password cowrie
sudo su - cowrie
git clone <https://github.com/cowrie/cowrie.git> /opt/cowrie
cd /opt/cowrie
git checkout v2.9.12
python3 -m venv cowrie-env
source cowrie-env/bin/activate
pip install --upgrade pip
pip install -e .

3. Authbind (non-root bind to port 22)

sudo apt install -y authbind
sudo touch /etc/authbind/byport/22
sudo chown cowrie:cowrie /etc/authbind/byport/22
sudo chmod 770 /etc/authbind/byport/22

Starting Cowrie with authbind wrapping inherits the preload into all child processes (--deep is essential because Twisted spawns subprocesses):

authbind --deep cowrie start

4. Cowrie Configuration

Key changes in /opt/cowrie/etc/cowrie.cfg:

[honeypot]
hostname = webserver01
[ssh]
listen_endpoints = tcp:22:interface=0.0.0.0

5. Realistic Credential Policy

Default Cowrie accepts almost any credentials and even “no password”, which floods logs with meaningless successes and gives to much successfull login intel. Custom etc/userdb.txt built around three principles:

  1. Deny trivial guesses (root/root, root/123456, etc.) forces bots to work a bit harder
  2. Allow realistic but guessable passwords so bots eventually succeed and we can log shell activity
  3. Deny everything else (removed the :*:* fallback)
# Deny trivial guesses
root:x:!root
root:x:!123456
root:x:!password
root:x:!toor
root:x:!admin
# Allow realistic (but easy to brute force) passwords
root:x:admin123
root:x:P@ssw0rd2024
root:x:webserver01
admin:x:admin123
ubuntu:x:ubuntu
phil:x:phil123
# Deny everything else (including empty)
*:*:!

Gotcha logged: Cowrie’s userdb parser uses ASCII codec. Swedish characters (å/ä/ö) in comments crash the auth handler with UnicodeDecodeError. Kept all comments ASCIIonly.

6. Decoy Files (Rickroll)

Planted base64-encoded rickroll URLs in plausible locations to trap curious attackers.

fsctl /opt/cowrie/src/cowrie/data/fs.pickle
  > cd /root
  > touch backup_urls.txt
  > touch .bash_history
  > cd /home/phil && mkdir .config && cd .config
  > touch deploy.conf

Example decoy /root/backup_urls.txt:

# Production server backup locations
# Encoded for security - decode with: base64 -d
Primary backup endpoint:
aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUQo=

The base64 decodes to a youtube link with a classic rickroll.

Future Improvement: replace these with Canarytokens to receive email notifications when an attacker decodes and visits the URL. Converts decoys into active alerts.

7. Tailscale Mesh VPN

Installed Tailscale on both AWS EC2 and the on-prem Wazuh VM (Splunk LXC was already on the tailnet). This eliminates exposing Splunk/Wazuh ports to the public internet while allowing cross-site log shipping over encrypted tunnels.

curl -fsSL <https://tailscale.com/install.sh> | sh
sudo tailscale up

8. Splunk Universal Forwarder

Installed Splunk UF 10.2.2 as the splunkfwd user:

cd /opt && sudo tar xzf splunkforwarder-*.tgz
sudo chown -R splunkfwd:splunkfwd /opt/splunkforwarder
sudo -u splunkfwd /opt/splunkforwarder/bin/splunk start \\
  --accept-license --answer-yes --no-prompt
sudo -u splunkfwd /opt/splunkforwarder/bin/splunk add forward-server \\
  100.104.168.45:9997 -auth admin:<pass>
sudo -u splunkfwd /opt/splunkforwarder/bin/splunk add monitor \\
  /opt/cowrie/var/log/cowrie/cowrie.json \\
  -index cowrie -sourcetype cowrie -auth admin:<pass>
sudo /opt/splunkforwarder/bin/splunk enable boot-start \\
  -user splunkfwd -systemd-managed 1 -create-polkit-rules 1

On the Splunk indexer, /opt/splunk/etc/system/local/props.conf:

[cowrie]
KV_MODE = json
TIME_FORMAT = %Y-%m-%dT%H:%M:%S.%6NZ
TIME_PREFIX = "timestamp":"
SHOULD_LINEMERGE = false

9. Wazuh Agent

Deployed via the Wazuh dashboard’s “Deploy new agent” wizard (generates exact install command with manager address and agent name).

Added Cowrie log to /var/ossec/etc/ossec.conf:

<localfile>
  <log_format>json</log_format>
  <location>/opt/cowrie/var/log/cowrie/cowrie.json</location>
</localfile>

Enabled full archive mode on the manager by setting <logall_json>yes</logall_json> in ossec.conf so all Cowrie events are captured (not just rule-matched alerts).

Splunk Dashboard

The Splunk dashboard Cowrie Honeypot Overview surfaces the metrics a SOC analyst actually cares about:

Example attack case study

One attacker from 47.114.107.233 (Alibaba Cloud, China) generated 347 events in under an hour, a clear automated brute-force pattern. Analysis query:

index=cowrie src_ip="47.114.107.233" (eventid=cowrie.login.failed OR eventid=cowrie.login.success)
| stats count by username, password
| sort - count

Lessons Learned

Documented gotchas that cost time during deployment, worth knowing before attempting this yourself:

  1. Cowrie startup scripts movedbin/cowrie start was replaced by the cowrie pip entry point. Install with pip install -e . and invoke directly.
  2. Github vs Docker, Deployed through docker my first time but was very limited in adjusting content and password etc. Prefered way in git clone install.
  3. userdb.txt is ASCII-only, if you´re Swedish like me write in english.
  4. Honeyfs files won’t show in ls unless they're also added to fs.pickle via fsctl or createfs.
  5. Wazuh only stores rule-matched events by default — enable <logall_json>yes</logall_json> or write custom rules to surface events.
  6. AWS default public IPs change on instance stop/start — allocate an Elastic IP (or accept occasional rebinding pain).
  7. scp uses P for port, ssh uses p — yes, this is inconsistent; yes, it will catch you out.
  8. Admin SSH must stay IP-locked when port 22 is opened to 0.0.0.0/0 — otherwise you compete with attackers on the same port.

메타데이터
post_id
07d71fd4f59b
slug
homelab-cowrie-07d71fd4f59b
url
https://medium.com/@ipzen/homelab-cowrie-07d71fd4f59b
canonical_url
https://medium.com/@ipzen/homelab-cowrie-07d71fd4f59b
author_url
https://medium.com/@ipzen
status
ok
fetched_at
2026-07-11 02:55:32