|
|
|
|
@@ -1025,6 +1025,13 @@ void WiFiScan::StopScan(uint8_t scan_mode)
|
|
|
|
|
this->analyzer_name_update = true;
|
|
|
|
|
this->mgmt_frames = 0;
|
|
|
|
|
this->data_frames = 0;
|
|
|
|
|
this->beacon_frames = 0;
|
|
|
|
|
this->req_frames = 0;
|
|
|
|
|
this->resp_frames = 0;
|
|
|
|
|
this->deauth_frames = 0;
|
|
|
|
|
this->eapol_frames = 0;
|
|
|
|
|
this->min_rssi = 0;
|
|
|
|
|
this->max_rssi = -128;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1368,7 +1375,6 @@ void WiFiScan::RunLoadAPList() {
|
|
|
|
|
display_obj.tft.setCursor(0, 100);
|
|
|
|
|
display_obj.tft.setTextSize(1);
|
|
|
|
|
display_obj.tft.setTextColor(TFT_CYAN);
|
|
|
|
|
|
|
|
|
|
display_obj.tft.println("Could not open /APs_0.log");
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
@@ -1386,7 +1392,6 @@ void WiFiScan::RunLoadAPList() {
|
|
|
|
|
display_obj.tft.setCursor(0, 100);
|
|
|
|
|
display_obj.tft.setTextSize(1);
|
|
|
|
|
display_obj.tft.setTextColor(TFT_CYAN);
|
|
|
|
|
|
|
|
|
|
display_obj.tft.println("Could not deserialize JSON");
|
|
|
|
|
display_obj.tft.println(error.c_str());
|
|
|
|
|
#endif
|
|
|
|
|
@@ -1396,25 +1401,36 @@ void WiFiScan::RunLoadAPList() {
|
|
|
|
|
JsonArray array = doc.as<JsonArray>();
|
|
|
|
|
for (JsonObject obj : array) {
|
|
|
|
|
AccessPoint ap;
|
|
|
|
|
ap.essid = obj["essid"].as<String>();
|
|
|
|
|
ap.channel = obj["channel"];
|
|
|
|
|
|
|
|
|
|
ap.essid = obj.containsKey("essid") ? obj["essid"].as<String>() : "";
|
|
|
|
|
ap.channel = obj.containsKey("channel") ? obj["channel"].as<uint8_t>() : 1;
|
|
|
|
|
ap.selected = false;
|
|
|
|
|
parseBSSID(obj["bssid"], ap.bssid);
|
|
|
|
|
|
|
|
|
|
if (obj.containsKey("bssid")) {
|
|
|
|
|
parseBSSID(obj["bssid"], ap.bssid);
|
|
|
|
|
} else {
|
|
|
|
|
memset(ap.bssid, 0, 6); // Zero BSSID if missing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ap.stations = new LinkedList<uint16_t>();
|
|
|
|
|
ap.rssi = obj.containsKey("rssi") ? obj["rssi"].as<int>() : -127;
|
|
|
|
|
ap.packets = obj.containsKey("packet") ? obj["packet"].as<uint32_t>() : 0;
|
|
|
|
|
ap.sec = obj.containsKey("sec") ? obj["sec"].as<uint8_t>() : 0;
|
|
|
|
|
ap.wps = obj.containsKey("wps") ? obj["wps"].as<bool>() : false;
|
|
|
|
|
ap.man = obj.containsKey("man") ? obj["man"].as<String>() : "Unknown";
|
|
|
|
|
|
|
|
|
|
access_points->add(ap);
|
|
|
|
|
Serial.println("Got: " + ap.essid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
|
|
//doc.clear();
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
display_obj.tft.setTextWrap(false);
|
|
|
|
|
display_obj.tft.setFreeFont(NULL);
|
|
|
|
|
display_obj.tft.setCursor(0, 100);
|
|
|
|
|
display_obj.tft.setTextSize(1);
|
|
|
|
|
display_obj.tft.setTextColor(TFT_CYAN);
|
|
|
|
|
|
|
|
|
|
display_obj.tft.print("Loaded APs: ");
|
|
|
|
|
display_obj.tft.println((String)access_points->size());
|
|
|
|
|
#endif
|
|
|
|
|
@@ -1444,6 +1460,11 @@ void WiFiScan::RunSaveAPList(bool save_as) {
|
|
|
|
|
ap.bssid[0], ap.bssid[1], ap.bssid[2],
|
|
|
|
|
ap.bssid[3], ap.bssid[4], ap.bssid[5]);
|
|
|
|
|
jsonAp["bssid"] = bssidStr;
|
|
|
|
|
jsonAp["rssi"] = ap.rssi;
|
|
|
|
|
jsonAp["packets"] = ap.packets;
|
|
|
|
|
jsonAp["sec"] = ap.sec;
|
|
|
|
|
jsonAp["wps"] = ap.wps;
|
|
|
|
|
jsonAp["man"] = ap.man;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String jsonString;
|
|
|
|
|
@@ -1624,7 +1645,6 @@ void WiFiScan::RunAPScan(uint8_t scan_mode, uint16_t color)
|
|
|
|
|
delete access_points;
|
|
|
|
|
access_points = new LinkedList<AccessPoint>();
|
|
|
|
|
|
|
|
|
|
//esp_wifi_init(&cfg);
|
|
|
|
|
esp_wifi_init(&cfg2);
|
|
|
|
|
esp_wifi_set_storage(WIFI_STORAGE_RAM);
|
|
|
|
|
esp_wifi_set_mode(WIFI_MODE_NULL);
|
|
|
|
|
@@ -1632,10 +1652,7 @@ void WiFiScan::RunAPScan(uint8_t scan_mode, uint16_t color)
|
|
|
|
|
this->setMac();
|
|
|
|
|
esp_wifi_set_promiscuous(true);
|
|
|
|
|
esp_wifi_set_promiscuous_filter(&filt);
|
|
|
|
|
//if (scan_mode == WIFI_SCAN_TARGET_AP_FULL)
|
|
|
|
|
esp_wifi_set_promiscuous_rx_cb(&apSnifferCallbackFull);
|
|
|
|
|
//else
|
|
|
|
|
// esp_wifi_set_promiscuous_rx_cb(&apSnifferCallback);
|
|
|
|
|
esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
|
|
|
|
|
this->wifi_initialized = true;
|
|
|
|
|
initTime = millis();
|
|
|
|
|
@@ -1714,13 +1731,23 @@ void WiFiScan::RunClearSSIDs() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WiFiScan::setMac() {
|
|
|
|
|
wifi_mode_t currentWiFiMode;
|
|
|
|
|
esp_wifi_get_mode(¤tWiFiMode);
|
|
|
|
|
esp_err_t result;
|
|
|
|
|
result = esp_wifi_set_mac(WIFI_IF_AP, this->ap_mac);
|
|
|
|
|
if (result != ESP_OK) Serial.printf("Failed to set AP MAC: %s | 0x%X\n", macToString(this->ap_mac), result);
|
|
|
|
|
else Serial.println("Successfully set AP MAC: " + macToString(this->ap_mac));
|
|
|
|
|
if ((result != ESP_OK) &&
|
|
|
|
|
((currentWiFiMode == WIFI_MODE_AP) || (currentWiFiMode == WIFI_MODE_APSTA) || (currentWiFiMode == WIFI_MODE_NULL)))
|
|
|
|
|
Serial.printf("Failed to set AP MAC: %s | 0x%X\n", macToString(this->ap_mac), result);
|
|
|
|
|
else if ((currentWiFiMode == WIFI_MODE_AP) || (currentWiFiMode == WIFI_MODE_APSTA) || (currentWiFiMode == WIFI_MODE_NULL))
|
|
|
|
|
Serial.println("Successfully set AP MAC: " + macToString(this->ap_mac));
|
|
|
|
|
|
|
|
|
|
// Do the station
|
|
|
|
|
result = esp_wifi_set_mac(WIFI_IF_STA, this->sta_mac);
|
|
|
|
|
if (result != ESP_OK) Serial.printf("Failed to set STA MAC: %s | 0x%X\n", macToString(this->sta_mac), result);
|
|
|
|
|
else Serial.println("Successfully set STA MAC: " + macToString(this->sta_mac));
|
|
|
|
|
if ((result != ESP_OK) &&
|
|
|
|
|
((currentWiFiMode == WIFI_MODE_STA) || (currentWiFiMode == WIFI_MODE_APSTA)))
|
|
|
|
|
Serial.printf("Failed to set STA MAC: %s | 0x%X\n", macToString(this->sta_mac), result);
|
|
|
|
|
else if ((currentWiFiMode == WIFI_MODE_STA) || (currentWiFiMode == WIFI_MODE_APSTA))
|
|
|
|
|
Serial.println("Successfully set STA MAC: " + macToString(this->sta_mac));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WiFiScan::RunSetMac(uint8_t * mac, bool ap) {
|
|
|
|
|
@@ -2014,6 +2041,31 @@ void WiFiScan::RunAPInfo(uint16_t index, bool do_display) {
|
|
|
|
|
Serial.println(" RSSI: " + (String)access_points->get(index).rssi);
|
|
|
|
|
Serial.println(" Frames: " + (String)access_points->get(index).packets);
|
|
|
|
|
Serial.println("Stations: " + (String)access_points->get(index).stations->size());
|
|
|
|
|
Serial.println(" Brand: " + (String)access_points->get(index).man);
|
|
|
|
|
|
|
|
|
|
uint8_t sec = access_points->get(index).sec;
|
|
|
|
|
bool wps = access_points->get(index).wps;
|
|
|
|
|
|
|
|
|
|
Serial.print("Security: ");
|
|
|
|
|
switch (sec) {
|
|
|
|
|
case WIFI_SECURITY_OPEN: Serial.println("Open"); break;
|
|
|
|
|
case WIFI_SECURITY_WEP: Serial.println("WEP"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA: Serial.println("WPA"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA2: Serial.println("WPA2"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA3: Serial.println("WPA3"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA_WPA2_MIXED: Serial.println("WPA/WPA2 Mixed"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA2_ENTERPRISE: Serial.println("WPA2 Enterprise"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA3_ENTERPRISE: Serial.println("WPA3 Enterprise"); break;
|
|
|
|
|
case WIFI_SECURITY_WAPI: Serial.println("WAPI"); break;
|
|
|
|
|
default: Serial.println("Unknown"); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Serial.print(" WPS: ");
|
|
|
|
|
switch (wps) {
|
|
|
|
|
case true: Serial.println("true"); break;
|
|
|
|
|
case false: Serial.println("false"); break;
|
|
|
|
|
default: Serial.println("false"); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
if (do_display) {
|
|
|
|
|
@@ -2023,6 +2075,28 @@ void WiFiScan::RunAPInfo(uint16_t index, bool do_display) {
|
|
|
|
|
display_obj.tft.println(" RSSI: " + (String)access_points->get(index).rssi);
|
|
|
|
|
display_obj.tft.println(" Frames: " + (String)access_points->get(index).packets);
|
|
|
|
|
display_obj.tft.println("Stations: " + (String)access_points->get(index).stations->size());
|
|
|
|
|
display_obj.tft.println(" Brand: " + (String)access_points->get(index).man);
|
|
|
|
|
|
|
|
|
|
display_obj.tft.print("Security: ");
|
|
|
|
|
switch (sec) {
|
|
|
|
|
case WIFI_SECURITY_OPEN: display_obj.tft.println("Open"); break;
|
|
|
|
|
case WIFI_SECURITY_WEP: display_obj.tft.println("WEP"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA: display_obj.tft.println("WPA"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA2: display_obj.tft.println("WPA2"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA3: display_obj.tft.println("WPA3"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA_WPA2_MIXED: display_obj.tft.println("WPA/WPA2 Mixed"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA2_ENTERPRISE: display_obj.tft.println("WPA2 Enterprise"); break;
|
|
|
|
|
case WIFI_SECURITY_WPA3_ENTERPRISE: display_obj.tft.println("WPA3 Enterprise"); break;
|
|
|
|
|
case WIFI_SECURITY_WAPI: display_obj.tft.println("WAPI"); break;
|
|
|
|
|
default: display_obj.tft.println("Unknown"); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
display_obj.tft.print(" WPS: ");
|
|
|
|
|
switch (wps) {
|
|
|
|
|
case true: display_obj.tft.println("true"); break;
|
|
|
|
|
case false: display_obj.tft.println("false"); break;
|
|
|
|
|
default: display_obj.tft.println("false"); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
@@ -3261,6 +3335,68 @@ void WiFiScan::pwnSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WiFiScan::checkMatchAP(char addr[]) {
|
|
|
|
|
for (int i = 0; i < access_points->size(); i++) {
|
|
|
|
|
bool mac_match = true;
|
|
|
|
|
|
|
|
|
|
for (int x = 0; x < 6; x++) {
|
|
|
|
|
if ((uint8_t)strtol(&addr[x * 3], NULL, 16) != access_points->get(i).bssid[x]) {
|
|
|
|
|
mac_match = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mac_match) {
|
|
|
|
|
AccessPoint ap = access_points->get(i);
|
|
|
|
|
ap.packets += 1;
|
|
|
|
|
access_points->set(i, ap);
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String WiFiScan::extractManufacturer(const uint8_t* payload) {
|
|
|
|
|
const int fixedHeaderSize = 36; // 802.11 mgmt header (24) + fixed fields (12)
|
|
|
|
|
int pos = fixedHeaderSize;
|
|
|
|
|
|
|
|
|
|
while (pos < 512) { // safety bounds
|
|
|
|
|
uint8_t tagNumber = payload[pos];
|
|
|
|
|
uint8_t tagLength = payload[pos + 1];
|
|
|
|
|
|
|
|
|
|
// Check for vendor-specific IE (Tag number 221)
|
|
|
|
|
if (tagNumber == 0xdd && tagLength >= 4) {
|
|
|
|
|
const uint8_t* oui = &payload[pos + 2];
|
|
|
|
|
|
|
|
|
|
// Check if OUI is 00:50:F2 (Microsoft WPS)
|
|
|
|
|
if (oui[0] == 0x00 && oui[1] == 0x50 && oui[2] == 0xF2) {
|
|
|
|
|
int wpsPos = pos + 6; // Skip: tag + len + OUI (2 + 1 + 3)
|
|
|
|
|
int end = pos + 2 + tagLength;
|
|
|
|
|
|
|
|
|
|
// Iterate through WPS sub-TLVs
|
|
|
|
|
while (wpsPos + 4 <= end) {
|
|
|
|
|
uint16_t type = (payload[wpsPos] << 8) | payload[wpsPos + 1];
|
|
|
|
|
uint16_t len = (payload[wpsPos + 2] << 8) | payload[wpsPos + 3];
|
|
|
|
|
|
|
|
|
|
if (type == 0x1021) { // Manufacturer
|
|
|
|
|
char buffer[65]; // reasonable max
|
|
|
|
|
int copyLen = len > 64 ? 64 : len;
|
|
|
|
|
memcpy(buffer, &payload[wpsPos + 4], copyLen);
|
|
|
|
|
buffer[copyLen] = '\0';
|
|
|
|
|
return String(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wpsPos += 4 + len;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos += 2 + tagLength;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return String(""); // not found
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WiFiScan::apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type) {
|
|
|
|
|
extern WiFiScan wifi_scan_obj;
|
|
|
|
|
wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
|
|
|
|
|
@@ -3277,47 +3413,64 @@ void WiFiScan::apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type
|
|
|
|
|
if (type == WIFI_PKT_MGMT)
|
|
|
|
|
{
|
|
|
|
|
len -= 4;
|
|
|
|
|
int fctl = ntohs(frameControl->fctl);
|
|
|
|
|
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
|
|
|
|
|
const WifiMgmtHdr *hdr = &ipkt->hdr;
|
|
|
|
|
//int fctl = ntohs(frameControl->fctl);
|
|
|
|
|
//const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
|
|
|
|
|
//const WifiMgmtHdr *hdr = &ipkt->hdr;
|
|
|
|
|
|
|
|
|
|
// If we dont the buffer size is not 0, don't write or else we get CORRUPT_HEAP
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
int buf = display_obj.display_buffer->size();
|
|
|
|
|
#else
|
|
|
|
|
int buf = 0;
|
|
|
|
|
#endif
|
|
|
|
|
int buf = 0;
|
|
|
|
|
|
|
|
|
|
bool wps = wifi_scan_obj.beaconHasWPS(snifferPacket->payload, len);
|
|
|
|
|
|
|
|
|
|
// We got a probe resp. Check for WPS configs
|
|
|
|
|
if (snifferPacket->payload[0] == 0x50) {
|
|
|
|
|
|
|
|
|
|
String man = wifi_scan_obj.extractManufacturer(snifferPacket->payload);
|
|
|
|
|
|
|
|
|
|
if (wps) {
|
|
|
|
|
char addr[] = "00:00:00:00:00:00";
|
|
|
|
|
getMAC(addr, snifferPacket->payload, 10);
|
|
|
|
|
|
|
|
|
|
int index = wifi_scan_obj.checkMatchAP(addr);
|
|
|
|
|
|
|
|
|
|
if ((index > 0) && (!access_points->get(index).wps)) {
|
|
|
|
|
AccessPoint new_ap = access_points->get(index);
|
|
|
|
|
new_ap.wps = true;
|
|
|
|
|
new_ap.man = man;
|
|
|
|
|
access_points->set(index, new_ap);
|
|
|
|
|
Serial.println((String)access_points->get(index).essid + ": RXd WPS Configs");
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
display_string = RED_KEY;
|
|
|
|
|
display_string.concat((String)access_points->get(index).essid + ": RXd WPS Configs");
|
|
|
|
|
int temp_len = display_string.length();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 50 - temp_len; i++)
|
|
|
|
|
display_string.concat(" ");
|
|
|
|
|
|
|
|
|
|
display_obj.display_buffer->add(display_string);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We got an AP. Check if in list and add if not
|
|
|
|
|
if ((snifferPacket->payload[0] == 0x80) && (buf == 0))
|
|
|
|
|
{
|
|
|
|
|
// Get security info
|
|
|
|
|
uint8_t security_type = wifi_scan_obj.getSecurityType(snifferPacket->payload, len);
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
display_string = GREEN_KEY;
|
|
|
|
|
if (!wps)
|
|
|
|
|
display_string = GREEN_KEY;
|
|
|
|
|
else
|
|
|
|
|
display_string = RED_KEY;
|
|
|
|
|
#endif
|
|
|
|
|
char addr[] = "00:00:00:00:00:00";
|
|
|
|
|
getMAC(addr, snifferPacket->payload, 10);
|
|
|
|
|
|
|
|
|
|
bool in_list = false;
|
|
|
|
|
bool mac_match = true;
|
|
|
|
|
int in_list = wifi_scan_obj.checkMatchAP(addr);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < access_points->size(); i++) {
|
|
|
|
|
mac_match = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int x = 0; x < 6; x++) {
|
|
|
|
|
if (snifferPacket->payload[x + 10] != access_points->get(i).bssid[x]) {
|
|
|
|
|
mac_match = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (mac_match) {
|
|
|
|
|
in_list = true;
|
|
|
|
|
AccessPoint ap = access_points->get(i);
|
|
|
|
|
ap.packets = ap.packets + 1;
|
|
|
|
|
access_points->set(i, ap);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!in_list) {
|
|
|
|
|
if (in_list < 0) {
|
|
|
|
|
|
|
|
|
|
Serial.print("RSSI: ");
|
|
|
|
|
Serial.print(snifferPacket->rx_ctrl.rssi);
|
|
|
|
|
@@ -3373,19 +3526,6 @@ void WiFiScan::apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type
|
|
|
|
|
Serial.print(essid + " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//LinkedList<char> beacon = new LinkedList<char>();
|
|
|
|
|
|
|
|
|
|
/*AccessPoint ap = {essid,
|
|
|
|
|
snifferPacket->rx_ctrl.channel,
|
|
|
|
|
{snifferPacket->payload[10],
|
|
|
|
|
snifferPacket->payload[11],
|
|
|
|
|
snifferPacket->payload[12],
|
|
|
|
|
snifferPacket->payload[13],
|
|
|
|
|
snifferPacket->payload[14],
|
|
|
|
|
snifferPacket->payload[15]},
|
|
|
|
|
false,
|
|
|
|
|
NULL};*/
|
|
|
|
|
|
|
|
|
|
if (wifi_scan_obj.checkMem()) {
|
|
|
|
|
|
|
|
|
|
AccessPoint ap;
|
|
|
|
|
@@ -3422,6 +3562,14 @@ void WiFiScan::apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type
|
|
|
|
|
|
|
|
|
|
ap.rssi = snifferPacket->rx_ctrl.rssi;
|
|
|
|
|
|
|
|
|
|
ap.sec = security_type;
|
|
|
|
|
|
|
|
|
|
ap.wps = wps;
|
|
|
|
|
|
|
|
|
|
ap.packets = 0;
|
|
|
|
|
|
|
|
|
|
ap.man = "";
|
|
|
|
|
|
|
|
|
|
access_points->add(ap);
|
|
|
|
|
|
|
|
|
|
Serial.print(access_points->size());
|
|
|
|
|
@@ -3438,6 +3586,8 @@ void WiFiScan::apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We got a client possibly. Check for AP association
|
|
|
|
|
if ((snifferPacket->payload[0] != 0x80) && (wifi_scan_obj.currentScanMode == WIFI_SCAN_AP_STA)) {
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
display_string = CYAN_KEY;
|
|
|
|
|
@@ -3584,6 +3734,129 @@ void WiFiScan::apSnifferCallbackFull(void* buf, wifi_promiscuous_pkt_type_t type
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool WiFiScan::beaconHasWPS(const uint8_t* payload, int len) {
|
|
|
|
|
int i = 36; // skip radiotap + fixed 802.11 header
|
|
|
|
|
|
|
|
|
|
while (i < len - 2) {
|
|
|
|
|
uint8_t tagNumber = payload[i];
|
|
|
|
|
uint8_t tagLength = payload[i + 1];
|
|
|
|
|
|
|
|
|
|
if (i + 2 + tagLength > len) break; // prevent overflow
|
|
|
|
|
const uint8_t* tagData = &payload[i + 2];
|
|
|
|
|
|
|
|
|
|
// Look for Tag Number 0xDD (Vendor Specific)
|
|
|
|
|
if (tagNumber == 0xDD && tagLength >= 6) {
|
|
|
|
|
// Check for WPS OUI: 00:50:F2 and WPS type: 0x04
|
|
|
|
|
if (tagData[0] == 0x00 && tagData[1] == 0x50 && tagData[2] == 0xF2 && tagData[3] == 0x04) {
|
|
|
|
|
// Parse the WPS IE data starting after the OUI and type
|
|
|
|
|
int wpsLen = tagLength - 4;
|
|
|
|
|
const uint8_t* wpsData = &tagData[4];
|
|
|
|
|
int j = 0;
|
|
|
|
|
|
|
|
|
|
while (j + 4 <= wpsLen) {
|
|
|
|
|
uint16_t attrType = (wpsData[j] << 8) | wpsData[j + 1];
|
|
|
|
|
uint16_t attrLen = (wpsData[j + 2] << 8) | wpsData[j + 3];
|
|
|
|
|
|
|
|
|
|
if (j + 4 + attrLen > wpsLen) break; // prevent overflow
|
|
|
|
|
|
|
|
|
|
if (attrType == 0x1008 && attrLen == 2) { // Config Methods attribute
|
|
|
|
|
uint16_t configMethods = (wpsData[j + 4] << 8) | wpsData[j + 5];
|
|
|
|
|
|
|
|
|
|
// Check for any vulnerable method
|
|
|
|
|
if (configMethods & (WPS_CONFIG_LABEL |
|
|
|
|
|
WPS_CONFIG_DISPLAY |
|
|
|
|
|
WPS_CONFIG_KEYPAD |
|
|
|
|
|
WPS_CONFIG_VIRT_DISPLAY |
|
|
|
|
|
WPS_CONFIG_PHY_DISPLAY |
|
|
|
|
|
WPS_CONFIG_PUSH_BUTTON |
|
|
|
|
|
WPS_CONFIG_VIRT_PUSH_BUTTON |
|
|
|
|
|
WPS_CONFIG_PHY_PUSH_BUTTON)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
j += 4 + attrLen;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i += 2 + tagLength;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t WiFiScan::getSecurityType(const uint8_t* beacon, uint16_t len) {
|
|
|
|
|
const uint8_t* frame = beacon;
|
|
|
|
|
const uint8_t* ies = beacon + 36; // Start of tagged parameters
|
|
|
|
|
uint16_t ies_len = len - 36;
|
|
|
|
|
|
|
|
|
|
bool hasRSN = false;
|
|
|
|
|
bool hasWPA = false;
|
|
|
|
|
bool hasWEP = false;
|
|
|
|
|
bool isEnterprise = false;
|
|
|
|
|
bool isWPA3 = false;
|
|
|
|
|
bool isWAPI = false;
|
|
|
|
|
|
|
|
|
|
uint16_t i = 0;
|
|
|
|
|
while (i + 2 <= ies_len) {
|
|
|
|
|
uint8_t tag_id = ies[i];
|
|
|
|
|
uint8_t tag_len = ies[i + 1];
|
|
|
|
|
|
|
|
|
|
if (i + 2 + tag_len > ies_len) break;
|
|
|
|
|
|
|
|
|
|
const uint8_t* tag_data = ies + i + 2;
|
|
|
|
|
|
|
|
|
|
// Check for RSN (WPA2)
|
|
|
|
|
if (tag_id == 48) {
|
|
|
|
|
hasRSN = true;
|
|
|
|
|
|
|
|
|
|
// WPA2-Enterprise usually uses 802.1X AKM (type 1)
|
|
|
|
|
if (tag_len >= 20 && tag_data[14] == 0x01 && tag_data[15] == 0x00 && tag_data[16] == 0x00 && tag_data[17] == 0x0f && tag_data[18] == 0xac) {
|
|
|
|
|
isEnterprise = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WPA3 typically uses SAE (type 8)
|
|
|
|
|
if (tag_len >= 20 && tag_data[14] == 0x01 && tag_data[15] == 0x00 && tag_data[16] == 0x00 && tag_data[17] == 0x0f && tag_data[18] == 0xac && tag_data[19] == 0x08) {
|
|
|
|
|
isWPA3 = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for WPA (in vendor specific tag)
|
|
|
|
|
else if (tag_id == 221 && tag_len >= 8 &&
|
|
|
|
|
tag_data[0] == 0x00 && tag_data[1] == 0x50 && tag_data[2] == 0xF2 && tag_data[3] == 0x01) {
|
|
|
|
|
hasWPA = true;
|
|
|
|
|
|
|
|
|
|
// WPA-Enterprise (AKM 1)
|
|
|
|
|
if (tag_len >= 20 && tag_data[14] == 0x01 && tag_data[15] == 0x00 && tag_data[16] == 0x00 && tag_data[17] == 0x50 && tag_data[18] == 0xf2) {
|
|
|
|
|
isEnterprise = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for WAPI (Chinese standard)
|
|
|
|
|
else if (tag_id == 221 && tag_len >= 4 &&
|
|
|
|
|
tag_data[0] == 0x00 && tag_data[1] == 0x14 && tag_data[2] == 0x72 && tag_data[3] == 0x01) {
|
|
|
|
|
isWAPI = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i += 2 + tag_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decision tree
|
|
|
|
|
if (isWAPI) return WIFI_SECURITY_WAPI;
|
|
|
|
|
if (hasRSN && isWPA3) return WIFI_SECURITY_WPA3;
|
|
|
|
|
if (hasRSN && isEnterprise) return WIFI_SECURITY_WPA2_ENTERPRISE;
|
|
|
|
|
if (hasRSN && hasWPA) return WIFI_SECURITY_WPA_WPA2_MIXED;
|
|
|
|
|
if (hasRSN) return WIFI_SECURITY_WPA2;
|
|
|
|
|
if (hasWPA) return isEnterprise ? WIFI_SECURITY_WPA2_ENTERPRISE : WIFI_SECURITY_WPA;
|
|
|
|
|
|
|
|
|
|
// WEP is identified via capability flags
|
|
|
|
|
uint16_t capab_info = ((uint16_t)frame[34] << 8) | frame[35];
|
|
|
|
|
if (capab_info & 0x0010) return WIFI_SECURITY_WEP;
|
|
|
|
|
|
|
|
|
|
return WIFI_SECURITY_OPEN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WiFiScan::apSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
|
|
|
|
|
{
|
|
|
|
|
extern WiFiScan wifi_scan_obj;
|
|
|
|
|
@@ -3672,6 +3945,11 @@ void WiFiScan::apSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
|
|
|
|
|
essid = bssid;
|
|
|
|
|
Serial.print(essid + " ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get security info
|
|
|
|
|
uint8_t security_type = wifi_scan_obj.getSecurityType(snifferPacket->payload, snifferPacket->rx_ctrl.sig_len);
|
|
|
|
|
|
|
|
|
|
bool wps = wifi_scan_obj.beaconHasWPS(snifferPacket->payload, snifferPacket->rx_ctrl.sig_len);
|
|
|
|
|
|
|
|
|
|
AccessPoint ap = {essid,
|
|
|
|
|
snifferPacket->rx_ctrl.channel,
|
|
|
|
|
@@ -3685,7 +3963,9 @@ void WiFiScan::apSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
|
|
|
|
|
NULL,
|
|
|
|
|
snifferPacket->rx_ctrl.rssi,
|
|
|
|
|
new LinkedList<uint16_t>(),
|
|
|
|
|
0};
|
|
|
|
|
0,
|
|
|
|
|
security_type,
|
|
|
|
|
wps};
|
|
|
|
|
|
|
|
|
|
access_points->add(ap);
|
|
|
|
|
|
|
|
|
|
@@ -4189,6 +4469,25 @@ void WiFiScan::rawSnifferCallback(void* buf, wifi_promiscuous_pkt_type_t type)
|
|
|
|
|
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
|
|
|
|
|
const WifiMgmtHdr *hdr = &ipkt->hdr;
|
|
|
|
|
wifi_scan_obj.mgmt_frames++;
|
|
|
|
|
|
|
|
|
|
// Do our counts
|
|
|
|
|
if (snifferPacket->payload[0] == 0x40) // Probe request
|
|
|
|
|
wifi_scan_obj.req_frames++;
|
|
|
|
|
else if (snifferPacket->payload[0] == 0x50) // Probe response
|
|
|
|
|
wifi_scan_obj.resp_frames++;
|
|
|
|
|
else if (snifferPacket->payload[0] == 0x80) // Beacon
|
|
|
|
|
wifi_scan_obj.beacon_frames++;
|
|
|
|
|
else if (snifferPacket->payload[0] == 0xC0) // Deauth
|
|
|
|
|
wifi_scan_obj.deauth_frames++;
|
|
|
|
|
else if (((snifferPacket->payload[30] == 0x88 && snifferPacket->payload[31] == 0x8e) || ( snifferPacket->payload[32] == 0x88 && snifferPacket->payload[33] == 0x8e))) // eapol
|
|
|
|
|
wifi_scan_obj.eapol_frames++;
|
|
|
|
|
|
|
|
|
|
// Get min/max rssi
|
|
|
|
|
if (snifferPacket->rx_ctrl.rssi < wifi_scan_obj.min_rssi)
|
|
|
|
|
wifi_scan_obj.min_rssi = snifferPacket->rx_ctrl.rssi;
|
|
|
|
|
|
|
|
|
|
if (snifferPacket->rx_ctrl.rssi > wifi_scan_obj.max_rssi)
|
|
|
|
|
wifi_scan_obj.max_rssi = snifferPacket->rx_ctrl.rssi;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
wifi_scan_obj.data_frames++;
|
|
|
|
|
@@ -5799,19 +6098,32 @@ void WiFiScan::renderRawStats() {
|
|
|
|
|
|
|
|
|
|
display_obj.tft.println("Stats\n");
|
|
|
|
|
|
|
|
|
|
display_obj.tft.println("Mgmt: " + (String)this->mgmt_frames);
|
|
|
|
|
display_obj.tft.println("Data: " + (String)this->data_frames);
|
|
|
|
|
display_obj.tft.println("Chan: " + (String)this->set_channel);
|
|
|
|
|
display_obj.tft.println(" Mgmt: " + (String)this->mgmt_frames);
|
|
|
|
|
display_obj.tft.println(" Data: " + (String)this->data_frames);
|
|
|
|
|
display_obj.tft.println(" Channel: " + (String)this->set_channel);
|
|
|
|
|
display_obj.tft.println(" Beacon: " + (String)this->beacon_frames);
|
|
|
|
|
display_obj.tft.println("Probe Req: " + (String)this->req_frames);
|
|
|
|
|
display_obj.tft.println("Probe Res: " + (String)this->resp_frames);
|
|
|
|
|
display_obj.tft.println(" Deauth: " + (String)this->deauth_frames);
|
|
|
|
|
display_obj.tft.println(" EAPOL: " + (String)this->eapol_frames);
|
|
|
|
|
display_obj.tft.println(" RSSI: " + (String)this->min_rssi + " - " + (String)this->max_rssi);
|
|
|
|
|
|
|
|
|
|
Serial.println("Mgmt: " + (String)this->mgmt_frames);
|
|
|
|
|
Serial.println("Data: " + (String)this->data_frames);
|
|
|
|
|
Serial.println("Chan: " + (String)this->set_channel);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Serial.println(" Mgmt: " + (String)this->mgmt_frames);
|
|
|
|
|
Serial.println(" Data: " + (String)this->data_frames);
|
|
|
|
|
Serial.println(" Channel: " + (String)this->set_channel);
|
|
|
|
|
Serial.println(" Beacon: " + (String)this->beacon_frames);
|
|
|
|
|
Serial.println("Probe Req: " + (String)this->req_frames);
|
|
|
|
|
Serial.println("Probe Res: " + (String)this->resp_frames);
|
|
|
|
|
Serial.println(" Deauth: " + (String)this->deauth_frames);
|
|
|
|
|
Serial.println(" EAPOL: " + (String)this->eapol_frames);
|
|
|
|
|
Serial.println(" RSSI: " + (String)this->min_rssi + " - " + (String)this->max_rssi);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WiFiScan::renderPacketRate() {
|
|
|
|
|
uint8_t line_count = 0;
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
uint8_t line_count = 0;
|
|
|
|
|
display_obj.tft.fillRect(0,
|
|
|
|
|
(STATUS_BAR_WIDTH * 2) + 1 + EXT_BUTTON_WIDTH,
|
|
|
|
|
TFT_WIDTH,
|
|
|
|
|
@@ -5820,62 +6132,65 @@ void WiFiScan::renderPacketRate() {
|
|
|
|
|
display_obj.tft.setCursor(0, (STATUS_BAR_WIDTH * 2) + CHAR_WIDTH + EXT_BUTTON_WIDTH);
|
|
|
|
|
display_obj.tft.setTextSize(1);
|
|
|
|
|
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
|
|
|
|
for (int i = 0; i < access_points->size(); i++) {
|
|
|
|
|
if (access_points->get(i).selected) {
|
|
|
|
|
display_obj.tft.println(access_points->get(i).essid + ": " + (String)access_points->get(i).packets);
|
|
|
|
|
Serial.println(access_points->get(i).essid + ": " + (String)access_points->get(i).packets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < stations->size(); i++) {
|
|
|
|
|
if (stations->get(i).selected) {
|
|
|
|
|
display_obj.tft.println(macToString(stations->get(i).mac) + ": " + (String)stations->get(i).packets);
|
|
|
|
|
Serial.println(macToString(stations->get(i).mac) + ": " + (String)stations->get(i).packets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < access_points->size(); i++) {
|
|
|
|
|
if (access_points->get(i).selected) {
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
display_obj.tft.println(access_points->get(i).essid + ": " + (String)access_points->get(i).packets);
|
|
|
|
|
#endif
|
|
|
|
|
Serial.println(access_points->get(i).essid + ": " + (String)access_points->get(i).packets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < stations->size(); i++) {
|
|
|
|
|
if (stations->get(i).selected) {
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
display_obj.tft.println(macToString(stations->get(i).mac) + ": " + (String)stations->get(i).packets);
|
|
|
|
|
#endif
|
|
|
|
|
Serial.println(macToString(stations->get(i).mac) + ": " + (String)stations->get(i).packets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WiFiScan::packetRateLoop(uint32_t tick) {
|
|
|
|
|
#ifdef HAS_SCREEN
|
|
|
|
|
if (tick - this->initTime >= BANNER_TIME * 10) {
|
|
|
|
|
this->initTime = millis();
|
|
|
|
|
if (this->currentScanMode == WIFI_SCAN_PACKET_RATE)
|
|
|
|
|
this->renderPacketRate();
|
|
|
|
|
else if (this->currentScanMode == WIFI_SCAN_RAW_CAPTURE)
|
|
|
|
|
this->renderRawStats();
|
|
|
|
|
if (tick - this->initTime >= BANNER_TIME * 10) {
|
|
|
|
|
this->initTime = millis();
|
|
|
|
|
if (this->currentScanMode == WIFI_SCAN_PACKET_RATE)
|
|
|
|
|
this->renderPacketRate();
|
|
|
|
|
else if (this->currentScanMode == WIFI_SCAN_RAW_CAPTURE)
|
|
|
|
|
this->renderRawStats();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_ILI9341
|
|
|
|
|
int8_t b = this->checkAnalyzerButtons(millis());
|
|
|
|
|
|
|
|
|
|
if (b == 6) {
|
|
|
|
|
this->StartScan(WIFI_SCAN_OFF);
|
|
|
|
|
this->orient_display = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAS_ILI9341
|
|
|
|
|
int8_t b = this->checkAnalyzerButtons(millis());
|
|
|
|
|
|
|
|
|
|
if (b == 6) {
|
|
|
|
|
this->StartScan(WIFI_SCAN_OFF);
|
|
|
|
|
this->orient_display = true;
|
|
|
|
|
else if (b == 4) {
|
|
|
|
|
if (set_channel > 1) {
|
|
|
|
|
set_channel--;
|
|
|
|
|
display_obj.tftDrawChannelScaleButtons(set_channel, false);
|
|
|
|
|
display_obj.tftDrawExitScaleButtons(false);
|
|
|
|
|
changeChannel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (b == 4) {
|
|
|
|
|
if (set_channel > 1) {
|
|
|
|
|
set_channel--;
|
|
|
|
|
display_obj.tftDrawChannelScaleButtons(set_channel, false);
|
|
|
|
|
display_obj.tftDrawExitScaleButtons(false);
|
|
|
|
|
changeChannel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Channel + button pressed
|
|
|
|
|
else if (b == 5) {
|
|
|
|
|
if (set_channel < MAX_CHANNEL) {
|
|
|
|
|
set_channel++;
|
|
|
|
|
display_obj.tftDrawChannelScaleButtons(set_channel, false);
|
|
|
|
|
display_obj.tftDrawExitScaleButtons(false);
|
|
|
|
|
changeChannel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Channel + button pressed
|
|
|
|
|
else if (b == 5) {
|
|
|
|
|
if (set_channel < MAX_CHANNEL) {
|
|
|
|
|
set_channel++;
|
|
|
|
|
display_obj.tftDrawChannelScaleButtons(set_channel, false);
|
|
|
|
|
display_obj.tftDrawExitScaleButtons(false);
|
|
|
|
|
changeChannel();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|