/** * @file simple_web_server.c * @brief ESP32-C5 Toolkit Web Server with Dual-Band Deauth * * Features: * - Multi-target selection (2.4GHz + 5GHz) * - Real dual-band deauth attack * - BSSID display for proper targeting */ #include "esp_http_server.h" #include "esp_log.h" #include "esp_wifi.h" #include "esp_system.h" #include "esp_chip_info.h" #include "esp_mac.h" #include "cJSON.h" #include "deauth_engine.h" #include "bt_scanner.h" #include "driver/temperature_sensor.h" #include #include // Temperature sensor handle static temperature_sensor_handle_t temp_sensor = NULL; #define TAG "WebServer" // Store last scan results for target selection static wifi_ap_record_t scan_results[30]; static uint16_t scan_count = 0; // Forward declare HTML static const char* get_index_html(void); // ============================================================================ // HANDLERS // ============================================================================ static esp_err_t root_handler(httpd_req_t *req) { ESP_LOGI(TAG, "Serving index.html"); const char* html = get_index_html(); httpd_resp_set_type(req, "text/html"); httpd_resp_send(req, html, strlen(html)); return ESP_OK; } // Enhanced scan with BSSID and security static esp_err_t scan_handler(httpd_req_t *req) { ESP_LOGI(TAG, "WiFi scan requested"); wifi_scan_config_t scan_config = { .ssid = NULL, .bssid = NULL, .channel = 0, .show_hidden = true, .scan_type = WIFI_SCAN_TYPE_ACTIVE, .scan_time.active.min = 100, .scan_time.active.max = 300 }; esp_wifi_scan_start(&scan_config, true); scan_count = 30; esp_wifi_scan_get_ap_records(&scan_count, scan_results); cJSON *root = cJSON_CreateObject(); cJSON *networks = cJSON_CreateArray(); for (int i = 0; i < scan_count; i++) { cJSON *ap = cJSON_CreateObject(); // SSID cJSON_AddStringToObject(ap, "ssid", (char*)scan_results[i].ssid); // BSSID as string char bssid[18]; snprintf(bssid, sizeof(bssid), "%02x:%02x:%02x:%02x:%02x:%02x", scan_results[i].bssid[0], scan_results[i].bssid[1], scan_results[i].bssid[2], scan_results[i].bssid[3], scan_results[i].bssid[4], scan_results[i].bssid[5]); cJSON_AddStringToObject(ap, "bssid", bssid); cJSON_AddNumberToObject(ap, "rssi", scan_results[i].rssi); cJSON_AddNumberToObject(ap, "channel", scan_results[i].primary); cJSON_AddStringToObject(ap, "band", scan_results[i].primary > 14 ? "5GHz" : "2.4GHz"); // Security const char* security; switch (scan_results[i].authmode) { case WIFI_AUTH_OPEN: security = "Open"; break; case WIFI_AUTH_WEP: security = "WEP"; break; case WIFI_AUTH_WPA_PSK: security = "WPA"; break; case WIFI_AUTH_WPA2_PSK: security = "WPA2"; break; case WIFI_AUTH_WPA_WPA2_PSK: security = "WPA/WPA2"; break; case WIFI_AUTH_WPA3_PSK: security = "WPA3"; break; case WIFI_AUTH_WPA2_WPA3_PSK: security = "WPA2/WPA3"; break; default: security = "Unknown"; } cJSON_AddStringToObject(ap, "security", security); cJSON_AddNumberToObject(ap, "index", i); cJSON_AddItemToArray(networks, ap); } cJSON_AddItemToObject(root, "networks", networks); cJSON_AddNumberToObject(root, "count", scan_count); char *json_str = cJSON_PrintUnformatted(root); httpd_resp_set_type(req, "application/json"); httpd_resp_send(req, json_str, strlen(json_str)); free(json_str); cJSON_Delete(root); ESP_LOGI(TAG, "Found %d networks", scan_count); return ESP_OK; } // System info with attack status and ESP32-C5 features static esp_err_t sysinfo_handler(httpd_req_t *req) { cJSON *root = cJSON_CreateObject(); // Chip info esp_chip_info_t chip_info; esp_chip_info(&chip_info); cJSON_AddStringToObject(root, "chip", "ESP32-C5"); cJSON_AddNumberToObject(root, "cores", chip_info.cores); cJSON_AddNumberToObject(root, "revision", chip_info.revision); // Memory cJSON_AddNumberToObject(root, "heap", esp_get_free_heap_size()); cJSON_AddNumberToObject(root, "min_heap", esp_get_minimum_free_heap_size()); // Temperature sensor float temp_celsius = 0; if (temp_sensor == NULL) { temperature_sensor_config_t temp_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80); temperature_sensor_install(&temp_config, &temp_sensor); } if (temp_sensor) { temperature_sensor_enable(temp_sensor); temperature_sensor_get_celsius(temp_sensor, &temp_celsius); temperature_sensor_disable(temp_sensor); } cJSON_AddNumberToObject(root, "temp", (int)(temp_celsius * 10) / 10.0); // MAC address uint8_t mac[6]; esp_read_mac(mac, ESP_MAC_WIFI_STA); char mac_str[18]; snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); cJSON_AddStringToObject(root, "mac", mac_str); // Features cJSON_AddStringToObject(root, "features", "WiFi6,BLE5,Thread"); cJSON_AddStringToObject(root, "version", "2.0.0"); cJSON_AddBoolToObject(root, "attacking", deauth_is_running()); // Get attack stats if running if (deauth_is_running()) { uint32_t total, p24, p5, elapsed; deauth_get_stats(&total, &p24, &p5, &elapsed); cJSON_AddNumberToObject(root, "packets_total", total); cJSON_AddNumberToObject(root, "packets_24ghz", p24); cJSON_AddNumberToObject(root, "packets_5ghz", p5); cJSON_AddNumberToObject(root, "elapsed", elapsed); } char *json_str = cJSON_PrintUnformatted(root); httpd_resp_set_type(req, "application/json"); httpd_resp_send(req, json_str, strlen(json_str)); free(json_str); cJSON_Delete(root); return ESP_OK; } // REAL deauth start - parses JSON with targets static esp_err_t deauth_start_handler(httpd_req_t *req) { ESP_LOGI(TAG, "Deauth start requested"); // Read POST body char buf[512]; int ret = httpd_req_recv(req, buf, sizeof(buf) - 1); if (ret <= 0) { httpd_resp_set_type(req, "application/json"); httpd_resp_sendstr(req, "{\"status\":\"error\",\"message\":\"No data\"}"); return ESP_OK; } buf[ret] = '\0'; ESP_LOGI(TAG, "Received: %s", buf); cJSON *root = cJSON_Parse(buf); if (!root) { httpd_resp_set_type(req, "application/json"); httpd_resp_sendstr(req, "{\"status\":\"error\",\"message\":\"Invalid JSON\"}"); return ESP_OK; } deauth_target_t target_24 = {0}; deauth_target_t target_5 = {0}; // Parse 2.4GHz target cJSON *t24 = cJSON_GetObjectItem(root, "target_24ghz"); if (t24) { cJSON *bssid = cJSON_GetObjectItem(t24, "bssid"); cJSON *ssid = cJSON_GetObjectItem(t24, "ssid"); cJSON *channel = cJSON_GetObjectItem(t24, "channel"); if (cJSON_IsString(bssid) && cJSON_IsNumber(channel)) { sscanf(bssid->valuestring, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &target_24.bssid[0], &target_24.bssid[1], &target_24.bssid[2], &target_24.bssid[3], &target_24.bssid[4], &target_24.bssid[5]); target_24.channel = (uint8_t)channel->valueint; if (cJSON_IsString(ssid)) { strncpy(target_24.ssid, ssid->valuestring, sizeof(target_24.ssid) - 1); } target_24.active = true; ESP_LOGI(TAG, "2.4GHz target: %s CH:%d", target_24.ssid, target_24.channel); } } // Parse 5GHz target cJSON *t5 = cJSON_GetObjectItem(root, "target_5ghz"); if (t5) { cJSON *bssid = cJSON_GetObjectItem(t5, "bssid"); cJSON *ssid = cJSON_GetObjectItem(t5, "ssid"); cJSON *channel = cJSON_GetObjectItem(t5, "channel"); if (cJSON_IsString(bssid) && cJSON_IsNumber(channel)) { sscanf(bssid->valuestring, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &target_5.bssid[0], &target_5.bssid[1], &target_5.bssid[2], &target_5.bssid[3], &target_5.bssid[4], &target_5.bssid[5]); target_5.channel = (uint8_t)channel->valueint; if (cJSON_IsString(ssid)) { strncpy(target_5.ssid, ssid->valuestring, sizeof(target_5.ssid) - 1); } target_5.active = true; ESP_LOGI(TAG, "5GHz target: %s CH:%d", target_5.ssid, target_5.channel); } } // Get duration (default 30 seconds) cJSON *dur = cJSON_GetObjectItem(root, "duration"); uint32_t duration = cJSON_IsNumber(dur) ? dur->valueint : 30; cJSON_Delete(root); // Start the REAL attack bool success = deauth_start_attack( target_24.active ? &target_24 : NULL, target_5.active ? &target_5 : NULL, duration ); httpd_resp_set_type(req, "application/json"); if (success) { ESP_LOGI(TAG, "Attack started for %lu seconds", duration); httpd_resp_sendstr(req, "{\"status\":\"ok\",\"message\":\"Attack started\"}"); } else { ESP_LOGW(TAG, "Failed to start attack"); httpd_resp_sendstr(req, "{\"status\":\"error\",\"message\":\"Failed to start - check targets\"}"); } return ESP_OK; } // Stop attack static esp_err_t deauth_stop_handler(httpd_req_t *req) { ESP_LOGI(TAG, "Deauth stop requested"); deauth_stop_attack(); httpd_resp_set_type(req, "application/json"); httpd_resp_sendstr(req, "{\"status\":\"ok\",\"message\":\"Attack stopped\"}"); return ESP_OK; } // Attack status endpoint static esp_err_t deauth_status_handler(httpd_req_t *req) { cJSON *root = cJSON_CreateObject(); bool running = deauth_is_running(); cJSON_AddBoolToObject(root, "running", running); if (running) { uint32_t total, p24, p5, elapsed; deauth_get_stats(&total, &p24, &p5, &elapsed); cJSON_AddNumberToObject(root, "packets_total", total); cJSON_AddNumberToObject(root, "packets_24ghz", p24); cJSON_AddNumberToObject(root, "packets_5ghz", p5); cJSON_AddNumberToObject(root, "elapsed", elapsed); } char *json_str = cJSON_PrintUnformatted(root); httpd_resp_set_type(req, "application/json"); httpd_resp_send(req, json_str, strlen(json_str)); free(json_str); cJSON_Delete(root); return ESP_OK; } // Bluetooth scan start (NimBLE) static esp_err_t bt_scan_start_handler(httpd_req_t *req) { ESP_LOGI(TAG, "BLE scan start requested"); httpd_resp_set_type(req, "application/json"); bool success = bt_scan_start(); if (success) { httpd_resp_sendstr(req, "{\"status\":\"ok\",\"message\":\"BLE scan started\"}"); } else { httpd_resp_sendstr(req, "{\"status\":\"error\",\"message\":\"Failed to start BLE scan\"}"); } return ESP_OK; } // Bluetooth scan stop static esp_err_t bt_scan_stop_handler(httpd_req_t *req) { ESP_LOGI(TAG, "BLE scan stop requested"); httpd_resp_set_type(req, "application/json"); bool success = bt_scan_stop(); if (success) { httpd_resp_sendstr(req, "{\"status\":\"ok\",\"message\":\"BLE scan stopped\"}"); } else { httpd_resp_sendstr(req, "{\"status\":\"error\",\"message\":\"Failed to stop BLE scan\"}"); } return ESP_OK; } // Bluetooth devices list static esp_err_t bt_devices_handler(httpd_req_t *req) { ESP_LOGI(TAG, "BLE devices requested"); bt_device_t bt_devs[30]; int count = bt_get_devices(bt_devs, 30); cJSON *root = cJSON_CreateObject(); cJSON *device_array = cJSON_CreateArray(); for (int i = 0; i < count; i++) { cJSON *dev = cJSON_CreateObject(); // MAC address char addr[18]; snprintf(addr, sizeof(addr), "%02X:%02X:%02X:%02X:%02X:%02X", bt_devs[i].addr[0], bt_devs[i].addr[1], bt_devs[i].addr[2], bt_devs[i].addr[3], bt_devs[i].addr[4], bt_devs[i].addr[5]); cJSON_AddStringToObject(dev, "addr", addr); cJSON_AddStringToObject(dev, "name", bt_devs[i].name[0] ? bt_devs[i].name : "Unknown"); cJSON_AddNumberToObject(dev, "rssi", bt_devs[i].rssi); cJSON_AddStringToObject(dev, "type", "BLE"); cJSON_AddItemToArray(device_array, dev); } cJSON_AddItemToObject(root, "devices", device_array); cJSON_AddNumberToObject(root, "count", count); char *json_str = cJSON_PrintUnformatted(root); httpd_resp_set_type(req, "application/json"); httpd_resp_send(req, json_str, strlen(json_str)); free(json_str); cJSON_Delete(root); ESP_LOGI(TAG, "Returned %d BLE devices", count); return ESP_OK; } // ============================================================================ // URI DEFINITIONS // ============================================================================ static httpd_uri_t uri_root = {.uri = "/", .method = HTTP_GET, .handler = root_handler}; static httpd_uri_t uri_scan = {.uri = "/api/scan", .method = HTTP_GET, .handler = scan_handler}; static httpd_uri_t uri_sysinfo = {.uri = "/api/system-info", .method = HTTP_GET, .handler = sysinfo_handler}; static httpd_uri_t uri_deauth_start = {.uri = "/api/deauth/start", .method = HTTP_POST, .handler = deauth_start_handler}; static httpd_uri_t uri_deauth_stop = {.uri = "/api/deauth/stop", .method = HTTP_GET, .handler = deauth_stop_handler}; static httpd_uri_t uri_deauth_status = {.uri = "/api/deauth/status", .method = HTTP_GET, .handler = deauth_status_handler}; static httpd_uri_t uri_bt_scan_start = {.uri = "/api/bt/scan/start", .method = HTTP_GET, .handler = bt_scan_start_handler}; static httpd_uri_t uri_bt_scan_stop = {.uri = "/api/bt/scan/stop", .method = HTTP_GET, .handler = bt_scan_stop_handler}; static httpd_uri_t uri_bt_devices = {.uri = "/api/bt/devices", .method = HTTP_GET, .handler = bt_devices_handler}; // ============================================================================ // WEB SERVER // ============================================================================ static httpd_handle_t server = NULL; httpd_handle_t start_webserver(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.stack_size = 8192; config.max_uri_handlers = 15; ESP_LOGI(TAG, "Starting web server on port %d", config.server_port); if (httpd_start(&server, &config) == ESP_OK) { httpd_register_uri_handler(server, &uri_root); httpd_register_uri_handler(server, &uri_scan); httpd_register_uri_handler(server, &uri_sysinfo); httpd_register_uri_handler(server, &uri_deauth_start); httpd_register_uri_handler(server, &uri_deauth_stop); httpd_register_uri_handler(server, &uri_deauth_status); httpd_register_uri_handler(server, &uri_bt_scan_start); httpd_register_uri_handler(server, &uri_bt_scan_stop); httpd_register_uri_handler(server, &uri_bt_devices); ESP_LOGI(TAG, "Web Server started at http://192.168.4.1"); } else { ESP_LOGE(TAG, "Failed to start web server!"); } return server; } void stop_webserver(void) { if (server) { httpd_stop(server); server = NULL; } } void init_web_server(void) { start_webserver(); } // ============================================================================ // HTML - Multi-target selection with Channel Graph // ============================================================================ static const char* get_index_html(void) { static const char html[] = "" "" "" "" "ESP32-C5 Toolkit" "" "" "
" "

📡 ESP32-C5 TOOLKIT

" "
" "

🔍 WiFi Scanner

" "" "" "
" "
" "
" "

📶 Channel Usage

" "
" "
" "

2.4 GHz (CH 1-13)

" "
" "
" "
" "

5 GHz

" "
" "
" "
" "
" "
" "

⚡ Dual-Band Deauth

" "
⚠ WiFi AP offline during attack! Auto-restores after.
" "

Click networks to select targets:

" "
" "
2.4GHz: None
" "
5GHz: None
" "
" "

Duration: sec

" "" "" "" "
Status: Idle
" "
" "
" "

📶 Bluetooth Scanner

" "" "" "" "
" "
" "
" "

💻 System

" "
Loading...
" "
" "
" "" ""; return html; }