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
37#ifndef POLITICIAN_MAX_INSTANCES
38#define POLITICIAN_MAX_INSTANCES 2
58#define FC_TYPE_MASK 0x000C
59#define FC_SUBTYPE_MASK 0x00F0
60#define FC_TODS_MASK 0x0100
61#define FC_FROMDS_MASK 0x0200
62#define FC_TYPE_MGMT 0x0000
63#define FC_TYPE_CTRL 0x0004
64#define FC_TYPE_DATA 0x0008
65#define FC_ORDER_MASK 0x8000
67#define MGMT_SUB_ASSOC_REQ 0x00
68#define MGMT_SUB_ASSOC_RESP 0x10
69#define MGMT_SUB_PROBE_REQ 0x40
70#define MGMT_SUB_PROBE_RESP 0x50
71#define MGMT_SUB_BEACON 0x80
72#define MGMT_SUB_AUTH 0xB0
73#define MGMT_SUB_DISASSOC 0xA0
74#define MGMT_SUB_DEAUTH 0xC0
77#define EAPOL_LLC_OFFSET 0
78#define EAPOL_ETHERTYPE_HI 0x88
79#define EAPOL_ETHERTYPE_LO 0x8E
80#define EAPOL_LLC_SIZE 8
81#define EAPOL_MIN_FRAME_LEN (EAPOL_LLC_SIZE + 4)
83#define EAPOL_KEY_DESC_TYPE 0
84#define EAPOL_KEY_INFO 1
85#define EAPOL_REPLAY_COUNTER 5
86#define EAPOL_KEY_NONCE 13
87#define EAPOL_KEY_MIC 77
88#define EAPOL_KEY_DATA_LEN 93
89#define EAPOL_KEY_DATA 95
91#define KEYINFO_TYPE_MASK 0x0007
92#define KEYINFO_PAIRWISE 0x0008
93#define KEYINFO_ACK 0x0080
94#define KEYINFO_MIC 0x0100
95#define KEYINFO_SECURE 0x0200
96#define KEYINFO_INSTALL 0x0040
132 void setIgnoreList(
const uint8_t (*bssids)[6], uint8_t count);
325 void forEachAp(
void (*cb)(
const ApRecord &ap,
void *ctx),
void *ctx =
nullptr)
const;
327#ifndef POLITICIAN_NO_STD_FUNCTION
349 bool getClient(
const uint8_t *bssid,
int idx, uint8_t out_sta[6])
const;
351 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);
354#ifndef POLITICIAN_NO_STD_FUNCTION
359 using PacketCb = std::function<void(
const uint8_t *payload, uint16_t len, int8_t rssi, uint8_t channel, uint32_t ts_usec)>;
366#ifndef POLITICIAN_NO_MSCHAPV2
374 using PacketCb = void (*)(
const uint8_t *payload, uint16_t len, int8_t rssi, uint8_t channel, uint32_t ts_usec);
381#ifndef POLITICIAN_NO_MSCHAPV2
391 static const char*
getVendor(
const uint8_t *mac);
407 Error injectCustomFrame(
const uint8_t *payload,
size_t len, uint8_t channel, uint32_t lock_ms = 0,
bool wait_for_channel =
false);
466#ifndef POLITICIAN_NO_MSCHAPV2
482#ifndef POLITICIAN_NO_KARMA
518 _probeWordlist = wordlist;
519 _probeWordlistLen = count;
523 static void IRAM_ATTR _promiscuousCb(
void *buf, wifi_promiscuous_pkt_type_t type);
524 static void _workerTask(
void *pvParameters);
528 static bool _wifiInitialized;
530 RingbufHandle_t _rb =
nullptr;
531 TaskHandle_t _task =
nullptr;
532 SemaphoreHandle_t _lock =
nullptr;
534 void _handleFrame(
const wifi_promiscuous_pkt_t *pkt, wifi_promiscuous_pkt_type_t type);
535 void _handleMgmt(
const ieee80211_hdr_t *hdr,
const uint8_t *payload, uint16_t len, int8_t rssi);
536 void _handleData(
const ieee80211_hdr_t *hdr,
const uint8_t *payload, uint16_t len, int8_t rssi);
537 bool _parseEapol(
const uint8_t *bssid,
const uint8_t *sta,
538 const uint8_t *eapol, uint16_t len, int8_t rssi);
539 void _parseEapIdentity(
const uint8_t *bssid,
const uint8_t *sta,
540 const uint8_t *eapol, uint16_t len, int8_t rssi);
541 void _parseWpsFrame(
const uint8_t *bssid,
const uint8_t *sta,
542 const uint8_t *eapol, uint16_t len, int8_t rssi);
543#ifndef POLITICIAN_NO_MSCHAPV2
544 void _parseEapMsChap(
const uint8_t *bssid,
const uint8_t *sta,
545 const uint8_t *eapol, uint16_t len, int8_t rssi);
547 void _parseSsid(
const uint8_t *ie, uint16_t ie_len,
char *out, uint8_t &out_len);
548 uint8_t _classifyEnc(
const uint8_t *ie, uint16_t ie_len);
549 uint8_t _classifyPairwiseCipher(
const uint8_t *ie, uint16_t ie_len);
550 bool _detectWpa3Only(
const uint8_t *ie, uint16_t ie_len);
551 void _detectPmfFlags(
const uint8_t *ie, uint16_t ie_len,
bool &pmf_capable,
bool &pmf_required);
552 bool _detectFt(
const uint8_t *ie, uint16_t ie_len);
553#ifndef POLITICIAN_NO_KARMA
554 void _sendKarmaResponse(
const uint8_t *client,
const char *ssid, uint8_t ssid_len, uint8_t channel, int8_t rssi);
557 bool _initialized =
false;
558 volatile bool _active;
562 volatile bool _channelTrafficSeen;
564 uint32_t _lastDiagMs;
569 uint32_t _csaFallbackMs;
571 static const int MAX_INJECT_QUEUE = 4;
574 uint8_t payload[256];
579 InjectFrame _injectQueue[MAX_INJECT_QUEUE];
581 static const int MAX_ATTACK_OVERRIDES = 8;
582 struct AttackOverride {
bool active; uint8_t bssid[6]; uint8_t mask; };
583 AttackOverride _attackOverrides[MAX_ATTACK_OVERRIDES];
584 struct SsidOverride {
bool active;
char ssid[33]; uint8_t ssid_len; uint8_t mask;
bool substring; };
585 static const int MAX_SSID_OVERRIDES = 8;
586 SsidOverride _ssidOverrides[MAX_SSID_OVERRIDES];
587 uint8_t _ssidOverrideIdx = 0;
588 struct EapMethodSeen { uint8_t bssid[6]; uint8_t method; };
589 static const uint8_t MAX_EAP_METHODS = 8;
590 EapMethodSeen _eapMethods[MAX_EAP_METHODS];
591 uint8_t _eapMethodIdx = 0;
592 uint8_t _getAttackMask(
const uint8_t *bssid)
const;
595 uint8_t _targetBssid[6];
596 uint8_t _targetChannel;
599 uint32_t _m1LockEndMs;
602 uint32_t _probeLockEndMs;
605 uint8_t _customChannelCount;
609 bool _autoTarget =
false;
610 bool _autoTargetActive =
false;
612 uint8_t _lastCapBssid[6] = {};
613 uint8_t _lastCapSta[6] = {};
614 uint32_t _lastCapMs = 0;
617 LogCb _logCb =
nullptr;
629 WpsCb _wpsCb =
nullptr;
630#ifndef POLITICIAN_NO_KARMA
632 bool _karmaEnabled =
false;
634 static const int MAX_KARMA_SEEN = 16;
635 struct KarmaSeen { uint8_t client[6];
char ssid[33]; uint32_t last_ms; };
636 KarmaSeen _karmaSeen[MAX_KARMA_SEEN];
637 uint8_t _karmaSeenIdx = 0;
639#ifndef POLITICIAN_NO_MSCHAPV2
642 static const int MAX_MSCHAP_SESSIONS = 4;
643 struct MsChapSession {
647 uint8_t challenge[16];
649 MsChapSession _msChapSessions[MAX_MSCHAP_SESSIONS];
652 const char *
const * _probeWordlist =
nullptr;
653 uint8_t _probeWordlistLen = 0;
655 void _log(
const char *fmt, ...);
657 static const int MAX_IGNORE = 128;
658 uint8_t _ignoreList[MAX_IGNORE][6];
659 uint8_t _ignoreCount;
662 struct ApCacheEntry {
669 uint32_t first_seen_ms;
670 uint32_t last_seen_ms;
671 uint32_t last_probe_ms;
672 uint32_t last_stimulate_ms;
673 uint32_t last_hidden_probe_ms;
674 uint8_t known_stas[4][6];
675 uint8_t known_sta_count;
676 uint16_t beacon_count;
677 uint8_t total_attempts;
679 uint16_t beacon_interval;
680 uint8_t max_rate_mbps;
685 uint8_t network_type;
688 uint16_t has_active_clients : 1;
689 uint16_t is_wpa3_only : 1;
690 uint16_t is_hidden : 1;
691 uint16_t wps_enabled : 1;
692 uint16_t pmf_capable : 1;
693 uint16_t pmf_required : 1;
694 uint16_t ft_capable : 1;
699 uint8_t probe_word_idx;
700 uint32_t last_attack_ms;
701 uint8_t capture_count;
702 uint8_t pairwise_cipher;
704 ApCacheEntry _apCache[MAX_AP_CACHE];
706 ApCacheEntry* _cacheAp(
const uint8_t *bssid,
const char *ssid, uint8_t ssid_len,
707 uint8_t enc, uint8_t channel, int8_t rssi,
708 bool is_wpa3_only =
false,
bool wps =
false,
709 bool pmf_capable =
false,
bool pmf_required =
false,
710 bool ft_capable =
false, uint16_t sta_count = 0, uint8_t chan_util = 0,
711 uint8_t venue_group = 0, uint8_t venue_type = 0, uint8_t network_type = 0);
712 bool _lookupSsid(
const uint8_t *bssid,
char *out_ssid, uint8_t &out_len)
const;
713 bool _lookupEnc(
const uint8_t *bssid, uint8_t &out_enc)
const;
714 bool _lookupCipher(
const uint8_t *bssid, uint8_t &out_cipher)
const;
716 enum FishState : uint8_t { FISH_IDLE = 0, FISH_CONNECTING = 1, FISH_CSA_WAIT = 2 };
717 FishState _fishState;
718 uint32_t _fishStartMs;
719 uint8_t _fishBssid[6];
722 uint8_t _fishSsidLen;
723 uint8_t _fishChannel;
725 uint8_t _ownStaMac[6];
726 bool _fishAuthLogged;
727 bool _fishAssocLogged;
728 bool _csaSecondBurstSent;
730 void _startFishing(
const uint8_t *bssid,
const char *ssid,
731 uint8_t ssid_len, uint8_t channel);
732 void _processFishing();
733 void _randomizeMac();
734 void _sendCsaBurst();
735 void _sendDeauthBurst(uint8_t count,
const uint8_t *sta =
nullptr);
736 void _sendBtmRequest(
const uint8_t *bssid,
const uint8_t *sta);
737 void _sendProbeRequest(
const uint8_t *bssid,
const char *ssid =
nullptr, uint8_t ssid_len = 0);
738 void _recordClientForAp(
const uint8_t *bssid,
const uint8_t *sta, int8_t rssi = 0);
739 void _markCapturedSsidGroup(
const char *ssid, uint8_t ssid_len);
740 void _markCaptured(
const uint8_t *bssid);
741 void _incCaptureCount(
const uint8_t *bssid);
753 uint8_t m1_replay_counter[8];
758 uint8_t eapol_buffer[400];
759 uint16_t m2_off, m2_len;
760 uint16_t m3_off, m3_len;
761 uint16_t m4_off, m4_len;
771 Session _sessions[MAX_SESSIONS];
773 Session* _findSession(
const uint8_t *bssid,
const uint8_t *sta);
774 Session* _createSession(
const uint8_t *bssid,
const uint8_t *sta);
775 void _expireSessions(uint32_t timeoutMs);
778 uint8_t _captured[MAX_CAPTURED][6];
781 bool _isCaptured(
const uint8_t *bssid)
const;
783 static const uint8_t HOP_SEQ[];
784 static const uint8_t HOP_COUNT;
#define POLITICIAN_MAX_CHANNELS
#define POLITICIAN_MAX_AP_CACHE
#define POLITICIAN_MAX_INSTANCES
Maximum number of concurrent Politician instances that can be active at once.
#define POLITICIAN_MAX_SESSIONS
#define POLITICIAN_MAX_CAPTURED
The core WiFi handshake capturing engine.
void stop()
Full engine teardown.
std::function< void(const ClientRecord &rec)> ClientFoundCb
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 setAttackMaskForSsid(const char *ssid, uint8_t mask, bool substring=false)
Sets an attack mask for all APs whose SSID matches the given string.
void setDisruptCallback(DisruptCb cb)
Sets the callback fired on deauthentication and disassociation frames.
std::function< void(const MsChapRecord &rec)> MsChapCb
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.
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.
void setMsChapCallback(MsChapCb cb)
Sets the callback fired on a bare EAP-MSCHAPv2 challenge/response exchange.
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.
std::function< void(const ProbeRequestRecord &rec)> ProbeRequestCb
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 setWpsCallback(WpsCb cb)
Sets the callback fired when a WPS Enrollee's M1 message is captured.
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 setKarmaCallback(KarmaCb cb)
Sets the callback fired each time the KARMA responder echoes a probe.
void setRogueApCallback(RogueApCb cb)
Sets the callback fired when a potential evil twin or rogue AP is detected.
void forEachAp(void(*cb)(const ApRecord &ap, void *ctx), void *ctx=nullptr) const
Iterates all active APs in the cache, calling cb for each one.
void setApFoundCallback(ApFoundCb cb)
Sets the callback for when a new Access Point is discovered.
std::function< void(const HandshakeRecord &rec)> EapolCb
uint8_t getChannel() const
std::function< void(const ApRecord &ap)> ApFoundCb
void setDisconnectionStrategy(DisconnectStrategy strategy)
Configures how the engine handles disconnection when both CSA and Deauth are enabled.
void _setFingerprintHook(_FpHookCb cb)
std::function< void(const DisruptRecord &rec)> DisruptCb
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.
void setAttackMaskForBssid(const uint8_t *bssid, uint8_t mask)
Overrides the attack mask for a specific BSSID.
std::function< void(const EapIdentityRecord &rec)> IdentityCb
void setTargetFilter(TargetFilterCb cb)
Sets an early filter callback.
std::function< int(const ApRecord &ap, const char *vendor)> TargetScoreCb
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.
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.
std::function< void(const WpsRecord &rec)> WpsCb
void enableKarma(bool en)
Enable or disable the KARMA rogue AP responder at runtime.
uint8_t setAutoChannelList(uint8_t topN=13)
Feeds the top-N most active channels (from getChannelsSortedByActivity) into setChannelList(),...
uint8_t getChannelsSortedByActivity(uint8_t *out, uint8_t count) const
Returns the N most active channels sorted by descending frame count.
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.
std::function< void(const AttackResultRecord &rec)> AttackResultCb
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.
void setProbeWordlist(const char *const *wordlist, uint8_t count)
Sets an SSID wordlist for directed probes against hidden access points.
std::function< void(const uint8_t *payload, uint16_t len, int8_t rssi, uint8_t channel, uint32_t ts_usec)> PacketCb
std::function< bool(const ApRecord &ap)> TargetFilterCb
std::function< void(const KarmaRecord &rec)> KarmaCb
std::function< void(const char *msg)> LogCb
std::function< void(const RogueApRecord &rec)> RogueApCb
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.
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.
Bare EAP-MSCHAPv2 challenge/response pair harvested passively.
A probe request frame observed on the air, delivered to the ProbeRequestCb callback.
Cumulative frame and capture counters for the engine session.
WPS M1 device attributes harvested from an EAP-WSC exchange.