CLI toolkit for captive-portal paywall analysis — MAC/session binding, walled-garden leakage, pre-auth egress, and DNS tunneling — built for authorized security research (vendor-hosted hackathons, lab replicas, networks you own).
Scope & ethics. GhostLink is a research instrument. Use it only on networks you own or are explicitly authorized to test (e.g. a hackathon's designated test SSID). See docs/venue-runbook.md for the operating procedure and guardrails.
npm install -g @adams-404/ghostlink
ghostlink recon --no-colorThis ships the same stdlib-only Python CLI in a Node wrapper — at runtime it
needs Python 3.10+ and iproute2 (ip -j) on the box. The wrapper
locates python3 (override with GHOSTLINK_PYTHON), checks the version, and
execs python -m ghostlink.
git clone https://github.com/Adams-404/GhostLink.git && cd GhostLink
python -m unittest discover -s tests # 27 tests, no network needed
python -m venv .venv && . .venv/bin/activate && pip install -e .
ghostlink --helpRequires Python ≥ 3.10 and iproute2 (ip). Everything else is stdlib.
Actual MAC changes need sudo -n (non-interactive) — nothing is ever changed
without --apply.
# 1. who am I on, and is there a portal?
python -m ghostlink recon --no-color
# 2. everything at once + a findings report (ghostlink-report.md/.json)
python -m ghostlink all --no-color --timeout 2.0
# 3. the MAC toolkit
python -m ghostlink mac list --no-color # interfaces: type, driver, vendor
python -m ghostlink mac neighbors --no-color # devices: mDNS/PTR/NetBIOS names
python -m ghostlink mac discover --no-color # sweep subnet + name everyone
python -m ghostlink mac watch aa:bb:cc:dd:ee:ff --duration 300
python -m ghostlink mac gen --vendor apple --count 5
python -m ghostlink mac spoof f0:18:98:2a:07:06 # dry-run
python -m ghostlink mac spoof f0:18:98:2a:07:06 --apply --force
python -m ghostlink mac restore
# 4. the wall
python -m ghostlink egress --no-color
python -m ghostlink walled --portal-url http://portal/login --no-color
# 5. extras: IPv6 leak, path divergence, DHCP fingerprint
python -m ghostlink extras --no-colorAll commands accept --json for machine-readable output and --iface to
override the auto-detected interface.
| Command | Purpose |
|---|---|
| Command | Purpose |
| --- | --- |
recon |
iface/gateway/resolver discovery + captive-portal detection via OS probe URLs |
egress |
pre-auth TCP/UDP/ICMP egress matrix + DNS leak test (gateway vs. upstream) |
walled |
portal splash-page dissection + walled-garden reachability matrix |
extras |
IPv6 leak, traceroute/gateway divergence, DHCP hostname disclosure |
mac |
list (interfaces: type/driver/vendor) · neighbors (named devices: mDNS/PTR/NetBIOS + OUI) · discover (subnet sweep) · gen · spoof · restore · watch |
report |
render markdown from a saved run's JSON |
all |
full sweep + findings report with severity heuristics |
Device identities are best-effort: mDNS covers Apple/Linux/Android, NetBIOS
covers Windows, reverse-PTR the rest. Vendor attribution from OUIs is a hint
only — devices with locally-administered (randomized) MACs are flagged as
randomized, since a randomized MAC is a much weaker session identity to
inherit.
Paid-WiFi gateways enforce the paywall with three components: a redirect splash page, a firewall rule set (walled garden), and a session state machine keyed to the client (usually MAC). GhostLink maps one module onto each:
recon→ detects the splash-page interceptionegress+walled→ characterizes the firewall and its leaksmac+extras→ probes the session/identity layerreport+docs/findings/→ durable evidence for the vendor writeup
See docs/README.md for per-technique deep dives and the venue runbook.
ghostlink/ CLI + modules (config, recon, egress, walledgarden, mac, extras, report, dnswire)
tests/ stdlib unittest suite (27 tests, offline)
docs/ index, techniques/, findings/, venue-runbook.md
npm/ npm wrapper (bin shim + package.json; sync-python.sh bundles the Python code at pack time)
- Pure stdlib; iproute2 JSON (
ip -j) for link/neighbor/recon facts. sudo -nfor privileged MAC changes — fails loudly instead of hanging.- Every
allrun emits a markdown + JSON findings report. - Severity escalation in
report.pyonly fires when a portal is actually present, so open-network runs stay informational.