73 Commits
Author SHA1 Message Date
c4ch3c4d3 18bd6e3f9a feat(webui,dashboard): add RAM Usage card between Disk Usage and Uptime, live-verified on Pager 2026-08-24 18:12:32 -06:00
c4ch3c4d3 0f31bfe885 fix(portals,capture): round-2 validation fixes, live-verified on Pager
- portals: replace zipfile with struct+zlib ZIP writer in portal download
  (python3-light has no zipfile; GET /api/portals/<name>/download 500ed)
- capture: revive watchdog re-arms the 5 GHz deploy auto-capture if the
  post-deploy radio settle kills it (was: empty pcap, dead tcpdump)
- capture: route GET /api/attacks/capture to status (was unrouted -> 404)

New tests/test_validation_fixes2.py covers each fix (TDD); full suite
(30 modules) green. Live-verified: download CRC-clean via stock zipfile,
capture survived settle window and revived automatically (56 MB pcap),
GET status returns proper JSON.

Round-2 validation report added at docs/validation/ (8/9 attack types
PASS against in-scope networks; enterprise PARTIAL per firmware limits).
2026-08-24 08:23:26 -06:00
c4ch3c4d3 d23ea56364 fix(portals,dns,radio1,capture): live-validation fixes, verified on Pager 24.10.1
- portals: replace zipfile with struct+zlib ZIP reader (python3-light has
  no urllib; import endpoint was dead on device)
- dns hijack: uci add_list/del_list for dhcp.@dnsmasq[0].address (list
  option; plain set was silently dropped from generated dnsmasq config)
- radio1: bridge attack APs into br-lan via network.brlan.ports so
  victims get DHCP/portal reach; wlan1ent runtime-bridged after hostapd
  verify (retry loop may recreate the iface)
- capture: auto-start pinned wlan1mon pcap on 5GHz WPA deploy, teardown
  on stop; loot flows via hc22000 export (crack-verified end-to-end)
- enterprise: pineapd restart after ctrl link + re-assert PineAPE toggles

Documented residual: pineapd refuses forwarding from foreign hostapd
instances (broken pipe), and daemon set_ap rejects radio1 names - so
hostap_handshake rows for radio1 twins and enterprise cred tables cannot
populate without a Hak5 firmware change.

New tests/test_validation_fixes.py covers each fix (TDD); full suite
(29 modules) green.
2026-08-23 21:44:21 -06:00
c4ch3c4d3 88d7141d45 feat(deauth,evilportal,capture): bulk deauth UX, Hak5-compatible Evil Portal, monitor capture fixes
- Recon AP focus sidebar: 'Deauth All Clients' with engagement-scope confirm
- Deauth Targeting card: 'Deauth All' behind the same scope confirmation
- New POST /api/attacks/deauth/bulk (max 32 targets, per-target results)
- Evil Portal tab: import EvilPortalNano-format portal zips into
  /mmc/mk8/portals, serve active portal on port 80 to unauthenticated
  clients via a minimal PHP shim, capture all form POSTs (.logs in stock
  MyPortal.php format + captures.jsonl), dnsmasq address=/#/ DNS hijack
- OpenAP: Evil Portal template dropdown (greyed when none), activated with
  the attack and stopped with it
- Monitor Capture fix: iface-less status now reports whichever monitor is
  actually capturing; pcap dir mkdir'd; tcpdump stderr surfaced instead of
  discarded
2026-08-23 19:50:41 -06:00
c4ch3c4d3 ed50cd7b5a fix(enterprise,deauth,filters): PineAP validation round fixes, live-verified on Pager 24.10.1
- 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.
2026-08-23 18:29:47 -06:00
bzuccaro a04319dfc8 feat(webui,recon): drop PineAP mode card, sort recon report APs by signal
- Remove the Passive/Active/Advanced mode card from the PineAP dashboard
  and move the RF Role (radio1) card into its slot, along with the now
  dead mode state machinery and mode-card-only CSS.
- Sort recon HTML report access points by signal strength (strongest first).
2026-08-23 09:29:10 -06:00
bzuccaro 2ef07a28fc feat(reliability): PSK uplink security-mode fallback chain (sae-mixed/sae/psk2 with PMF) 2026-08-23 08:19:20 -06:00
bzuccaro 501fa455ce fix(reliability): resolve STA netdev by phy membership (netifd ignores ifname); sae-mixed for PSK uplinks 2026-08-22 20:37:11 -06:00
bzuccaro 132cf4d77a fix(reliability): explicit hop baseline restore, immune to stale pager snapshot 2026-08-22 19:37:57 -06:00
bzuccaro 712d381093 fix(reliability): supervisor restores hop baseline unless a role holds the pause 2026-08-22 19:31:15 -06:00
bzuccaro 6b84665347 fix(deploy): no dangling symlink on first-deploy failure, deadline-capped health poll, release pruning, honest commit rc 2026-08-22 19:18:42 -06:00
bzuccaro 55d4beb9d4 fix(reliability): probe section existence via uci show, not an option key 2026-08-22 18:59:57 -06:00
bzuccaro 1133068a09 fix(reliability): recreate missing pineapd section; honest uci-set reporting 2026-08-22 18:45:44 -06:00
bzuccaro 23ca901e82 feat(reliability): supervisor continuously enforces known-good UCI set 2026-08-22 18:37:22 -06:00
bzuccaro b9a64c6560 fix(reliability): supervisor re-parks stock-resurrected dummy STA on interval 2026-08-22 18:31:06 -06:00
bzuccaro 5625310977 fix(reliability): converge runtime after profile restore (park dummy STA, re-raise monitors) 2026-08-22 18:26:21 -06:00
bzuccaro 60db235f0b fix(reliability): converge runtime on uplink revert; bound health endpoint cost (I3,I4) 2026-08-22 16:52:29 -06:00
bzuccaro b25c98b7c7 fix(reliability): hop governance belongs to rfplan, not boot reconciler (I2) 2026-08-22 16:51:52 -06:00
bzuccaro ba3e1b1ae0 fix(reliability): clear boot marker on graceful shutdown (I1) 2026-08-22 16:51:33 -06:00
bzuccaro eae47d99bf fix(reliability): encode str stdin in device_run; smoke drill path fixes + regression tests 2026-08-22 16:23:50 -06:00
bzuccaro 1bb15de258 feat(deploy): reliability API routes, atomic releases, version single-source 2026-08-22 15:20:39 -06:00
bzuccaro bace45d6e4 fix(reliability): rfplan review fixes — cli commit, assoc poll, ensure_attack wiring, idle reload 2026-08-22 14:35:12 -06:00
bzuccaro 15cd3c5eb8 feat(reliability): phy1 RF role manager with uplink-on-radio1 2026-08-22 14:20:05 -06:00
bzuccaro a008bb9167 feat(reliability): risky-op preflight snapshots + detached rollback watchdog 2026-08-22 13:56:25 -06:00
bzuccaro 7a27218149 feat(reliability): supervisor sampling, event feed, boot marker 2026-08-22 13:41:49 -06:00
bzuccaro a05754f908 feat(reliability): boot-time UCI reconciler 2026-08-22 13:12:14 -06:00
bzuccaro 88e6471820 feat(reliability): UCI profile snapshot store 2026-08-22 13:00:59 -06:00
bzuccaro 1d17704f72 fix(reliability): journal fail-safe serialization, per-line parse, review hardening 2026-08-22 12:51:22 -06:00
bzuccaro 496f7c58e3 feat(reliability): JSONL event journal with rotation and counters 2026-08-22 12:39:19 -06:00
bzuccaro 883a839692 test: cover recon identity associations 2026-08-21 08:41:17 -05:00
bzuccaro 21e308386f feat: include recon identity in exports 2026-08-21 08:31:47 -05:00
bzuccaro a67faecee9 feat: associate recon clients with confirmed networks 2026-08-21 08:26:58 -05:00
bzuccaro 797db1816a feat: resolve recon device manufacturers locally 2026-08-21 08:15:21 -05:00
bzuccaroandCursor 7d48b7ad06 fix: harden UI actions and daemon calls for reliable control (v1.3.2)
Retry and serialize pineapd/hak5 calls, queue virtual-pager keys, and grey out buttons until the pager finishes. Deploy now installs python3-light after factory firmware. Bump version to 1.3.2.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 15:49:10 -05:00
bzuccaroandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> cd26553d21 fix: non-disruptive startup checks + clean service lifecycle (v1.3.1)
- Env check is read-only when state is sane: no pineapd command-socket
  writes, no live pool-list commits, no wifi reload; pineapd restarts only
  when a runtime-sensitive UCI value changed or the daemon was down
- Failed monitor repairs now fail the startup contract instead of being
  reported as fixed; runtime pool state is read from active config
- Enterprise AP recovery runs only on device boot (PAGER_WEBUI_BOOT), not
  on every web-service restart
- serve() gates the HTTP port on startup checks with bounded retries and
  shuts down cleanly on SIGTERM/SIGINT; the recon watchdog waits
  interruptibly
- Recon uses a bounded userspace channel scheduler that drives both
  monitor radios over non-DFS channels, with preflight verification,
  serialized starts, and per-cycle error reporting
- payload.sh waits for real readiness on start, fully removes the boot
  service (stop + disable + delete) on stop, and surfaces a
  stopped-but-enabled boot service; deploy.sh refreshes the installed
  init script even when the service is stopped
- Bump version to 1.3.1

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-08-19 12:03:11 -05:00
bzuccaro 6e3968c19a fix: non-disruptive env check — drop wifi reload + misleading hop warning
- STA uplink disable now uses uci commit + ip link set wlan0 down instead of
  wifi reload, so the env check never bounces radios/APs/drops monitors
- Removed the wlan0mon 'hop is off' warning: field-verified hop=0 is normal
  (wlan1mon also reports 0 while scanning both bands); the STA/AP pinning
  checks are the real signals
- recon/status drops wlan0_hopping; UI keeps wlan0_sta + wlan0_pinned pills
2026-08-19 10:55:26 -05:00
bzuccaro 5a72566381 feat: env check auto-disables dummy_radio0 STA (2.4GHz recon root cause)
The stock STA client interface (wlan0) holds phy0's channel, pinning wlan0mon
so 2.4GHz recon captures nothing (verified: iw set channel -> Resource busy
until wlan0 is down). env_check now disables it (uci wireless.dummy_radio0
disabled=1 + wifi reload) at startup and /api/recon/status exposes wlan0_sta
so the recon page can warn if it regresses.
2026-08-19 10:42:26 -05:00
bzuccaro 5eb81b90f1 fix: recon env-check verifies runtime wlan0mon hopping (2.4GHz starvation)
The band UCI config looked correct but pineapd was not hopping wlan0mon at
runtime, so 2.4GHz recon results were entirely absent. env_check now parses
_pineap INTERFACE LIST and warns when wlan0mon hop is off; /api/recon/status
exposes wlan0_hopping and the recon scan bar surfaces it.
2026-08-19 10:29:50 -05:00
bzuccaro 904843307e feat: startup environment check + self-heal (v1.3)
- env_check(): verifies daemon/pineapd/UCI/monitors/recon DB, auto-fixes
  fixable issues and re-verifies; forces runtime SSID-pool broadcast off to
  match the UI (kills the 'pool on but UI shows off' gap)
- server.py --env-check CLI; payload.sh runs it verbosely before starting,
  aborts on core failure
- serve() runs the check at every startup (boot + procd respawn)
- /api/health exposes env report + pool_runtime; /api/recon/status exposes
  wlan0_pinned (2.4GHz under-sampling warning); recon page warns when a
  radio0 AP pins wlan0mon
- recon start failures now include the daemon reason in the UI error
- shared stabilization refactor (_stabilize_uci/PINEAPD_SAFE_UCI/_raise_monitors)
- tests: test_env_check.py (18) + health/recon updates
2026-08-19 10:25:02 -05:00
bzuccaro f6b4cadc39 fix: client kick/deauth use full bssid/target/channel deauth form
hak5cmd on this firmware has no CLIENT_KICK command and PINEAPPLE_DEAUTH_CLIENT
requires (bssid, target, channel) — the UI kick/deauth buttons and the MCP
pineap.kick_client tool previously passed only the client MAC, which printed
usage and silently did nothing.

- _deauth_target/_deauth_client_via_iface resolve the client's association
  interface via iwinfo (Access Point + Channel), pick the band-aware inject
  interface, and issue DEAUTH_CLIENT <bssid> <mac> <channel>
- h_client_kick: deny-filter (persistent) + immediate deauth with rc checks
- h_deauth_client: deauth with the full form; 502 with detail when the
  client is not associated
- MCP pineap.kick_client: resolves the client first (no side effects on
  failure), then deny-filter + deauth; verified on device (clean error for
  unassociated clients, filter list restored)
- tests updated for the new command chain
2026-08-19 00:05:42 -05:00
bzuccaro 2044f08f1e test: delete-all-scans endpoint coverage 2026-08-18 22:37:42 -05:00
bzuccaro e93359fb69 feat: merge attacks into PineAP menu; auto channel; recon fixes; richer reports
- Rail: Attacks tab removed; PineAP becomes a grouped menu (Evil WPA /
  Evil Open / Evil Enterprise / Impersonation / Clients / Filtering);
  old #/attacks* hashes redirect to their PineAP equivalents.
- PineAP tabs gain Evil Enterprise; stock Open AP / Evil WPA / Enterprise
  pages replaced by the verified one-click launchers (status, capture,
  export, deauth, playbooks).
- Channel selects gain an Auto option: deploy resolves the target SSID's
  last-seen channel from recon.db (verified unit-tested end to end).
- Harness: pi.dev prompt section removed; Copy Token inline; robot icon.
- Recon: compare checkboxes no longer hide the AP list (multi-select
  stays visible, rows highlighted, clients table no longer suppressed);
  Previous Scans buttons moved above the dropdown with a Delete All;
  encryption chips + buckets now distinguish WPA2/WPA3 PSK vs Enterprise
  (AKM suites decoded from recon bitfield bits 32-47); scan JSON carries
  GPS when a fix exists; Reports tab shows a GPS column.
- fix: restore top-level EVIL_ENC definition lost in the repo (deployed
  build had it; repo would have thrown at init).
2026-08-18 22:35:51 -05:00
bzuccaro 1327bec03c test: reset monitor_fixes counter between health tests 2026-08-18 21:34:11 -05:00
bzuccaro 1d807a1fcf fix: health check repairs dropped monitors even when pineapd is healthy
wifi reloads during attack deploy/stop drop the monitor interfaces and
pineapd only recovers its primary; the monitor now brings both up
whenever it finds them down, with or without a pineapd failure.
2026-08-18 21:33:11 -05:00
bzuccaro ce1f6a8442 fix: passive health check + hop=0 in stabilization pass
Active PINGs on pineapd's command socket collided with the stock daemon's
own socket writes ('[PineAp] Error writing'), making the daemon watchdog
SIGTERM pineapd every ~30s while hopping. Monitor now checks pidof only
(no socket writes) and the stabilization pass pins wlan1mon hop=0.
2026-08-18 21:05:39 -05:00
bzuccaro 4c5b459f72 test: uci delete support in health test fake 2026-08-18 20:47:54 -05:00
bzuccaro b5d9ed39ff fix: health monitor stabilization pass for all pineapd crash sources
Field-verified crash stack on this firmware: SSID-pool broadcast (segfault),
wlan2mon hopping a nonexistent 6GHz iface (segfault), wlan1mon fast-hopping
6GHz channels (ASIO thread exit), and a large refilled pool. The fix path
now enforces: pool broadcast off, pool list cleared, wlan2mon off, wlan1mon
5GHz-only, wlan0mon 2.4GHz-only — idempotent, so collect refills self-heal.
8-minute continuous-PONG stability verified on-device.
2026-08-18 20:47:43 -05:00
bzuccaro c91d970a41 test: cover wlan2mon crash-source fix in health monitor 2026-08-18 20:26:29 -05:00
bzuccaro adfe8f784f fix: health monitor detects down monitors via ip link flags + disables wlan2mon
operstate reports 'unknown' on monitors (normal), so _iface_up now parses
admin flags from ip link. Discovered a second pineapd SIGSEGV source: the
wlan2mon 6GHz monitor this hardware never creates, hopping on the missing
iface (~85s crash cadence even with the SSID pool off). The monitor now
disables it in the fix path.
2026-08-18 20:26:16 -05:00
bzuccaro d10fba9d1b fix: never re-enable SSID pool broadcast (crash guard) + top-bar health chip
Mode 'active' and the advertise toggle could re-enable the SSID-pool
broadcast that segfaults pineapd. active preset now skips ssidpool/enable
(advertise stays false), the advertise endpoint refuses with an
explanation when the pool is disabled, get_ap reports the real pool
state, and the PineAP overview disables the toggle with a notice. Added
a top-bar health chip (PINEAP OK / POOL OFF / PINEAPD DOWN) polled every
15s.
2026-08-18 20:16:41 -05:00