4#include <esp_wifi_types.h>
5#include <freertos/FreeRTOS.h>
6#include <freertos/task.h>
7#include <freertos/ringbuf.h>
8#include <freertos/semphr.h>
13#ifndef POLITICIAN_MAX_AP_CACHE
14#define POLITICIAN_MAX_AP_CACHE 48
17#ifndef POLITICIAN_MAX_SESSIONS
18#define POLITICIAN_MAX_SESSIONS 8
21#ifndef POLITICIAN_MAX_CAPTURED
22#define POLITICIAN_MAX_CAPTURED 128
25#ifndef POLITICIAN_MAX_CHANNELS
26#define POLITICIAN_MAX_CHANNELS 50
46#define FC_TYPE_MASK 0x000C
47#define FC_SUBTYPE_MASK 0x00F0
48#define FC_TODS_MASK 0x0100
49#define FC_FROMDS_MASK 0x0200
50#define FC_TYPE_MGMT 0x0000
51#define FC_TYPE_CTRL 0x0004
52#define FC_TYPE_DATA 0x0008
53#define FC_ORDER_MASK 0x8000
55#define MGMT_SUB_ASSOC_REQ 0x00
56#define MGMT_SUB_ASSOC_RESP 0x10
57#define MGMT_SUB_PROBE_REQ 0x40
58#define MGMT_SUB_PROBE_RESP 0x50
59#define MGMT_SUB_BEACON 0x80
60#define MGMT_SUB_AUTH 0xB0
61#define MGMT_SUB_DISASSOC 0xA0
62#define MGMT_SUB_DEAUTH 0xC0
65#define EAPOL_LLC_OFFSET 0
66#define EAPOL_ETHERTYPE_HI 0x88
67#define EAPOL_ETHERTYPE_LO 0x8E
68#define EAPOL_LLC_SIZE 8
69#define EAPOL_MIN_FRAME_LEN (EAPOL_LLC_SIZE + 4)
71#define EAPOL_KEY_DESC_TYPE 0
72#define EAPOL_KEY_INFO 1
73#define EAPOL_REPLAY_COUNTER 5
74#define EAPOL_KEY_NONCE 13
75#define EAPOL_KEY_MIC 77
76#define EAPOL_KEY_DATA_LEN 93
77#define EAPOL_KEY_DATA 95
79#define KEYINFO_TYPE_MASK 0x0007
80#define KEYINFO_PAIRWISE 0x0008
81#define KEYINFO_ACK 0x0080
82#define KEYINFO_MIC 0x0100
83#define KEYINFO_SECURE 0x0200
84#define KEYINFO_INSTALL 0x0040
120 void setIgnoreList(
const uint8_t (*bssids)[6], uint8_t count);
284 bool getClient(
const uint8_t *bssid,
int idx, uint8_t out_sta[6])
const;
286 using _FpHookCb = void (*)(
const uint8_t *mac,
const char *ssid, uint8_t ssid_len, uint8_t ch, int8_t rssi,
const uint8_t *ie, uint16_t ie_len);
293 using PacketCb = void (*)(
const uint8_t *payload, uint16_t len, int8_t rssi, uint8_t channel, uint32_t ts_usec);
298 using ClientFoundCb = void (*)(
const uint8_t *bssid,
const uint8_t *sta, int8_t rssi);
305 static const char*
getVendor(
const uint8_t *mac);
321 Error injectCustomFrame(
const uint8_t *payload,
size_t len, uint8_t channel, uint32_t lock_ms = 0,
bool wait_for_channel =
false);
379 static void IRAM_ATTR _promiscuousCb(
void *buf, wifi_promiscuous_pkt_type_t type);
380 static void _workerTask(
void *pvParameters);
383 RingbufHandle_t _rb =
nullptr;
384 TaskHandle_t _task =
nullptr;
385 SemaphoreHandle_t _lock =
nullptr;
387 void _handleFrame(
const wifi_promiscuous_pkt_t *pkt, wifi_promiscuous_pkt_type_t type);
388 void _handleMgmt(
const ieee80211_hdr_t *hdr,
const uint8_t *payload, uint16_t len, int8_t rssi);
389 void _handleData(
const ieee80211_hdr_t *hdr,
const uint8_t *payload, uint16_t len, int8_t rssi);
390 bool _parseEapol(
const uint8_t *bssid,
const uint8_t *sta,
391 const uint8_t *eapol, uint16_t len, int8_t rssi);
392 void _parseEapIdentity(
const uint8_t *bssid,
const uint8_t *sta,
393 const uint8_t *eapol, uint16_t len, int8_t rssi);
394 void _parseSsid(
const uint8_t *ie, uint16_t ie_len,
char *out, uint8_t &out_len);
395 uint8_t _classifyEnc(
const uint8_t *ie, uint16_t ie_len);
396 bool _detectWpa3Only(
const uint8_t *ie, uint16_t ie_len);
397 void _detectPmfFlags(
const uint8_t *ie, uint16_t ie_len,
bool &pmf_capable,
bool &pmf_required);
398 bool _detectFt(
const uint8_t *ie, uint16_t ie_len);
400 bool _initialized =
false;
401 volatile bool _active;
405 volatile bool _channelTrafficSeen;
411 uint32_t _csaFallbackMs;
413 static const int MAX_INJECT_QUEUE = 4;
416 uint8_t payload[256];
421 InjectFrame _injectQueue[MAX_INJECT_QUEUE];
423 static const int MAX_ATTACK_OVERRIDES = 8;
424 struct AttackOverride {
bool active; uint8_t bssid[6]; uint8_t mask; };
425 AttackOverride _attackOverrides[MAX_ATTACK_OVERRIDES];
426 uint8_t _getAttackMask(
const uint8_t *bssid)
const;
429 uint8_t _targetBssid[6];
430 uint8_t _targetChannel;
433 uint32_t _m1LockEndMs;
436 uint32_t _probeLockEndMs;
439 uint8_t _customChannelCount;
443 bool _autoTarget =
false;
444 bool _autoTargetActive =
false;
446 uint8_t _lastCapBssid[6] = {};
447 uint8_t _lastCapSta[6] = {};
448 uint32_t _lastCapMs = 0;
451 LogCb _logCb =
nullptr;
464 void _log(
const char *fmt, ...);
466 static const int MAX_IGNORE = 128;
467 uint8_t _ignoreList[MAX_IGNORE][6];
468 uint8_t _ignoreCount;
471 struct ApCacheEntry {
478 uint32_t first_seen_ms;
479 uint32_t last_seen_ms;
480 uint32_t last_probe_ms;
481 uint32_t last_stimulate_ms;
482 uint32_t last_hidden_probe_ms;
483 uint8_t known_stas[4][6];
484 uint8_t known_sta_count;
485 uint16_t beacon_count;
486 uint8_t total_attempts;
488 uint16_t beacon_interval;
489 uint8_t max_rate_mbps;
494 uint8_t network_type;
497 uint8_t has_active_clients : 1;
498 uint8_t is_wpa3_only : 1;
499 uint8_t is_hidden : 1;
500 uint8_t wps_enabled : 1;
501 uint8_t pmf_capable : 1;
502 uint8_t pmf_required : 1;
503 uint8_t ft_capable : 1;
506 ApCacheEntry _apCache[MAX_AP_CACHE];
508 ApCacheEntry* _cacheAp(
const uint8_t *bssid,
const char *ssid, uint8_t ssid_len,
509 uint8_t enc, uint8_t channel, int8_t rssi,
510 bool is_wpa3_only =
false,
bool wps =
false,
511 bool pmf_capable =
false,
bool pmf_required =
false,
512 bool ft_capable =
false, uint16_t sta_count = 0, uint8_t chan_util = 0,
513 uint8_t venue_group = 0, uint8_t venue_type = 0, uint8_t network_type = 0);
514 bool _lookupSsid(
const uint8_t *bssid,
char *out_ssid, uint8_t &out_len);
515 bool _lookupEnc(
const uint8_t *bssid, uint8_t &out_enc);
517 enum FishState : uint8_t { FISH_IDLE = 0, FISH_CONNECTING = 1, FISH_CSA_WAIT = 2 };
518 FishState _fishState;
519 uint32_t _fishStartMs;
520 uint8_t _fishBssid[6];
523 uint8_t _fishSsidLen;
524 uint8_t _fishChannel;
526 uint8_t _ownStaMac[6];
527 bool _fishAuthLogged;
528 bool _fishAssocLogged;
529 bool _csaSecondBurstSent;
531 void _startFishing(
const uint8_t *bssid,
const char *ssid,
532 uint8_t ssid_len, uint8_t channel);
533 void _processFishing();
534 void _randomizeMac();
535 void _sendCsaBurst();
536 void _sendDeauthBurst(uint8_t count,
const uint8_t *sta =
nullptr);
537 void _sendProbeRequest(
const uint8_t *bssid);
538 void _recordClientForAp(
const uint8_t *bssid,
const uint8_t *sta, int8_t rssi = 0);
539 void _markCapturedSsidGroup(
const char *ssid, uint8_t ssid_len);
540 void _markCaptured(
const uint8_t *bssid);
552 uint8_t m1_replay_counter[8];
557 uint8_t eapol_buffer[400];
558 uint16_t m2_off, m2_len;
559 uint16_t m3_off, m3_len;
560 uint16_t m4_off, m4_len;
570 Session _sessions[MAX_SESSIONS];
572 Session* _findSession(
const uint8_t *bssid,
const uint8_t *sta);
573 Session* _createSession(
const uint8_t *bssid,
const uint8_t *sta);
574 void _expireSessions(uint32_t timeoutMs);
577 uint8_t _captured[MAX_CAPTURED][6];
580 bool _isCaptured(
const uint8_t *bssid)
const;
582 static const uint8_t HOP_SEQ[];
583 static const uint8_t HOP_COUNT;
#define POLITICIAN_MAX_CHANNELS
#define POLITICIAN_MAX_AP_CACHE
#define POLITICIAN_MAX_SESSIONS
#define POLITICIAN_MAX_CAPTURED
The core WiFi handshake capturing engine.
void stop()
Full engine teardown.
Error lockChannel(uint8_t ch)
Stops hopping and locks the radio to a specific channel.
void clearCapturedList()
Clears the captured BSSID list.
void markCaptured(const uint8_t *bssid)
Manually adds a BSSID to the "already captured" list to skip it.
static const char * getVendor(const uint8_t *mac)
Looks up the vendor name for a given MAC address (OUI).
void setDisruptCallback(DisruptCb cb)
Sets the callback fired on deauthentication and disassociation frames.
Error injectCustomFrame(const uint8_t *payload, size_t len, uint8_t channel, uint32_t lock_ms=0, bool wait_for_channel=false)
Injects a custom 802.11 frame.
void(*)(const uint8_t *bssid, const uint8_t *sta, int8_t rssi) ClientFoundCb
bool getClient(const uint8_t *bssid, int idx, uint8_t out_sta[6]) const
Reads a client MAC from the per-AP client table.
void clearAttackMaskOverrides()
Clears all per-BSSID attack mask overrides.
void setAutoTarget(bool enable)
Continuously locks onto the strongest uncaptured AP in the cache.
int getClientCount(const uint8_t *bssid) const
Returns the number of unique clients seen associated to a given AP.
void resetStats()
Resets all frame and capture statistics to zero.
void tick()
Main worker method.
int8_t getLastRssi() const
void setProbeRequestCallback(ProbeRequestCb cb)
Sets the callback fired on every probe request frame.
void setPacketLogger(PacketCb cb)
Sets the callback for raw promiscuous mode packets.
Error setTargetBySsid(const char *ssid)
Searches the AP cache by SSID and locks onto the strongest match.
void setLogger(LogCb cb)
Sets a custom logging callback to intercept library output.
void(*)(const uint8_t *mac, const char *ssid, uint8_t ssid_len, uint8_t ch, int8_t rssi, const uint8_t *ie, uint16_t ie_len) _FpHookCb
void(*)(const HandshakeRecord &rec) EapolCb
void(*)(const ApRecord &ap) ApFoundCb
void setActive(bool active)
Enables or disables frame processing.
void setChannelBands(bool ghz24, bool ghz5)
Restricts hopping to 2.4GHz, 5GHz, or both bands.
void setRogueApCallback(RogueApCb cb)
Sets the callback fired when a potential evil twin or rogue AP is detected.
void setApFoundCallback(ApFoundCb cb)
Sets the callback for when a new Access Point is discovered.
void(*)(const AttackResultRecord &rec) AttackResultCb
void(*)(const ProbeRequestRecord &rec) ProbeRequestCb
uint8_t getChannel() const
void setDisconnectionStrategy(DisconnectStrategy strategy)
Configures how the engine handles disconnection when both CSA and Deauth are enabled.
void _setFingerprintHook(_FpHookCb cb)
void(*)(const EapIdentityRecord &rec) IdentityCb
void stopHopping()
Stops autonomous channel hopping and goes idle.
void setClientFoundCallback(ClientFoundCb cb)
Sets the callback fired when a new client (STA) is first seen associated to an AP.
bool(*)(const ApRecord &ap) TargetFilterCb
void setAttackMaskForBssid(const uint8_t *bssid, uint8_t mask)
Overrides the attack mask for a specific BSSID.
void(*)(const uint8_t *payload, uint16_t len, int8_t rssi, uint8_t channel, uint32_t ts_usec) PacketCb
void setTargetFilter(TargetFilterCb cb)
Sets an early filter callback.
void setTargetScoreCallback(TargetScoreCb cb)
Sets the callback for calculating a custom priority score during autoTarget.
void setIgnoreList(const uint8_t(*bssids)[6], uint8_t count)
Sets a list of BSSIDs that should always be ignored by the engine.
void setEapolCallback(EapolCb cb)
Sets the callback for when a handshake (EAPOL or PMKID) is captured.
Error setTarget(const uint8_t *bssid, uint8_t channel)
Focuses the engine on a single BSSID.
void setIdentityCallback(IdentityCb cb)
Sets the callback for passive 802.1X Enterprise Identity harvesting.
Error setChannel(uint8_t ch)
Manually sets the WiFi radio to a specific channel.
void(*)(const DisruptRecord &rec) DisruptCb
bool getApByBssid(const uint8_t *bssid, ApRecord &out) const
Looks up an AP in the discovery cache by BSSID.
void clearTarget()
Clears the specific target and resumes autonomous wardriving.
bool getAp(int idx, ApRecord &out) const
Reads an AP from the discovery cache by index.
Error begin(const Config &cfg=Config())
Initializes the WiFi driver in promiscuous mode.
void startHopping(uint16_t dwellMs=0)
Starts autonomous channel hopping.
void setAttackResultCallback(AttackResultCb cb)
Sets the callback fired when an attack attempt exhausts all options without capturing.
void setAttackMask(uint8_t mask)
Configures which attack techniques are enabled globally.
void setChannelList(const uint8_t *channels, uint8_t count)
Restricts hopping to a specific list of channels.
int(*)(const ApRecord &ap, const char *vendor) TargetScoreCb
void(* LogCb)(const char *msg)
void(* RogueApCb)(const RogueApRecord &rec)
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.
Configuration for the Politician engine.
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.
A probe request frame observed on the air, delivered to the ProbeRequestCb callback.
Cumulative frame and capture counters for the engine session.