Politician 1.0.0
WiFi Auditing Library for ESP32
Loading...
Searching...
No Matches
PoliticianTypes.h
Go to the documentation of this file.
1#pragma once
2#include <stdint.h>
3#include "politician_compat.h"
4
5#ifndef POLITICIAN_NO_STD_FUNCTION
6#include <functional>
7#endif
8
9namespace politician {
10
11// ─── Compile-Time Feature Gates ──────────────────────────────────────────────
12// Define these before including Politician.h or via build flags (e.g. -DNAME)
13// #define POLITICIAN_NO_DB // Strip 14KB OUI Database (Vendor lookups)
14// #define POLITICIAN_NO_PCAPNG // Strip PCAPNG serialization logic
15// #define POLITICIAN_NO_HC22000 // Strip Hashcat mode 22000 formatter
16// #define POLITICIAN_NO_LOGGING // Strip all internal Serial _log() output
17// #define POLITICIAN_NO_STD_FUNCTION // Use raw fn pointers instead of std::function (saves ~2KB, no lambda captures)
18// #define POLITICIAN_NO_MSCHAPV2 // Strip bare EAP-MSCHAPv2 capture (MsChapRecord, MsChapCb, challenge table)
19// #define POLITICIAN_NO_KARMA // Strip KARMA rogue AP responder (KarmaRecord, KarmaCb, probe-response injection)
20
21// ─── Capture Types ────────────────────────────────────────────────────────────
22#define CAP_PMKID 0x01 // PMKID fishing (fake association)
23#define CAP_EAPOL 0x02 // Passive EAPOL (natural client reconnection)
24#define CAP_EAPOL_CSA 0x03 // EAPOL triggered by CSA beacon injection
25#define CAP_EAPOL_HALF 0x04 // M2-only capture (no anonce) — active attack pivot triggered
26#define CAP_EAPOL_GROUP 0x05 // Non-pairwise EAPOL-Key (GTK rotation)
27#define CAP_SAE 0x06 // WPA3 SAE (Simultaneous Authentication of Equals) Commit/Confirm frame
28
29// ─── Encryption Type Constants ────────────────────────────────────────────────
30// Used in ApRecord.enc and Config.enc_filter_mask (bit N = enc value N)
31#define ENC_OPEN 0 // Open network (no encryption)
32#define ENC_WEP 1 // WEP (Privacy bit set, no RSN/WPA IE)
33#define ENC_WPA 2 // WPA (vendor IE 00:50:F2:01)
34#define ENC_WPA2 3 // WPA2/WPA3-Transition (RSN IE with PSK or SAE AKM)
35#define ENC_ENT 4 // 802.1X Enterprise (RSN IE with 802.1X AKM suite 1)
36#define ENC_OWE 5 // OWE — Opportunistic Wireless Encryption (AKM suite 18); no PSK, no PMKID
37
38// ─── Attack Selection Bits ────────────────────────────────────────────────────
39#define ATTACK_PMKID 0x01 // PMKID fishing
40#define ATTACK_CSA 0x02 // CSA beacon injection
41#define ATTACK_PASSIVE 0x04 // Passive EAPOL capture
42#define ATTACK_DEAUTH 0x08 // Classic Reason 7 Deauthentication
43#define ATTACK_STIMULATE 0x10 // Zero-delay QoS Null Client Stimulation
44#define ATTACK_BTM 0x20 // 802.11v BSS Transition Management Request (polite client steering)
45#define ATTACK_ALL 0x3F
46
47// ─── Capture Filters ──────────────────────────────────────────────────────────
48// NOTE: Logging High-Frequency Intel (like Beacons) via standard SPI (SD.h) will
49// create massive blocking delays (20-50ms per flush) that destroy the hopper's
50// attack loop. If you enable LOG_FILTER_BEACONS or LOG_FILTER_ALL, you MUST
51// use a board wired for SDMMC (4-bit DMA) for non-blocking background writes.
52#define LOG_FILTER_HANDSHAKES 0x01 // EAPOLs, PMKIDs (Crackable info, SPI Safe)
53#define LOG_FILTER_PROBES 0x02 // Probe Requests & Responses (Scouting, SPI Safe)
54#define LOG_FILTER_BEACONS 0x04 // Beacons (Network Mapping, SDMMC ONLY!)
55#define LOG_FILTER_PROBE_REQ 0x08 // Probe Requests as raw EPBs (Client Device History, SPI Safe)
56#define LOG_FILTER_MGMT_DISRUPT 0x10 // Deauth/Disassoc frames as raw EPBs (Attack Detection, SPI Safe)
57#define LOG_FILTER_ALL 0xFF // Everything (SDMMC ONLY!)
58
59// ─── Logging Callback ─────────────────────────────────────────────────────────
60#ifndef POLITICIAN_NO_STD_FUNCTION
61using LogCb = std::function<void(const char *msg)>;
62#else
63typedef void (*LogCb)(const char *msg);
64#endif
65
66// ─── Callbacks ────────────────────────────────────────────────────────────────
67struct ApRecord;
68struct HandshakeRecord;
71struct DisruptRecord;
72struct WpsRecord;
73#ifndef POLITICIAN_NO_MSCHAPV2
74struct MsChapRecord;
75#endif
76
77typedef void (*ApFoundCb)(const ApRecord &ap);
78typedef int (*TargetScoreCb)(const ApRecord &ap, const char *vendor); // Returns a priority score for autoTarget
79typedef void (*PacketCb)(const uint8_t *payload, uint16_t len, int8_t rssi, uint8_t channel, uint32_t ts_usec);
80typedef void (*EapolCb)(const HandshakeRecord &rec);
81typedef void (*IdentityCb)(const EapIdentityRecord &rec);
82typedef void (*ProbeRequestCb)(const ProbeRequestRecord &rec);
83typedef void (*DisruptCb)(const DisruptRecord &rec);
84typedef void (*WpsCb)(const WpsRecord &rec);
85#ifndef POLITICIAN_NO_MSCHAPV2
86typedef void (*MsChapCb)(const MsChapRecord &rec);
87#endif
88
89// ─── Error Codes ──────────────────────────────────────────────────────────────
90enum Error {
91 OK = 0,
97 /** Returned by begin() when all POLITICIAN_MAX_INSTANCES slots are occupied. */
102
103/**
104 * @brief Configuration for the Politician engine.
105 */
106struct Config {
107 uint16_t hop_dwell_ms = 200; // Time per channel
108 bool smart_hopping = true; // Dynamic channel dwell time based on traffic
109 uint16_t hop_min_dwell_ms = 50; // Minimum dwell if no traffic is seen
110 uint16_t hop_max_dwell_ms = 400; // Maximum dwell if traffic is active
111 uint32_t m1_lock_ms = 800; // How long to stay on channel after seeing M1
112 uint32_t fish_timeout_ms = 2000; // Time for PMKID association
113 uint8_t fish_max_retries = 2; // PMKID retries before giving up or CSA
114 uint32_t csa_wait_ms = 4000; // How long to wait for reconnect after CSA
115 uint8_t csa_beacon_count = 8; // Number of CSA beacons to burst
116 uint8_t deauth_burst_count = 16; // Number of classic Deauth frames to send
117 uint16_t probe_aggr_interval_s = 30; // Seconds to wait between attacking same AP
118 uint32_t session_timeout_ms = 60000; // How long orphaned handshakes live in RAM
119 bool capture_half_handshakes = false; // Save M2-only captures and pivot to active attack
120 bool skip_immune_networks = true; // Ignore Pure WPA3 / PMF Required networks
121 uint8_t csa_deauth_count = 15; // Number of standard deauths to append
122 uint8_t capture_filter = LOG_FILTER_HANDSHAKES | LOG_FILTER_PROBES; // Exclude Beacons by default to save SD storage
123 int8_t min_rssi = -100; // Ignore APs with signal weaker than this (dBm)
124 uint32_t ap_expiry_ms = 300000; // Evict APs not seen for this long (0 = never expire)
125 bool unicast_deauth = true; // Send deauth to known client MAC instead of broadcast
126 uint32_t probe_hidden_interval_ms = 0; // How often to probe hidden APs for SSID (0 = disabled, opt-in)
127 uint8_t deauth_reason = 7; // 802.11 reason code for deauth frames (7=Class 3 from non-assoc)
128 bool deauth_reason_cycling = true; // Cycle through effective reason codes during burst (fuzzing)
129 bool capture_group_keys = false; // Fire eapolCb with CAP_EAPOL_GROUP on GTK rotation frames
130 uint8_t min_beacon_count = 0; // Min times AP must be seen before attack/apFoundCb (0 = no minimum)
131 uint8_t max_total_attempts = 0; // Permanently skip BSSID after this many failed attacks (0 = unlimited)
132 uint8_t sta_filter[6] = {}; // Only record EAPOL sessions from this client MAC (zero = no filter)
133 char ssid_filter[33] = {}; // Only cache APs matching this SSID (empty = no filter)
134 bool ssid_filter_exact = true; // True = exact SSID match, false = substring match
135 uint8_t enc_filter_mask = 0xFF; // Bitmask of enc types to cache: bit0=Open,bit1=WEP,bit2=WPA,bit3=WPA2,bit4=Ent,bit5=OWE
136 bool require_active_clients = false; // Skip attack initiation if no active clients seen on AP
137 const char* soft_ap_ssid = nullptr; // Custom SSID for the engine's soft AP (nullptr = use default hidden AP)
138 uint8_t btm_burst_count = 8; // Number of BTM Request frames per client per trigger
139 uint16_t btm_disassoc_timer = 3; // Disassociation Timer in TBTTs (~100ms each); 0 = immediate
140#ifndef POLITICIAN_NO_KARMA
141 bool karma_enabled = false; // Enable KARMA rogue AP responder
142 bool karma_open_only = true; // Only respond to probes for open/unknown networks (skip known WPA APs)
143 uint8_t karma_max_ssids = 16; // Max unique SSIDs to track for dedup (circular eviction)
144#endif
145};
146
147/**
148 * @brief Validates a Config struct and returns human-readable warning strings
149 * for values that will be silently clamped or that may cause unexpected behavior.
150 *
151 * Call this before engine.begin(cfg) to surface misconfigurations early.
152 *
153 * @param cfg The Config to validate.
154 * @param out Output array; each element is set to a static warning string.
155 * @param maxOut Capacity of @p out.
156 * @return Number of warnings written (0 = configuration looks clean).
157 *
158 * Example:
159 * @code
160 * const char *warnings[8];
161 * int n = politician::validateConfig(cfg, warnings, 8);
162 * for (int i = 0; i < n; i++) Serial.println(warnings[i]);
163 * @endcode
164 */
165inline int validateConfig(const Config &cfg, const char **out, uint8_t maxOut) {
166 int n = 0;
167 auto w = [&](const char *msg) { if (n < maxOut) out[n++] = msg; };
168 if (cfg.smart_hopping && cfg.hop_min_dwell_ms >= cfg.hop_max_dwell_ms)
169 w("hop_min_dwell_ms >= hop_max_dwell_ms — max will be clamped to min+50ms");
170 if (cfg.fish_timeout_ms < 500)
171 w("fish_timeout_ms < 500 — will be clamped to 500ms");
172 if (cfg.csa_wait_ms < 1000)
173 w("csa_wait_ms < 1000 — will be clamped to 1000ms");
174 if (cfg.hop_dwell_ms == 0)
175 w("hop_dwell_ms = 0 — hopper will spin with no delay");
176 if (cfg.deauth_burst_count == 0)
177 w("deauth_burst_count = 0 — deauth attacks send zero frames");
178 if (cfg.csa_beacon_count == 0)
179 w("csa_beacon_count = 0 — CSA attacks send zero beacons");
180 if (cfg.probe_aggr_interval_s == 0)
181 w("probe_aggr_interval_s = 0 — APs attacked every beacon (very aggressive)");
182 if (cfg.min_rssi < -100 || cfg.min_rssi > -20)
183 w("min_rssi out of useful range [-100, -20] dBm");
184 return n;
185}
186
187// ─── AP Record ────────────────────────────────────────────────────────────────
188/** @brief Snapshot of a discovered Access Point from the internal cache. Populated by getAp(), getApByBssid(), and the ApFoundCb callback. */
189struct ApRecord {
190 uint8_t bssid[6];
191 char ssid[33];
192 uint8_t ssid_len;
193 uint8_t channel;
194 int8_t rssi;
195 uint8_t enc; // ENC_OPEN=0 ENC_WEP=1 ENC_WPA=2 ENC_WPA2=3 ENC_ENT=4 ENC_OWE=5
196 bool wps_enabled; // WPS IE detected in beacon/probe-response
197 bool pmf_capable; // MFPC bit set in RSN Capabilities (PMF supported)
198 bool pmf_required; // MFPR bit set in RSN Capabilities (PMF mandatory)
199 uint8_t total_attempts; // Number of failed attack attempts recorded
200 bool captured; // True if BSSID is on the captured or ignore list
201 bool ft_capable; // 802.11r FT AKM advertised (FT-PSK or FT-EAP)
202 uint32_t first_seen_ms; // millis() timestamp when this AP was first observed
203 uint32_t last_seen_ms; // millis() timestamp of the most recent beacon or probe response
204 char country[3]; // ISO 3166-1 alpha-2 country code from IE 7 (e.g. "US"), empty if absent
205 uint16_t beacon_interval; // Advertised beacon interval in TUs (1 TU = 1024 µs), 0 if unknown
206 uint8_t max_rate_mbps; // Highest legacy data rate from Supported Rates IEs (Mbps), 0 if unknown
207 bool is_hidden; // True if AP broadcasts an empty SSID (hidden network)
208 uint16_t sta_count; // Connected client count from BSS Load IE (if present)
209 uint8_t chan_util; // Channel utilization from BSS Load IE (0-255)
210 uint8_t venue_group; // 802.11u Venue Group (e.g., 2=Education, 10=Residential)
211 uint8_t venue_type; // 802.11u Venue Type (e.g., 8=University, 1=Coffee Shop)
212 uint8_t network_type; // 802.11u Access Network Type (1=Free Public, 2=Chargeable, etc.)
213 bool is_vht; // 802.11ac (VHT / Wi-Fi 5) capable
214 bool is_he; // 802.11ax (HE / Wi-Fi 6) capable
215 uint8_t chan_width; // Max channel width: 0=20MHz 1=40MHz 2=80MHz 3=160MHz 4=80+80MHz
216 uint16_t beacon_count; ///< Number of beacons observed from this AP in the current session
217 uint8_t capture_count; ///< Number of successful handshake/PMKID captures for this BSSID
218 uint32_t last_attack_ms; ///< millis() of the most recent attack initiation (0 = never attacked)
219};
220
221// ─── Frame Stats ──────────────────────────────────────────────────────────────
222/** @brief Cumulative frame and capture counters for the engine session. Accessible via getStats(), reset with resetStats(). */
223struct Stats {
224 uint32_t total;
225 uint32_t mgmt;
226 uint32_t ctrl;
227 uint32_t data;
228 uint32_t eapol;
229 uint32_t pmkid_found;
230 uint32_t sae_found;
231 uint32_t beacons;
232 uint32_t captures;
233 uint32_t failed_pmkid; // PMKID retries exhausted without capture
234 uint32_t failed_csa; // CSA/Deauth wait expired without EAPOL
235 volatile uint32_t dropped; // Frames dropped due to ringbuffer overflow
236 uint32_t rb_max; // Max observed ringbuffer usage (bytes)
237 uint16_t channel_frames[200]; // Frames received per channel, indexed by channel number (e.g. ch1=index1, ch36=index36). Index 0 unused.
238};
239
240// ─── Handshake Record ─────────────────────────────────────────────────────────
241// Pairwise cipher suite constants for HandshakeRecord.cipher
242static const uint8_t CIPHER_UNKNOWN = 0;
243static const uint8_t CIPHER_TKIP = 1; ///< TKIP (00-0F-AC:2) — legacy, crackable offline
244static const uint8_t CIPHER_CCMP = 2; ///< CCMP/AES (00-0F-AC:4) — current standard
245
246/** @brief A captured handshake or PMKID record delivered to the EapolCb callback. The @p type field identifies the capture path; fields not relevant to that path are zeroed. */
248 uint8_t type; // CAP_PMKID / CAP_EAPOL / ...
249 uint8_t channel;
250 int8_t rssi;
251 uint8_t bssid[6];
252 uint8_t sta[6];
253 char ssid[33];
254 uint8_t ssid_len;
255 uint8_t enc; // 0=open, 1=WEP, 2=WPA, 3=WPA2/WPA3, 4=Enterprise
256 uint8_t cipher; ///< Pairwise cipher suite: CIPHER_TKIP / CIPHER_CCMP / CIPHER_UNKNOWN
257 // PMKID path
258 uint8_t pmkid[16];
259 // EAPOL path
260 uint8_t anonce[32];
261 uint8_t snonce[32];
262 uint8_t mic[16];
263 union {
264 uint8_t eapol_m2[256];
265 uint8_t sae_data[256];
266 };
267 uint8_t eapol_m3[256];
268 uint8_t eapol_m4[256];
269 union {
270 uint16_t eapol_m2_len;
271 uint16_t sae_len;
272 };
273 uint16_t eapol_m3_len;
274 uint16_t eapol_m4_len;
278 bool has_m3;
279 bool has_m4;
280 bool is_full; // True if this is a complete 4-way sequence or full SAE exchange
281 uint8_t sae_seq; // SAE Auth Sequence (1=Commit, 2=Confirm)
282};
283
284// ─── Disconnection Strategy ───────────────────────────────────────────────────
285enum DisconnectStrategy : uint8_t {
286 STRATEGY_AUTO_FALLBACK = 0, // CSA first, fallback to Deauth halfway through wait window
287 STRATEGY_SIMULTANEOUS = 1, // CSA and Deauth simultaneously (Legacy behavior)
288};
289
290// ─── Attack Result ────────────────────────────────────────────────────────────
291enum AttackResult : uint8_t {
292 RESULT_PMKID_EXHAUSTED = 1, // All PMKID retries failed, no PMKID captured
293 RESULT_CSA_EXPIRED = 2, // CSA/Deauth wait window closed, no EAPOL captured
294};
295
296/** @brief Identifies the AP and failure reason for a failed attack, delivered to the AttackResultCb callback. */
298 uint8_t bssid[6];
299 char ssid[33];
300 uint8_t ssid_len;
302};
303
304typedef void (*AttackResultCb)(const AttackResultRecord &rec);
305
306/**
307 * @brief Snapshot of a client station observed associated with an AP.
308 * Delivered to the ClientFoundCb callback and enriched with vendor lookup,
309 * timing, and MAC-randomization detection.
310 */
312 uint8_t bssid[6]; ///< BSSID of the AP this client is associated with
313 uint8_t sta[6]; ///< Client (station) MAC address
314 int8_t rssi; ///< Signal strength at time of observation (dBm)
315 uint32_t first_seen_ms; ///< millis() when this client was first seen on this BSSID
316 uint32_t last_seen_ms; ///< millis() of the most recent frame from this client
317 bool rand_mac; ///< True if the locally administered bit is set (MAC randomization)
318 char vendor[32]; ///< OUI vendor string; empty if POLITICIAN_NO_DB is defined
319};
320
321typedef void (*ClientFoundCb)(const ClientRecord &rec);
322
323/**
324 * @brief Fired when a second BSSID advertising the same SSID is observed on the same channel.
325 * This indicates a potential evil twin or rogue AP. Both the known AP and the newcomer are included.
326 */
328 uint8_t known_bssid[6]; // BSSID of the first AP already cached with this SSID
329 uint8_t rogue_bssid[6]; // BSSID of the newly observed AP sharing the same SSID
330 char ssid[33]; // The shared SSID
331 uint8_t ssid_len;
332 uint8_t channel; // Channel on which the conflict was detected
333 int8_t rssi; // Signal strength of the rogue AP (dBm)
334};
335
336#ifndef POLITICIAN_NO_STD_FUNCTION
337using RogueApCb = std::function<void(const RogueApRecord &rec)>; // Fired when an evil twin / rogue AP is detected
338#else
339typedef void (*RogueApCb)(const RogueApRecord &rec); // Fired when an evil twin / rogue AP is detected
340#endif
341
342// ─── KARMA Record ─────────────────────────────────────────────────────────────
343#ifndef POLITICIAN_NO_KARMA
344/**
345 * @brief Delivered to the KarmaCb callback when the KARMA responder replies to a
346 * named probe request. Contains the client that probed and the SSID that was echoed.
347 *
348 * The engine injects a probe response and one beacon spoofed as an AP with
349 * that exact SSID and an open authentication mode, enticing the client to
350 * auto-associate.
351 */
353 uint8_t client[6]; // Probing client MAC
354 char ssid[33]; // SSID that was requested and echoed
355 uint8_t ssid_len;
356 uint8_t channel;
357 int8_t rssi; // RSSI of the incoming probe request
358 uint8_t ap_mac[6]; // Spoofed AP MAC used in the probe response
359};
360
361#ifndef POLITICIAN_NO_STD_FUNCTION
362using KarmaCb = std::function<void(const KarmaRecord &rec)>;
363#else
364typedef void (*KarmaCb)(const KarmaRecord &rec);
365#endif
366#endif // POLITICIAN_NO_KARMA
367
368// ─── 802.1X Enterprise Identity Record ─────────────────────────────────────────
369// EAP method constants (RFC 3748 / RFC 5281)
370static const uint8_t EAP_METHOD_IDENTITY = 0x01; ///< EAP Identity (always 0x01 for harvested records)
371static const uint8_t EAP_METHOD_TLS = 0x0D; ///< EAP-TLS (RFC 5216) — mutual cert auth
372static const uint8_t EAP_METHOD_TTLS = 0x15; ///< EAP-TTLS (RFC 5281) — outer tunnel, inner MSCHAPv2
373static const uint8_t EAP_METHOD_PEAP = 0x19; ///< PEAP (draft-josefsson-pppext-eap-tls-eap) — outer tunnel
374static const uint8_t EAP_METHOD_MSCHAPV2 = 0x1A; ///< Bare EAP-MSCHAPv2 (no tunnel — crackable)
375
376/** @brief A harvested 802.1X Enterprise plaintext identity, delivered to the IdentityCb callback. */
378 uint8_t bssid[6]; // Access Point MAC
379 uint8_t client[6]; // Enterprise Client MAC
380 char identity[65]; // The Plaintext Identity / Email Address
381 uint8_t channel;
382 int8_t rssi;
383 uint8_t eap_method; ///< EAP method negotiated by the AP (EAP_METHOD_* constant); 0 if not yet observed
384};
385
386// ─── Probe Request Record ─────────────────────────────────────────────────────
387/** @brief A probe request frame observed on the air, delivered to the ProbeRequestCb callback. */
389 uint8_t client[6]; // Probing device MAC
390 uint8_t channel;
391 int8_t rssi;
392 char ssid[33]; // Requested SSID (empty = wildcard probe)
393 uint8_t ssid_len;
394 bool rand_mac; // True if locally administered bit is set (iOS/Android MAC randomization)
395};
396
397// ─── Disruption Record ────────────────────────────────────────────────────────
398/** @brief A deauthentication or disassociation frame observed on the air, delivered to the DisruptCb callback. */
400 uint8_t src[6]; // Frame source MAC
401 uint8_t dst[6]; // Frame destination MAC
402 uint8_t bssid[6]; // BSSID (addr3)
403 uint16_t reason; // 802.11 reason code
404 uint8_t subtype; // MGMT_SUB_DEAUTH (0xC0) or MGMT_SUB_DISASSOC (0xA0)
405 uint8_t channel;
406 int8_t rssi;
407 bool rand_mac; // True if source MAC has locally administered bit set (randomized)
408};
409
410// ─── WPS Record ───────────────────────────────────────────────────────────────
411/**
412 * @brief WPS M1 device attributes harvested from an EAP-WSC exchange.
413 * Delivered to the WpsCb callback when a WPS Enrollee sends its M1 message.
414 * Only M1 (Enrollee → AP) is unencrypted; subsequent messages cannot be parsed passively.
415 */
416struct WpsRecord {
417 uint8_t bssid[6]; // Access Point MAC
418 uint8_t sta[6]; // WPS Enrollee (client) MAC
419 uint8_t channel;
420 int8_t rssi;
421 char device_name[33]; // Device Name attribute (0x1011)
422 char manufacturer[65]; // Manufacturer attribute (0x1021)
423 char model_name[33]; // Model Name attribute (0x1023)
424 char model_number[33]; // Model Number attribute (0x1024)
425 char serial_number[33]; // Serial Number attribute (0x1042)
426 uint16_t auth_type_flags; // Auth Type Flags (0x1004): bit0=Open,bit1=WPA-PSK,bit2=WPA-Ent,bit5=WPA2-PSK
427 uint16_t config_methods; // Config Methods (0x1008): bit2=NFC,bit3=PushButton,bit6=PIN
428 uint8_t rf_bands; // RF Bands (0x103C): bit0=2.4GHz, bit1=5GHz
429 uint16_t primary_dev_type_cat; // Primary Device Type category (0x1054, bytes 0-1)
430};
431
432// ─── EAP-MSCHAPv2 Record ──────────────────────────────────────────────────────
433#ifndef POLITICIAN_NO_MSCHAPV2
434/**
435 * @brief Bare EAP-MSCHAPv2 challenge/response pair harvested passively.
436 * Only available when the AP serves MSCHAPv2 without a TLS tunnel (no PEAP/TTLS).
437 * The nt_response can be cracked offline with tools like asleap or hashcat (-m 5500).
438 *
439 * Crack with hashcat:
440 * echo "username::::peer_challenge_hex:nt_response_hex:server_challenge_hex" | hashcat -m 5500
441 */
443 uint8_t bssid[6]; // Access Point MAC
444 uint8_t sta[6]; // Client MAC
445 uint8_t channel;
446 int8_t rssi;
447 char username[65]; // Plaintext username from MSCHAPv2 Response
448 uint8_t server_challenge[16]; // Server challenge from MSCHAPv2 Challenge frame
449 uint8_t peer_challenge[16]; // Peer challenge from MSCHAPv2 Response frame
450 uint8_t nt_response[24]; // NT-Hash response (offline crackable)
451};
452#endif
453
454// ─── Device Fingerprint ───────────────────────────────────────────────────────
455
456// match_flags bits (reported in DeviceRecord)
457#define FP_MATCH_OUI 0x01
458#define FP_MATCH_PROBE_SSID 0x02
459#define FP_MATCH_HT_CAP 0x04
460#define FP_MATCH_RATES 0x08
461#define FP_MATCH_IE_FLAGS 0x10
462
463// ie_flags / ie_flags_mask bits (in DeviceFingerprint)
464#define FP_IEF_NO_HT 0x01 // IE 45 (HT Capabilities) absent
465#define FP_IEF_NO_EXT_CAP 0x02 // IE 127 (Extended Capabilities) absent
466#define FP_IEF_HAS_WMM 0x04 // WMM vendor IE (00:50:F2:01) present
467#define FP_IEF_HAS_WPS 0x08 // WPS vendor IE (00:50:F2:04) present
468
469/** @brief One fingerprint entry in the built-in or user-defined database. */
471 const char* vendor;
472 const char* model;
473 uint8_t oui[3];
474 const char* probeSsid;
475 uint8_t confidence;
476 // IE-based signals — zero values mean "don't check this signal"
477 uint8_t ht_cap_info[2]; // expected HT Capabilities Info bytes 0–1
478 uint8_t ht_cap_mask[2]; // bitmask: which bits of ht_cap_info to compare
479 uint8_t rate_sig[4]; // first 4 bytes of Supported Rates IE
480 uint8_t ie_flags; // expected IE presence flags (FP_IEF_*)
481 uint8_t ie_flags_mask; // which ie_flags bits to check
482};
483
484/** @brief A matched device, delivered to the DeviceFoundCb callback. */
486 uint8_t mac[6];
487 char vendor[32];
488 char model[32];
489 uint8_t channel;
490 int8_t rssi;
491 uint8_t confidence;
492 uint8_t match_flags;
493};
494
495} // namespace politician
#define LOG_FILTER_HANDSHAKES
#define LOG_FILTER_PROBES
void(* EapolCb)(const HandshakeRecord &rec)
char vendor[32]
OUI vendor string; empty if POLITICIAN_NO_DB is defined.
static const uint8_t CIPHER_UNKNOWN
uint16_t channel_frames[200]
void(* MsChapCb)(const MsChapRecord &rec)
int8_t rssi
Signal strength at time of observation (dBm)
uint8_t sta[6]
Client (station) MAC address.
const char * soft_ap_ssid
uint32_t probe_hidden_interval_ms
void(* AttackResultCb)(const AttackResultRecord &rec)
int(* TargetScoreCb)(const ApRecord &ap, const char *vendor)
uint32_t first_seen_ms
millis() when this client was first seen on this BSSID
uint8_t eap_method
EAP method negotiated by the AP (EAP_METHOD_* constant); 0 if not yet observed.
static const uint8_t EAP_METHOD_TLS
EAP-TLS (RFC 5216) — mutual cert auth.
uint8_t cipher
Pairwise cipher suite: CIPHER_TKIP / CIPHER_CCMP / CIPHER_UNKNOWN.
static const uint8_t EAP_METHOD_MSCHAPV2
Bare EAP-MSCHAPv2 (no tunnel — crackable)
void(* WpsCb)(const WpsRecord &rec)
void(* ProbeRequestCb)(const ProbeRequestRecord &rec)
int validateConfig(const Config &cfg, const char **out, uint8_t maxOut)
Validates a Config struct and returns human-readable warning strings for values that will be silently...
static const uint8_t EAP_METHOD_PEAP
PEAP (draft-josefsson-pppext-eap-tls-eap) — outer tunnel.
uint32_t last_seen_ms
millis() of the most recent frame from this client
uint16_t beacon_count
Number of beacons observed from this AP in the current session.
static const uint8_t EAP_METHOD_IDENTITY
EAP Identity (always 0x01 for harvested records)
void(* ApFoundCb)(const ApRecord &ap)
static const uint8_t EAP_METHOD_TTLS
EAP-TTLS (RFC 5281) — outer tunnel, inner MSCHAPv2.
bool rand_mac
True if the locally administered bit is set (MAC randomization)
static const uint8_t CIPHER_TKIP
TKIP (00-0F-AC:2) — legacy, crackable offline.
static const uint8_t CIPHER_CCMP
CCMP/AES (00-0F-AC:4) — current standard.
void(* IdentityCb)(const EapIdentityRecord &rec)
uint32_t last_attack_ms
millis() of the most recent attack initiation (0 = never attacked)
uint8_t bssid[6]
BSSID of the AP this client is associated with.
std::function< void(const KarmaRecord &rec)> KarmaCb
std::function< void(const char *msg)> LogCb
void(* PacketCb)(const uint8_t *payload, uint16_t len, int8_t rssi, uint8_t channel, uint32_t ts_usec)
volatile uint32_t dropped
void(* ClientFoundCb)(const ClientRecord &rec)
std::function< void(const RogueApRecord &rec)> RogueApCb
@ ERR_MAX_INSTANCES
Returned by begin() when all POLITICIAN_MAX_INSTANCES slots are occupied.
void(* DisruptCb)(const DisruptRecord &rec)
uint8_t capture_count
Number of successful handshake/PMKID captures for this BSSID.
Snapshot of a discovered Access Point from the internal cache.
Identifies the AP and failure reason for a failed attack, delivered to the AttackResultCb callback.
Snapshot of a client station observed associated with an AP.
Configuration for the Politician engine.
One fingerprint entry in the built-in or user-defined database.
A matched device, delivered to the DeviceFoundCb callback.
A deauthentication or disassociation frame observed on the air, delivered to the DisruptCb callback.
A harvested 802.1X Enterprise plaintext identity, delivered to the IdentityCb callback.
A captured handshake or PMKID record delivered to the EapolCb callback.
Delivered to the KarmaCb callback when the KARMA responder replies to a named probe request.
Bare EAP-MSCHAPv2 challenge/response pair harvested passively.
A probe request frame observed on the air, delivered to the ProbeRequestCb callback.
Fired when a second BSSID advertising the same SSID is observed on the same channel.
Cumulative frame and capture counters for the engine session.
WPS M1 device attributes harvested from an EAP-WSC exchange.