CVE-2016-4290
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.
Hancom Office 2014 VP Trial HShow.exe Product version: 9.1.0.2176 HncBM90.dll Product version: 9.1.0.2291
http://www.hancom.com http://www.hancom.com/en/product/product2014vp_01.jsp
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 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
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
2016-03-28 - Discovery
2016-04-19 - Vendor Notification
2016-08-04 - Public Disclosure
Discovered by Cisco Talos.