Lion Cipher Lab
Turn rules of engagement into a machine-checked scope guard
- Penetration Testing / Red Team
- Intermediate
- ~45 min
- Free · no account required
Why it matters
The single fact that separates a penetration tester from a criminal is written permission, and that permission has edges. The rules of engagement say exactly which addresses and names you may touch, which ones you must never touch, and when. Step one address outside them and you can take down a client's production database, attack a third party who never agreed to anything, or break the law -- and a good intention is no defence. The scary part is how ordinary the mistakes are. Someone checks scope by eye or with a quick text match, and 10.1.2.30 looks like 10.1.2.3, evilexample.com contains…
What you'll learn
- reading a rules-of-engagement (RoE) document the way a professional tester does -- in-scope networks, in-scope hostnames and wildcards, explicit exclusions, and a testing window with a named time zone -- and turning it into a machine-readable roe.json
- building an ALLOWLIST scope guard in pure Python (ipaddress, json, csv, hashlib, datetime, zoneinfo) that denies every target unless it is proven in scope, instead of a denylist that allows everything not explicitly forbidden
- matching IP addresses by real network membership (10.1.2.30 is NOT inside 10.1.2.0/28 even though it starts with the text 10.1.2.3), handling IPv6 written short-hand or long-hand, and refusing ambiguous input such as 10.1.2.009
- matching hostnames on a label boundary (*.example.com covers www.example.com, never evilexample.com or example.com.attacker.net), normalising case and the trailing dot, and following a CNAME chain from an offline resolution table so a friendly name that points at a third party is blocked
- checking a testing window in the client's own time zone with zoneinfo, so the change from summer to winter time does not silently move the window by an hour
- measuring the before/after on 40 seeded planned targets: the naive check leaked 17 of the 23 should-be-blocked targets and wrongly blocked 3 in-scope ones; the guard got all 40 right
- logging every decision with a timestamp and a SHA-256 of the exact scope file, so the report can show which signed scope version authorized each test
- naming what a scope guard can NEVER know -- shared hosting and cloud IP reuse, DNS changes after sign-off, verbal scope changes -- and why it never replaces written authorization
Steps in this lab
- What rules of engagement are -- every term, defined once
- Open a terminal and check Python (and, on Windows, the time zone data)
- Turn the signed scope into data: seed.py
- Write the guard -- and the naive check it replaces: scope_guard.py
- Run the guard on all 40 planned targets
- Measure the before/after: what the naive check would have let through
- Put the guard in front of every tool: the check mode and its exit code
- The honest negatives: what no scope guard can know
- When, why, and how to do it better
- What you built -- and the reflex to keep