Talos Vulnerability Report
Hancom Hangul Office HShow!NXDeleteLineObj+0x47269 Code Execution Vulnerability
August 4, 2016
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 use a static size to allocate a heap buffer yet explicitly trust a size from the file when modifying data inside of it. Due to this, an aggressor can corrupt memory outside the bounds of this buffer which can lead to code execution under the context of the application.
Hancom Office 2014 VP Trial HShow.exe Product version: 188.8.131.526 HncBM90.dll Product version: 184.108.40.2061
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 structure from the file, the application will allocate 0xa0 bytes for it and initialize it with data from the file. Later, the application will trust another length when modifying data in this buffer which can allow one to corrupt memory outside the bounds of the 0xa0 byte buffer.
First the application will read a structure from the file. This structure has 5 different cases and will read a 16-bit value from the file. This 16-bit value is used to control the number of iterations within a loop that is later used during the oob write.
HShow!NXDeleteLineObj+0x89851: 0190d2e1 8d442430 lea eax,[esp+30h] 0190d2e5 8bcd mov ecx,ebp 0190d2e7 e814d8fbff call HShow!NXDeleteLineObj+0x47070 (018cab00) ; \ 0190d2ec 03d8 add ebx,eax \ HShow!NXDeleteLineObj+0x47258: 018cace8 03f0 add esi,eax 018cacea 8b07 mov eax,dword ptr [edi] 018cacec 8b5014 mov edx,dword ptr [eax+14h] 018cacef 6a00 push 0 018cacf1 6a02 push 2 018cacf3 8d4b2a lea ecx,[ebx+2Ah] 018cacf6 51 push ecx 018cacf7 8bcf mov ecx,edi 018cacf9 ffd2 call edx ; XXX: read a uint16_t 018cacfb 83e802 sub eax,2 018cacfe f7d8 neg eax 018cad00 1bc0 sbb eax,eax 018cad02 83e0fe and eax,0FFFFFFFEh 018cad05 83c002 add eax,2
After reading this structure, the application will then encounter the following code. This code will allocate 0xa0 bytes for a buffer. This is done at address 0x18fc9d1. Immediately afterwards, the application will initialize it with memset followed by initializing it with data from the file at address 0x18fc9f5. This statically sized buffer will be the one that can be corrupted later.
HShow!NXDeleteLineObj+0x78f41: 018fc9d1 68a0000000 push 0A0h 018fc9d6 e8c83b6e00 call HShow!NGLSetSurfaceMetal+0xe87d3 (01fe05a3) ; allocation 018fc9db 68a0000000 push 0A0h 018fc9e0 6a00 push 0 018fc9e2 50 push eax 018fc9e3 e8c21b6f00 call HShow!NGLSetSurfaceMetal+0xf67da (01fee5aa) ; memset 018fc9e8 89432c mov dword ptr [ebx+2Ch],eax ... 018fc9eb 8b752c mov esi,dword ptr [ebp+2Ch] 018fc9ee 8bf8 mov edi,eax 018fc9f0 b928000000 mov ecx,28h 018fc9f5 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
Afterwards, the application will enter the following loop at 0x18fca10. This loop will iterate the number of times as specified in the structure that was read previously. Due to this value being 15-bits in length, and the 0xa0 being less than 15-bits…this loop will act on data outside the bounds of the heap allocation.
HShow!NXDeleteLineObj+0x78f6e: 018fc9fe 663b4b2a cmp cx,word ptr [ebx+2Ah] ; XXX 018fca02 0f8d05010000 jge HShow!NXDeleteLineObj+0x7907d (018fcb0d) 018fca08 eb06 jmp HShow!NXDeleteLineObj+0x78f80 (018fca10) ... 018fca10 8b532c mov edx,dword ptr [ebx+2Ch] ... 018fca48 0fbf532a movsx edx,word ptr [ebx+2Ah] ; XXX 018fca4c 40 inc eax 018fca4d 3bc2 cmp eax,edx 018fca4f 7cbf jl HShow!NXDeleteLineObj+0x78f80 (018fca10)
Inside the loop, the application will test to see if a 16-bit value has it’s signed bit set, and if it doesn’t it will write the current index into that pointer. Due to the sentinel for this loop possibly being larger than 0xa0, this write will corrupt data after the 0xa0 byte buffer.
HShow!NXDeleteLineObj+0x78f80: 018fca10 8b532c mov edx,dword ptr [ebx+2Ch] 018fca13 8d0c42 lea ecx,[edx+eax*2] ; XXX: use iteration count to calculate index into buffer 018fca16 0fb75326 movzx edx,word ptr [ebx+26h] 018fca1a 663911 cmp word ptr [ecx],dx 018fca1d 7d04 jge HShow!NXDeleteLineObj+0x78f93 (018fca23) 018fca1f 42 inc edx 018fca20 668911 mov word ptr [ecx],dx ; XXX: write current iteration count to %ecx 0:010> lm start end module name 012f0000 027c9000 HShow (export symbols) HShow.exe
(330.67c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000050 ebx=5b00aedc ecx=59ad5000 edx=00002e00 esi=ffffc763 edi=ffffc764 eip=018fca1a esp=5c9fd638 ebp=5c9fd67c iopl=0 nv up ei ng nz na pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010287 HShow!NXDeleteLineObj+0x78f8a: 018fca1a 663911 cmp word ptr [ecx],dx ds:0023:59ad5000=???? 0:010> u . HShow!NXDeleteLineObj+0x78f8a: 018fca1a 663911 cmp word ptr [ecx],dx 018fca1d 7d04 jge HShow!NXDeleteLineObj+0x78f93 (018fca23) 018fca1f 42 inc edx 018fca20 668911 mov word ptr [ecx],dx 0:010> ? wo(@ebx+2a) Evaluate expression: 11776 = 00002e00 0:010> ? poi(@ebx+2c) Evaluate expression: 1504530272 = 59ad4f60
Discovered by Cisco Talos
2016-03-28 - Discovery
2016-04-19 - Vendor Notification
2016-08-04 - Public Disclosure