Skip to content

Buffer-overflow (out-of-bounds read) occured in two positions #95

Description

@bladchan

Hi,

I am running some experiments for AFLAPI and it has found two buffer-overflows (read) in cparse::packToken::str[abi:cxx11] and cparse::calculator::toRPN.

Environment: Ubuntu 18.04 + clang 6.0.0

Poc 1:

// heap_overflow_1.cc
#include "shunting-yard.h"

using namespace cparse;

int main(){
	TokenMap vars;
	calculator::calculate("C'\\", &vars);
}

Poc 2

// heap_overflow_2.cc
#include "shunting-yard.h"

using namespace cparse;

int main(){
	TokenMap vars;
	vars["pi"] = 1535;	
calculator::calculate("7pi~pp\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\u0005\x84ipp\u0005?", &vars);
}

Files are here:
heap_overflow_files.zip

To reproduce:

  1. Complie the pocs and the whole project with ASAN;
  2. Run pocs

For Poc1, ASAN says:

$ ./heap_overflow_1 
=================================================================
==28967==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000005e7b64 at pc 0x000000540fac bp 0x7ffecd066850 sp 0x7ffecd066848
READ of size 1 at 0x0000005e7b64 thread T0
    #0 0x540fab in cparse::calculator::toRPN(char const*, cparse::TokenMap, char const*, char const**, cparse::Config_t) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:359:14
    #1 0x54cd52 in cparse::calculator::calculate(char const*, cparse::TokenMap, char const*, char const**) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:512:27
    #2 0x518a1a in main /home/ubuntu/some_c_test/cparse/fuzz/heap_overflow_1.cc:7:2
    #3 0x7f7132a53c86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310
    #4 0x41bf89 in _start (/home/ubuntu/some_c_test/cparse/fuzz/heap_overflow_1+0x41bf89)

0x0000005e7b64 is located 0 bytes to the right of global variable '<string literal>' defined in 'heap_overflow_1.cc:7:24' (0x5e7b60) of size 4
  '<string literal>' is ascii string 'C'\'
SUMMARY: AddressSanitizer: global-buffer-overflow /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:359:14 in cparse::calculator::toRPN(char const*, cparse::TokenMap, char const*, char const**, cparse::Config_t)
Shadow bytes around the buggy address:
  0x0000800b4f10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4f20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4f30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4f40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4f50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0000800b4f60: 00 00 00 00 00 00 00 00 00 00 00 00[04]f9 f9 f9
  0x0000800b4f70: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4f90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800b4fb0: 00 00 00 00 00 00 00 00 00 00 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
==28967==ABORTING

For poc2, ASAN says:

$ ./heap_overflow_2
=================================================================
==31104==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000208 at pc 0x00000058b95e bp 0x7ffdc41d0710 sp 0x7ffdc41d0708
READ of size 8 at 0x603000000208 thread T0
    #0 0x58b95d in cparse::packToken::str[abi:cxx11](unsigned int) const /home/ubuntu/some_c_test/cparse/packToken.cpp:200:25
    #1 0x58b95d in cparse::packToken::str[abi:cxx11](cparse::TokenBase const*, unsigned int) /home/ubuntu/some_c_test/cparse/packToken.cpp:218
    #2 0x52bc86 in cparse::rpnBuilder::handle_token(cparse::TokenBase*) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:220:69
    #3 0x536221 in cparse::calculator::toRPN(char const*, cparse::TokenMap, char const*, char const**, cparse::Config_t) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:346:16
    #4 0x54cc32 in cparse::calculator::calculate(char const*, cparse::TokenMap, char const*, char const**) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:512:27
    #5 0x518c85 in main /home/ubuntu/some_c_test/cparse/fuzz/heap_overflow_2.cc:7:21
    #6 0x7fae23be5c86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310
    #7 0x41bf89 in _start (/home/ubuntu/some_c_test/cparse/fuzz/heap_overflow_2+0x41bf89)

0x603000000208 is located 0 bytes to the right of 24-byte region [0x6030000001f0,0x603000000208)
allocated by thread T0 here:
    #0 0x5143f0 in operator new(unsigned long) (/home/ubuntu/some_c_test/cparse/fuzz/heap_overflow_2+0x5143f0)
    #1 0x51c7b5 in cparse::Token<long>::clone() const /home/ubuntu/some_c_test/cparse/fuzz/../shunting-yard.h:74:12
    #2 0x52bc86 in cparse::rpnBuilder::handle_token(cparse::TokenBase*) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:220:69
    #3 0x536221 in cparse::calculator::toRPN(char const*, cparse::TokenMap, char const*, char const**, cparse::Config_t) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:346:16
    #4 0x54cc32 in cparse::calculator::calculate(char const*, cparse::TokenMap, char const*, char const**) /home/ubuntu/some_c_test/cparse/shunting-yard.cpp:512:27
    #5 0x518c85 in main /home/ubuntu/some_c_test/cparse/fuzz/heap_overflow_2.cc:7:21
    #6 0x7fae23be5c86 in __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:310

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ubuntu/some_c_test/cparse/packToken.cpp:200:25 in cparse::packToken::str[abi:cxx11](unsigned int) const
Shadow bytes around the buggy address:
  0x0c067fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c067fff8000: fa fa fd fd fd fd fa fa 00 00 00 00 fa fa fd fd
  0x0c067fff8010: fd fd fa fa 00 00 00 00 fa fa fd fd fd fa fa fa
  0x0c067fff8020: 00 00 00 fa fa fa fd fd fd fd fa fa 00 00 00 00
  0x0c067fff8030: fa fa 00 00 00 fa fa fa 00 00 00 fa fa fa 00 00
=>0x0c067fff8040: 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fff8090: 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
==31104==ABORTING

Notes that for normal using, it seems that usage above won't happen. However for library's robustness, I report these bugs here.
Hope that helps. 😄

Metadata

Metadata

Assignees

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