Lion Cipher Lab
Build an SSH tarpit from scratch and measure the slowdown
- Cyber / Security Engineer
- Intermediate
- ~45 min
- Free · no account required
Why it matters
Any SSH service exposed to the internet is hit within minutes by automated scanners trying default and leaked credentials, around the clock. The common answer is to BLOCK them -- fail2ban, CrowdSec and sshguard all watch the logs and firewall an IP after a few failures, and Lion Cipher has labs for each. A tarpit is the opposite, older, and oddly satisfying idea, popularised by Chris Wellons' 'endlessh': instead of slamming the door, you hold it open a crack and waste the bot's time. The SSH protocol lets a server send arbitrary banner lines before it identifies itself, so a tarpit accepts…
What you'll learn
- explaining what an SSH tarpit is and how it differs from a ban: a tarpit HOLDS the connection open and dribbles an endless banner to waste the scanner's time, where fail2ban/CrowdSec/sshguard DROP the packet and firewall the IP
- reading the one line of RFC 4253 the trick rides on: a server MAY send other CRLF-terminated lines before the 'SSH-2.0-...' identification string, as long as they do not begin with 'SSH-' -- so an endless stream of such lines keeps a well-behaved client reading forever
- writing a minimal tarpit server in stdlib Python (socket + threading): accept(), then loop sending a few random bytes + CRLF every N seconds and never sending the final SSH identification line
- writing a stdlib measuring 'scanner' that reads until it sees a valid 'SSH-' banner or a time budget expires, and reporting the two numbers that matter: seconds held and bytes received
- measuring the asymmetry from a real run: a normal server answers in ~0.002s/21 bytes, while the tarpit still holds the client at a 12s budget having spent only ~77 bytes -- you pay almost nothing, they pay a connection slot plus time
- proving the concurrency point: holding 50 simultaneous fake scanners at once (50/50 still trapped after 8.1s, ~52 bytes each) so it ties up the SCANNER'S parallelism, not yours
- why a concurrency CAP is mandatory, not optional: one thread/fd per trapped client means an uncapped tarpit DoSes itself; a BoundedSemaphore caps it and refuses excess connections instantly (measured: cap=5 traps 5 and refuses the rest)
- the honest limits and the right deployment: the slowdown is bounded by the bot's patience not your delay, a tarpit does nothing against an attacker who ignores the banner and attacks your real SSH, so run real SSH on another port/key-only and pair the tarpit with fail2ban -- tarpit the noise, ban the persistent
Steps in this lab
- What a tarpit is -- and how it is the opposite of a ban
- The one rule of the SSH banner the whole trick rides on
- Write the tarpit server (accept, then dribble forever)
- Write the measuring client and a normal server to compare against
- Run it and read the two numbers that matter
- Concurrency: hold many at once, and prove the cap is mandatory
- Honest negatives: what a tarpit does NOT do
- Do it better: when to use it, and how to pair it with a ban