Skip to content

Heap-Buffer-Overflow in TelnetLayer::getSubCommand() #2152

Description

@TYGLS

Bug description

Describe the bug

An out-of-bounds read vulnerability exists in the Telnet protocol parsing module of PcapPlusPlus. When processing truncated and malformed Telnet subnegotiation packets, the getSubCommand function accesses memory at offset 2 without rigorous buffer length verification. This invalid heap memory access triggers heap buffer overflow read error, which can cause program crash and lead to denial of service attack risk.

Cause

The function accesses pos[2] without validating sufficient buffer length (TelnetLayer.cpp:206-211):

int16_t TelnetLayer::getSubCommand(uint8_t* pos, size_t len)
{
    if (len < 3 || pos[1] < static_cast<int>(TelnetCommand::Subnegotiation))
        return TelnetOptionNoOption;
    return pos[2]; // line 210: OUT-OF-BOUNDS READ
}

When a truncated Telnet packet is parsed:

  • len is 1 or 2
  • The condition len < 3 is not properly enforced
  • The code reads pos[2] out of bounds

To Reproduce
Steps to reproduce the behavior:

  1. 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'
  1. Run the PoC using FuzzTarget:

poc.zip

The PoC is provided as a zip archive. After extracting, run:

./FuzzTarget ./poc

ASAN Report

~/fuzz$ ./fuzzers/FuzzTarget ./crashes/poc 
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 3766770891
./fuzzers/FuzzTarget: Running 1 inputs 1 time(s) each.
Running: ./crashes/poc
Read 0 packets successfully and 0 packets could not be read
Ethernet II Layer, Src: 00:00:c0:9f:a0:97, Dst: 00:a0:cc:3b:bf:fa
IPv4 Layer, Src: 192.168.0.1, Dst: 192.168.0.2
TCP Layer, [ACK], Src port: 23, Dst port: 1550
Telnet Control
Telnet command is 'Will Perform'
Telnet option is 'Suppress Go Ahead'
Telnet command is 'Do Perform'
Telnet option is 'Terminal Type'
Telnet command is 'Do Perform'
Telnet option is 'Negotiate About Window Size'
Telnet command is 'Do Perform'
Telnet option is 'Terminal Speed'
Telnet command is 'Do Perform'
Telnet option is 'Remote Flow Control'
Telnet command is 'Do Perform'
Telnet option is 'Line mode'
Telnet command is 'Subnegotiation'
Telnet option is 'Line mode'
Telnet command is 'Subnegotiation End'
Telnet option is 'No option for this command'
Telnet command is 'Reached end of packet while parsing'
Telnet option is 'No option for this command'
Ethernet II Layer, Src: 00:00:c0:9f:a0:97, Dst: 00:a0:cc:3b:bf:fa
IPv4 Layer, Src: 192.168.0.1, Dst: 192.168.0.2
TCP Layer, [ACK], Src port: 23, Dst port: 1550
Telnet Data
Telnet command is 'Will Perform'
Telnet option is 'Suppress Go Ahead'
Telnet command is 'Do Perform'
Telnet option is 'Terminal Type'
Telnet command is 'Do Perform'
=================================================================
==3543760==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50b000001b72 at pc 0x5634e6576295 bp 0x7fff743f1350 sp 0x7fff743f1348
READ of size 1 at 0x50b000001b72 thread T0
    #0 0x5634e6576294 in pcpp::TelnetLayer::getSubCommand(unsigned char*, unsigned long) /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/TelnetLayer.cpp:210:10
    #1 0x5634e6576294 in pcpp::TelnetLayer::getOption() /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/TelnetLayer.cpp:349:37
    #2 0x5634e6405831 in readParsedPacket(pcpp::Packet, pcpp::Layer*) /home/hexijie/fuzz/project/PcapPlusPlus/Tests/Fuzzers/ReadParsedPacket.h:42:59
    #3 0x5634e64048e9 in LLVMFuzzerTestOneInput /home/hexijie/fuzz/project/PcapPlusPlus/Tests/Fuzzers/FuzzTarget.cpp:66:5
    #4 0x5634e630f0c4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x1160c4) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #5 0x5634e62f81f6 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0xff1f6) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #6 0x5634e62fdcaa in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x104caa) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #7 0x5634e6328466 in main (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x12f466) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #8 0x7f6534c2a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #9 0x7f6534c2a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #10 0x5634e62f2dc4 in _start (/home/hexijie/fuzz/fuzzers/FuzzTarget+0xf9dc4) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)

0x50b000001b72 is located 0 bytes after 98-byte region [0x50b000001b10,0x50b000001b72)
allocated by thread T0 here:
    #0 0x5634e6401911 in operator new[](unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x208911) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #1 0x5634e6411002 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 0x5634e6411002 in pcpp::PcapFileReaderDevice::getNextPacket(pcpp::RawPacket&) /home/hexijie/fuzz/project/PcapPlusPlus/Pcap++/src/PcapFileDevice.cpp:475:23
    #3 0x5634e64049b4 in LLVMFuzzerTestOneInput /home/hexijie/fuzz/project/PcapPlusPlus/Tests/Fuzzers/FuzzTarget.cpp:71:19
    #4 0x5634e630f0c4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x1160c4) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #5 0x5634e62f81f6 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0xff1f6) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #6 0x5634e62fdcaa in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x104caa) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #7 0x5634e6328466 in main (/home/hexijie/fuzz/fuzzers/FuzzTarget+0x12f466) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)
    #8 0x7f6534c2a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #9 0x7f6534c2a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #10 0x5634e62f2dc4 in _start (/home/hexijie/fuzz/fuzzers/FuzzTarget+0xf9dc4) (BuildId: a4a415ba67789b2d8c736acb1b373274c76440c3)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/hexijie/fuzz/project/PcapPlusPlus/Packet++/src/TelnetLayer.cpp:210:10 in pcpp::TelnetLayer::getSubCommand(unsigned char*, unsigned long)
Shadow bytes around the buggy address:
  0x50b000001880: 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
  0x50b000001900: fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa
  0x50b000001980: fa fa fa fa fa fa fd fd fd fd fd fd fd fd fd fd
  0x50b000001a00: fd fd fd fa fa fa fa fa fa fa fa fa fd fd fd fd
  0x50b000001a80: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa
=>0x50b000001b00: fa fa 00 00 00 00 00 00 00 00 00 00 00 00[02]fa
  0x50b000001b80: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x50b000001c00: fd fd fd fd fd fa fa fa fa fa fa fa fa fa fd fd
  0x50b000001c80: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x50b000001d00: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
  0x50b000001d80: fd fa fa fa fa fa fa fa fa fa 00 00 00 00 00 00
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
==3543760==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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions