Skip to content

Dev to main v2.5 - #38

Merged
r4ulcl merged 152 commits into
mainfrom
dev
Aug 21, 2026
Merged

Dev to main v2.5#38
r4ulcl merged 152 commits into
mainfrom
dev

Conversation

@r4ulcl

@r4ulcl r4ulcl commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Changelog: WiFiChallengeLab v2.5

Added

  • Host-only RDP networks (VirtualBox, VMware) and Start/Stop Nzyme desktop launchers
  • EAP-TLS identity-leak scenario (hardened vs. leaking client certificates)
  • SIM/USIM AP (wifi-passpoint, EAP-SIM/AKA/AKA') with two EAP-AKA' clients backed by a software HLR/AuC (hlr_auc_gw + Milenage, no physical SIM): a leaking one (permanent IMSI in the clear, any passive sniffer) and a privacy-preserving one (anonymous outer identity + pseudonym/fast-reauth: no passive leak, yet still surrenders its IMSI to a student-built evil-twin/rogue AP that actively requests the permanent identity)
  • Client-less PMKID AP (wifi-campus): a lone WPA2-PSK BSSID (channel 7, no client on purpose) on radio wlan31. Capture the PMKID straight from the BSSID and crack the PSK offline (see APs/PMKID_TESTING.md)
  • WPA3 Cookie Guzzler airgeddon plugin and Vagrant audio support (QEMU, VirtualBox)

Modifications

  • Consolidated host networking on NetworkManager + systemd-resolved (VirtualBox, VMware, QEMU, Hyper-V) and made the Nzyme web UI reachable from other computers (auto-detects host IP)
  • Grew the client radio pool 20 → 30 (wlan40-69, radios=71) and moved the nzyme WIDS tap to wlan70, freeing 10 slots for new scenarios
  • Management EAP-TLS AP now offers both TLS 1.3 and legacy TLS 1.2; updated wifi_db to v1.6
  • Clients now carry a realm in the EAP anonymous outer identity (e.g. anonymous@CONTOSOREG) on the TLS and MSCHAPv2-relay networks, matching real supplicant behaviour

Bug Fixes

  • Networking: fixed DNS on networks that block public resolvers and AP internet sharing (name-independent uplink detection); fixed host DHCP service startup failures
  • Certificates: added the missing clientAuth EKU to EAP-TLS client certs, made the CA RFC 5280-conformant, corrected the server cert subject/SAN, deduplicated them into a single generated set, and removed a stray wget in the AP Dockerfile; extended the server cert SAN through 192.168.40.1 so every lab portal (including 192.168.21.1) validates in Firefox
  • Web portals: fixed PHP errors and session handling across the AP and client portals, plus lab.php not showing the username
  • MGT/EAP: fixed a regional/locale error connecting to MGT (EAP relay) networks and the MSCHAP/GTC simulated logins using a MAC instead of the gateway IP; removed ieee80211w from the MSCHAPv2 relay client to match the AP; set MFP optional (ieee80211w=1) on the WPA3 downgrade AP so its SAE/WPA2-PSK transition mode works (mandatory MFP would block the WPA2-PSK downgrade path); fixed the wifi-regional relay client (wlan50) being macchanger'd to the AP's own BSSID (MAC_MGT_RELAY instead of MAC_CLIENT_MGT_RELAY): a station whose MAC equals its target BSSID has every authentication rejected by mac80211 (SME: Authentication request to the driver failed)
  • Build/misc: made the ath_masker build best-effort (no more aborted image builds), removed the hardcoded gcc/g++ 12, fixed a stale exit in the deauth-on-drop patch and an image-tag error in the challenge compose file, fixed the challenge flags in wlan_config_challenge, updated the pcapFilter.sh helper to the latest gist revision, and fixed the hostapd-mana build under Vagrant while making provisioning abort if installTools.sh doesn't finish

Miscellaneous Improvements

  • network self-heal service to recover the uplink on boot; disabled Debian automatic updates
  • Added automatic Apache portal recovery that monitors login.php and restarts the web service when it becomes unavailable
  • Removed email/PII and legacy Netscape fields from generated certificates
  • Reworked healthchecks and compose files across all variants; hostapd per-SSID logs now capture stderr (2>&1)
  • Gave each AP/client a distinct, stable signal via per-radio RSSI jitter (~±3 dB) in the mac80211_hwsim driver (in-kernel, deterministic per radio, no per-beacon flicker) instead of a racy userspace iw txpower loop that hostapd overrode
  • Ran each MGT relay supplicant in its own loop (a stall no longer blocks the others) and backgrounded the client fping keepalive
  • Stopped the GNOME session from locking on inactivity (system-wide dconf no-idle-lock) for both RDP and local desktop sessions, so long-running attacks aren't interrupted
  • New AP web console (login and recovered-flag pages): Dracula theme, animations, single sign-out, flag on top and pink username with placeholder
  • Gave the lab user access to the compiled tool tree so the tools run without extra permissions
  • Updated OPEN_SOURCE_REFERENCES.md

r4ulcl and others added 30 commits February 24, 2026 17:00
vagrantfile: Improve audio support on non-windows (QEMU/VBOX)
r4ulcl and others added 26 commits August 7, 2026 16:20
The BSSID allowlist added in 0eca0c7 never took effect as deployed: there is no
/root/wlan_config file (docker-compose passes wlan_config via env_file, so the
MAC_*/WLAN_* vars live only in the environment), and ns-inet.sh runs the module
build as `sudo bash install.sh`. With the AP image's default sudoers env_reset,
sudo stripped MAC_DOWNGRADE/MAC_6GHZ/MAC_OWE, so PATCH_ALLOW_BSSIDS came out ",,"
and dragondrain.sh fell back to detect-all -- re-exposing wifi-management (wacker)
and wifi-campus (PMKID) to the self-DoS.

- ns-inet.sh: drop the redundant sudo (the script already requires root) so
  install.sh inherits the env_file MAC_* vars.
- install.sh: strip stray quotes/space from the joined value defensively, and
  make the empty-allowlist warning explicit about the consequence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…bump

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ey selectable

FLAG_MGT_RELAY_TABLETS decoded to "flag{...}\r\n". Both templates interpolated
the decoded flag straight into onclick="copyFlagToClipboard('<flag>')", so the
trailing CRLF landed inside a JS string literal and the parser threw
"'' string literal contains an unescaped line break" -- the copy button was dead
on 192.168.18.1 (IP_MGT_RELAY_TABLETS) only. Scanned every FLAG_*/PASS_* in
wlan_config and wlan_config_challenge; that was the only corrupted value.

- wlan_config: re-encode FLAG_MGT_RELAY_TABLETS without the trailing CRLF.
- login.php.tmp / index.php.tmp: stop inlining the key into JS. trim() +
  htmlspecialchars() and emit <div class="flag"><code class="flag-text">key
  </code><button class="flag-copy">, so no flag content can break the page.
- script.js: delegated .flag-copy listener reads the key from .flag-text
  textContent; keeps the execCommand fallback (lab is plain HTTP, so
  navigator.clipboard is undefined) and reports COPIED / SELECT + CTRL-C.
- style.css: the key is now a <code> with user-select: text so it can be
  drag-selected by hand; COPY is a separate control beside it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…builds

The BSSID allowlist that keeps the flood/DoS detector off wifi-management (wacker)
and wifi-campus (PMKID) is a compile-time constant in the module, but MODULE_VERSION
is the fixed string "2.5.1-WiFiChallengeLab-version" and doesn't change when the
allowlist changes. install.sh skips the build whenever the installed version matches,
and /lib/modules is a host bind-mount, so the first detect-all build (from before the
a2b63e4 env fix took effect) stuck on the host and every container start since then
early-exited without recompiling. Result: a stale detect-all module kept self-DoSing
wifi-management -- confirmed live by "[HWSIM-PATCH][phy95] DragonDrain detected -> DoS
mode" firing on wlan24's own radio during a wacker run.

- install.sh: after computing PATCH_ALLOW_BSSIDS, append a hash of the (lowercased)
  set to MODULE_VERSION -> e.g. "...+scope-9753fbcb", or "+noscope" when empty. Any
  change to the scoped set now yields a new version -> forced rebuild; an empty
  allowlist is both force-rebuilt and visible in modinfo/sys. Idempotent, so an
  unchanged set still early-exits. Also fix the TARGET_VERSION_ERROR fallback typo
  (2.5 -> 2.5.1).
- uninstall.sh: match on the "WiFiChallengeLab-version" marker instead of the exact
  "2.5-..." string (which never matched the installed 2.5.1, so a plain uninstall
  silently kept the module). Now removes any of our builds regardless of numeric
  version or +scope/+noscope tag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… a stale detect-all module can't self-DoS wifi-management
service apache2 start was a one-shot fire-and-forget call. If apache2
ever died, its stale /var/run/apache2/apache2.pid could get reused by
an unrelated process, causing the sysvinit script to believe apache
was "already running" and refuse to restart it - permanently wedging
login.php (and the aps healthcheck) even though the container stayed
Up.

Replace the one-shot start with a supervise_apache() loop that
health-checks http://localhost/login.php every 15s and force-restarts
apache2 (stop, kill by exact process name, clear stale pidfile, start)
whenever it stops responding. Uses `pkill -x` rather than `pkill -f`
so the kill doesn't match the loop's own command line when invoked via
bash -c.

Add docker-compose.override.yml to bind-mount the patched script over
the one baked into the r4ulcl/wifichallengelab-aps image, so the fix
survives image pulls/recreation without needing a rebuild.
Make aps apache2 startup self-healing
@r4ulcl r4ulcl self-assigned this Aug 21, 2026
@r4ulcl
r4ulcl marked this pull request as ready for review August 21, 2026 10:31
@r4ulcl
r4ulcl merged commit 3761257 into main Aug 21, 2026
4 checks passed
@r4ulcl
r4ulcl deleted the dev branch August 21, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants