tfussell / xlnt

:bar_chart: Cross-platform user-friendly xlsx library for C++11+
Other
1.47k stars 409 forks source link

Integer Overflow in compound_document::read_sector leads to Heap Buffer Overflow #626

Open kobrineli opened 2 years ago

kobrineli commented 2 years ago

Hi! I've been fuzzing your projects and found an input, that leads to integer overflow and source/detail/cryptography/compound_document.cpp:591. Executing with this input leads to later heap buffer overflow in /xlnt/source/detail/cryptography/compound_document.cpp:975.

Steps for reproducing:

  1. Build docker container for xlnt from https://github.com/ispras/oss-sydr-fuzz/tree/master/projects/xlnt
  2. Run docker container and execute /load_fuzzer overflow_input.txt with this input: crash-sydr_dfe5d3280e194d75ab9efc14ba3a679e304690a2_int_overflow_6_unsigned.txt

You will see something like this:

    /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/ext/new_allocator.h:147:27: runtime error: implicit conversion from type 'char' of value -48 (8-bit, signed) to type 'unsigned char' changed the value to 208 (8-bit, unsigned)
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/ext/new_allocator.h:147:27 in 
    /xlnt/source/detail/cryptography/compound_document.cpp:532:40: runtime error: shift exponent 201 is too large for 64-bit type 'std::size_t' (aka 'unsigned long')
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /xlnt/source/detail/cryptography/compound_document.cpp:532:40 in 
    /xlnt/source/detail/cryptography/compound_document.cpp:591:80: runtime error: unsigned integer overflow: 512 * 18446744073709551615 cannot be represented in type 'unsigned long'
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /xlnt/source/detail/cryptography/compound_document.cpp:591:80 in 
    /xlnt/source/detail/cryptography/compound_document.cpp:591:64: runtime error: unsigned integer overflow: 512 + 18446744073709551104 cannot be represented in type 'unsigned long'
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /xlnt/source/detail/cryptography/compound_document.cpp:591:64 in 
    =================================================================
    ==17==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x615000002380 at pc 0x0000004dafd7 bp 0x7fffffffb8b0 sp 0x7fffffffb078
    READ of size 128 at 0x615000002380 thread T0
        #0 0x4dafd6 in __asan_memcpy /llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
        #1 0x10a16a9 in xlnt::detail::compound_document::read_directory() /xlnt/source/detail/cryptography/compound_document.cpp:975:34
        #2 0x109e3eb in xlnt::detail::compound_document::compound_document(std::istream&) /xlnt/source/detail/cryptography/compound_document.cpp:517:5
        #3 0x986850 in (anonymous namespace)::decrypt_xlsx(std::vector<unsigned char, std::allocator<unsigned char> > const&, std::__cxx11::basic_string<char16_t, std::char_traits<char16_t>, std::allocator<char16_t> > const&) /xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:320:37
        #4 0x98604a in xlnt::detail::decrypt_xlsx(std::vector<unsigned char, std::allocator<unsigned char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:339:12
        #5 0x9877fe in xlnt::detail::xlsx_consumer::read(std::istream&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:345:28
        #6 0x547148 in xlnt::workbook::load(std::istream&) /xlnt/source/workbook/workbook.cpp:901:22
        #7 0x56dfa7 in xlnt::workbook::load(std::vector<unsigned char, std::allocator<unsigned char> > const&) /xlnt/source/workbook/workbook.cpp:919:5
        #8 0x514db2 in LLVMFuzzerTestOneInput /xlnt/build/../load_fuzzer.cc:9:23
        #9 0x441d51 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
        #10 0x42c36c in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
        #11 0x4320db in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:860:9
        #12 0x45ae22 in main /llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
        #13 0x7ffff7a760b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
        #14 0x426c8d in _start (/load_fuzzer+0x426c8d)

    0x615000002380 is located 768 bytes to the right of 512-byte region [0x615000001e80,0x615000002080) allocated by thread T0 here:
        #0 0x51235d in operator new(unsigned long) /llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:95:3
        #1 0x110db5e in __gnu_cxx::new_allocator<xlnt::detail::compound_document_entry>::allocate(unsigned long, void const*) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/ext/new_allocator.h:114:27
        #2 0x110d9ca in std::allocator_traits<std::allocator<xlnt::detail::compound_document_entry> >::allocate(std::allocator<xlnt::detail::compound_document_entry>&, unsigned long) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/alloc_traits.h:444:20
        #3 0x110cf2e in std::_Vector_base<xlnt::detail::compound_document_entry, std::allocator<xlnt::detail::compound_document_entry> >::_M_allocate(unsigned long) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:343:20
        #4 0x111bf85 in void std::vector<xlnt::detail::compound_document_entry, std::allocator<xlnt::detail::compound_document_entry> >::_M_realloc_insert<xlnt::detail::compound_document_entry>(__gnu_cxx::__normal_iterator<xlnt::detail::compound_document_entry*, std::vector<xlnt::detail::compound_document_entry, std::allocator<xlnt::detail::compound_document_entry> > >, xlnt::detail::compound_document_entry&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/vector.tcc:440:33
        #5 0x111b705 in void std::vector<xlnt::detail::compound_document_entry, std::allocator<xlnt::detail::compound_document_entry> >::emplace_back<xlnt::detail::compound_document_entry>(xlnt::detail::compound_document_entry&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/vector.tcc:121:4
        #6 0x10bea14 in std::vector<xlnt::detail::compound_document_entry, std::allocator<xlnt::detail::compound_document_entry> >::push_back(xlnt::detail::compound_document_entry&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1201:9
        #7 0x10a0c57 in xlnt::detail::compound_document::read_directory() /xlnt/source/detail/cryptography/compound_document.cpp:949:18
       #8 0x109e3eb in xlnt::detail::compound_document::compound_document(std::istream&) /xlnt/source/detail/cryptography/compound_document.cpp:517:5
        #9 0x986850 in (anonymous namespace)::decrypt_xlsx(std::vector<unsigned char, std::allocator<unsigned char> > const&, std::__cxx11::basic_string<char16_t, std::char_traits<char16_t>, std::allocator<char16_t> > const&) /xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:320:37
        #10 0x98604a in xlnt::detail::decrypt_xlsx(std::vector<unsigned char, std::allocator<unsigned char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:339:12
        #11 0x9877fe in xlnt::detail::xlsx_consumer::read(std::istream&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:345:28
        #12 0x547148 in xlnt::workbook::load(std::istream&) /xlnt/source/workbook/workbook.cpp:901:22
        #13 0x56dfa7 in xlnt::workbook::load(std::vector<unsigned char, std::allocator<unsigned char> > const&) /xlnt/source/workbook/workbook.cpp:919:5
        #14 0x514db2 in LLVMFuzzerTestOneInput /xlnt/build/../load_fuzzer.cc:9:23
        #15 0x441d51 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:611:15
        #16 0x42c36c in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
        #17 0x4320db in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:860:9
        #18 0x45ae22 in main /llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
        #19 0x7ffff7a760b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16

    SUMMARY: AddressSanitizer: heap-buffer-overflow /llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3 in __asan_memcpy
    Shadow bytes around the buggy address:
      0x0c2a7fff8420: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff8430: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff8440: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff8450: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff8460: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    =>0x0c2a7fff8470:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff8480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff8490: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff84a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff84b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c2a7fff84c0: 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
    ==17==ABORTING

OS version: ubuntu 20.04

xlnt version: d88c901faa539f9272a81ba0bab72def70ca18d7