Submit #764643: xlnt-community xlnt commit bceb706 and before Heap-based Buffer Overflowinfo

Titelxlnt-community xlnt commit bceb706 and before Heap-based Buffer Overflow
Beschreibung### Description We discovered a Heap-buffer-overflow vulnerability in xlnt. The crash occurs in the xlnt::detail::binary_writer::append function when parsing a malformed Compound Document (typically used for encrypted XLSX files). The ASAN report indicates a WRITE of size 64 occurring exactly 0 bytes after a 512-byte allocated region. This suggests that the code is attempting to append data to a sector buffer that has already reached its capacity (512 bytes), leading to a heap corruption. Vendor confirmed and create a pull request [#147](https://github.com/xlnt-community/xlnt/pull/147). ### Environment - OS: Linux x86_64 - Complier: Clang - Build Configuration: Release mode with ASan enabled. ### Vulnerability Details - Target: xlnt - Vulnerability Type: CWE-122: Heap-based Buffer Overflow - Function: xlnt::detail::binary_writer::append - Location: source/detail/binary.hpp:278 - Caller: xlnt::detail::compound_document::read_sector at source/detail/cryptography/compound_document.cpp:594 - Context: read_msat -> read_sector - Root Cause Analysis: The compound_document implementation allocates a buffer of 512 bytes (standard OLE sector size). The function read_sector attempts to read data and append it to this buffer using binary_writer. It appears that during the parsing of the Master Sector Allocation Table (MSAT), the logic fails to correctly check if the write destination has sufficient remaining space, or it calculates the offset incorrectly, causing a memcpy of 64 bytes to land immediately after the allocated sector buffer. ### Reproduce 1. Build xlnt and harness with Release optimization and ASAN enabled. <details> <summary>harness.c</summary> ``` #include <xlnt/xlnt.hpp> #include <iostream> #include <string> #include <vector> int main(int argc, char **argv) { if (argc < 2) { return 0; } std::string filepath = argv[1]; try { xlnt::workbook wb; wb.load(filepath); if (wb.sheet_count() > 0) { auto ws = wb.active_sheet(); for (auto row : ws.rows(false)) { for (auto cell : row) { (void)cell.to_string(); } } } } catch (const xlnt::exception& e) { } catch (const std::exception& e) { } catch (...) { } return 0; } ``` </details> 2. Run with the crashing [file](https://github.com/oneafter/0128/blob/main/xl2/repro): ``` ./harness repro ``` <details> <summary>ASAN report</summary> ``` ==44107==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x515000001400 at pc 0x55592a844192 bp 0x7ffcfd52b170 sp 0x7ffcfd52a930 WRITE of size 64 at 0x515000001400 thread T0 #0 0x55592a844191 in __asan_memcpy (/src/xlnt/fuzz_xlnt+0xcb191) (BuildId: 9402de847aab9fb45990c4e2333074ba128dc968) #1 0x7f75fe4917b3 in void xlnt::detail::binary_writer<int>::append<unsigned char>(xlnt::detail::binary_reader<unsigned char>&, unsigned long) /src/xlnt/source/../source/detail/binary.hpp:278:9 #2 0x7f75fe487263 in void xlnt::detail::binary_writer<int>::append<unsigned char>(std::vector<unsigned char, std::allocator<unsigned char>> const&) /src/xlnt/source/../source/detail/binary.hpp:259:9 #3 0x7f75fe487263 in void xlnt::detail::compound_document::read_sector<int>(int, xlnt::detail::binary_writer<int>&) /src/xlnt/source/detail/cryptography/compound_document.cpp:594:12 #4 0x7f75fe45ef8b in xlnt::detail::compound_document::read_msat() /src/xlnt/source/detail/cryptography/compound_document.cpp:1258:13 #5 0x7f75fe45df68 in xlnt::detail::compound_document::compound_document(std::istream&) /src/xlnt/source/detail/cryptography/compound_document.cpp:514:5 #6 0x7f75fe4aae2d 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&) /src/xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:320:37 #7 0x7f75fe4aae2d 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&) /src/xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:339:12 #8 0x7f75fe4aded2 in xlnt::detail::xlsx_consumer::read(std::istream&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /src/xlnt/source/detail/cryptography/xlsx_crypto_consumer.cpp:345:28 #9 0x7f75fe3226c9 in xlnt::workbook::load(std::istream&) /src/xlnt/source/workbook/workbook.cpp:906:22 #10 0x7f75fe320f77 in xlnt::workbook::load(xlnt::path const&) /src/xlnt/source/workbook/workbook.cpp:942:5 #11 0x7f75fe348018 in xlnt::workbook::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /src/xlnt/source/workbook/workbook.cpp:929:12 #12 0x55592a88a27e in main /src/xlnt/fuzz_xlnt.cpp:18:12 #13 0x7f75fdb5b1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) #14 0x7f75fdb5b28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e) #15 0x55592a7a6594 in _start (/src/xlnt/fuzz_xlnt+0x2d594) (BuildId: 9402de847aab9fb45990c4e2333074ba128dc968) 0x515000001400 is located 0 bytes after 512-byte region [0x515000001200,0x515000001400) allocated by thread T0 here: #0 0x55592a887a41 in operator new(unsigned long) (/src/xlnt/fuzz_xlnt+0x10ea41) (BuildId: 9402de847aab9fb45990c4e2333074ba128dc968) #1 0x7f75fe48fa07 in std::__new_allocator<int>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27 #2 0x7f75fe48fa07 in std::allocator_traits<std::allocator<int>>::allocate(std::allocator<int>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20 #3 0x7f75fe48fa07 in std::_Vector_base<int, std::allocator<int>>::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20 #4 0x7f75fe48fa07 in std::vector<int, std::allocator<int>>::_M_fill_insert(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int>>>, unsigned long, int const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:587:34 SUMMARY: AddressSanitizer: heap-buffer-overflow (/src/xlnt/fuzz_xlnt+0xcb191) (BuildId: 9402de847aab9fb45990c4e2333074ba128dc968) in __asan_memcpy Shadow bytes around the buggy address: 0x515000001180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x515000001200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x515000001280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x515000001300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x515000001380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x515000001400:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x515000001480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x515000001500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x515000001580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x515000001600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x515000001680: 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 ==44107==ABORTING ``` </details>
Quelle⚠️ https://github.com/xlnt-community/xlnt/issues/138
Benutzer Oneafter (UID 92781)
Einreichung21.02.2026 04:50 (vor 2 Monaten)
Moderieren03.03.2026 07:04 (10 days later)
StatusAkzeptiert
VulDB Eintrag348530 [xlnt-community xlnt bis 1.6.1 Compound Document Parser source/detail/binary.hpp append Pufferüberlauf]
Punkte20

Want to stay up to date on a daily basis?

Enable the mail alert feature now!