Talos Vulnerability Report


AntennaHouse DMC HTMLFilter GetIndexArray Code Execution Vulnerability

May 4, 2017
CVE Number



An exploitable heap corruption vulnerability exists in the GetIndexArray functionality of AntennaHouse DMC HTMLFilter as used by MarkLogioc 8.0-6. A specially crafted XLS file can cause a heap corruption resulting in arbitrary code execution. An attacker can send/provide a malicious XLS file to trigger this vulnerability.

Tested Versions

AntennaHouse DMC HTMLFilter shiped with MarkLogic 8.0-6 fb1a22fa08c986ec3614284f4e912b0a /opt/MarkLogic/Converters/cvtofc/libdhf_rdoc.so 15b0acc464fba28335239f722a62037f /opt/MarkLogic/Converters/cvtofc/libdmc_comm.so 1eabb31236c675f9856a7d001b339334 /opt/MarkLogic/Converters/cvtofc/libdhf_rxls.so 1415cbc784f05db0e9db424636df581a /opt/MarkLogic/Converters/cvtofc/libdhf_comm.so 4ae366fbd4540dd4c750e6679eb63dd4 /opt/MarkLogic/Converters/cvtofc/libdmc_conf.so 81db1b55e18a0cb70a78410147f50b9c /opt/MarkLogic/Converters/cvtofc/libdhf_htmlif.so d716dd77c8e9ee88df435e74fad687e6 /opt/MarkLogic/Converters/cvtofc/libdhf_whtml.so e01d37392e2b2cea757a52ddb7873515 /opt/MarkLogic/Converters/cvtofc/convert

Product URLs


CVSSv3 Score

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


This vulnerability is present in the AntennaHouse DMC HTMLFilter which is used, among others, to convert XLS files to (X)HTML form.   This product is mainly used by MarkLogic for office document conversions as part of their web based document search and rendering engine.  A specially crafted XLS file can lead to heap corruption and can ultimately result in remote code execution. 

Running the XLS to HTML converter under Valgrind we can see the following result:

icewall@ubuntu:~/bugs/cvtofc_86$ valgrind ./convert config_xls/
==38273== Memcheck, a memory error detector
==38273== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==38273== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==38273== Command: ./convert config_xls/
Return from GetFileInfo=0
==38273== Invalid write of size 4
==38273==    at 0x4053B38: GetIndexArray (in /home/icewall/bugs/cvtofc_86/libdhf_rxls.so)
==38273==    by 0x405325C: DHF_RGetObject (in /home/icewall/bugs/cvtofc_86/libdhf_rxls.so)
==38273==    by 0x403979E: FilterToHtml (in /home/icewall/bugs/cvtofc_86/libdhf_htmlif.so)
==38273==    by 0x4038AFB: DHF_GetHtml_V11 (in /home/icewall/bugs/cvtofc_86/libdhf_htmlif.so)
==38273==    by 0x8049AF7: main (in /home/icewall/bugs/cvtofc_86/convert)
==38273==  Address 0x4c5b474 is 4,820 bytes inside an unallocated block of size 6,248 in arena "client"	

The out-of-bounds write occurs in the GetIndexArray function. Let’s check the pseudocode of the GetIndexArray function and try to spot the vulnerable code:

Line 1 	signed int __cdecl GetIndexArray(struct_a1_1 *a1)
Line 2 	{
Line 3 	  struct_v1 *blankRec; // eax@1
Line 4 	  int word1_1; // edx@1
Line 5 	  int _size; // edx@1
Line 6 	  _DWORD *_buffer; // eax@1
Line 7 	  int index; // esi@3
Line 8 
Line 9 	  blankRec = (struct_v1 *)(a1->dword7A4 + (a1->dword7B0 << 6) - 64);
Line 10	  rw_1 = blankRec->rw + 1;
Line 11	  a1->col_1 = blankRec->col + 1;
Line 12	  _size = a1->col_1 * rw_1;
Line 13	  a1->size = _size;
Line 14	  _buffer = (_DWORD *)DMC_malloc(4 * _size);
Line 15	  a1->buffer = _buffer;
Line 16	  if ( !_buffer )
Line 17		return 12;
Line 18	  memset(a1->buffer, 0xFF, 4 * a1->size);
Line 19	  for ( index = 0; index < a1->count; ++index )
Line 20		a1->buffer[a1->col_1 * a1->labelSstes[index].cell.rw + (unsigned __int16)a1->labelSstes[index].cell.col] = index;
Line 21	  return 0;
Line 22	}

There are plenty of places where integer overflows can occur, however, looking for write operations, we see the line 20 has the potential to result in an out-of-bounds write. The space for a1->buffer is allocated at line 14, based on the mulitplication of blankRec->col and blankRec->rw.

The BlankRec in MS-XLS is:

2.4.20 Blank
The Blank record specifies an empty cell with no formula (section 2.2.2) or value.

And its location in our PoC is 0x13D1:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

000013C0                                        0E 00 06 00               ....
000013D0   1B 00                                              ..

Where the a1->labelSstes structure is :

2.4.149 LabelSst
The LabelSst record specifies a cell that contains a string.

and the location of this structure in the PoC is 0x13BE:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

000013B0                                              0E 00                 ..
000013C0   FF FF 80 00 10 00 00 00                            ˇˇÄ.....

In our case the result of the multiplication of a1->col_1 (0x08) and a1->labelSstes[index].cell.rw (0x0E) and adding a1->labelSstes[index].cell.col (0xFF) to it (0x1006fF) is much bigger than allocated space of a1->buffer which
leads to an arbitrary out-of-bounds write.

Crash Information

Program received signal SIGSEGV, Segmentation fault.
EAX: 0x810bbb8 --> 0x0 
EBX: 0xf7fd1c24 --> 0x1fb2c 
ECX: 0x810afb0 --> 0x0 
EDX: 0x1006f 
ESI: 0x3c ('<')
EDI: 0x8097d10 --> 0x0 
EBP: 0xfffec8b8 --> 0xfffec8e8 --> 0xfffec918 --> 0xfffeccf8 --> 0xffffd068 --> 0x0 
ESP: 0xfffec8a0 --> 0x6 
EIP: 0xf7fcab38 (mov    DWORD PTR [eax+edx*4],esi)
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
   0xf7fcab29:	imul   eax,DWORD PTR [edi+0x9ec]
   0xf7fcab30:	add    edx,eax
   0xf7fcab32:	mov    eax,DWORD PTR [edi+0x9f4]
=> 0xf7fcab38:	mov    DWORD PTR [eax+edx*4],esi
   0xf7fcab3b:	inc    esi
   0xf7fcab3c:	cmp    esi,DWORD PTR [edi+0x9a4]
   0xf7fcab42:	jl     0xf7fcab14
   0xf7fcab44:	mov    eax,0x0
0000| 0xfffec8a0 --> 0x6 
0004| 0xfffec8a4 --> 0xe 
0008| 0xfffec8a8 --> 0x4 
0012| 0xfffec8ac --> 0xf7fd1c24 --> 0x1fb2c 
0016| 0xfffec8b0 --> 0x0 
0020| 0xfffec8b4 --> 0x8097d10 --> 0x0 
0024| 0xfffec8b8 --> 0xfffec8e8 --> 0xfffec918 --> 0xfffeccf8 --> 0xffffd068 --> 0x0 
0028| 0xfffec8bc --> 0xf7fca25d (mov    esi,eax)
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0xf7fcab38 in GetIndexArray () from ./libdhf_rxls.so
gdb-peda$ bt
#0  0xf7fcab38 in GetIndexArray () from ./libdhf_rxls.so
#1  0xf7fca25d in DHF_RGetObject () from ./libdhf_rxls.so
#2  0xf7fd479f in FilterToHtml () from ./libdhf_htmlif.so
#3  0xf7fd3afc in DHF_GetHtml_V11 () from ./libdhf_htmlif.so
#4  0x08049af8 in main ()
#5  0xf7d74af3 in __libc_start_main (main=0x8049730 <main>, argc=0x2, argv=0xffffd104, init=0x8049f70 <__libc_csu_init>, fini=0x8049f60 <__libc_csu_fini>, rtld_fini=0xf7feb160 <_dl_fini>, 
	stack_end=0xffffd0fc) at libc-start.c:287
#6  0x08048ad1 in _start ()
gdb-peda$ exploitable
Description: Access violation on destination operand
Short description: DestAv (9/29)
Hash: 6f45d697880ae583ed9077b284dc1049.6f45d697880ae583ed9077b284dc1049
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)


2017-02-28 - Vendor Disclosure
2017-05-04 - Public Release


Discovered by Marcin 'Icewall' Noga of Cisco Talos.