A multi-sensor honeynet running on a single Azure Ubuntu VM. Two deception sensors (an SSH/Telnet honeypot and a malware-capture honeypot) feed a Splunk Enterprise SIEM that renders attacker telemetry as a live threat-intelligence dashboard — source IPs, geolocation, guessed credentials, executed commands, and SHA-256 hashes of every payload the attacker pulled down.
The deployment has been exposed to the public internet continuously since
2026-04-28. It is not a lab simulation with synthetic traffic: the numbers
in docs/10-observed-attack-data.md are real
opportunistic attacks against a real host.
Codename note. "Project Zeus" is the fictional company the honeypot pretends to be. The bait files reference a
zeus_proddatabase and aProject_Zeus_Master_DB_Backup.sqldump. None of it is real. That is the point.
▶ Play the title sequence · 33s · 6 MB
GitHub does not play video inline in a README — the image above opens the clip.
This is a documentation and configuration repository, reverse-engineered
from a live running deployment. Every config file under config/ was
pulled off the running VM verbatim, and every claim in the docs is backed by
output captured from that VM.
It is written so that someone who has never seen the deployment can rebuild it, operate it, demo it, and understand where it is wired incorrectly.
| Property | Value |
|---|---|
| Host | Azure Ubuntu VM, mousahoneypot |
| Kernel | Linux 6.17.0-1011-azure (Ubuntu 24.04 base) |
| Public IP | <VM_PUBLIC_IP> — see note below |
| Private IP | 10.0.0.4/24 |
| Orchestration | Docker Compose V2, project name honeynet |
| Sensors | Cowrie 2.9.17 (SSH/Telnet), Dionaea (16 emulated services) |
| SIEM | Splunk Enterprise (Docker image splunk/splunk:latest) |
| Deployment root | /home/azureuser/honeynet |
Throughout these docs,
<VM_PUBLIC_IP>stands in for the honeypot VM's public address. Substitute your own — every command is otherwise copy-paste ready.The real address is deliberately not published here. Two reasons: an Azure public IP allocated dynamically changes whenever the VM is deallocated (this one has already moved once during the project's life), so any hardcoded address would go stale; and naming a live honeypot's address alongside its exact configuration lets anyone fingerprint it as a honeypot, which is precisely what a deception sensor must avoid.
To find yours: Azure portal → Virtual machines → your VM → Overview → Public IP address, or
az vm list-ip-addresses -g <rg> -n <vm> -o table. See doc 02 §2.1 for making it static.
| Service | Endpoint | Purpose |
|---|---|---|
| Splunk Web | http://<VM_PUBLIC_IP>:8000 |
SIEM dashboard. User admin. |
| Cowrie SSH trap | ssh -p 2222 root@<VM_PUBLIC_IP> |
The bait. Any password works (see §3). |
| Cowrie Telnet trap | telnet <VM_PUBLIC_IP> 2223 |
Second bait vector. |
| Dionaea FTP | ftp <VM_PUBLIC_IP> 21 |
Malware capture. |
| Dionaea FTP fallback | ftp <VM_PUBLIC_IP> 2121 |
Use when ISPs filter port 21. |
| Real admin SSH | ssh -i <key>.pem azureuser@<VM_PUBLIC_IP> |
The real host. Port 22. |
Splunk is HTTP, not HTTPS. Browsing to
https://<VM_PUBLIC_IP>:8000fails. Usehttp://.
The Splunk dashboard is titled "Project Zeus: Executive Security Command" and lives at:
http://<VM_PUBLIC_IP>:8000/en-US/app/search/mousas_honeynet
Its source XML is preserved at
config/splunk/dashboards/mousas_honeynet.xml
and documented panel-by-panel in
docs/05-splunk-config.md.
A capture of the live dashboard, taken 2026-04-28 over a single day's window. Top to bottom, the panels answer one question each:
| Panel | Question it answers | Backed by |
|---|---|---|
| Total Forensic Events / Unique Threat Actors / CRITICAL: Successful Breaches | How loud is it right now? | doc 05 |
| Compromised Accounts | Which account did they get into? (root, every time) |
doc 03 |
| Active Breach Details | Who, from where, with which password | doc 10 |
| Global Threat Map | iplocation geo-enrichment of every source IP |
doc 05 |
| Live Attack Narrative | Every command the attacker typed, in order | doc 03 |
| Signature Intelligence | SHA-256 of every payload pulled down, plus source URL | doc 04 |
The window shown is one day, so the counters read 329 events / 9 actors. The cumulative figures across the whole exposure period — 2,987 events from 318 unique IPs — are in doc 10, and the all-time dashboard variant that produces them is
mousas_honeynet.alltime.xml.The attacker IPs visible in the screenshot are real. The honeypot's own address is not shown anywhere in it.
Four infographics, ordered the way the activity actually runs: build the
environment → understand the protocol you are baiting → run the capture-and-
analyse loop → place it in a real network. Each one has a prose counterpart in
docs/ — the diagram is the orientation, the doc is the authority.
Attacker → Azure → VM → container, plus the network topology (VNet, NSG, NIC) and the reason the honeypot listens on 2222 while the real SSH stays on 22.
→ doc 01 Architecture · doc 02 Azure & host setup
The SSH handshake end to end: key exchange, host-key verification, public-key auth, and the cryptography at each step. This is both how you reach the real host on port 22 and what Cowrie imitates on port 2222.
→ doc 02 Azure & host setup · doc 03 Cowrie configuration
The ten-minute live demo as six steps, then the pipeline underneath it: attacker interaction → log capture → parsing and IOC extraction → enrichment → dashboard, alerts and reports.
→ doc 08 Demo playbook · doc 06 Log pipeline · doc 05 Splunk configuration
This deployment is a single VM. In a production estate the decoy sits in the DMZ alongside the real public-facing servers, with its monitor/log server behind the internal firewall. The reference topology, for contrast with what is actually built here.
Redaction note. The first two infographics originally printed the VM's live public IP. It has been replaced in-image with
<VM_PUBLIC_IP>for the same reason it is withheld everywhere else in this repo — see the box above. Nothing else in them has been altered.
Read in order for a full understanding, or jump to what you need.
| # | Document | What it covers |
|---|---|---|
| 01 | Architecture | Component layout, network topology, data flow |
| 02 | Azure & host setup | VM sizing, NSG rules, Docker install, directory layout |
| 03 | Cowrie configuration | SSH honeypot, credential policy, fake filesystem, honeytokens |
| 04 | Dionaea configuration | Malware-capture honeypot, 16 emulated services, capture paths |
| 05 | Splunk configuration | Ingestion app, inputs.conf, props.conf, dashboard panels, all SPL |
| 06 | Log pipeline | The anonymous-volume problem and the tail -F bridge that solves it |
| 07 | Operations runbook | Health checks, is-it-up commands, restart procedures, troubleshooting |
| 08 | Demo playbook | Red-team vs blue-team live demo script |
| 09 | Findings & fixes | Six defects found in the live config, with fixes |
| 10 | Observed attack data | Real telemetry: 2,987 events, 318 unique attacker IPs |
| 11 | Rebuild from scratch | Disaster recovery — empty subscription to working honeynet in ~45 min |
.
├── README.md
├── .gitignore
├── assets/ # README media only — nothing here is runtime
│ ├── brand/project-zeus-logo.jpg
│ ├── infographics/01..04-*.png # IP-redacted; see the redaction note above
│ ├── screenshots/splunk-executive-security-command.png
│ └── video/project-zeus.mp4 (+ poster)
├── config/
│ ├── docker-compose.yml # AS-DEPLOYED record (contains the docs/09 defects)
│ ├── docker-compose.fixed.yml # ← USE THIS to rebuild; F-01/03/04/05 corrected
│ ├── .env.example
│ ├── sync_logs.sh # the log bridge
│ ├── systemd/
│ │ └── honeynet-sync.service # keeps the bridge alive
│ ├── cowrie-custom/
│ │ ├── Dockerfile # custom-image build (NOT currently deployed)
│ │ ├── build-fs.py # fake-filesystem generator
│ │ ├── userdb.txt # credential policy (NOT currently loaded — see F-01)
│ │ └── honeyfs/ # honeytoken file contents
│ │ ├── etc/{issue.net,motd}
│ │ ├── home/phil/{Project_Zeus_Master_DB_Backup.sql,notes.txt,
│ │ │ deploy.sh,.bash_history}
│ │ └── var/log/auth.log
│ ├── splunk_apps/honeynet_inputs/ # Splunk auto-ingestion app
│ │ ├── default/app.conf
│ │ └── local/{inputs.conf,props.conf}
│ └── splunk/dashboards/
│ └── mousas_honeynet.xml # the dashboard
└── docs/
└── 01..10-*.md
Rebuilding after losing the VM? Follow docs/11-rebuild-from-scratch.md instead — it is the complete disaster-recovery procedure, uses the corrected stack definition, and lists exactly what this repo can and cannot restore.
The steps below reproduce the deployment as it originally ran, defects included, so that the documentation and the historical reality match.
# 1. Provision an Ubuntu 22.04/24.04 VM, Standard_B2s or larger, 30 GB disk.
# Open NSG inbound: 22 (your IP only), 2222, 2223, 21, 2121, 8000 (your IP only).
# 2. Install Docker
sudo apt update
sudo apt install -y docker.io docker-compose-plugin jq curl
sudo systemctl enable --now docker
sudo usermod -aG docker $USER # log out and back in
# 3. Lay down the config
mkdir -p ~/honeynet && cd ~/honeynet
# copy everything from this repo's config/ directory here
cp .env.example .env && nano .env # set a real SPLUNK_PASSWORD
# 4. Launch
sudo docker compose up -d
# 5. Wait for Splunk to report healthy (2-5 minutes on a B2s)
watch -n5 'sudo docker ps --format "table {{.Names}}\t{{.Status}}"'
# 6. Install the log bridge (see docs/06-log-pipeline.md for why this is needed)
sudo cp systemd/honeynet-sync.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now honeynet-sync.service
# 7. Import the dashboard
# Splunk Web > Search & Reporting > Dashboards > Create New > Source
# Paste config/splunk/dashboards/mousas_honeynet.xmlBefore you rely on this deployment, read
docs/09-findings-and-fixes.md. The original
configuration has a container path-mismatch defect that silently disables the
honeytoken file contents and the custom credential policy. docker-compose.fixed.yml
corrects it, along with three other findings.
This honeynet was built for authorized security education. Some ground rules that are not optional:
- Only attack infrastructure you own or have written permission to test. The red-team half of the demo playbook assumes the target is your own VM.
- The captured payloads in
var/lib/cowrie/downloadsare real malware. Roughly 16 MB of it, pulled from the internet by real attackers. Never execute those files. Never commit them. The.gitignoreblocks them. - A honeypot is a compromised host by design. It must stay network-isolated from anything you care about. Do not deploy it on a VNet with production resources, and do not reuse credentials between the honeypot and anything real.
- Attacker source IPs are personal data in some jurisdictions. The observed- data document contains real IPs. If you publish this repo under a regime where that matters, redact them.
- Never commit the
.pemkey. The.gitignoreblocks*.pem, but checkgit statusbefore your first push anyway.
Deployment, configuration and dashboard by the project author. This repository documents that work; the documentation was assembled by reading the live system.
Media in assets/. The Project Zeus logo and the four infographics were
generated for this project. The Splunk screenshot is a capture of the live
dashboard. The title sequence in assets/video/project-zeus.mp4 uses footage
from Real Steel (2011, DreamWorks Pictures) under its first 27 seconds — that
footage is the property of its rights holders, is used here only as a
non-commercial title card for a student security project, and is not covered by
this repository's licence.





