Skip to content

Rdx1S/ShadowSentryS3

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

59 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ShadowSentry S3

Zero-Configuration, Serverless Hardware Honeypot on a Single ESP32-S3

🌐 Language: English Β· Π£ΠΊΡ€Π°Ρ—Π½ΡΡŒΠΊΠ°

Release Hackaday Platform Framework Language Traps Alerts Status

ShadowSentry S3 Dashboard

The live dashboard streaming captured attacks in real time β€” protocol traps, GeoIP-located sources, harvested credentials and a captured shell session. (Illustrative data.)

ShadowSentry S3 is a self-contained Edge Deception hardware honeypot. It turns a single ESP32-S3 board (~$5) into an invisible trap for botnets, scanners and malware inside your local network. No Raspberry Pi, no cloud servers, no external databases β€” all processing and logging happen on one chip.


Features

Honeypot traps (Core 0)

  • 5 protocol traps β€” RTSP (554, fake Hikvision camera), HTTP (80, fake NVR login + per-request fingerprinting), Telnet (23), SSH (22), FTP (21). Every credential pair is captured.
  • Real SSH server (wolfSSH) β€” genuine SSH-2.0 handshake (curve25519 + ECDSA host key) that decrypts the auth exchange and captures the plaintext username + password β€” not just a banner fingerprint.
  • Interactive fake shell (Cowrie-style) β€” Telnet and SSH accept the login and drop the attacker into a believable Ubuntu 20.04 shell that answers recon commands while logging every command; download/exec commands (wget/curl/chmod +x/./…) are flagged as IOCs and escalated.

Network & radio monitors (Core 1)

  • ARP-spoof / MITM monitor β€” watches the lwIP ARP cache for cache-poisoning signatures (gateway MAC change, one MAC claiming many IPs).
  • Wi-Fi threat monitor β€” detects 802.11 deauth/disassoc attacks (incl. the single-frame deauth used for handshake capture) via reason-code-classified forced disconnects + promiscuous broadcast-flood sniffing.
  • MAC + vendor for every event β€” resolves the attacker's L2 MAC from the ARP table with a best-effort OUI vendor guess; randomized (private) MACs flagged.
  • Threat-intel / GeoIP enrichment β€” resolves each attacker IP to country, ISP/ASN and a reputation tag (hosting/proxy/mobile) via ip-api.com; private IPs labelled Private LAN with no external call.

Platform

  • Live web dashboard + REST API on port 9999 (HTTP Basic Auth) β€” stat cards, attack feed, clickable attack-detail modal. A dedicated WebSocket push server (port 9998) streams every new attack to the dashboard in real time, so the feed updates the instant a probe lands instead of waiting for the next poll.
  • Telegram alerts β€” async queue with resilient delivery (waits for reconnect + retries, so an alert survives the very deauth that knocks the board offline).
  • SPIFFS persistence β€” attack log ring buffer + all-time counter survive reboots.
  • Dual-core design β€” honeypot traps on Core 0, admin/alerting/monitors on Core 1.
  • Zero-config & serverless β€” flash, set Wi-Fi + Telegram token, done. mDNS .local name, no cloud, no database.

How it works

Thanks to the dual-core Xtensa LX7 processor, the project is split into two isolated worlds:

Core Role Tasks
Core 0 β€” Hacker World Receives attacks RTSP :554 Β· HTTP :80 Β· Telnet :23 Β· SSH :22 Β· FTP :21
Core 1 β€” Admin World Management & alerts Admin Panel :9999 Β· Telegram Β· SPIFFS
Attacker / bot
     β”‚
     β”œβ”€ Port 554  (RTSP)   β†’ Fake Hikvision DS-2CD camera  ─┐
     β”œβ”€ Port  80  (HTTP)   β†’ Fake Hikvision NVR login page  β”‚
     β”œβ”€ Port  23  (Telnet) β†’ Fake Ubuntu 20.04 server       β”œβ”€β”€β–Ί log_store β†’ SPIFFS
     β”œβ”€ Port  22  (SSH)    β†’ Fake OpenSSH 8.9p1             β”‚         β”‚
     └─ Port  21  (FTP)    β†’ Fake vsFTPd 3.0.5             β”€β”˜         β–Ό
                                                                Telegram Alert
                                                                       β”‚
                                                              Admin Panel :9999
                                                             (Dark-mode Dashboard)

What gets captured

Protocol Captured Example
RTSP Username + Password admin:12345 from the Basic Auth header
HTTP Username + Password + path + User-Agent NVR login POST form; every request (GET/POST/other) is fingerprinted by path and the scanner's User-Agent
Telnet Username + Password + post-login commands Login prompt, then a fake interactive shell that logs every command
SSH Username + Password + post-login commands Real SSH-2.0 server (wolfSSH) β€” root:hunter2, then the interactive shell
FTP Username + Password USER admin / PASS password (RFC 959)

Real SSH server (wolfSSH). Port 22 is a genuine SSH-2.0 server, not a banner: wolfSSH performs the full key exchange (curve25519) and presents an ECDSA host key, so the device terminates the crypto and captures the plaintext username and password the attacker submits β€” something a banner-only trap can't do. The login is then accepted (any password; it's a decoy) and the attacker lands in the same interactive fake shell as Telnet, with every command logged. One caveat: wolfSSH advertises its own version string, so a fingerprinting client can tell it isn't OpenSSH β€” the value here is credential + command capture, not banner mimicry.

Interactive fake shell (Cowrie-style). Instead of endlessly replying "Login incorrect", the Telnet and SSH honeypots accept the login and drop the attacker into a believable Ubuntu 20.04 shell that answers common recon commands (ls, cat /etc/passwd, uname -a, ps, ifconfig, wget, …) while logging every command they type as a Shell event. Capturing the post-login command set reveals attacker TTPs and IOCs β€” which payloads they fetch, which binaries they try to run β€” that a credential-only honeypot never sees. Download/exec commands (wget/curl/tftp/chmod +x/./…) are flagged and escalated to a Telegram alert. Nothing is ever executed: responses are canned, the filesystem is fictional, and downloads are faked. Tunable via TELNET_SHELL_ENABLE / TELNET_LOGIN_GRANT_ATTEMPT in config.h.

MAC address for every protocol. Since the attacker is on the same local network, for each event ShadowSentry resolves their MAC via the lwIP ARP table and shows it together with a best-effort vendor guess (OUI). A randomized MAC (private, typical for smartphones) is flagged separately. The MAC is shown both in the dashboard and in the Telegram alert.

Threat-intel enrichment. A background worker resolves each attacker IP to its country, ISP/ASN and a reputation tag (hosting / proxy / mobile) via ip-api.com β€” free and key-less, so it works the moment you flash it. The result (with a country flag) shows in the dashboard and the Telegram alert; private/LAN source IPs are labelled Private LAN without any external call. Lookups run off the hot path and are cached by IP. Tunable via GEOIP_ENABLE / GEOIP_CACHE_SIZE in config.h.

Wi-Fi threat monitor (radio layer). The ESP32 isn't just a TCP stack β€” it's a Wi-Fi radio, so it can catch 802.11 deauthentication / disassociation attacks that no software honeypot on a normal network stack can see β€” including the single-frame deauth used to force a reconnect and capture a WPA2 handshake. Two signals: (1) forced disconnects β€” a deauth knocks the device off-air, so it always observes its own drop, and each drop is classified by its 802.11 reason code (a deauth-induced drop carries a low code 1–9; a benign RF loss reports 200+ and is ignored), so even one deauth-attributable disconnect fires an alert with no false positives from a flaky link; (2) broadcast deauth floods sniffed in promiscuous mode, carrying the attacker's transmitter MAC and target BSSID. Either raises a WiFi event. Runs on the channel the device is associated to β€” no channel hopping. (Rogue/evil-twin AP detection would need channel hopping and is out of scope for now.) Tunable via WIFI_MON_ENABLE / WIFI_MON_DEAUTH_DISC_THRESHOLD in config.h.

ARP-spoof / MITM monitor. A background task periodically scans the lwIP ARP cache for cache-poisoning signatures β€” the gateway's MAC changing after a stable baseline is learned, or one MAC claiming several IPs β€” and raises an ARP event (dashboard feed + Telegram) when it sees one. This catches L2 man-in-the-middle attacks that the port honeypots are blind to, since they never complete a TCP handshake. Scope: it detects spoofing that targets this host or is broadcast network-wide (the default for bettercap/ettercap); a strictly point-to-point spoof between two other hosts is out of scope. Tunable via ARP_MONITOR_ENABLE / ARP_SCAN_INTERVAL_S / ARP_ALERT_COOLDOWN_S in config.h.

Detection in action. Verified on real ESP32-S3 hardware against a live bettercap ARP spoof β€” the instant the attacker poisoned the board's gateway entry, the monitor logged it and pushed a Telegram alert (values below are anonymized):

ARP-MON: Gateway 192.168.1.1 MAC changed
         aa:bb:cc:dd:ee:01  ->  de:ad:be:ef:13:37   (MITM redirect)

Requirements

Hardware

  • ESP32-S3 DevKit (any board with β‰₯ 4 MB Flash)
  • USB cable for flashing
  • 2.4 GHz Wi-Fi network

Software

Component Version
ESP-IDF v5.2+
Python 3.8+
CMake 3.16+

Installing ESP-IDF

macOS / Linux

git clone --recursive https://github.com/espressif/esp-idf.git ~/esp/esp-idf
cd ~/esp/esp-idf
git checkout v5.2.1
./install.sh esp32s3
. ./export.sh

Windows

Download and run the ESP-IDF Windows Installer.

After installation, open the ESP-IDF Command Prompt for all commands below.


Configuration

# Copy the configuration template
cp main/config.h.example main/config.h

# Edit it for your setup
nano main/config.h

All parameters live in a single file β€” main/config.h:

// Network identity (what shows up in the router's device list)
#define DEVICE_HOSTNAME     "Hikvision-NVR"

// Wi-Fi
#define WIFI_SSID           "YourWiFiSSID"
#define WIFI_PASSWORD       "YourWiFiPassword"

// Telegram (get it from @BotFather)
#define TELEGRAM_BOT_TOKEN  "YOUR_BOT_TOKEN"
#define TELEGRAM_CHAT_ID    "YOUR_CHAT_ID"

// Admin panel  β†’  http://<ip>:9999
#define ADMIN_PASSWORD      "changeme1"
#define ADMIN_PORT          9999

// Honeypot ports
#define RTSP_PORT           554
#define HTTP_PORT           80
#define TELNET_PORT         23
#define SSH_PORT            22
#define FTP_PORT            21

main/config.h is added to .gitignore β€” real credentials never reach the repository.

Getting a Telegram Bot Token

  1. Send /newbot to @BotFather
  2. Copy the returned token into TELEGRAM_BOT_TOKEN
  3. Send any message to your bot, then open: https://api.telegram.org/bot<TOKEN>/getUpdates
  4. Find "chat":{"id":...} β€” that is your TELEGRAM_CHAT_ID

Build & flash

# 1. Clone the repository
git clone https://github.com/Rdx1S/ShadowSentryS3.git
cd ShadowSentryS3

# 2. Activate ESP-IDF
. ~/esp/esp-idf/export.sh

# 3. Copy and fill in the config
cp main/config.h.example main/config.h
nano main/config.h

# 4. Build and flash (replace /dev/ttyUSB0 with your port)
idf.py -p /dev/ttyUSB0 flash monitor

Finding the port

OS Command
Linux ls /dev/ttyUSB* or ls /dev/ttyACM*
macOS ls /dev/cu.usb*
Windows Device Manager β†’ Ports (COM & LPT)

First boot

After flashing, the monitor shows:

I (426) MAIN: ╔══════════════════════════════════════╗
I (428) MAIN: β•‘    ShadowSentry S3  v1.0             β•‘
I (434) MAIN: β•‘    Edge Deception HoneyPot           β•‘
I (439) MAIN: β•‘    ESP32-S3  |  ESP-IDF v5.x         β•‘
I (444) MAIN: β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
I (1827) WIFI: IP acquired: 192.168.1.105
I (1830) WIFI: Admin panel β†’ http://192.168.1.105:9999
I (1842) WIFI: mDNS started β†’ http://hikvision-nvr.local:9999
I (1904) RTSP: Honeypot listening on port 554
I (1910) HTTP: Honeypot listening on port 80
I (1916) TELNET: Honeypot listening on port 23
I (1924) SSH: Honeypot listening on port 22
I (1930) FTP: Honeypot listening on port 21
I (1938) ADMIN: Admin panel on port 9999

Open a browser β†’ http://192.168.1.105:9999
Login: admin / the password from ADMIN_PASSWORD.

No need to memorize the IP. Thanks to mDNS the device is always reachable at a stable name β€” http://hikvision-nvr.local:9999 β€” regardless of the address DHCP assigns. Works out of the box on macOS, Linux (avahi), Windows 10+, iOS and Android. The name is configurable via MDNS_HOSTNAME in config.h.


Admin Dashboard

A dark-mode web interface with a real-time WebSocket feed (new attacks appear instantly), backed by a 10-second poll for reconciliation and threat-intel updates. Every stat card and distribution row is clickable to filter the feed/table by attack type:

  • 6 stat cards β€” Total, Unique IPs, RTSP, HTTP, Telnet, SSH, FTP
  • Donut chart β€” real-time breakdown of attacks per protocol
  • Attack table β€” timestamp, IP, MAC + vendor, protocol, captured credentials, payload
  • Footer β€” device uptime, free heap, Wi-Fi signal strength (RSSI)
  • Clear button β€” wipes the logs from flash

REST API

Method Endpoint Description
GET /api/attacks Attack log + statistics (JSON)
GET /api/status Uptime / heap / RSSI (JSON)
POST /api/clear Clear the log

All endpoints are protected with HTTP Basic Auth (admin / ADMIN_PASSWORD).


Project structure

ShadowSentryS3/
β”œβ”€β”€ CMakeLists.txt              ESP-IDF root build file
β”œβ”€β”€ sdkconfig.defaults          ESP32-S3 defaults (240 MHz, dual-core)
β”œβ”€β”€ partitions.csv              NVS(24KB) + App(3MB) + SPIFFS(1MB)
└── main/
    β”œβ”€β”€ config.h.example        ← Configuration template (copy to config.h)
    β”œβ”€β”€ config.h                ← Real settings (in .gitignore)
    β”œβ”€β”€ idf_component.yml        Managed dependencies (espressif/mdns)
    β”œβ”€β”€ main.c                  Entry point, task distribution across cores
    β”œβ”€β”€ wifi_manager.c/h        Wi-Fi STA, DHCP hostname, SNTP, mDNS, ARP helpers
    β”œβ”€β”€ arp_monitor.c/h         ARP-spoof / MITM detector              (Core 1)
    β”œβ”€β”€ wifi_monitor.c/h        Wi-Fi deauth-flood detector (promisc)  (Core 1)
    β”œβ”€β”€ geoip.c/h               Threat-intel enrichment (ip-api.com)   (Core 1)
    β”œβ”€β”€ index.html              Dashboard HTML (embedded into the firmware)
    β”œβ”€β”€ CMakeLists.txt
    β”œβ”€β”€ honeypot/               ── Core 0 β€” Hacker World ──────────────
    β”‚   β”œβ”€β”€ rtsp_trap.c/h       Port 554, Fake Hikvision, Base64 creds
    β”‚   β”œβ”€β”€ http_trap.c/h       Port 80, Fake NVR login page
    β”‚   β”œβ”€β”€ telnet_trap.c/h     Port 23, Fake Ubuntu 20.04 login
    β”‚   β”œβ”€β”€ fake_shell.c/h      Interactive post-login shell (command capture)
    β”‚   β”œβ”€β”€ ssh_trap.c/h        Port 22, Real SSH server (wolfSSH) β€” captures creds
    β”‚   β”œβ”€β”€ ssh_hostkey.h       Embedded ECDSA host key (decoy)
    β”‚   └── ftp_trap.c/h        Port 21, Fake vsFTPd 3.0.5, full creds
    β”œβ”€β”€ admin/                  ── Core 1 β€” Admin World ───────────────
    β”‚   β”œβ”€β”€ admin_panel.c/h     Port 9999, HTTP Basic Auth, REST API
    β”‚   β”œβ”€β”€ ws_server.c/h       Port 9998, live WebSocket event push
    β”‚   └── telegram.c/h        Async FreeRTOS queue β†’ Telegram Bot API
    └── storage/
        └── log_store.c/h       RAM ring buffer (200 entries) + SPIFFS

How an attack is detected

No legitimate home-network device (laptop, phone, Smart TV) ever connects to ports 554, 80, 23, 22 or 21 on the ESP32 board.

Any connection to ShadowSentry S3 = a 100% anomaly.

Typical detection scenarios:

Threat Behaviour Detection time
Mirai / Mozi botnet Brute-force RTSP/Telnet/FTP < 5 s
Post-login intrusion Commands run in the fake Telnet shell (recon, payload fetch) per command
Ransomware lateral movement Subnet scanning < 5 s
SSH scanner Version fingerprint on port 22 < 1 s
Web scanner GET / on port 80 < 1 s
Manual scan (nmap) SYN on any port < 1 s
ARP spoofing / MITM Gateway MAC change or one MAC claiming many IPs ≀ scan interval (8 s)
Wi-Fi deauth / disassoc attack Reason-code-classified forced disconnect (β‰₯1) or broadcast flood (promiscuous) ≀ window (2 s)

ESP-IDF dependencies

All components ship with ESP-IDF β€” nothing to install separately:

  • lwIP β€” TCP/IP stack, raw sockets
  • FreeRTOS β€” multitasking, queues
  • esp_http_client β€” Telegram Bot API
  • mbedTLS β€” Base64 decode for Basic Auth
  • SPIFFS β€” flash file system
  • esp_netif_sntp β€” time synchronization

One component is fetched automatically by the component manager (declared in main/idf_component.yml, downloaded on the first build):

  • espressif/mdns β€” .local name resolution (reach the admin panel by name)

Troubleshooting

Won't connect to Wi-Fi

ESP32-S3 supports 2.4 GHz only. Check the SSID/password in config.h.

idf.py: command not found

. ~/esp/esp-idf/export.sh

Permission denied on /dev/ttyUSB0 (Linux)

sudo usermod -a -G dialout $USER
# Log out and back in

SPIFFS: mount failed error

idf.py -p /dev/ttyUSB0 erase-flash
idf.py -p /dev/ttyUSB0 flash

Telegram doesn't send alerts

Make sure the bot isn't blocked and you sent it /start.
TELEGRAM_CHAT_ID is a number (can be negative for groups).

Roadmap

Shipped

  • 5 protocol honeypot traps (RTSP / HTTP / Telnet / SSH / FTP)
  • Per-attack MAC + vendor (OUI) resolution
  • HTTP request fingerprinting (method / path / User-Agent)
  • Telegram alerts with resilient delivery + retry
  • Live web dashboard + REST API, clickable attack-detail modal
  • mDNS .local resolution
  • ARP-spoof / MITM monitor
  • Threat-intel / GeoIP enrichment (country Β· ASN Β· reputation)
  • Wi-Fi deauth/disassoc threat monitor (reason-code classified)
  • Interactive fake shell with per-command logging + IOC escalation (Telnet)
  • Real SSH server via wolfSSH β€” credential capture + fake shell
  • Live WebSocket dashboard β€” real-time event push (polling fallback)

Planned

  • SSH version-banner spoofing (present as OpenSSH, not wolfSSH)
  • Per-device SSH host-key generation at first boot (NVS-cached)
  • Rogue / evil-twin AP detection (requires channel hopping)
  • Additional protocol traps (SMB, MQTT, UPnP)

License

MIT β€” use, modify and distribute freely.

About

πŸ›‘οΈ Zero-config hardware honeypot on a single ESP32-S3 β€” fake RTSP/HTTP/Telnet/SSH/FTP traps that capture attacker credentials, MAC/vendor & User-Agent, with Telegram alerts and a dark-mode dashboard. Pure ESP-IDF / C, no cloud, no Raspberry Pi.

Topics

Resources

License

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors