Lucene search

K
talosTalos IntelligenceTALOS-2017-0417
HistoryNov 09, 2017 - 12:00 a.m.

libxls xls_addCell MulBlank Code Execution Vulnerability

2017-11-0900:00:00
Talos Intelligence
www.talosintelligence.com
13

8.8 High

CVSS3

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.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

6.8 Medium

CVSS2

Access Vector

NETWORK

Access 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

0.006 Low

EPSS

Percentile

77.7%

Summary

An exploitable Out-of-bounds Write vulnerability exists in the xls_addCell function of libxls 1.4. 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

libxls 1.4 readxl package 1.0.0 for R (tested using Microsoft R 4.3.1)

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

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 of the `Microsoft R` programming language. An out-of-bounds write appears in the `xls_addCell` function during parsing of the MULBLANK record. Let's take a look at the vulnerable code:

Line 399	void xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)
Line 400	{
Line 401	(...)
Line 402		row=&pWS-&gt;rows.row[((COL*)buf)-&gt;row];
Line 403		cell=&row-&gt;cells.cell[((COL*)buf)-&gt;col-row-&gt;fcell];
Line 404
Line 405		cell-&gt;id=bof-&gt;id;
Line 406		cell-&gt;xf=((COL*)buf)-&gt;xf;
Line 407
Line 408		switch (bof-&gt;id)
Line 409		{
Line 410			case 0x0BE:	//MULBLANK
Line 411			for (i=0;i&lt;=*(WORD *)(buf+(bof-&gt;size-2))-((COL*)buf)-&gt;col;i++)
Line 412			{
Line 413				cell=&row-&gt;cells.cell[((COL*)buf)-&gt;col-row-&gt;fcell+i];
Line 414				//				col=row-&gt;cols[i];
Line 415				cell-&gt;id=bof-&gt;id;
Line 416				cell-&gt;xf=*((WORD *)(buf+(4+i*2)));
Line 417				cell-&gt;str=xls_getfcell(pWS-&gt;workbook,cell);
Line 418			}	

According to the Microsoft MS-XLS document: 2.4.174 MulBlank is

>
> The MulBlank record specifies a series of blank cells in a sheet row. This record can store up to 256
> IXFCell structures.
>

At line 411 the amount of IXFCells is calculated as follows:

*(WORD *)(buf+(bof-&gt;size-2))-((COL*)buf)-&gt;col where
*(WORD *)(buf+(bof-&gt;size-2)) == colLast

and ((COL*)buf)->col == colFirst

In our PoC the MulBlank record is located at offset 0x1bcc. Next at line 413 using the loop index i, further cells are pulled out from a particular row.

There is no check to ensure that the calculated index : ((COL*)buf)->col-row->fcell+i does not exceed the available amount of cells in that particular row.

Also lines

Line 402		row=&pWS-&gt;rows.row[((COL*)buf)-&gt;row];
Line 403		cell=&row-&gt;cells.cell[((COL*)buf)-&gt;col-row-&gt;fcell];

contain the same vulnerability because :

((COL*)buf)-&gt;row

is not checked and its value comes directly from the file. That situation leads to out of bounds writes and finally heap corruption.

(gdb) p/x *bof
$5 = {id = 0xbe, size = 0x52}
(gdb) p *row
$6 = {index = 0, fcell = 0, lcell = 232, height = 1395, flags = 448, xf = 36, xfflags = 0 '\000', cells = {count = 0, cell = 0x607500}}
(gdb) p/x *pWS
$8 = {filepos = 0xb6f, defcolwidth = 0x800, rows = {lastcol = 0xe8, lastrow = 0x6, row = 0x607440}, workbook = 0x603010, colinfo = {count = 0x4c, col = 0x607140}, maxcol = 0x0}

Crash Information

Starting program: /home/icewall/bugs/libxls-0.2.0/build/bin/xls2csv ./crashes/9204a990ea8f1f0d57cf6d7102e166fc

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bd165c in xls_addCell (pWS=0x606980, bof=0x7fffffffdc10, buf=0x6066b0 "") at xls.c:438
438                 cell-&gt;str=xls_getfcell(pWS-&gt;workbook,cell);
(gdb) bt
#0  0x00007ffff7bd165c in xls_addCell (pWS=0x606980, bof=0x7fffffffdc10, buf=0x6066b0 "") at xls.c:438
#1  0x00007ffff7bd2ceb in xls_parseWorkSheet (pWS=0x606980) at xls.c:875
#2  0x0000000000400aed in main (pintArgc=2, ptstrArgv=0x7fffffffdd78) at xls2csv.c:90

[----------------------------------registers-----------------------------------]
RAX: 0x665fe8 --&gt; 0xbe0000000000be 
RBX: 0x0 
RCX: 0x0 
RDX: 0x6647f0 --&gt; 0x0 
RSI: 0x7fffffffb390 --&gt; 0x6469206c6c6100 ('')
RDI: 0x6647f0 --&gt; 0x0 
RBP: 0x7fffffffdbf0 --&gt; 0x7fffffffdc30 --&gt; 0x7fffffffdc90 --&gt; 0x400e30 (&lt;__libc_csu_init&gt;:      push   r15)
RSP: 0x7fffffffdbb0 --&gt; 0x1 
RIP: 0x7ffff7bd165c (&lt;xls_addCell+743&gt;: mov    QWORD PTR [rax+0x18],rdx)
R8 : 0x645000 --&gt; 0x0 
R9 : 0x0 
R10: 0x645000 --&gt; 0x0 
R11: 0x1 
R12: 0x400820 (&lt;_start&gt;:        xor    ebp,ebp)
R13: 0x7fffffffdd70 --&gt; 0x2 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x7ffff7bd1650 &lt;xls_addCell+731&gt;:    call   0x7ffff7bcda00 &lt;xls_getfcell@plt&gt;
   0x7ffff7bd1655 &lt;xls_addCell+736&gt;:    mov    rdx,rax
   0x7ffff7bd1658 &lt;xls_addCell+739&gt;:    mov    rax,QWORD PTR [rbp-0x10]
=&gt; 0x7ffff7bd165c &lt;xls_addCell+743&gt;:    mov    QWORD PTR [rax+0x18],rdx
   0x7ffff7bd1660 &lt;xls_addCell+747&gt;:    add    DWORD PTR [rbp-0x14],0x1
   0x7ffff7bd1664 &lt;xls_addCell+751&gt;:    mov    rax,QWORD PTR [rbp-0x30]
   0x7ffff7bd1668 &lt;xls_addCell+755&gt;:    movzx  eax,WORD PTR [rax+0x2]
   0x7ffff7bd166c &lt;xls_addCell+759&gt;:    movzx  eax,ax
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdbb0 --&gt; 0x1 
0008| 0x7fffffffdbb8 --&gt; 0x6066b0 --&gt; 0xf000f00020000 
0016| 0x7fffffffdbc0 --&gt; 0x7fffffffdc10 --&gt; 0x5200be 
0024| 0x7fffffffdbc8 --&gt; 0x606980 --&gt; 0xe8080000000b6f 
0032| 0x7fffffffdbd0 --&gt; 0x52 ('R')
0040| 0x7fffffffdbd8 --&gt; 0x26d600000052 
0048| 0x7fffffffdbe0 --&gt; 0x665fe8 --&gt; 0xbe0000000000be 
0056| 0x7fffffffdbe8 --&gt; 0x607440 --&gt; 0x57300e800000000 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV

Timeline

2017-08-15 - Vendor Disclosure
2017-11-09 - Public Release

8.8 High

CVSS3

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.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

6.8 Medium

CVSS2

Access Vector

NETWORK

Access 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

0.006 Low

EPSS

Percentile

77.7%

Related for TALOS-2017-0417