Bug description
Describe the bug
A heap-buffer-overflow read vulnerability exists in the Modbus protocol parsing module of PcapPlusPlus. The vulnerability occurs when parsing malformed, truncated Modbus packets with insufficient payload length.
Several getter functions in ModbusLayer.cpp directly access Modbus header fields without validating the actual packet data length. A specially crafted short packet can trigger an out-of-bounds memory read, causing program crash (DoS).
File: Packet++/src/ModbusLayer.cpp
Function: ModbusLayer::getLength() (Line 45)
Cause
The standard Modbus TCP header requires at least 6 bytes to read the length field. However, the current implementation does not check m_DataLen before accessing header fields:
getTransactionId() requires 2 bytes
getProtocolId() requires 4 bytes
getLength() requires 6 bytes
Feeding a truncated packet shorter than 6 bytes leads to heap out-of-bounds read and ASan abort.
To Reproduce
Steps to reproduce the behavior:
- Clone the pcapplusplus repository and build it refer to oss-fuzz.
export CC=clang \
CXX=clang++ \
CFLAGS='-fsanitize=address -O0 -g' \
CXXFLAGS='-fsanitize=address -O0 -g' \
LIB_FUZZING_ENGINE='-fsanitize=fuzzer'
- Run the PoC using FuzzTarget:
poc.zip
The PoC is provided as a zip archive. After extracting, run:
ASAN Report
~/fuzz$ ./fuzzers/FuzzTarget ./crashes/poc
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 2210324020
./fuzzers/FuzzTarget: Running 1 inputs 1 time(s) each.
Running: ./crashes/poc
Read 0 packets successfully and 0 packets could not be read
=================================================================
==230375==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50700000030e at pc 0x55cabead5d47 bp 0x7ffc977568d0 sp 0x7ffc977568c8
READ of size 2 at 0x50700000030e thread T0
#0 0x55cabead5d46 in pcpp::ModbusLayer::getLength() const /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/ModbusLayer.cpp:45:10
#1 0x55cabead5d46 in pcpp::ModbusLayer::toString[abi:cxx11]() const /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/ModbusLayer.cpp:98:94
#2 0x55cabe939f70 in pcpp::Packet::toStringList(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, bool) const /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/Packet.cpp:942:31
#3 0x55cabe93922b in pcpp::Packet::toString[abi:cxx11](bool) const /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/Packet.cpp:930:3
#4 0x55cabe8696f6 in LLVMFuzzerTestOneInput /home/hexijie/fuzz/project/PcapPlusPlus/Tests/Fuzzers/FuzzTarget.cpp:60:17
#5 0x55cabe7740c4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x1160c4) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
#6 0x55cabe75d1f6 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0xff1f6) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
#7 0x55cabe762caa in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x104caa) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
#8 0x55cabe78d466 in main (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x12f466) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
#9 0x7f3fa422a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#10 0x7f3fa422a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#11 0x55cabe757dc4 in _start (/home/hexijie/fuzz/fuzzers/FuzzTarget+0xf9dc4) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
0x50700000030e is located 0 bytes after 78-byte region [0x5070000002c0,0x50700000030e)
allocated by thread T0 here:
#0 0x55cabe866911 in operator new[](unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x208911) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
#1 0x55cabe876002 in std::__detail::_MakeUniq<unsigned char []>::__array std::make_unique<unsigned char []>(unsigned long) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/unique_ptr.h:1085:30
#2 0x55cabe876002 in pcpp::PcapFileReaderDevice::getNextPacket(pcpp::RawPacket&) /home/hexijie/fuzz/project/PcapPlusPlus/Pcap++/src/PcapFileDevice.cpp:475:23
#3 0x55cabe87340a in pcpp::IFileReaderDevice::getNextPackets(pcpp::PointerVector<pcpp::RawPacket, std::default_delete<pcpp::RawPacket>>&, int) /home/hexijie/fuzz/project/PcapPlusPlus/Pcap++/src/PcapFileDevice.cpp:285:22
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/ModbusLayer.cpp:45:10 in pcpp::ModbusLayer::getLength() const
Shadow bytes around the buggy address:
0x507000000080: fa fa fd fd fd fd fd fd fd fd fd fd fa fa fa fa
0x507000000100: 00 00 00 00 00 00 00 00 05 fa fa fa fa fa 00 00
0x507000000180: 00 00 00 00 00 00 00 02 fa fa fa fa fd fd fd fd
0x507000000200: fd fd fd fd fd fa fa fa fa fa 00 00 00 00 00 00
0x507000000280: 00 00 07 fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x507000000300: 00[06]fa fa fa fa 00 00 00 00 00 00 00 00 05 fa
0x507000000380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x507000000400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x507000000480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x507000000500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x507000000580: 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
==230375==ABORTING
PcapPlusPlus versions tested on
v25.05
Other PcapPlusPlus version (if applicable)
No response
Operating systems tested on
Linux
Other operation systems (if applicable)
No response
Compiler version
Ubuntu clang version 18.1.3 (1ubuntu1)
Packet capture backend (if applicable)
No response
Bug description
Describe the bug
A heap-buffer-overflow read vulnerability exists in the Modbus protocol parsing module of PcapPlusPlus. The vulnerability occurs when parsing malformed, truncated Modbus packets with insufficient payload length.
Several getter functions in
ModbusLayer.cppdirectly access Modbus header fields without validating the actual packet data length. A specially crafted short packet can trigger an out-of-bounds memory read, causing program crash (DoS).File:
Packet++/src/ModbusLayer.cppFunction:
ModbusLayer::getLength()(Line 45)Cause
The standard Modbus TCP header requires at least 6 bytes to read the
lengthfield. However, the current implementation does not checkm_DataLenbefore accessing header fields:getTransactionId()requires 2 bytesgetProtocolId()requires 4 bytesgetLength()requires 6 bytesFeeding a truncated packet shorter than 6 bytes leads to heap out-of-bounds read and ASan abort.
To Reproduce
Steps to reproduce the behavior:
poc.zip
The PoC is provided as a zip archive. After extracting, run:
ASAN Report
PcapPlusPlus versions tested on
v25.05
Other PcapPlusPlus version (if applicable)
No response
Operating systems tested on
Linux
Other operation systems (if applicable)
No response
Compiler version
Ubuntu clang version 18.1.3 (1ubuntu1)
Packet capture backend (if applicable)
No response