Talos Vulnerability Report


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

August 4, 2016

Report ID



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 list of elements using a length from the file. When calculating this length, an integer overflow can be made to occur which will cause the buffer to be undersized when the application tries to copy file data into the object containing this structure. 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: HncBM90.dll Product version:

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


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 multiply it by 0x228. Later, the application will use this result to perform an allocation for a buffer that is used by a loop that reads content from the file. Due to the application not checking for an upper bounds on this value, the integer can be made to overflow causing the heap allocation to be undersized at which point the loop can be made to write outside this buffer.

After reading the header and decompressing the zlibbed data section in the file, the application will eventually encounter the following function. This function is responsible for reading a 0x10 byte structure from the file. When the function returns, the function only checks if the dword has it’s signed-bit set.

00fd9b55 8b4534          mov     eax,dword ptr [ebp+34h]
00fd9b58 50              push    eax
00fd9b59 8bc3            mov     eax,ebx
00fd9b5b e8e05dffff      call    HShow!NXDeleteLineObj+0x4beb0 (00fcf940)   ; XXX
00fd9b60 8b4534          mov     eax,dword ptr [ebp+34h]
00fd9b63 83c404          add     esp,4
00fd9b66 833800          cmp     dword ptr [eax],0
00fd9b69 7e7a            jle     HShow!NXDeleteLineObj+0x56155 (00fd9be5)

Inside this function, the application will read a dword into the structure that’s passed as an argument in the %eax register.

00fcf940 53              push    ebx
00fcf941 55              push    ebp
00fcf942 8b6c240c        mov     ebp,dword ptr [esp+0Ch]
00fcf946 56              push    esi
00fcf947 57              push    edi
00fcf948 8bd8            mov     ebx,eax    ; target structure
00fcf94a 8b03            mov     eax,dword ptr [ebx]
00fcf94c 8b5014          mov     edx,dword ptr [eax+14h]
00fcf94f 6a00            push    0
00fcf951 6a04            push    4
00fcf953 55              push    ebp
00fcf954 8bcb            mov     ecx,ebx
00fcf956 ffd2            call    edx        ; read 4-bytes form file
00fcf958 8bf0            mov     esi,eax

After reading the dword, the application will use the dword in the following code. This code multiplies the dword by 0x228 and then passes it to a function to allocate memory followed by initializing the memory using the memset function. Due to the application failing to check the bounds of this multiply, an integer overflow can be made to occur. This will later be used in an allocation.

00fd9b6b 8b08            mov     ecx,dword ptr [eax]
00fd9b6d 8b7804          mov     edi,dword ptr [eax+4]
00fd9b70 69c928020000    imul    ecx,ecx,228h       ; XXX: integer overflow
00fd9b76 51              push    ecx
00fd9b77 e8276a7000      call    HShow!NGLSetSurfaceMetal+0xe87d3 (016e05a3)    ; memory allocation
00fd9b7c 8b5534          mov     edx,dword ptr [ebp+34h]
00fd9b7f 8b0a            mov     ecx,dword ptr [edx]
00fd9b81 69c928020000    imul    ecx,ecx,228h
00fd9b87 83c404          add     esp,4
00fd9b8a 51              push    ecx
00fd9b8b 6a00            push    0
00fd9b8d 50              push    eax    ; XXX
00fd9b8e e8174a7100      call    HShow!NGLSetSurfaceMetal+0xf67da (016ee5aa)    ; memset

Later, the application will use the dword from the file as a counter to a loop that’s responsible for reading each structure from the file. This loop will iterate the number of times that’s specified by the dword and will eventually call a function with the same parameters as fread(…) to decompressed the zlibbed data into the allocated buffer. Due to this loop using a different value than the one used to allocate the space to write to, a heap-based buffer overflow can be made to occur.

00fd9bb4 8b4004          mov     eax,dword ptr [eax+4]
00fd9bb7 0344241c        add     eax,dword ptr [esp+1Ch]
00fd9bbb ff742414        push    dword ptr [esp+14h]
00fd9bbf 8d0c37          lea     ecx,[edi+esi]
00fd9bc2 8bd3            mov     edx,ebx
00fd9bc4 e887e1ffff      call    HShow!NXDeleteLineObj+0x542c0 (00fd7d50)   ; XXX: reads data from file
00fd9bc9 8b4c2424        mov     ecx,dword ptr [esp+24h]
00fd9bcd 8144241c28020000 add     dword ptr [esp+1Ch],228h
00fd9bd5 03f8            add     edi,eax
00fd9bd7 8b4534          mov     eax,dword ptr [ebp+34h]
00fd9bda 41              inc     ecx
00fd9bdb 3b08            cmp     ecx,dword ptr [eax]    ; XXX: dword from file
00fd9bdd 894c2424        mov     dword ptr [esp+24h],ecx
00fd9be1 7cd1            jl      HShow!NXDeleteLineObj+0x56124 (00fd9bb4)

With the provided proof-of-concept, the particular fread that overflows this buffer is located here.

00fcf89b bd00010000      mov     ebp,100h
00fcf8a0 8b06            mov     eax,dword ptr [esi]
00fcf8a2 8b5014          mov     edx,dword ptr [eax+14h]
00fcf8a5 6a00            push    0
00fcf8a7 6a02            push    2
00fcf8a9 57              push    edi
00fcf8aa 8bce            mov     ecx,esi
00fcf8ac ffd2            call    edx    ; fread(...)
00fcf8ae 83c702          add     edi,2
00fcf8b1 83ed01          sub     ebp,1
00fcf8b4 75ea            jne     HShow!NXDeleteLineObj+0x4be10 (00fcf8a0)

0:005> lm
start    end        module name
009f0000 01ec9000   HShow      (export symbols)       HShow.exe
6ba90000 6bad5000   HncBM90    (export symbols)       HncBM90.dll

Crash Analysis

eax=543efff0 ebx=5c51ddd8 ecx=00000000 edx=00000008 esi=00005957 edi=41a00000
eip=00fd9b77 esp=5c51d1e0 ebp=67217ee8 iopl=0         ov up ei pl nz na pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000a07
00fd9b77 e8276a7000      call    HShow!NGLSetSurfaceMetal+0xe87d3 (016e05a3)

0:010> ub .
00fd9b62 3483            xor     al,83h
00fd9b64 c40483          les     eax,fword ptr [ebx+eax*4]
00fd9b67 3800            cmp     byte ptr [eax],al
00fd9b69 7e7a            jle     HShow!NXDeleteLineObj+0x56155 (00fd9be5)
00fd9b6b 8b08            mov     ecx,dword ptr [eax]
00fd9b6d 8b7804          mov     edi,dword ptr [eax+4]
00fd9b70 69c928020000    imul    ecx,ecx,228h
00fd9b76 51              push    ecx

0:010> ? poi(@eax)
Evaluate expression: 1073741824 = 40000000

0:010> ? poi(@eax)*228
Evaluate expression: 0 = 00000000

(a40.8a0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=67226000 ebx=00000002 ecx=671b892b edx=671acaff esi=5baa6f98 edi=67226000
eip=6bab3376 esp=5c51ce88 ebp=5c51cee0 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
6bab3376 8810            mov     byte ptr [eax],dl          ds:0023:67226000=??0:010> kv

0:010> kv
ChildEBP RetAddr  Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
5c51cee0 6baa88d9 5baa6f98 00000002 67226000 HncBM90!HncGZUpdateCRC+0xa686
5c51d16c 00ff8918 67226000 00000002 000086c5 HncBM90!HncGZRead+0x79
5c51d18c 00fcf8ae 67226000 00000002 00000000 HShow!NXDeleteLineObj+0x74e88
5c51ddd8 5c51de40 00001000 00000000 00000000 HShow!NXDeleteLineObj+0x4be1e
5c51dddc 00000000 00000000 00000000 00000000 0x5c51de40

0:010> dc 67226000
67226000  ???????? ???????? ???????? ????????  ????????????????
67226010  ???????? ???????? ???????? ????????  ????????????????

Description of the proof-of-concept

Inside the provided proof of concept, the 0x10 byte structure that’s read is located at offset 0x7faf within the decompressed zlib data. The first dword is the value multiplied by 0x228 for the allocation.

7fa0  00 00 00 00 00 58 64 a0  00 96 00 00 07 07 00 00  .....Xd.........
7fb0  00 00 40 00 00 a0 41 00  00 49 00 00 00 09 00 00  ..@...A..I......
7fc0  00 01 00 01 00 01 00 ff  ff ff 00 01 00 8c 8c 8c  ................
7fd0  00 00 00 01 00 01 00 ff  78 69 63 00 4a 00 75 8c  ........xic.J.u.


Discovered by Cisco Talos


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