### 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 the `record_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.
暂无评论