Skip to content

Potential out-of-bounds read in CPF parsing logic (Heap-Overflow) #558

@InvincibleMadman

Description

@InvincibleMadman

OpENer version

OpENer v2.3-558-g1e99582

Commit

1e99582227c86cbdc7c86caeb7ba04c56134d174

OS and/or distribution

Ubuntu 24.04.5

Environment

Build type:

  • non-ASan debug build for GDB reproduction
  • ASan-instrumented build for sanitizer verification

Description

An out-of-bounds read vulnerability was found in OpENer in the CPF parsing logic, specifically in:

  • CreateCommonPacketFormatStructure()
  • source/src/enet_encap/cpf.c

The issue is caused by trusting an attacker-controlled CPF item_count value without consistently validating subsequent reads against the provided data_length.

During debugging, the CPF parser was entered with a 16-byte CPF slice, but the first two bytes:

01 e8

were parsed as:

item_count = 0xe801

As a result, the parser continued processing structured fields after data had already reached cpf_start + data_length, leading to an out-of-bounds read.

Relevant code region:

size_t length_count = 0;
CipUint item_count = GetUintFromMessage(&data);
// OPENER_ASSERT(4U >= item_count); /* Sanitizing data - probably needs to be changed for productive code */
common_packet_format_data->item_count = item_count;
...
for(size_t j = 0; j < (address_item_count > 2 ? 2 : address_item_count); j++) /* TODO there needs to be a limit check here???*/
{
  common_packet_format_data->address_info_item[j].type_id =
    GetIntFromMessage(&data);

Actual behavior if applicable

  • ASan build reports a heap-buffer-overflow
  • In a non-ASan debug build, GDB shows that parsing continues even when:
    data == cpf_start + data_length
  • The first invalid read is observed around:
    source/src/enet_encap/cpf.c:280

Expected behavior or suggestion

The parser should reject malformed CPF data and stop parsing before any read that would advance beyond the provided data_length.

Steps to reproduce

1.Complie with afl-gcc/afl-g++:

cd bin/posix
###afl
CC=afl-gcc \
CXX=afl-g++ \
cmake  \
 -DOpENer_PLATFORM=POSIX \
 -DUSE_FUZZ_AFL=ON \
 -DBUILD_SHARED_LIBS=OFF \
 ../../source

make -j"$(nproc)" OpENer_afl

###asan
AFL_USE_ASAN=1 \
CC=afl-gcc \
CXX=afl-g++ \
cmake \
 -DOpENer_PLATFORM=POSIX \
 -DUSE_FUZZ_AFL=ON \
 -DBUILD_SHARED_LIBS=OFF \
 -DCMAKE_BUILD_TYPE=RelWithDebInfo \
 -DCMAKE_C_FLAGS="-O1 -g -fno-omit-frame-pointer" \
 -DCMAKE_CXX_FLAGS="-O1 -g -fno-omit-frame-pointer" \
 ../../source

make -j"$(nproc)" OpENer_afl_asan

2.Then using inputs:

./OpENer_afl < poc.bin
./OpENer_afl_asan < poc.bin

POC File

POC.zip

GDB output

Breakpoint 6, NotifyCommonPacketFormat (...) at /root/OpENer/source/src/enet_encap/cpf.c:42

(gdb) p/x $cpf_start
$13 = 0x50e92e
(gdb) p $cpf_len
$14 = 16
(gdb) p/x $cpf_end
$15 = 0x50e93e
(gdb) p (long)($cpf_end - $cpf_start)
$16 = 16

(gdb) x/16bx $cpf_start
0x50e92e:  0x01  0xe8  0x00  0x00  0x00  0x00  0xb2  0x00
0x50e936:  0x06  0x00  0x04  0x02  0x20  0x01  0x24  0x01

(gdb) next
245   common_packet_format_data->item_count = item_count;
(gdb) p item_count
$17 = 59393
(gdb) p/x item_count
$18 = 0xe801

(gdb) rwatch *$cpf_end
Hardware read watchpoint 7: *$cpf_end
(gdb) continue

Hardware read watchpoint 7: *$cpf_end

CreateCommonPacketFormatStructure (data=0x50e93e "", data_length=16, ...)
    at /root/OpENer/source/src/enet_encap/cpf.c:280

(gdb) bt
#0  CreateCommonPacketFormatStructure (...) at /root/OpENer/source/src/enet_encap/cpf.c:280
#1  NotifyCommonPacketFormat (...) at /root/OpENer/source/src/enet_encap/cpf.c:46
#2  HandleReceivedSendRequestResponseDataCommand (...) at /root/OpENer/source/src/enet_encap/encap.c:558
#3  HandleReceivedExplictTcpData (...) at /root/OpENer/source/src/enet_encap/encap.c:186

(gdb) info locals
length_count = 16
item_count = 59393

ASAN output

=================================================================
==14630==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5060000000bc at pc 0x61b74ecb235c bp 0x7ffe079445f0 sp 0x7ffe079445e8
READ of size 1 at 0x5060000000bc thread T0
    #0 0x61b74ecb235b in CreateCommonPacketFormatStructure /root/OpENer/source/src/enet_encap/cpf.c:298:75
    #1 0x61b74ecb0629 in NotifyCommonPacketFormat /root/OpENer/source/src/enet_encap/cpf.c:46:12
    #2 0x61b74ecb62c7 in HandleReceivedSendRequestResponseDataCommand /root/OpENer/source/src/enet_encap/encap.c:558:22
    #3 0x61b74ecb62c7 in HandleReceivedExplictTcpData /root/OpENer/source/src/enet_encap/encap.c:186:26
    #4 0x61b74ec75bc2 in CallTcp /root/OpENer/source/src/ports/POSIX/OpENer_afl.c:163:8
    #5 0x61b74ec75bc2 in ExecuteFallbackSinglePacket /root/OpENer/source/src/ports/POSIX/OpENer_afl.c:497:9
    #6 0x61b74ec75bc2 in main /root/OpENer/source/src/ports/POSIX/OpENer_afl.c:515:5
    #7 0x7cbf3522a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #8 0x7cbf3522a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #9 0x61b74eb92a94 in _start (/home/ivcm/OpENer/poc/OpENer_afl_asan+0x70a94) (BuildId: d74ed6c3acba79ce)

0x5060000000bc is located 0 bytes after 60-byte region [0x506000000080,0x5060000000bc)
allocated by thread T0 here:
    #0 0x61b74ec2d8e3 in malloc (/home/ivcm/OpENer/poc/OpENer_afl_asan+0x10b8e3) (BuildId: d74ed6c3acba79ce)
    #1 0x61b74ec75a8a in CallTcp /root/OpENer/source/src/ports/POSIX/OpENer_afl.c:154:28
    #2 0x61b74ec75a8a in ExecuteFallbackSinglePacket /root/OpENer/source/src/ports/POSIX/OpENer_afl.c:497:9
    #3 0x61b74ec75a8a in main /root/OpENer/source/src/ports/POSIX/OpENer_afl.c:515:5
    #4 0x7cbf3522a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #5 0x7cbf3522a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #6 0x61b74eb92a94 in _start (/home/ivcm/OpENer/poc/OpENer_afl_asan+0x70a94) (BuildId: d74ed6c3acba79ce)

SUMMARY: AddressSanitizer: heap-buffer-overflow /root/OpENer/source/src/enet_encap/cpf.c:298:75 in CreateCommonPacketFormatStructure
Shadow bytes around the buggy address:
  0x505ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x505ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x505fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x505fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x506000000000: fa fa fa fa 00 00 00 00 00 00 04 fa fa fa fa fa
=>0x506000000080: 00 00 00 00 00 00 00[04]fa fa fa fa fa fa fa fa
  0x506000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x506000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x506000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x506000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x506000000300: 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
==14630==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions