Files
Mark-VIII/payload/user/remote_access/pager-webui/skills/pineapple-control.md
T
bzuccaro e871e49466 feat: local MCP harness (tools/resources/prompts) + Harness UI page
Streamable-HTTP MCP server on POST /mcp: device.state, attack.deploy/stop/
status/deauth/capture/export_hc22000, loot.handshakes/enterprise_creds,
recon.aps/isearch/devices, pineap.kick_client/set_filter tools; recon DB +
bundled opencode skills resources; attack playbook prompts. Cookie or Bearer
auth. Harness page shows endpoint, token, curl snippet, capability explorer
and a copy-paste pi.dev prompt. scripts/harness_stdio.py for stdio-only
agents.
2026-08-18 20:00:13 -05:00

7.8 KiB

name, description
name description
pineapple-control 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.

Access

sshpass -p '<pw>' ssh -o StrictHostKeyChecking=no root@<ip>       # 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 <iface> 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:
    cp /etc/config/wireless /etc/config/wireless.bak
    # wifi-iface section: ssid 'TargetSSID', encryption 'psk2', key '<passphrase>'
    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:

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):
    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):
    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 </dev/null &
    
  • Stop captures: killall tcpdump (pkill missing).
  • Pull evidence locally with scp; analyze with tshark/capinfos/hcxpcapngtool (brew wireshark, hcxtools).

Verification & troubleshooting

  • AP up but silent? iw dev <iface> info for ssid/type/channel; hostapd_cli -i <iface> 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.