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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions