Talos Vulnerability Report

TALOS-2016-0145

Hancom Hangul Office HShow!NXDeleteLineObj+0x6960c Code Execution Vulnerability

August 4, 2016
CVE Number

CVE-2016-4290

Description

This vulnerability was discovered within the Hangul HShow application which is part of the Hangul Office Suite. Hangul Office is published by Hancom, Inc. and is considered one of the more popular Office suites used within South Korea. When opening a Hangul HShow Document (.hpt) and processing a structure within the document, the application will attempt to allocate space for a block of data within the file. When calculating this length, the application will use a value from the file and add a constant to it without checking whether the addition of the constant will cause the integer to overflow which will cause the buffer to be undersized when the application tries to copy file data into it. This allows one to overwrite contiguous data in the heap which can lead to code-execution under the context of the application.

Tested Versions

Hancom Office 2014 VP Trial HShow.exe Product version: 9.1.0.2176 HncBM90.dll Product version: 9.1.0.2291

Product Urls

http://www.hancom.com http://www.hancom.com/en/product/product2014vp_01.jsp

CVSSv3 Score

8.6 – CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H

Details

Hangul HShow is prefixed with a header which can describe whether it’s contents are encoded with the zlib library. After processing the header, the application will take the version and use it to determine which structures need to be decoded within the zlib-encoded data. When reading a particular uint32_t from the file, the application will take this value and add 0x16 to it when allocating space for data. Later, the application will try to read file data into the allocated space. Due to the application not checking that the addition will cause the integer to overflow, a heap-based buffer overflow can be made to occur.

After reading the header and decompressing the zlibbed data section in the file, the application will eventually call the function at HShow.exe+5fcf30. At the beginning of this function, the application will copy data from an argument onto the stack. The second dword of this data is used in a loop later in the function.

HShow!NXDeleteLineObj+0x694a0:
...
008bcf54 50              push    eax
008bcf55 8d842428010000  lea     eax,[esp+128h]
008bcf5c 64a300000000    mov     dword ptr fs:[00000000h],eax
008bcf62 8b4508          mov     eax,dword ptr [ebp+8]
008bcf65 8b4008          mov     eax,dword ptr [eax+8]
008bcf68 8db000010000    lea     esi,[eax+100h]
008bcf6e b940000000      mov     ecx,40h
008bcf73 8d7c2424        lea     edi,[esp+24h]
008bcf77 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

Later in the same function, the application will enter the following loop. This loop will use the second dword to terminate itself. The first function call in this loop will lead to our vulnerability.

HShow!NXDeleteLineObj+0x69607:
008bd097 8b4d08          mov     ecx,dword ptr [ebp+8]
008bd09a 56              push    esi
008bd09b 51              push    ecx
008bd09c e85f000000      call    HShow!NXDeleteLineObj+0x69670 (008bd100)   ; XXX
008bd0a1 0fbf4c2428      movsx   ecx,word ptr [esp+28h]
008bd0a6 33d2            xor     edx,edx
008bd0a8 8bc3            mov     eax,ebx
008bd0aa f7f1            div     eax,ecx
008bd0ac 8b7d08          mov     edi,dword ptr [ebp+8]
008bd0af 83c028          add     eax,28h
008bd0b2 50              push    eax
008bd0b3 e808f9ffff      call    HShow!NXDeleteLineObj+0x68f30 (008bc9c0)
008bd0b8 0fbf442428      movsx   eax,word ptr [esp+28h]
008bd0bd 46              inc     esi
008bd0be 83c332          add     ebx,32h
008bd0c1 3bf0            cmp     esi,eax
008bd0c3 72d2            jb      HShow!NXDeleteLineObj+0x69607 (008bd097)

Inside the function that’s called, the application will set a variable on the stack to point to a linked-list. One of the structures within this linked list contains all the variables required by our vulnerability. At address 0x8b22a, the application will pass the linked-list as the second argument.

HShow!NXDeleteLineObj+0x696f3:
008bd183 8bfe            mov     edi,esi
008bd185 69ff04080000    imul    edi,edi,804h
008bd18b 03b808010000    add     edi,dword ptr [eax+108h]
008bd191 897c2418        mov     dword ptr [esp+18h],edi
008bd195 0f84fa000000    je      HShow!NXDeleteLineObj+0x69805 (008bd295)
...
HShow!NXDeleteLineObj+0x69796:
008bd226 8b4d00          mov     ecx,dword ptr [ebp]
008bd229 56              push    esi
008bd22a 57              push    edi    ; linked-list
008bd22b 53              push    ebx
008bd22c e8df260000      call    HShow!NXDeleteLineObj+0x6be80 (008bf910)

Once the linked-list is passed to the function call at 0x8bd22c, the application will enter the following loop at 0x8bf95c. This loop increments an index in the %edx register, which is used to fetch the structure that’s located within the linked list that’s passed as an argument.

HShow!NXDeleteLineObj+0x6becc:
008bf95c 8b8110050000    mov     eax,dword ptr [ecx+510h]
008bf962 3bc2            cmp     eax,edx
008bf964 89542414        mov     dword ptr [esp+14h],edx
008bf968 8954241c        mov     dword ptr [esp+1Ch],edx
008bf96c 0f8ee2010000    jle     HShow!NXDeleteLineObj+0x6c0c4 (008bfb54)
008bf972 85d2            test    edx,edx
008bf974 0f8cbf010000    jl      HShow!NXDeleteLineObj+0x6c0a9 (008bfb39)
008bf97a 3bd0            cmp     edx,eax
008bf97c 0f8db7010000    jge     HShow!NXDeleteLineObj+0x6c0a9 (008bfb39)
008bf982 8bc1            mov     eax,ecx    ; XXX: index
008bf984 e8f7fdfeff      call    HShow!NXDeleteLineObj+0x5bcf0 (008af780)   ; fetch index of linked-list
...
008bfb39 8b54241c        mov     edx,dword ptr [esp+1Ch]
008bfb3d 8b4c2438        mov     ecx,dword ptr [esp+38h]
008bfb41 8b8110050000    mov     eax,dword ptr [ecx+510h]
008bfb47 42              inc     edx
008bfb48 3bd0            cmp     edx,eax
008bfb4a 8954241c        mov     dword ptr [esp+1Ch],edx
008bfb4e 0f8c1efeffff    jl      HShow!NXDeleteLineObj+0x6bee2 (008bf972)

Once the structure is fetched at the beginning of the loop, the application will pass the structure as an argument to the following function call. This function call contains a list of 0x24 different cases. In case 0xd, the application will pass an object containing the size as the third argument to the function.

HShow!NXDeleteLineObj+0x6bff5:
008bfa85 8b442438        mov     eax,dword ptr [esp+38h]    ; linked-list
008bfa89 8b5500          mov     edx,dword ptr [ebp]
008bfa8c 56              push    esi
008bfa8d 53              push    ebx    ; XXX: object
008bfa8e 50              push    eax
008bfa8f 57              push    edi
008bfa90 8d4c2444        lea     ecx,[esp+44h]
008bfa94 51              push    ecx
008bfa95 52              push    edx    ; index
008bfa96 e8a5050300      call    HShow!NXDeleteLineObj+0x9c5b0 (008f0040) ; \
...
\
...
HShow!NXDeleteLineObj+0x9c85c:
008f02ec 8b8c2488000000  mov     ecx,dword ptr [esp+88h]
008f02f3 55              push    ebp    ; XXX: object containing size
008f02f4 8d442444        lea     eax,[esp+44h]
008f02f8 83c128          add     ecx,28h
008f02fb 50              push    eax
008f02fc 51              push    ecx
008f02fd 8bcb            mov     ecx,ebx
008f02ff e83c130200      call    HShow!NXDeleteLineObj+0xbdbb0 (00911640)
008f0304 8bf0            mov     esi,eax

Inside the function at 0x911640, in the function the application will pull a uint32_t length out of the third argument and then add the constant 0x16 to it. This constant does is not checked and can be made to overflow. Later, this constant is passed down the call-chain and is eventually used to allocate a buffer.

HShow!NXDeleteLineObj+0xbdc8e:
0091171e 8b742418        mov     esi,dword ptr [esp+18h]
00911722 8d5816          lea     ebx,[eax+16h]      ; XXX: integer overflow
00911725 56              push    esi
00911726 e8a5b41600      call    HShow!NXDeleteLineObj+0x229140 (00a7cbd0)  ; \
\
HShow!NXDeleteLineObj+0x229160:
00a7cbf0 50              push    eax
00a7cbf1 8b4218          mov     eax,dword ptr [edx+18h]
00a7cbf4 ffd0            call    eax    ; XXX: size still in %ebx
00a7cbf6 894670          mov     dword ptr [esi+70h],eax
00a7cbf9 5e              pop     esi
00a7cbfa c20400          ret     4
\
HShow!NXDeleteLineObj+0x2674ec:
00abaf7c 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
00abaf7f 56              push    esi
00abaf80 53              push    ebx    ; XXX: size
00abaf81 51              push    ecx    ; XXX: source data
00abaf82 50              push    eax
00abaf83 e898f9ffff      call    HShow!NXDeleteLineObj+0x266e90 (00aba920)
00abaf88 eb02            jmp     HShow!NXDeleteLineObj+0x2674fc (00abaf8c)

After passing the size as an argument at the function call to 0xaba920, the application will store the size into the %ebp register. Later in the function, this size will be used as an argument for an allocation and then later a memcpy operation occurs. Due to an integer-wrap occurring, this memcpy will overflow the heap buffer which can lead to the overwriting of a contiguous structure on the heap.

00aba944 8b6c242c        mov     ebp,dword ptr [esp+2Ch]    ; size from argument
...
HShow!NXDeleteLineObj+0x266efc:
00aba98c 55              push    ebp
00aba98d e8115c4f00      call    HShow!NGLSetSurfaceMetal+0xe87d3 (00fb05a3)    ; allocation
00aba992 55              push    ebp    ; source size
00aba993 57              push    edi
00aba994 55              push    ebp    ; dest size
00aba995 50              push    eax    ; buffer
00aba996 8906            mov     dword ptr [esi],eax
00aba998 ff15f8870f01    call    dword ptr [HShow!NGLSetSurfaceMetal+0x230a28 (010f87f8)]   ; memcpy_s
00aba99e 83c414          add     esp,14h

0:009> lm m hshow
start    end        module name
002c0000 01799000   HShow      (export symbols)       HShow.exe

Crash Analysis

0:011> lm m hshow
start    end        module name
01070000 02549000   HShow      (export symbols)       HShow.exe

(408.f18): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00930000 ecx=005e0000 edx=00930000 esi=139728ba edi=0092fff8
eip=778c2d2d esp=1172dfc8 ebp=1172dffc iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
ntdll!RtlpLowFragHeapFree+0x37:
778c2d2d c6470780        mov     byte ptr [edi+7],80h       ds:0023:0092ffff=dc
0:011> kv
ChildEBP RetAddr  Args to Child
1172dffc 778c2cd8 00930000 06412070 128e93b0 ntdll!RtlpLowFragHeapFree+0x37 (FPO: [Non-Fpo])
1172e014 77a2c4d4 005e0000 00000000 00930000 ntdll!RtlFreeHeap+0x105 (FPO: [Non-Fpo])
1172e028 717e3c1b 005e0000 00000000 00930000 kernel32!HeapFree+0x14 (FPO: [Non-Fpo])
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for HShow.exe -
1172e074 0167d3f4 00930000 0167d4eb 00000000 MSVCR90!free+0xcd (FPO: [Non-Fpo])
WARNING: Stack unwind information not available. Following frames may be wrong.
00000000 00000000 00000000 00000000 00000000 HShow!NXDeleteLineObj+0x79964

Timeline

2016-03-28 - Discovery
2016-04-19 - Vendor Notification
2016-08-04 - Public Disclosure

Credit

Discovered by Cisco Talos.