Lucene search

K
talosTalos IntelligenceTALOS-2017-0463
HistoryNov 15, 2017 - 12:00 a.m.

libxls xls_addCell Formula Code Execution Vulnerability

2017-11-1500:00:00
Talos Intelligence
www.talosintelligence.com
37

CVSS2

6.8

Attack Vector

NETWORK

Attack Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

CVSS3

8.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

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

EPSS

0.022

Percentile

89.6%

Summary

An exploitable out-of-bounds vulnerability exists in the xls_addCell function of libxls 1.4. A specially crafted XLS file with a formula record can cause memory corruption resulting in remote code execution. An attacker can send a malicious XLS file to trigger this vulnerability.

Tested Versions

libxls 1.4

Product URLs

<http://libxls.sourceforge.net/&gt;

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H CVSSv3 Calculator: https://www.first.org/cvss/calculator/3.0

CWE

CWE-787: Out-of-bounds Write

Details

libxls is a C library supported on windows, mac, cygwin which can read Microsoft Excel File Format ( XLS ) files. The library is used by the readxl package that can be installed in the R programming language. However this particular vulnerability does not impact the readxl package.

To analyze this vulnerability, we need to start at the xls_preparseWorkSheet function.

Line 970	void xls_preparseWorkSheet(xlsWorkSheet* pWS)
Line 971	{
			(...)
Line 1018			case 0x0203:        //NUMBER
Line 1019			case 0x027e:        //RK
Line 1020			case 0x00FD:        //LABELSST
Line 1021			case 0x0201:        //BLANK
Line 1022			case 0x0204:        //LABEL
Line 1023			case 0x0006:        //FORMULA
Line 1024				if (pWS-&gt;rows.lastcol&lt;xlsShortVal(((COL*)buf)-&gt;col))
Line 1025					pWS-&gt;rows.lastcol=xlsShortVal(((COL*)buf)-&gt;col);
Line 1026				if (pWS-&gt;rows.lastrow&lt;xlsShortVal(((COL*)buf)-&gt;row))
Line 1027					pWS-&gt;rows.lastrow=xlsShortVal(((COL*)buf)-&gt;row);
Line 1028				break;
Line 1029			}

The xls_preparseWorkSheet function iterates over all existing records and tries to find a maximum value for the col and row fields, these values are stored in pWS-&gt;rows.lastcol and pWS-&gt;rows.lastcol, respectively. These values are later used for buffers allocations inside the xls_makeTable function:

Line 409	void xls_makeTable(xlsWorkSheet* pWS)
Line 410	{
				(...)
Line 415		pWS-&gt;rows.row=(struct st_row_data *)calloc((pWS-&gt;rows.lastrow+1),sizeof(struct st_row_data));
				(...)
Line 426			tmp-&gt;cells.cell=(struct st_cell_data *)calloc(tmp-&gt;cells.count,sizeof(struct st_cell_data));	

Later in the xls_parseWorkSheet function, the xls_addCell function is called for nearly the same set of records that we saw in the xls_preparseWorkSheet but with one exception, FORMULA (Apple Numbers Bug):

Line 1063	void xls_parseWorkSheet(xlsWorkSheet* pWS)
Line 1064	{
				(...)
Line 1141				case 0x00BD:		//MULRK
Line 1142				case 0x00BE:		//MULBLANK
Line 1143				case 0x0203:		//NUMBER
Line 1144				case 0x027e:		//RK
Line 1145				case 0x00FD:		//LABELSST
Line 1146				case 0x0201:		//BLANK
Line 1147				case 0x0204:		//LABEL
Line 1148				case 0x0006:		//FORMULA
Line 1149				case 0x0406:		//FORMULA (Apple Numbers Bug)
Line 1150					cell = xls_addCell(pWS,&tmp,buf);	

We did not see FORMULA (Apple Numbers Bug) with id 0x0406 in thexls_preparseWorkSheet function. This means that for this record, the fields col and row have not been checked whether their value exceed the current maximum values stored in pWS-&gt;rows.lastcol, pWS-&gt;rows.lastrow. That lack of check for this type of record leads to an out of bound write in the xls_addCell function. Let’s take a look at the vulnerable code:

Line 446	struct st_cell_data *xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
Line 447	{
Line 448		struct st_cell_data*	cell;
Line 449		struct st_row_data*		row;
Line 450		int						i;
Line 451
Line 452		verbose ("xls_addCell");
Line 453
Line 454		// printf("ROW: %u COL: %u\n", xlsShortVal(((COL*)buf)-&gt;row), xlsShortVal(((COL*)buf)-&gt;col));
Line 455		row=&pWS-&gt;rows.row[xlsShortVal(((COL*)buf)-&gt;row)];
Line 456		//cell=&row-&gt;cells.cell[((COL*)buf)-&gt;col - row-&gt;fcell]; DFH - inconsistent
Line 457		cell=&row-&gt;cells.cell[xlsShortVal(((COL*)buf)-&gt;col)];
Line 458		cell-&gt;id=bof-&gt;id;
Line 459		cell-&gt;xf=xlsShortVal(((COL*)buf)-&gt;xf);	

The col value coming from the record is used as an index for the row-&gt;cells.cell array at line 457. The malformed Formula record is located at offset : 0xCB1F

 CB1Fh: 06 04 20 00 00 01 FF FF                          .. ...ΓΏΓΏ

 `col` field is set to 0xFFFF

Because this value has not been checked, it can easily exceed array’s range. Write operations at lines 458-459 can subsequently cause an out-of-bounds write which subsequently leads to memory corruption.

Crash Information

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x27fff9 
RBX: 0x21 ('!')
RCX: 0x7fffffffdb40 --&gt; 0x200406 
RDX: 0x406 
RSI: 0x7fffffffdb40 --&gt; 0x200406 
RDI: 0xffffffff 
RBP: 0x7fffffffdb20 --&gt; 0x7fffffffdbc0 --&gt; 0x7fffffffdc30 --&gt; 0x401610 (&lt;__libc_csu_init&gt;:      push   r15)
RSP: 0x7fffffffdac0 --&gt; 0x60f3a0 --&gt; 0x8000000c90b 
RIP: 0x7ffff7bce936 (&lt;xls_addCell+144&gt;: mov    WORD PTR [rax],dx)
R8 : 0x60f360 --&gt; 0x0 
R9 : 0x800000003000000 
R10: 0x6f ('o')
R11: 0x7ffff7bce8a6 (&lt;xls_addCell&gt;:     push   rbp)
R12: 0x400b60 (&lt;_start&gt;:        xor    ebp,ebp)
R13: 0x7fffffffdd10 --&gt; 0x2 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff7bce92b &lt;xls_addCell+133&gt;:    mov    rax,QWORD PTR [rbp-0x50]
   0x7ffff7bce92f &lt;xls_addCell+137&gt;:    movzx  edx,WORD PTR [rax]
   0x7ffff7bce932 &lt;xls_addCell+140&gt;:    mov    rax,QWORD PTR [rbp-0x28]
=&gt; 0x7ffff7bce936 &lt;xls_addCell+144&gt;:    mov    WORD PTR [rax],dx
   0x7ffff7bce939 &lt;xls_addCell+147&gt;:    mov    rax,QWORD PTR [rbp-0x58]
   0x7ffff7bce93d &lt;xls_addCell+151&gt;:    movzx  eax,WORD PTR [rax+0x4]
   0x7ffff7bce941 &lt;xls_addCell+155&gt;:    cwde   
   0x7ffff7bce942 &lt;xls_addCell+156&gt;:    mov    edi,eax
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdac0 --&gt; 0x60f3a0 --&gt; 0x8000000c90b 
0008| 0x7fffffffdac8 --&gt; 0x6077d0 --&gt; 0xbbbbbbbbffff0100 
0016| 0x7fffffffdad0 --&gt; 0x7fffffffdb40 --&gt; 0x200406 
0024| 0x7fffffffdad8 --&gt; 0x60f3a0 --&gt; 0x8000000c90b 
0032| 0x7fffffffdae0 --&gt; 0x60f3a0 --&gt; 0x8000000c90b 
0040| 0x7fffffffdae8 --&gt; 0x60f360 --&gt; 0x0 
0048| 0x7fffffffdaf0 --&gt; 0x800000003000000 
0056| 0x7fffffffdaf8 --&gt; 0x27fff9 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00007ffff7bce936 in xls_addCell (pWS=0x60f3a0, bof=0x7fffffffdb40, buf=0x6077d0 "") at xls.c:458
458         cell-&gt;id=bof-&gt;id;
gdb-peda$ bt
#0  0x00007ffff7bce936 in xls_addCell (pWS=0x60f3a0, bof=0x7fffffffdb40, buf=0x6077d0 "") at xls.c:458
#1  0x00007ffff7bd0b1a in xls_parseWorkSheet (pWS=0x60f3a0) at xls.c:1150
#2  0x0000000000400ff8 in main (argc=0x2, argv=0x7fffffffdd18) at xls2csv.c:149
#3  0x00007ffff781c830 in __libc_start_main (main=0x400d78 &lt;main&gt;, argc=0x2, argv=0x7fffffffdd18, init=&lt;optimized out&gt;, fini=
&lt;optimized 
out&gt;, rtld_fini=&lt;optimized out&gt;, stack_end=0x7fffffffdd08) at ../csu/libc-start.c:291
#4  0x0000000000400b89 in _start ()
gdb-peda$ source ~/tools/triage_tools/exploitable/exploitable/exploitable.py 
gdb-peda$ exploitable -m
__main__:102: UserWarning: GDB v7.11 may not support required Python API
Warning: machine string printing is deprecated and may be removed in a future release.
EXCEPTION_FAULTING_ADDRESS:0x0000000027fff9
EXCEPTION_CODE:0xb
FAULTING_INSTRUCTION:mov    WORD PTR [rax],dx
MAJOR_HASH:34754c1fb7e7f36e18e374f783e4c876
MINOR_HASH:34754c1fb7e7f36e18e374f783e4c876
STACK_DEPTH:3
STACK_FRAME:/home/icewall/bugs/libxls-1.4.0/build/lib/libxlsreader.so.1.2.1!xls_addCell+0x0
STACK_FRAME:/home/icewall/bugs/libxls-1.4.0/build/lib/libxlsreader.so.1.2.1!xls_parseWorkSheet+0x0
STACK_FRAME:/home/icewall/bugs/libxls-1.4.0/build/bin/xls2csv!main+0x0
INSTRUCTION_ADDRESS:0x007ffff7bce936
INVOKING_STACK_FRAME:0
DESCRIPTION:Access violation on destination operand
SHORT_DESCRIPTION:DestAv (9/29)
OTHER_RULES:AccessViolation (28/29)
CLASSIFICATION:EXPLOITABLE
EXPLANATION:The target crashed on an access violation at an address matching the destination operand of the instruction. This   
     likely indicates a write access violation, which means the attacker may control the write address and/or value.
Description: Access violation on destination operand
Short description: DestAv (9/29)
Hash: 34754c1fb7e7f36e18e374f783e4c876.34754c1fb7e7f36e18e374f783e4c876
Exploitability Classification: EXPLOITABLE
Explanation: The target crashed on an access violation at an address matching the destination operand of the instruction. This  
    likely indicates a write access violation, which means the attacker may control the write address and/or value.
Other tags: AccessViolation (28/29)

Timeline

2017-10-25 - Vendor Disclosure
2017-11-15 - Public Release

CVSS2

6.8

Attack Vector

NETWORK

Attack Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

CVSS3

8.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

REQUIRED

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

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

EPSS

0.022

Percentile

89.6%