tfussell / xlnt

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

Heap-buffer-overflow in xlnt::detail::xlsx_producer::write_relationships at xlsx_producer.cpp:3440 #675

Open bladchan opened 1 year ago

bladchan commented 1 year ago

Hi,

I am running some experiments for AFLAPI and it has found a heap-buffer-overflow in xlnt::detail::izstream::read_central_header. It seems to be hard to be exploited, but this bug also allows attackers to lead to Dos, so I report it here.

Environment: Ubuntu 20.04 + g++ 6.0

Driver Program:

// test.cpp
#include <xlnt/xlnt.hpp>

int main(int argc, char** argv) {
    xlnt::workbook wb;
    if(argc != 2) return 0;
    wb.load(argv[1]);
    auto ws = wb.active_sheet();
    for (auto row : ws.rows(false)) 
    { 
        for (auto cell : row) 
            { 
            cell.to_string();
            }
        }

    ws.cell("A1").value(5);
    ws.cell("B2").value("string data");
    ws.cell("C3").formula("=RAND()");
    ws.merge_cells("C3:C4");
    ws.freeze_panes("B2");
    wb.save("test.xlsx");
    return 0;
}

Poc here: Poc.zip

To reproduce: • Complie the hole project with ASAN • Complie the deiver program with ASAN:

g++-6 -fsanitize=address -o test test.cpp -lxlnt

• Run harness:

./test ./id\:002657\,arg\:00

ASAN says:

=================================================================
==36032==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100000db80 at pc 0x7f95047f0e64 bp 0x7ffc2007fe30 sp 0x7ffc2007fe20
READ of size 8 at 0x62100000db80 thread T0
    #0 0x7f95047f0e63 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_data() const /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/basic_string.h:176
    #1 0x7f95047f0e63 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/basic_string.h:440
    #2 0x7f95047f0e63 in relationship /home/ubuntu/some_c_test/xlnt/source/../include/xlnt/packaging/relationship.hpp:102
    #3 0x7f9504fa59e9 in xlnt::detail::xlsx_producer::write_relationships(std::vector<xlnt::relationship, std::allocator<xlnt::relationship> > const&, xlnt::path const&) /home/ubuntu/some_c_test/xlnt/source/detail/serialization/xlsx_producer.cpp:3440
    #4 0x7f9504fca815 in xlnt::detail::xlsx_producer::write_workbook(xlnt::relationship const&) /home/ubuntu/some_c_test/xlnt/source/detail/serialization/xlsx_producer.cpp:721
    #5 0x7f9504f9b355 in xlnt::detail::xlsx_producer::populate_archive(bool) /home/ubuntu/some_c_test/xlnt/source/detail/serialization/xlsx_producer.cpp:159
    #6 0x7f9504a208dd in xlnt::workbook::save(std::ostream&) const /home/ubuntu/some_c_test/xlnt/source/workbook/workbook.cpp:1018
    #7 0x7f9504a208dd in xlnt::workbook::save(xlnt::path const&) const /home/ubuntu/some_c_test/xlnt/source/workbook/workbook.cpp:1005
    #8 0x7f9504a2057f in xlnt::workbook::save(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const /home/ubuntu/some_c_test/xlnt/source/workbook/workbook.cpp:993
    #9 0x55d6e71a8fe0 in main /home/ubuntu/some_c_test/xlnt/Fuzz/test.cpp:21
    #10 0x7f9503d08c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
    #11 0x55d6e71a99f9 in _start (/home/ubuntu/some_c_test/xlnt/Fuzz/test+0x39f9)

0x62100000db80 is located 0 bytes to the right of 4736-byte region [0x62100000c900,0x62100000db80)
allocated by thread T0 here:
    #0 0x7f9505731448 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0448)
    #1 0x7f950486ad93 in __gnu_cxx::new_allocator<xlnt::relationship>::allocate(unsigned long, void const*) /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/ext/new_allocator.h:111
    #2 0x7f950486ad93 in std::allocator_traits<std::allocator<xlnt::relationship> >::allocate(std::allocator<xlnt::relationship>&, unsigned long) /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/alloc_traits.h:436
    #3 0x7f950486ad93 in std::_Vector_base<xlnt::relationship, std::allocator<xlnt::relationship> >::_M_allocate(unsigned long) /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/stl_vector.h:172
    #4 0x7f950486ad93 in void std::vector<xlnt::relationship, std::allocator<xlnt::relationship> >::_M_realloc_insert<xlnt::relationship const&>(__gnu_cxx::__normal_iterator<xlnt::relationship*, std::vector<xlnt::relationship, std::allocator<xlnt::relationship> > >, xlnt::relationship const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/vector.tcc:406

SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/basic_string.h:176 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_data() const
Shadow bytes around the buggy address:
  0x0c427fff9b20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff9b30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff9b40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff9b50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff9b60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c427fff9b70:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff9b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff9b90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff9bc0: 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
==36032==ABORTING