CVE: CVE-2019-16338

Tested Versions:

  • Hancom Office NEO (HwordApp)

Product URL(s): https://www.hancom.com/cs_center/csDownload.do

Description of the vulnerability

Hangul Office is published by Hancom, Inc. and is considered one of the more popular Office suites used within South Korea. When opening a specially crafted Office Open XML Document (.docx), HwordApp does not properly process a tfo_common object which will cause a use-after-free. This may lead to code execution under the context of the application.

Vulnerability

Crash context:

(d4c.2f8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=2e2e0f58 ebx=0000004b ecx=2e2e0f58 edx=02f110d0 esi=57848fe8 edi=57848fe8
eip=70a4d8cf esp=0070a3d8 ebp=0070a3e0 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210206
HwordApp!HwordDeletePropertyArray+0xb6f68f:
70a4d8cf 8b01       mov     eax,dword ptr [ecx]  ds:002b:2e2e0f58=????????

ECX points to a block of freed memory:

address 2e2e0f58 found in
   _DPH_HEAP_ROOT @ 2f11000
   in free-ed allocation (  DPH_HEAP_BLOCK:     VirtAddr     VirtSize)
                                  5b8d071c:     2e2e0000         2000
   73a290b2 verifier!VerifierDisableFaultInjectionExclusionRange+0x00003162
   7779180c ntdll!RtlpNtEnumerateSubKey+0x00004935
   7774a8fe ntdll!RtlUlonglongByteSwap+0x0000db5e
   776f2c45 ntdll!RtlQueryPerformanceCounter+0x00000281
   75f714ad kernel32!HeapFree+0x00000014
   7256ecfa MSVCR120!free+0x0000001a
   701a3d1e HwordApp!HwordDeletePropertyArray+0x002c5ade
   70a4d8cc HwordApp!HwordDeletePropertyArray+0x00b6f68c
   70a5572f HwordApp!HwordDeletePropertyArray+0x00b774ef
   7020ff31 HwordApp!HwordDeletePropertyArray+0x00331cf1
   70b0be74 HwordApp!HwordDeletePropertyArray+0x00c2dc34
   70adfb4b HwordApp!HwordDeletePropertyArray+0x00c0190b
   70491857 HwordApp!HwordDeletePropertyArray+0x005b3617
   701564de HwordApp!HwordDeletePropertyArray+0x0027829e
   70154e7a HwordApp!HwordDeletePropertyArray+0x00276c3a
   6fef74b3 HwordApp!HwordDeletePropertyArray+0x00019273

As indicated by the verifier, this is a use-after-free bug.

There is also a call dword ptr [eax] following with the crash instruction, that means if we can control the freed memory, we can easily cause arbitrary code execution.

We are going to see what object it is and when it is going to be freed. ECX comes from EDI , so we are going to add a breakpoint at 0x70A4D8B8. When the breakpoint is hit, we will see what the object it is.

Breakpoint 0 hit
eax=00000000 ebx=0000004b ecx=57838fe8 edx=57838fe8 esi=57838fe8 edi=57838fe8
eip=70a4d8b8 esp=0070a3d8 ebp=0070a3e0 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200206
HwordApp!HwordDeletePropertyArray+0xb6f678:
70a4d8b8 837f0400        cmp     dword ptr [edi+4],0  ds:002b:57838fec=2da66f58

Breakpoint 0 hit
eax=00000000 ebx=0000004b ecx=57838fe8 edx=57838fe8 esi=57838fe8 edi=57838fe8
eip=70a4d8b8 esp=0070a3d8 ebp=0070a3e0 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200206
HwordApp!HwordDeletePropertyArray+0xb6f678:
70a4d8b8 837f0400        cmp     dword ptr [edi+4],0  ds:002b:57838fec=2da66f58
0:000> dd edi
57838fe8  70f1d1c8 2da66f58 00000000 c0c00000
57838ff8  0000004b d0d0d0d0 ???????? ????????
57839008  ???????? ???????? ???????? ????????
57839018  ???????? ???????? ???????? ????????
57839028  ???????? ???????? ???????? ????????
57839038  ???????? ???????? ???????? ????????
57839048  ???????? ???????? ???????? ????????
57839058  ???????? ???????? ???????? ????????

0:000> dd 2da66f58
2da66f58  70ecc3d8 70ecc3e4 00000020 00000000
2da66f68  00000000 41700000 00000002 49000000
2da66f78  00000001 00000000 00000001 00000001
2da66f88  00000000 00000001 00000001 70ecc330
2da66f98  70ecc33c 00000000 c0c0c001 00000000
2da66fa8  70ec9584 00000002 00000007 00000000
2da66fb8  00000000 00000000 70ec9584 00000002
2da66fc8  00000088 00000000 00000000 00000000
address 2da66f58 found in
   _DPH_HEAP_ROOT @ 2f11000
   in busy allocation (  DPH_HEAP_BLOCK:   UserAddr   UserSize -   VirtAddr   VirtSize)
                               2db61ed4:   2da66f58         a8 -   2da66000       2000
         ? HwordApp!HwordDeletePropertyArray+fee198
   73a28e89 verifier!VerifierDisableFaultInjectionExclusionRange+0x00002f39
   7779103e ntdll!RtlpNtEnumerateSubKey+0x00004167
   7774abe2 ntdll!RtlUlonglongByteSwap+0x0000de42
   776f34a1 ntdll!RtlQueryPerformanceCounter+0x00000add
   7256ed63 MSVCR120!malloc+0x00000033
   7256ee1f MSVCR120!operator new+0x0000000e
   72606184 MSVCR120!operator new+0x0000000b
   70a56397 HwordApp!HwordDeletePropertyArray+0x00b78157
   7020ff31 HwordApp!HwordDeletePropertyArray+0x00331cf1

We now know this object is created at 0x70A56392, when we look into the code near this location, we find an interesting string:

v9 is the object and sub_701A3A60 seems to be the initialization function:

Thus we conclude that this object is called tfo_common.

But when is the object is freed? At 0x70A4D8C9, there will a call to 0x701a3cc0, and its only parameter is the integer 1. When we jump to 0x701A3CC0, we can see the logic behind this:

Let’s go back to function sub_70A4D8A0, the free and re-use behaviour is depicted here:

Timeline:

  • 2019-01-09 Vendor disclosure
  • 2019-01-10 Vendor silently patched

Vendor Response

The vendor has silently released a fix for the issue some time after reporting.