
ESP32용 최신 WiFi 감사 라이브러리로, 고급 802.11 기술을 사용합니다. PMKID 추출 및 CSA 인젝션(PMF 우회)을 통해 WPA/WPA2/WPA3 핸드셰이크를 캡처합니다. 엔터프라이즈 자격 증명을 수집하고, 듀얼 밴드(ESP32-C6에서 2.4GHz/5GHz)를 지원하며, PCAPNG/Hashcat으로 내보냅니다. 9개의 예제가 포함된 깔끔한 C++ API를 제공합니다.
ESP32 마이크로컨트롤러를 위한 정교한 WiFi 감사 라이브러리
Politician은 ESP32 플랫폼에서 WiFi 보안 감사를 위해 설계된 임베디드 C++ 라이브러리입니다. 고급 802.11 프로토콜 기술을 활용하여 WPA/WPA2/WPA3 핸드셰이크 캡처와 엔터프라이즈 자격 증명 수집을 위한 깔끔하고 현대적인 API를 제공합니다.
라이브러리는 채널 호핑, 대상 선택, 공격 실행 및 캡처 처리를 관리하는 비차단 상태 머신을 기반으로 구축되었습니다. 모든 작업은 politician 네임스페이스 내에 포함됩니다.
| 구성 요소 | 설명 |
|---|---|
Politician | 감사 수명 주기를 관리하는 주 엔진 클래스 |
PoliticianFormat | PCAPNG 캡처 직렬화; 보조 HC22000 텍스트 내보내기 |
PoliticianStorage | 선택적 SD 카드 로깅 및 NVS 영속성 |
PoliticianStress | 분리된 DoS/혼란 페이로드 전달 (옵트인) |
PoliticianTypes | 핵심 데이터 구조 및 열거형 |
기존 비인증 공격은 최신 WPA3 및 보호 관리 프레임(PMF/802.11w)이 있는 WPA2 네트워크에 대해 비효율적입니다. Politician은 현대적인 대안을 구현합니다:
| 모드 | 설명 | 효과 |
|---|---|---|
ATTACK_PMKID | 더미 인증을 통한 PMKID 추출 | 모든 WPA2/WPA3-전환에서 작동 |
ATTACK_CSA | 채널 전환 알림 주입 | PMF 보호 우회 |
ATTACK_DEAUTH | 레거시 비인증 (Reason 7) | PMF가 없는 WPA2 전용 |
ATTACK_STIMULATE | 절전 클라이언트용 QoS Null Data | 비침습적 클라이언트 깨우기 |
ATTACK_PASSIVE | 수신 전용 모드 | 전송 없음 |
ATTACK_ALL | 모든 활성 공격 벡터 활성화 | 최대 공격성 |
platformio.ini에 추가:```ini
[env:myboard]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
Politician
또는 프로젝트의 `lib/` 디렉토리에 직접 클론하십시오:```bash
cd lib/
git clone https://github.com/0ldev/Politician.git
저장소를 프로젝트의 components/ 디렉토리로 클론합니다:```bash
cd components/
git clone https://github.com/0ldev/Politician.git
`components/Politician/CMakeLists.txt` 컴포넌트 설명자를 생성합니다:```cmake
idf_component_register(
SRCS
"src/Politician.cpp"
"src/PoliticianFormat.cpp"
"src/PoliticianStress.cpp"
INCLUDE_DIRS "src"
)
PoliticianStorage.h는 ESP-IDF에서 사용할 수 없습니다 — Arduino 외부에서 포함되면 컴파일 타임에 #error를 발생시킵니다. 지속성이 필요한 경우 ESP-IDF의 VFS 및 nvs_flash API를 직접 사용하세요.
#include <Arduino.h> #include <SD.h> #include <Politician.h> #include <PoliticianStorage.h>
using namespace politician; using namespace politician::storage;
Politician engine;
void onHandshake(const HandshakeRecord &rec) { Serial.printf("\n[✓] Captured: %s ch%d rssi=%d type=%d\n", rec.ssid, rec.channel, rec.rssi, rec.type); // Primary output: PCAPNG — open in Wireshark or convert with hcxpcapngtool PcapngFileLogger::append(SD, "/captures.pcapng", rec); }
void setup() { Serial.begin(115200); SD.begin();
engine.setEapolCallback(onHandshake);
Config cfg;
engine.begin(cfg);
engine.setAttackMask(ATTACK_ALL);
}
void loop() { engine.tick(); }
### 기본 ESP-IDF 빠른 시작
ESP-IDF에서 `begin()`은 내부적으로 `esp_wifi_init()`을 호출하지만, NVS와 기본 이벤트 루프가 이미 초기화되어 있어야 합니다. `begin()` 전에 이들을 호출한 후, FreeRTOS 태스크에서 엔진을 구동하십시오.```cpp
#include <nvs_flash.h>
#include <esp_event.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <Politician.h>
using namespace politician;
static Politician engine;
static void on_handshake(const HandshakeRecord &rec) {
printf("[+] Captured: %s ch%d rssi=%d type=%d\n",
rec.ssid, rec.channel, rec.rssi, rec.type);
}
static void audit_task(void *) {
Config cfg;
engine.setEapolCallback(on_handshake);
if (engine.begin(cfg) != OK) {
printf("[!] WiFi init failed\n");
vTaskDelete(nullptr);
return;
}
engine.setAttackMask(ATTACK_ALL);
for (;;) {
engine.tick();
vTaskDelay(pdMS_TO_TICKS(1));
}
}
extern "C" void app_main(void) {
nvs_flash_init();
esp_event_loop_create_default();
xTaskCreate(audit_task, "politician", 8192, nullptr, 5, nullptr);
}
메인 엔진 클래스입니다. 메인 루프에서 tick()을 호출해야 합니다.
Error begin(const Config& cfg = Config());
엔진을 초기화합니다. 성공 시 `OK`를 반환하고 실패 시 `Error` 코드를 반환합니다. 다른 메서드보다 먼저 호출되어야 합니다.
#### 설정 구조```cpp
struct Config {
uint16_t hop_dwell_ms = 200; // Static time spent on each channel (ms)
bool smart_hopping = true; // Dynamic channel dwell time based on traffic
uint16_t hop_min_dwell_ms = 50; // Minimum dwell if no traffic is seen
uint16_t hop_max_dwell_ms = 400; // Maximum dwell if traffic is active
uint32_t m1_lock_ms = 800; // How long to stay on channel after seeing M1
uint32_t fish_timeout_ms = 2000; // Timeout per PMKID association attempt
uint8_t fish_max_retries = 2; // PMKID retries before pivoting to CSA
uint32_t csa_wait_ms = 4000; // Wait window after CSA/Deauth burst
uint8_t csa_beacon_count = 8; // Number of CSA beacons per burst
uint8_t deauth_burst_count = 16; // Frames per standalone deauth burst
uint8_t csa_deauth_count = 15; // Deauth frames appended after CSA burst
uint16_t probe_aggr_interval_s = 30; // Seconds between re-attacking the same AP
uint32_t session_timeout_ms = 60000; // How long orphaned sessions live in RAM
bool capture_half_handshakes = false; // Fire callback on M2-only captures and pivot to active attack
bool skip_immune_networks = true; // Skip pure WPA3 / PMF-Required networks
uint8_t capture_filter = LOG_FILTER_HANDSHAKES | LOG_FILTER_PROBES;
int8_t min_rssi = -100; // Ignore APs weaker than this signal (dBm)
uint32_t ap_expiry_ms = 300000; // Evict APs not seen for this long (0 = never expire)
bool unicast_deauth = true; // Send deauth to known client MAC instead of broadcast
uint32_t probe_hidden_interval_ms = 0; // How often to probe hidden APs for SSID (0 = disabled, opt-in)
uint8_t deauth_reason = 7; // 802.11 reason code in deauth frames
bool deauth_reason_cycling = true; // Cycle through effective reason codes (fuzzing)
// ── Frame capture
bool capture_group_keys = false; // Fire eapolCb(CAP_EAPOL_GROUP) on GTK rotation frames
// ── Filtering
uint8_t min_beacon_count = 0; // Min times AP must be seen before attack/apFoundCb (0 = off)
uint8_t max_total_attempts = 0; // Permanently skip BSSID after N failed attacks (0 = unlimited)
uint8_t sta_filter[6] = {}; // Only record EAPOL from this client MAC (zero = no filter)
char ssid_filter[33] = {}; // Only cache APs matching this SSID (empty = no filter)
bool ssid_filter_exact = true; // True = exact match, false = substring match
uint8_t enc_filter_mask = 0xFF; // Bitmask of enc types to cache
bool require_active_clients = false; // Skip attack initiation if no active clients seen on AP
};