### SummaryAn exploitable integer overflow vulnerability exists in the xls_preparseWorkSheet function of libxls 1.4 when handling a MULRK record. 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 Versionslibxls 1.4 readxl package 1.0.0 for R (tested using Microsoft R 4.3.1)### Product URLshttp://libxls.sourceforge.net/### CVSSv3 Score8.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### CWECWE-680: Integer Overflow to Buffer Overflow### Detailslibxls 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.The integer overflow appears in the xls_preparseWorkSheet function, so let's take a look at the vulnerable code:“`Line 970 void xls_preparseWorkSheet(xlsWorkSheet* pWS)Line 971 { (…)Line 985 read = ole2_read(buf, 1,tmp.size,pWS->workbook->olestr);Line 986 assert(read == tmp.size);Line 987 // xls_showBOF(&tmp);Line 988 switch (tmp.id)Line 989 { (…) Line 1004 /* If the ROW record is incorrect or missing, infer the information fromLine 1005 * cell data. */Line 1006 case 0x00BD: //MULRKLine 1007 if (pWS->rows.lastcol<xlsShortVal(((MULRK*)buf)->col) + (tmp.size – 6)/6 – 1)Line 1008 pWS->rows.lastcol=xlsShortVal(((MULRK*)buf)->col) + (tmp.size – 6)/6 – 1;Line 1009 if (pWS->rows.lastrow<xlsShortVal(((MULRK*)buf)->row))Line 1010 pWS->rows.lastrow=xlsShortVal(((MULRK*)buf)->row);Line 1011 break;“`The general purpose of the `xls_preparseWorkSheet` function is to obtain the maximal size of `col` and `row` value from records present in the worksheet and update the `lastcol` and `lastrow` fields with that value.As we can see in lines `1007-1008` an integer overflow can occur. This can have two potential impacts. In one case, the maximum value stored in `lastcol` will not be updated even if the MULRK col field is greater than the value in `lastcol`. The other case will result in the lastcol value being updated to the overflowed value.The malformed `MULRK` record is located at offset : 0xCB1F and looks as follows:“`0xCB1F BD 00 20 00 AA AA FF FF“`Setting breakpoint at `line 1007` we can obtain the following information:“`(gdb) p/x tmp$1 = {id = 0xbd, size = 0x20}(gdb) p/x *((MULRK*)buf)$3 = {row = 0xaaaa, col = 0xffff, rk = 0x60f3e4}(gdb) p/x pWS->rows.lastcol$4 = 0x0“`stepping further after `line 1008`:“`(gdb) p/x pWS->rows.lastcol$5 = 0x2“`We see that `lastcol` field has been updated with overflowed value 0x2.It has further consequences in function `xls_makeTable` where based on the `lastcol` field an array for cells is allocated:“`Line 409 void xls_makeTable(xlsWorkSheet* pWS)Line 410 {Line 412 struct st_row_data* tmp;Line 418 for (t=0;t<=pWS->rows.lastrow;t++) {Line 420 tmp=&pWS->rows.row[t]; (…)Line 425 tmp->cells.count = pWS->rows.lastcol+1;Line 426 tmp->cells.cell=(struct st_cell_data *)calloc(tmp->cells.count,sizeof(struct st_cell_data)); “`Next during the final parsing of the malformed `MULRK` record in `xls_addCell`, an out of bound write occurs because the `col` value being used as index for the `cell` array is greater than amount of allocated elements for that array.“`Line 446 struct st_cell_data *xls_addCell(xlsWorkSheet* pWS,BOF* bof,BYTE* buf)Line 447 {Line 448 struct st_cell_data* cell; (…)Line 457 cell=&row->cells.cell[xlsShortVal(((COL*)buf)->col)];Line 458 cell->id=bof->id;Line 459 cell->xf=xlsShortVal(((COL*)buf)->xf); “`At `line 457` the `cell` element points to a value outside of the array range which leads to an out-of-bounds write at `lines 458,459`…“`Program received signal SIGSEGV, Segmentation fault.0x00007ffff7bce936 in xls_addCell (pWS=0x60f3a0, bof=0x7fffffffdb80, buf=0x607c50 "\252\252\377\377\273\273\273\273\314\314\314\314\335\335\335\335", <incomplete sequence \345>) at xls.c:458458 cell->id=bof->id;gdb-peda$ p cell$8 = (struct st_cell_data *) 0xdea898gdb-peda$ vmmap 0xdea898Warning: not found or cannot access procfs“`### Crash Information“`Microsoft R crash(94c.c74): Access violation – code c0000005 (first chance)First chance exceptions are reported before any exception handling.This exception may be expected and handled.*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Users\Icewall\Documents\R\win- library\3.4\readxl\libs\x64\readxl.dll – readxl!xls_addCell+0x61:00000000`6534b191 668903 mov word ptr [rbx],ax ds:00000000`312f5f58=????0:000> kb 10 # RetAddr : Args to Child : Call Site00 00000000`6534c8e2 : 00000000`48332fd0 00000000`31135ff0 00000000`00000006 00000000`00000000 : readxl!xls_addCell+0x6101 00000000`65382714 : 00000000`044079c0 00000000`00000000 00000000`00000000 00000000`00000000 : readxl!xls_parseWorkSheet+0x30202 00000000`6534572b : 00000000`04407750 00000000`044076b0 00000000`00000000 00007ffe`179295c9 : readxl!ZN12XlsWorkSheetC1E11XlsWorkBookiN4Rcpp6VectorILi13ENS1_15PreserveStorageEEEb+0x2b403 00000000`65343ddb : 00000000`044079b0 00007ffe`02922b4f 00000000`00000000 00000000`00000000 : readxl!Z9read_xls_SsiN4Rcpp6VectorILi13ENS_15PreserveStorageEEEbNS_12RObject_ImplIS1_EES4_St6vectorISsSaISsEEbi+0x31b*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Microsoft\R Open\R-3.4.1\bin\x64\R.dll – 04 00000000`6c7977cf : 00000000`25cecec8 00000000`10cfdf98 00000000`6cbfdbd0 00000000`04407cd0 : readxl!readxl_read_xls_+0x1db05 00000000`6c797f04 : 00000000`00000272 00000000`04407cc8 00000000`00000139 00000000`04407f00 : R!Rf_NewFrameConfirm+0x7b6f06 00000000`6c7ee8c8 : 00000000`23747fa0 00000000`2607c7c0 00000000`23747fa0 00000000`6cbfdcb8 : R!Rf_NewFrameConfirm+0x82a407 00000000`6c7f11dd : 00000000`6cbfdc08 00000000`6cbfdd20 00000000`6cbfdc90 00000000`6c7c070c : R!Rf_eval+0x6f808 00000000`6c7ee6ba : 00000000`23748010 00000000`14595aa8 00000000`23748010 00000000`25e0b818 : R!R_execMethod+0x8bd09 00000000`6c7f0550 : 00000000`31f17618 00000000`145dbd58 00000000`25f56dc0 00000000`264e3c08 : R!Rf_eval+0x4ea0a 00000000`6c7f08d2 : 00000000`237b8cb8 00000000`261e92b0 00000000`237b8cb8 00000000`264e4270 : R!R_cmpfun1+0xf500b 00000000`6c7e28ba : 00000000`6cbfdbd0 00000000`2607f130 00000000`14590600 00000000`6c7f08d2 : R!Rf_applyClosure+0x1920c 00000000`6c7ee341 : 00000000`31efd850 00000000`264e4270 00000000`2607cf08 00000000`6c7eebd5 : R!R_initAssignSymbols+0xf27a0d 00000000`6c7eeb9c : 00000000`31dfaad8 0000002e`2375f578 00000000`00000000 00000000`2607c4e8 : R!Rf_eval+0x1710e 00000000`6c7ee3dc : 00000000`00000000 00000000`14590670 00000000`2607cf08 00000000`324006f8 : R!Rf_eval+0x9cc0f 00000000`6c82251b : 00000000`2fa88528 00000000`14590788 00000000`23992b28 00000000`6c7f08d2 : R!Rf_eval+0x20c0:000> lmv m readxlBrowse full module liststart end module name00000000`65340000 00000000`6543f000 readxl (export symbols) C:\Users\Icewall\Documents\R\win-library\3.4\readxl\libs\x64\readxl.dll Loaded symbol image file: C:\Users\Icewall\Documents\R\win-library\3.4\readxl\libs\x64\readxl.dll Image path: C:\Users\Icewall\Documents\R\win-library\3.4\readxl\libs\x64\readxl.dll Image name: readxl.dll Browse all global symbols functions data Timestamp: Wed Aug 30 18:38:23 2017 (59A6E9FF) CheckSum: 001018F6 ImageSize: 000FF000 Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4Linux version [———————————-registers———————————–]RAX: 0xdea898 RBX: 0xb6a8c0 –> 0xaaaa0201 RCX: 0x7fffffffdb80 –> 0x2000bd RDX: 0xbd RSI: 0x7fffffffdb80 –> 0x2000bd RDI: 0xffffffff RBP: 0x7fffffffdb60 –> 0x7fffffffdc00 –> 0x7fffffffdc70 –> 0x401610 (<__libc_csu_init>: push r15)RSP: 0x7fffffffdb00 –> 0x60f3a0 –> 0x8000000c90b RIP: 0x7ffff7bce936 (<xls_addCell+144>: mov WORD PTR [rax],dx)R8 : 0x60f360 –> 0x0 R9 : 0x800000003000000 R10: 0x6f ('o')R11: 0x7ffff7bce8a6 (<xls_addCell>: push rbp)R12: 0x400b60 (<_start>: xor ebp,ebp)R13: 0x7fffffffdd50 –> 0x2 R14: 0x0 R15: 0x0EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)[————————————-code————————————-] 0x7ffff7bce92b <xls_addCell+133>: mov rax,QWORD PTR [rbp-0x50] 0x7ffff7bce92f <xls_addCell+137>: movzx edx,WORD PTR [rax] 0x7ffff7bce932 <xls_addCell+140>: mov rax,QWORD PTR [rbp-0x28]=> 0x7ffff7bce936 <xls_addCell+144>: mov WORD PTR [rax],dx 0x7ffff7bce939 <xls_addCell+147>: mov rax,QWORD PTR [rbp-0x58] 0x7ffff7bce93d <xls_addCell+151>: movzx eax,WORD PTR [rax+0x4] 0x7ffff7bce941 <xls_addCell+155>: cwde 0x7ffff7bce942 <xls_addCell+156>: mov edi,eax[————————————stack————————————-]0000| 0x7fffffffdb00 –> 0x60f3a0 –> 0x8000000c90b 0008| 0x7fffffffdb08 –> 0x607c50 –> 0xbbbbbbbbffffaaaa 0016| 0x7fffffffdb10 –> 0x7fffffffdb80 –> 0x2000bd 0024| 0x7fffffffdb18 –> 0x60f3a0 –> 0x8000000c90b 0032| 0x7fffffffdb20 –> 0x60f3a0 –> 0x8000000c90b 0040| 0x7fffffffdb28 –> 0x60f360 –> 0x0 0048| 0x7fffffffdb30 –> 0x800000003000000 0056| 0x7fffffffdb38 –> 0xdea898 [——————————————————————————]Legend: code, data, rodata, valueStopped reason: SIGSEGV0x00007ffff7bce936 in xls_addCell (pWS=0x60f3a0, bof=0x7fffffffdb80, buf=0x607c50 "\252\252\377\377\273\273\273\273\314\314\314\314\335\335\335\335", <incomplete sequence \345>) at xls.c:458458 cell->id=bof->id;gdb-peda$ bt#0 0x00007ffff7bce936 in xls_addCell (pWS=0x60f3a0, bof=0x7fffffffdb80, buf=0x607c50 "\252\252\377\377\273\273\273\273\314\314\314\314\335\335\335\335", <incomplete sequence \345>) at xls.c:458#1 0x00007ffff7bd0b1a in xls_parseWorkSheet (pWS=0x60f3a0) at xls.c:1150#2 0x0000000000400ff8 in main (argc=0x2, argv=0x7fffffffdd58) at xls2csv.c:149#3 0x00007ffff781c830 in __libc_start_main (main=0x400d78 <main>, argc=0x2, argv=0x7fffffffdd58, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdd48) at ../csu/libc-start.c:291#4 0x0000000000400b89 in _start ()gdb-peda$ exploitable -m__main__:102: UserWarning: GDB v7.11 may not support required Python APIWarning: machine string printing is deprecated and may be removed in a future release.EXCEPTION_FAULTING_ADDRESS:0x00000000dea898EXCEPTION_CODE:0xbFAULTING_INSTRUCTION:mov WORD PTR [rax],dxMAJOR_HASH:34754c1fb7e7f36e18e374f783e4c876MINOR_HASH:34754c1fb7e7f36e18e374f783e4c876STACK_DEPTH:3STACK_FRAME:/home/icewall/bugs/libxls-1.4.0/build/lib/libxlsreader.so.1.2.1!xls_addCell+0x0STACK_FRAME:/home/icewall/bugs/libxls-1.4.0/build/lib/libxlsreader.so.1.2.1!xls_parseWorkSheet+0x0STACK_FRAME:/home/icewall/bugs/libxls-1.4.0/build/bin/xls2csv!main+0x0INSTRUCTION_ADDRESS:0x007ffff7bce936INVOKING_STACK_FRAME:0DESCRIPTION:Access violation on destination operandSHORT_DESCRIPTION:DestAv (9/29)OTHER_RULES:AccessViolation (28/29)CLASSIFICATION:EXPLOITABLEEXPLANATION: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 operandShort description: DestAv (9/29)Hash: 34754c1fb7e7f36e18e374f783e4c876.34754c1fb7e7f36e18e374f783e4c876Exploitability Classification: EXPLOITABLEExplanation: 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