Talos Vulnerability Report

TALOS-2017-0286

AntennaHouse DMC HTMLFilter PPT DHFSummary Code Execution Vulnerability

May 4, 2017
CVE Number

CVE-2017-2794

Summary

An exploitable stack-based buffer overflow vulnerability exists in the DHFSummary functionality of AntennaHouse DMC HTMLFilter as used by MarkLogic 8.0-6. A specially crafted PPT file can cause a stack corruption resulting in arbitrary code execution. An attacker can send/provide malicious PPT file to trigger this vulnerability.

Tested Versions

AntennaHouse DMC HTMLFilter shipped 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

https://www.antennahouse.com/antenna1/

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

Details

This vulnerability is present in the AntennaHouse DMC HTMLFilter which is used, among others, to convert PPT 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 PPT file can lead to an stack corruption and ultimately to remote code execution.

Let's investigate this vulnerability. After executing the PPT to HTML converter with the malformed PPT file as an input we can easily observe a problem using Valgrind:

gdb-peda$ context
b[----------------------------------registers-----------------------------------]
EAX: 0x80ad640 --> 0xb3e3 
EBX: 0xf7f06000 --> 0x1aada8 
ECX: 0xebfebe6f 
EDX: 0xffffdff0 --> 0xb3d3 
ESI: 0x7c ('|')
EDI: 0xfffe9f58 ("TSER")
EBP: 0xfffe9f18 --> 0xfffea788 --> 0x50 ('P')
ESP: 0xfffe9e88 --> 0xf7cd2848 --> 0x3770 ('p7')
EIP: 0xf7e8f2fd (movntdq XMMWORD PTR [edx+0x10],xmm1)
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xf7e8f2f0:  lfence 
   0xf7e8f2f3:  sub    ecx,0x80
   0xf7e8f2f9:  movntdq XMMWORD PTR [edx],xmm0
=> 0xf7e8f2fd:  movntdq XMMWORD PTR [edx+0x10],xmm1
   0xf7e8f302:  movntdq XMMWORD PTR [edx+0x20],xmm2
   0xf7e8f307:  movntdq XMMWORD PTR [edx+0x30],xmm3
   0xf7e8f30c:  movntdq XMMWORD PTR [edx+0x40],xmm4
   0xf7e8f311:  movntdq XMMWORD PTR [edx+0x50],xmm5
[------------------------------------stack-------------------------------------]
0000| 0xfffe9e88 --> 0xf7cd2848 --> 0x3770 ('p7')
0004| 0xfffe9e8c --> 0xf7cd130d (add    esp,0x10)
0008| 0xfffe9e90 --> 0xfffe9f58 ("TSER")
0012| 0xfffe9e94 --> 0x8099528 ("TSER")
0016| 0xfffe9e98 --> 0xec000007 
0020| 0xfffe9e9c --> 0xf7cd100a (pop    ebx)
0024| 0xfffe9ea0 --> 0xfffe9f00 --> 0xfffea788 --> 0x50 ('P')
0028| 0xfffe9ea4 --> 0xf7fea161 (sub    esp,0x14)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ bt 10
#0  __memcpy_ssse3_rep () at ../sysdeps/i386/i686/multiarch/memcpy-ssse3-rep.S:1295
#1  0xf7cd130d in DHFSummary () from ./libdhf_comm.so
#2  0xf7cd1576 in DHF_SummaryInfo () from ./libdhf_comm.so
#3  0x00000050 in ?? ()
#4  0x00000051 in ?? ()
#5  0x00000051 in ?? ()
#6  0x00000052 in ?? ()
#7  0x00000052 in ?? ()
#8  0x00000053 in ?? ()
#9  0x00000053 in ?? ()
(More stack frames follow...)
gdb-peda$ exploitable 
Description: Possible stack corruption
Short description: PossibleStackCorruption (8/29)
Hash: ea379fd123d7bb722a0a3ac6a0b24fd7.4e17f16447b1c349dcaf3f667f35ae8d
Exploitability Classification: EXPLOITABLE
Explanation: GDB generated an error while unwinding the stack and/or the stack contained return addresses that were not mapped in the inferior's process address space and/or the stack pointer is pointing to a location outside the default stack region. These conditions likely indicate stack corruption, which is generally considered exploitable.
Other tags: DestAv (9/29), AccessViolation (28/29)

we see that memcpy called in DHFSummary function caused a stack based buffer overflow which resulted in stack corruption. Let's investigate the moment when memcpy is called:

[----------------------------------registers-----------------------------------]
EAX: 0x9228528 ("TSER")
EBX: 0xf740f848 --> 0x3770 ('p7')
ECX: 0x92284a8 --> 0x1 
EDX: 0xff833340 --> 0x0 
ESI: 0x7c ('|')
EDI: 0xff833358 ("Slide 1")
EBP: 0xff833318 --> 0xff833b88 --> 0xff835cd8 --> 0xff835d08 --> 0xff835d38 --> 0xff836118 --> 0xff846488 --> 0x0 
ESP: 0xff833290 --> 0xff833358 ("Slide 1")
EIP: 0xf740e308 --> 0xffec77e8
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xf740e300:  push   DWORD PTR [edx+0x820]
   0xf740e306:  push   eax
   0xf740e307:  push   edi
=> 0xf740e308:  call   0xf740cf84 <[email protected]>
   0xf740e30d:  add    esp,0x10
   0xf740e310:  mov    ecx,DWORD PTR [ebp+0x8]
   0xf740e313:  cmp    DWORD PTR [ecx+0x820],0x100
   0xf740e31d:  jle    0xf740e333
Guessed arguments:
arg[0]: 0xff833358 ("Slide 1")
arg[1]: 0x9228528 ("TSER")
arg[2]: 0xec000007

The size parameter is huge and equals 0xec000007. We can easily observe in the pseudo-code where the value is coming from:

Line 1 signed int __cdecl DHFSummary(struct_a1 *a1, int a2, int a3)
Line 2 {
Line 3      int 20;
Line 4      (...)
Line 5             else if ( v17 > 3 )
Line 6             {
Line 7               if ( v17 == 30 )
Line 8               {
Line 9                 v19 = DHFSum_GetDWord(a1, &fileBuffer[offset]);
Line 10                a1->overflowSize = v19;
Line 11                if ( v19 )
Line 12                {
Line 13                  v20 = v19 - 1;
Line 14                  a1->overflowSize = v20;
Line 15                  if ( v20 > 1026 )
Line 16                    a1->overflowSize = 1026;
Line 17                  memcpy(&a1->stackBuffer, &fileBuffer[offset + 4], a1->overflowSize);
Line 18                  if ( a1->overflowSize > 256 )
Line 19                    DHFCutString(&a1->stackBuffer, &a1->overflowSize);
Line 20                  DHFSum_CodeConv(a1, 2);
Line 21                  memcpy(dest, src, a1->dword824);
Line 22                }
Line 23              }

We see that v20 variable is read directly from the file by the DHFSum_GetDWord function line 9, so an attacker has nearly full control of this value. Nearly, because v20 is checked to see if its value exceeds 1026 at line 15. The problem is that v20 is a signed value and values greater than 0x7fffffff will cause a negative value to be compared, which bypasses this check causing stack corruption.

File structure analysis reveal that the value 0xec000007 (0xec000008 in the file, it's decreased by one before the memcpy at line 13) is located in Summary Information data structure.

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

00001A00 FE FF 00 00 05 01 02 00 00 00 00 00 00 00 00 00 ˛ˇ.............. 00001A10 00 00 00 00 00 00 00 00 01 00 00 00 E0 85 9F F2 ............‡ÖüÚ 00001A20 F9 4F 68 10 AB 91 08 00 2B 27 B3 D9 30 00 00 00 ˘Oh.´ë..+'≥Ÿ0... 00001A30 A4 05 00 00 0B 00 00 00 01 00 00 00 60 00 00 00 §.............. 00001A40 02 00 00 00 68 00 00 00 04 00 00 00 78 00 00 00 ....h.......x... 00001A50 08 00 00 00 88 00 00 00 09 00 00 00 98 00 00 00 ....à.......ò... 00001A60 12 00 00 00 A4 00 00 00 0A 00 00 00 C8 00 00 00 ....§.......»... 00001A70 0C 00 00 00 D4 00 00 00 0D 00 00 00 E0 00 00 00 ....‘.......‡... 00001A80 0F 00 00 00 EC 00 00 00 11 00 00 00 F4 00 00 00 ....Ï.......Ù... 00001A90 02 00 00 00 B6 03 00 00 1E 00 00 00 08 00 00 00 ....∂........... 00001AA0 53 6C 69 64 65 20 31 00 1E 00 00 00 08 00 00 EC Slide 1........Ï 00001AB0 54 53 45 52 00 00 00 00 1E 00 00 00 08 00 00 00 TSER............ 00001AC0 55 53 45 52 00 00 00 00 1E 00 00 00 04 00 00 00 USER............ 00001AD0 36 00 00 00 1E 00 00 00 1C 00 00 00 4D 69 63 72 6...........Micr 00001AE0 6F 73 6F 66 74 20 4F 66 66 69 63 7C 20 50 6F 77 osoft Offic| Pow 00001AF0 65 72 50 6F 69 6E 74 00 40 00 00 00 10 E3 A3 A9 [email protected]„£© 00001B00 00 00 00 00 40 00 00 00 A0 1E CC 1E D8 39 C5 01 [email protected]†.Ã.ÿ9≈. 00001B10 40 00 00 00 30 9F 60 87 D9 39 C5 01 03 00 00 00 @...0üáŸ9≈..... 00001B20 18 00 00 00 47 00 00 00 A8 04 00 00 FF FF FF FF ....G...®...ˇˇˇˇ

Summary Information starts at offset 00001A00 in the file, and the field used in the memcpy operation is located at offset: 0x1AAC.

Crash Information

gdb-peda$ context
b[----------------------------------registers-----------------------------------]
EAX: 0x80ad640 --> 0xb3e3 
EBX: 0xf7f06000 --> 0x1aada8 
ECX: 0xebfebe6f 
EDX: 0xffffdff0 --> 0xb3d3 
ESI: 0x7c ('|')
EDI: 0xfffe9f58 ("TSER")
EBP: 0xfffe9f18 --> 0xfffea788 --> 0x50 ('P')
ESP: 0xfffe9e88 --> 0xf7cd2848 --> 0x3770 ('p7')
EIP: 0xf7e8f2fd (movntdq XMMWORD PTR [edx+0x10],xmm1)
EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xf7e8f2f0:  lfence 
   0xf7e8f2f3:  sub    ecx,0x80
   0xf7e8f2f9:  movntdq XMMWORD PTR [edx],xmm0
=> 0xf7e8f2fd:  movntdq XMMWORD PTR [edx+0x10],xmm1
   0xf7e8f302:  movntdq XMMWORD PTR [edx+0x20],xmm2
   0xf7e8f307:  movntdq XMMWORD PTR [edx+0x30],xmm3
   0xf7e8f30c:  movntdq XMMWORD PTR [edx+0x40],xmm4
   0xf7e8f311:  movntdq XMMWORD PTR [edx+0x50],xmm5
[------------------------------------stack-------------------------------------]
0000| 0xfffe9e88 --> 0xf7cd2848 --> 0x3770 ('p7')
0004| 0xfffe9e8c --> 0xf7cd130d (add    esp,0x10)
0008| 0xfffe9e90 --> 0xfffe9f58 ("TSER")
0012| 0xfffe9e94 --> 0x8099528 ("TSER")
0016| 0xfffe9e98 --> 0xec000007 
0020| 0xfffe9e9c --> 0xf7cd100a (pop    ebx)
0024| 0xfffe9ea0 --> 0xfffe9f00 --> 0xfffea788 --> 0x50 ('P')
0028| 0xfffe9ea4 --> 0xf7fea161 (sub    esp,0x14)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
gdb-peda$ bt 10
#0  __memcpy_ssse3_rep () at ../sysdeps/i386/i686/multiarch/memcpy-ssse3-rep.S:1295
#1  0xf7cd130d in DHFSummary () from ./libdhf_comm.so
#2  0xf7cd1576 in DHF_SummaryInfo () from ./libdhf_comm.so
#3  0x00000050 in ?? ()
#4  0x00000051 in ?? ()
#5  0x00000051 in ?? ()
#6  0x00000052 in ?? ()
#7  0x00000052 in ?? ()
#8  0x00000053 in ?? ()
#9  0x00000053 in ?? ()
(More stack frames follow...)
gdb-peda$ exploitable 
Description: Possible stack corruption
Short description: PossibleStackCorruption (8/29)
Hash: ea379fd123d7bb722a0a3ac6a0b24fd7.4e17f16447b1c349dcaf3f667f35ae8d
Exploitability Classification: EXPLOITABLE
Explanation: GDB generated an error while unwinding the stack and/or the stack contained return addresses that were not mapped in the inferior's process address space and/or the stack pointer is pointing to a location outside the default stack region. These conditions likely indicate stack corruption, which is generally considered exploitable.
Other tags: DestAv (9/29), AccessViolation (28/29)

Timeline

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

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.