FreeXL read_biff_next_record Code Execution Vulnerability(CVE-2017-2923)

2017-09-12T00:00:00
ID SSV:96441
Type seebug
Reporter Root
Modified 2017-09-12T00:00:00

Description

Summary

An exploitable heap based buffer overflow vulnerability exists in the read_biff_next_record function of FreeXL 1.0.3. A specially crafted XLS file can cause a memory corruption resulting in remote code execution. An attacker can send malicious XLS file to trigger this vulnerability.

Tested Versions

freexl 1.0.3

Product URLs

https://www.gaia-gis.it/fossil/freexl/index

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-122: Heap-based Buffer Overflow

Details

FreeXL is a C library which can read Microsoft Excel File Format ( XLS ) files. The library is used by the SpatiaLite open source library. A heap-based buffer overflow appears in the read_biff_next_record function. The vulnerability appears in a situation when a BIFF record size is bigger than workbook->record field. The following code contains the vulnerability: ``` freexl_internals.h Line 278 unsigned char record[8224]; / current record /

freexl.c Line 3723 static int Line 3724 read_biff_next_record (biff_workbook * workbook, int swap, int errcode) Line 3725 { (...) Line 3772 / fetching record-type and record-size / Line 3773 memcpy (record_type.bytes, workbook->p_in, 2); Line 3774 workbook->p_in += 2; Line 3775 memcpy (record_size.bytes, workbook->p_in, 2); Line 3776 workbook->p_in += 2; (...) Line 3808 while (already_done < workbook->record_size) Line 3809 { Line 3810 / reading a further sector / Line 3811 ret = read_cfbf_next_sector (workbook, errcode); Line 3812 if (ret == -1) Line 3813 return -1; / EOF found / Line 3814 if (ret == 0) Line 3815 return 0; Line 3816 chunk = workbook->record_size - already_done; Line 3817 if (chunk <= workbook->fat->sector_size) Line 3818 { Line 3819 / ok, finished: whole record reassembled / Line 3820 memcpy (workbook->record + already_done, workbook->p_in, Line 3821 chunk); Line 3822 workbook->p_in += chunk; Line 3823 goto record_done; Line 3824 } Line 3825 / record still spanning on the following sector */ Line 3826 memcpy (workbook->record + already_done, workbook->p_in, Line 3827 workbook->fat->sector_size); Line 3828 workbook->p_in += workbook->fat->sector_size; Line 3829 already_done += workbook->fat->sector_size; Line 3830 } `` At line 3775 therecord_size` is read directly from the file, which is used to control the loop at line 3808. Then at lines 3820 and 3826 data will be copied into the record which has a fixed size of 8224. Since there are no checks to ensure that the record_size is smaller than this declared value, this will result in a heap-based buffer overflow.

Crash Information

icewall@ubuntu:~/bugs/freexl-1.0.3/bin$ valgrind ./test_xl ./crashes/ef69e246113c046810b7ef908cc7a09f ==99598== Memcheck, a memory error detector ==99598== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==99598== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==99598== Command: ./test_xl ./crashes/ef69e246113c046810b7ef908cc7a09f ==99598== ==99598== Invalid write of size 2 ==99598== at 0x4C32723: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==99598== by 0x4E43F66: read_biff_next_record (freexl.c:3826) ==99598== by 0x4E448A7: common_open (freexl.c:4102) ==99598== by 0x4E44B39: freexl_open (freexl.c:4202) ==99598== by 0x400C3B: main (test_xl.c:84) ==99598== Address 0x572b128 is 0 bytes after a block of size 65,768 alloc'd ==99598== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==99598== by 0x4E3D4E8: alloc_workbook (freexl.c:1193) ==99598== by 0x4E44720: common_open (freexl.c:4037) ==99598== by 0x4E44B39: freexl_open (freexl.c:4202) ==99598== by 0x400C3B: main (test_xl.c:84) ==99598== ==99598== Invalid read of size 8 ==99598== at 0x50BDF20: fseek (fseek.c:35) ==99598== by 0x4E4394A: read_cfbf_sector (freexl.c:3666) ==99598== by 0x4E43AC5: read_cfbf_next_sector (freexl.c:3701) ==99598== by 0x4E43E9E: read_biff_next_record (freexl.c:3811) ==99598== by 0x4E448A7: common_open (freexl.c:4102) ==99598== by 0x4E44B39: freexl_open (freexl.c:4202) ==99598== by 0x400C3B: main (test_xl.c:84) ==99598== Address 0x8670017086708 is not stack'd, malloc'd or (recently) free'd ==99598== ==99598== ==99598== Process terminating with default action of signal 11 (SIGSEGV) ==99598== General Protection Fault ==99598== at 0x50BDF20: fseek (fseek.c:35) ==99598== by 0x4E4394A: read_cfbf_sector (freexl.c:3666) ==99598== by 0x4E43AC5: read_cfbf_next_sector (freexl.c:3701) ==99598== by 0x4E43E9E: read_biff_next_record (freexl.c:3811) ==99598== by 0x4E448A7: common_open (freexl.c:4102) ==99598== by 0x4E44B39: freexl_open (freexl.c:4202) ==99598== by 0x400C3B: main (test_xl.c:84) ==99598== Invalid read of size 8 ==99598== at 0x50C4193: _IO_flush_all_lockp (genops.c:786) ==99598== by 0x50C4329: _IO_cleanup (genops.c:951) ==99598== by 0x51BC338: __libc_freeres (in /lib/x86_64-linux-gnu/libc-2.23.so) ==99598== by 0x4A2868C: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so) ==99598== Address 0x2000f0064001a is not stack'd, malloc'd or (recently) free'd ==99598== ==99598== ==99598== Process terminating with default action of signal 11 (SIGSEGV) ==99598== General Protection Fault ==99598== at 0x50C4193: _IO_flush_all_lockp (genops.c:786) ==99598== by 0x50C4329: _IO_cleanup (genops.c:951) ==99598== by 0x51BC338: __libc_freeres (in /lib/x86_64-linux-gnu/libc-2.23.so) ==99598== by 0x4A2868C: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so) ==99598== ==99598== HEAP SUMMARY: ==99598== in use at exit: 114,272 bytes in 401 blocks ==99598== total heap usage: 403 allocs, 2 frees, 114,432 bytes allocated ==99598== ==99598== LEAK SUMMARY: ==99598== definitely lost: 4,096 bytes in 1 blocks ==99598== indirectly lost: 0 bytes in 0 blocks ==99598== possibly lost: 0 bytes in 0 blocks ==99598== still reachable: 110,176 bytes in 400 blocks ==99598== suppressed: 0 bytes in 0 blocks ==99598== Rerun with --leak-check=full to see details of leaked memory ==99598== ==99598== For counts of detected and suppressed errors, rerun with: -v ==99598== ERROR SUMMARY: 74 errors from 3 contexts (suppressed: 0 from 0) Segmentation fault (core dumped)

Timeline

  • 2017-09-06 - Vendor Disclosure
  • 2017-09-11 - Public Release

CREDIT

  • Discovered by Marcin 'Icewall' Noga of Cisco Talos.