Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heap-buffer-overflow in LIEF::MachO::BinaryParser::parse_dyldinfo_generic_bind at MachO/BinaryParser.tcc:1629 #782

Closed
bladchan opened this issue Sep 11, 2022 · 0 comments
Assignees

Comments

@bladchan
Copy link

Describe the bug
A bad macho file which can lead LIEF::MachO::Parser::parse() to a heap-buffer-overflow(read) issue.
Poc here :
poc1.zip

To Reproduce

  1. Build the whole project with ASAN
  2. Drive program (compile it with ASAN too):
// read_mecho.c
#include <LIEF/LIEF.hpp>

int main(int argc, char** argv){
	
	if(argc != 2) return 0;

	try {
	    std::unique_ptr<LIEF::MachO::FatBinary> macho = LIEF::MachO::Parser::parse(argv[1]);
	} catch (const LIEF::exception& err) {
	    std::cerr << err.what() << std::endl;
	}

	return 0;
}
  1. Run Poc:
$ ./read_macho ./poc1.bin

Expected behavior
The code snippet where the issue happened should avoid the out-bounds read operation.

Environment (please complete the following information):

  • System and Version : Ubuntu 20.04 + gcc 9.4.0
  • Target format : Mach-O
  • LIEF commit version: ad81191

Additional context
ASAN says:

ubuntu@ubuntu:~/test/LIEF/fuzz$ ./read_macho poc1.bin
nlist[0].str_idx seems corrupted (0xaf000000)
nlist[1].str_idx seems corrupted (0xaf000000)
......
nlist[355].str_idx seems corrupted (0x3d000001)
Indirect symbol index is out of range (1493172225 vs max sym: 356)
Wrong index: 4
Wrong index: 4
Wrong index: 4
Wrong index: 4
Wrong index: 4
Wrong index: 4
Wrong index: 4
Wrong index: 4
Wrong index: 4
=================================================================
==502744==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000000420 at pc 0x55b43d8d9b42 bp 0x7ffe61a9cf10 sp 0x7ffe61a9cf00
READ of size 8 at 0x603000000420 thread T0
    #0 0x55b43d8d9b41 in std::enable_if<std::is_pointer<LIEF::MachO::SegmentCommand*>::value, LIEF::MachO::SegmentCommand&>::type LIEF::ref_iterator<std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> >&, LIEF::MachO::SegmentCommand*, __gnu_cxx::__normal_iterator<LIEF::MachO::SegmentCommand**, std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> > > >::operator*<LIEF::MachO::SegmentCommand*>() const /home/ubuntu/test/LIEF/include/LIEF/iterators.hpp:233
    #1 0x55b43d8bf315 in LIEF::ref_iterator<std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> >&, LIEF::MachO::SegmentCommand*, __gnu_cxx::__normal_iterator<LIEF::MachO::SegmentCommand**, std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> > > >::operator*() /home/ubuntu/test/LIEF/include/LIEF/iterators.hpp:226
    #2 0x55b43d892a91 in LIEF::ref_iterator<std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> >&, LIEF::MachO::SegmentCommand*, __gnu_cxx::__normal_iterator<LIEF::MachO::SegmentCommand**, std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> > > >::operator[](unsigned long) const /home/ubuntu/test/LIEF/include/LIEF/iterators.hpp:146
    #3 0x55b43d858628 in LIEF::ref_iterator<std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> >&, LIEF::MachO::SegmentCommand*, __gnu_cxx::__normal_iterator<LIEF::MachO::SegmentCommand**, std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> > > >::operator[](unsigned long) /home/ubuntu/test/LIEF/include/LIEF/iterators.hpp:133
    #4 0x55b43d8644a2 in boost::leaf::result<LIEF::ok_t> LIEF::MachO::BinaryParser::parse_dyldinfo_generic_bind<LIEF::MachO::details::MachO32>() /home/ubuntu/test/LIEF/src/MachO/BinaryParser.tcc:1629
    #5 0x55b43d831a79 in boost::leaf::result<LIEF::ok_t> LIEF::MachO::BinaryParser::parse_dyldinfo_binds<LIEF::MachO::details::MachO32>() /home/ubuntu/test/LIEF/src/MachO/BinaryParser.tcc:1357
    #6 0x55b43d801735 in boost::leaf::result<LIEF::ok_t> LIEF::MachO::BinaryParser::parse<LIEF::MachO::details::MachO32>() /home/ubuntu/test/LIEF/src/MachO/BinaryParser.tcc:113
    #7 0x55b43d7f2348 in LIEF::MachO::BinaryParser::init_and_parse() /home/ubuntu/test/LIEF/src/MachO/BinaryParser.cpp:145
    #8 0x55b43d7f1ab0 in LIEF::MachO::BinaryParser::parse(std::unique_ptr<LIEF::BinaryStream, std::default_delete<LIEF::BinaryStream> >, unsigned long, LIEF::MachO::ParserConfig const&) /home/ubuntu/test/LIEF/src/MachO/BinaryParser.cpp:125
    #9 0x55b43d07bc01 in LIEF::MachO::Parser::build() /home/ubuntu/test/LIEF/src/MachO/Parser.cpp:174
    #10 0x55b43d078995 in LIEF::MachO::Parser::parse(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, LIEF::MachO::ParserConfig const&) /home/ubuntu/test/LIEF/src/MachO/Parser.cpp:64
    #11 0x55b43cee3923 in main /home/ubuntu/test/LIEF/fuzz/read_macho.c:8
    #12 0x7f2be6489082 in __libc_start_main ../csu/libc-start.c:308
    #13 0x55b43cee355d in _start (/home/ubuntu/test/LIEF/fuzz/read_macho+0x33055d)

0x603000000420 is located 0 bytes to the right of 32-byte region [0x603000000400,0x603000000420)
allocated by thread T0 here:
    #0 0x7f2be6ab2587 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cc:104
    #1 0x55b43d7d7c50 in __gnu_cxx::new_allocator<LIEF::MachO::SegmentCommand*>::allocate(unsigned long, void const*) /usr/include/c++/9/ext/new_allocator.h:114
    #2 0xfffcc353843  (<unknown module>)
    #3 0x7ffe61a9deef  ([stack]+0x1deef)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ubuntu/test/LIEF/include/LIEF/iterators.hpp:233 in std::enable_if<std::is_pointer<LIEF::MachO::SegmentCommand*>::value, LIEF::MachO::SegmentCommand&>::type LIEF::ref_iterator<std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> >&, LIEF::MachO::SegmentCommand*, __gnu_cxx::__normal_iterator<LIEF::MachO::SegmentCommand**, std::vector<LIEF::MachO::SegmentCommand*, std::allocator<LIEF::MachO::SegmentCommand*> > > >::operator*<LIEF::MachO::SegmentCommand*>() const
Shadow bytes around the buggy address:
  0x0c067fff8030: fa fa 00 00 01 fa fa fa 00 00 01 fa fa fa fd fd
  0x0c067fff8040: fd fd fa fa fd fd fd fd fa fa 00 00 01 fa fa fa
  0x0c067fff8050: 00 00 01 fa fa fa 00 00 01 fa fa fa 00 00 01 fa
  0x0c067fff8060: fa fa 00 00 01 fa fa fa 00 00 01 fa fa fa 00 00
  0x0c067fff8070: 01 fa fa fa 00 00 01 fa fa fa 00 00 01 fa fa fa
=>0x0c067fff8080: 00 00 00 00[fa]fa 00 00 01 fa fa fa 00 00 01 fa
  0x0c067fff8090: fa fa 00 00 01 fa fa fa 00 00 01 fa fa fa 00 00
  0x0c067fff80a0: 01 fa fa fa 00 00 01 fa fa fa fd fd fd fd fa fa
  0x0c067fff80b0: 00 00 01 fa fa fa 00 00 01 fa fa fa 00 00 01 fa
  0x0c067fff80c0: fa fa 00 00 01 fa fa fa 00 00 01 fa fa fa 00 00
  0x0c067fff80d0: 01 fa fa fa 00 00 01 fa fa fa 00 00 01 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
  Shadow gap:              cc
==502744==ABORTING
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants