Talos Vulnerability Report


Hancom Hangul HCell Workbook Table and Pivot Style Code Execution Vulnerability

August 4, 2016

Report ID



This vulnerability was discovered within the Hangul Hcell 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 Hcell Document (.cell) and processing a record containing the table and pivot style within the Workbook stream, the application will copy arbitrarily sized data into the primary data structure used for the current Workbook. The vulnerability occurs due to a negligence of the application to check the length of the style names before copying them into a constantly sized buffer. This results in a heap-based buffer overflow which can lead to code execution under the context of the application.

Tested Versions

Hancom Office 2014 VP Trial HCell.exe Product version: HCellApp.dll Product version: HCellBook.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 Hcell uses the Structured Storage COM API to load and store the Spreadsheet generated by a user. Although there are various streams that can be specified wthin a document, the Hcell application stores the contents of a workbook within the “Workbook” stream as an array of Type-Length-Value structures. Each of these structures describe the worksheets and the cells that compose the document. Within a document, a user can create any number of styles that can be used to describe the look-and-feel of a document. During rendering of the workbook to the user, these styles will get applied to the document.

When parsing the Workbook stream, the application will perform 3 passes over each record. During the second pass, the application will collect the majority of the records containing formatting information as well as cell contents. If the record type is of the value 0x088e, then the application will execute a method at address 0x6b9c755a. Immediately after, the application will execute the method using the dynamic call at address 0x6b9c766f. This calls the function at address 0x6ba64180 which is responsible for parsing the contents of the 0x088e record.

6b9c71b1 0fb74704        movzx   eax,word ptr [edi+4]
6b9c71b5 3d3d010000      cmp     eax,13Dh
6b9c71ba 0f8f66020000    jg      HCellApp!CNexPTViewDefine::SetColLast+0x1ffa6 (6b9c7426)
6b9c7426 3d8d080000      cmp     eax,88Dh
6b9c742b 0f8fe6000000    jg      HCellApp!CNexPTViewDefine::SetColLast+0x20097 (6b9c7517)
6b9c7531 2d8e080000      sub     eax,88Eh
6b9c7536 83f806          cmp     eax,6
6b9c7539 0f8709010000    ja      HCellApp!CNexPTViewDefine::SetColLast+0x201c8 (6b9c7648)
6b9c753f ff248524799c6b  jmp     dword ptr HCellApp!CNexPTViewDefine::SetColLast+0x204a4 (6b9c7924)[eax*4]
6b9c7558 8b06            mov     eax,dword ptr [esi]
6b9c755a 8b503c          mov     edx,dword ptr [eax+3Ch]
6b9c755d 53              push    ebx        ; workbook container type
6b9c755e 8bce            mov     ecx,esi    ; wraps stream reader
6b9c7560 e90a010000      jmp     HCellApp!CNexPTViewDefine::SetColLast+0x201ef (6b9c766f)
6b9c766f ffd2            call    edx    ; XXX: calls method 6ba64180

Inside this function call, the application will enter a loop that will iterate through each record of type 0x088e and execute the method at 0x6ba64197 on it’s contents. This implies that it is common for the application to put a chain of these records next to each other. The method call at 0x6ba64197 executes a function at address 0x6ba2e870.

6ba64180 56              push    esi
6ba64181 57              push    edi
6ba64182 8b7c240c        mov     edi,dword ptr [esp+0Ch]    ; workbook container
6ba64186 8b7714          mov     esi,dword ptr [edi+14h]    ; stream object
6ba64190 8b07            mov     eax,dword ptr [edi]    ; workbook container
6ba64192 8b502c          mov     edx,dword ptr [eax+2Ch]
6ba64195 8bcf            mov     ecx,edi
6ba64197 ffd2            call    edx            ; XXX: calls workbcontainer's method at 6ba2e870
6ba641a2 b98e080000      mov     ecx,88Eh
6ba641a7 663bc1          cmp     ax,cx
6ba641aa 74e4            je      HCellApp!CHclUndoManager::AddRef+0xb220 (6ba64190)

This method at address 0x6ba2e870 is responsible specifically for parsing the contents of the 0x088e record. At the beginning of this function, the application constructs two std::basic_string objects, and then reads two lengths out of the contents of the record. The first length used at address 0x6ba2e92c is used to determine the number of wchars for the Table style, and the second length at address 0x6ba2e93c is used to determine the number of wchars for the Pivot style. These lengths are then used to allocate temporary space for them to be null-terminated, and then assigned as the contents of each of the two instances of the basic_string type.

6ba2e870 6aff            push    0FFFFFFFFh
6ba2e872 68fdabe26b      push    offset HCellApp!CHclDoc::IsPrinting+0x2246d (6be2abfd)
6ba2e877 64a100000000    mov     eax,dword ptr fs:[00000000h]
6ba2e87d 50              push    eax
6ba2e87e 83ec54          sub     esp,54h
6ba2e8a6 8d4c2448        lea     ecx,[esp+48h]          ; XXX: basic_string used to contain the Table style
6ba2e8aa 895c2420        mov     dword ptr [esp+20h],ebx
6ba2e8ae 895c2424        mov     dword ptr [esp+24h],ebx
6ba2e8b2 895c241c        mov     dword ptr [esp+1Ch],ebx
6ba2e8b6 895c2418        mov     dword ptr [esp+18h],ebx
6ba2e8ba 895c2414        mov     dword ptr [esp+14h],ebx
6ba2e8be ff152c6dee6b    call    dword ptr [HCellApp!CHclDoc::IsPrinting+0xde59c (6bee6d2c)]    ; basic_string constructor
6ba2e8c4 8d4c242c        lea     ecx,[esp+2Ch]          ; XXX: basic_string used to contain the Pivot style
6ba2e8c8 895c2470        mov     dword ptr [esp+70h],ebx
6ba2e8cc ff152c6dee6b    call    dword ptr [HCellApp!CHclDoc::IsPrinting+0xde59c (6bee6d2c)]    ; basic_string constructor
6ba2e91b 8b7e14          mov     edi,dword ptr [esi+14h]
6ba2e91e 8b17            mov     edx,dword ptr [edi]
6ba2e920 8b5204          mov     edx,dword ptr [edx+4]
6ba2e923 6a02            push    2
6ba2e925 8d44241c        lea     eax,[esp+1Ch]
6ba2e929 50              push    eax
6ba2e92a 8bcf            mov     ecx,edi
6ba2e92c ffd2            call    edx            ; XXX: read length of Table style
6ba2e92e 8b07            mov     eax,dword ptr [edi]
6ba2e930 8b5004          mov     edx,dword ptr [eax+4]
6ba2e933 6a02            push    2
6ba2e935 8d4c2418        lea     ecx,[esp+18h]
6ba2e939 51              push    ecx
6ba2e93a 8bcf            mov     ecx,edi
6ba2e93c ffd2            call    edx            ; XXX: read length of Pivot style

After building the two basic_string types for the Table and Pivot style name, the application will finally execute the method at address 0x6ba2ea15 for copying the Table style string into the CBook object. This method is exported as CBookBase::SetDefTableStyle and has a similar logic to the next method that is called at 0x6ba2ea36, CBookBase::SetDefPivotStyle. Both of these methods are responsible for populating the CBook object with the styles listed within the file. The vulnerability exists within both of these methods, however, the provided proof-of-concept triggers it within the Pivot style name first.

6ba2ea0c 8d44244c        lea     eax,[esp+4Ch]  ; Table style name
6ba2ea10 51              push    ecx            ; String length
6ba2ea11 8b4e08          mov     ecx,dword ptr [esi+8]
6ba2ea14 50              push    eax
6ba2ea15 ff15b45dee6b    call    dword ptr [HCellApp!CHclDoc::IsPrinting+0xdd624 (6bee5db4)]
6ba2ea2d 8d442430        lea     eax,[esp+30h]  ; Pivot style name
6ba2ea31 51              push    ecx            ; String length
6ba2ea32 8b4e08          mov     ecx,dword ptr [esi+8]
6ba2ea35 50              push    eax
6ba2ea36 ff15b85dee6b    call    dword ptr [HCellApp!CHclDoc::IsPrinting+0xdd628 (6bee5db8)]

Inside the HCellBook.dll!CBookBase::SetDefPivotStyle method, the application will first calculate the length of the string that was passed to it as a paremter. If this string length is zero, then the function will terminate early. At this point, the application will then check to see if the string length that was passed as a parameter is zero, if this is not the case then the application will then call the wcscpy_s function at address 0x6cc3a4a4 using this string along with the string’s length from the second argument. This string copying function (wcscpy_s) is then used to copy the string into one of the properties of the CBook object. Due to the application explicitly trusting the length provided from the file when copying this string, a buffer overflow can be made to occur. The logic within the HCellBook.dll!CBookBase::SetDefTableStyle method is the exact same.

6cc3a470 56              push    esi
6cc3a479 8bc6            mov     eax,esi        ; string argument
6cc3a47b 57              push    edi
6cc3a47c 8d7802          lea     edi,[eax+2]
6cc3a47f 90              nop
6cc3a480 668b10          mov     dx,word ptr [eax]
6cc3a483 83c002          add     eax,2
6cc3a486 6685d2          test    dx,dx
6cc3a489 75f5            jne     HCellBook!CBookBase::SetDefPivotStyle+0x10 (6cc3a480)  ; XXX: calculate string length
6cc3a48b 2bc7            sub     eax,edi
6cc3a48d d1f8            sar     eax,1          ; XXX: divide by the size of a wide character
6cc3a492 8b44240c        mov     eax,dword ptr [esp+0Ch]        ; string length from caller
6cc3a496 85c0            test    eax,eax
6cc3a498 7413            je      HCellBook!CBookBase::SetDefPivotStyle+0x3d (6cc3a4ad)
6cc3a49a 56              push    esi        ; string argument
6cc3a49b 40              inc     eax
6cc3a49c 50              push    eax        ; string length
6cc3a49d 81c1e0060000    add     ecx,6E0h   ; XXX: string destination -- CBook property
6cc3a4a3 51              push    ecx
6cc3a4a4 ff152c34cf6c    call    dword ptr [HCellBook!CSheetBase::IsIgnoreHiddenCellForSubTotal+0x1097c (6ccf342c)] ; XXX: wcscpy_s overflow
6cc3a4aa 83c40c          add     esp,0Ch
6cc3a4ad 5e              pop     esi
6cc3a4ae c20800          ret     8

Inside the copy constructor for the CBookBase object at HCellBook.dll!CBookBase::CBookBase, one can see the destination buffers for the wcscpy_s function are allocated with the size of 0x82 * sizeof(dword). This vulnerability occurs if the lengths specified within the 0x088e record plus one for the null byte are larger than 0x208 inclusive. At offset 0xa14 of the structure is a pointer to an HclDoc object that can be overwritten.

6ccc5130 6aff            push    0FFFFFFFFh
6ccc5132 68818cce6c      push    offset HCellBook!CSheetBase::IsIgnoreHiddenCellForSubTotal+0x61d1 (6cce8c81)
6ccc5137 64a100000000    mov     eax,dword ptr fs:[00000000h]
6ccc55db 8db5d8040000    lea     esi,[ebp+4D8h]
6ccc55e1 8dbbd8040000    lea     edi,[ebx+4D8h]
6ccc55e7 b982000000      mov     ecx,82h
6ccc55ec f3a5            rep movs dword ptr es:[edi],dword ptr [esi]    ; XXX: copy Table style from source to destination
6ccc55ee 8db5e0060000    lea     esi,[ebp+6E0h]
6ccc55f4 8dbbe0060000    lea     edi,[ebx+6E0h]
6ccc55fa b982000000      mov     ecx,82h
6ccc55ff f3a5            rep movs dword ptr es:[edi],dword ptr [esi]    ; XXX: copy Pivot style from source to destination

0:000> lm
6b560000 6c245000   HCellApp   (export symbols)       HCellApp.dll
6cc30000 6cf31000   HCellBook   (export symbols)       HCellBook.dll

Crash Analysis

(c04.eac): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000c0c0 ebx=00000801 ecx=1f9db000 edx=1f9d2c00 esi=102c3ff0 edi=00000000
eip=71777273 esp=0015d1ac ebp=0015d1b8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
71777273 668901          mov     word ptr [ecx],ax        ds:0023:1f9db000=????

0:000> kv
ChildEBP RetAddr  Args to Child
0015d1b8 6cc3a4aa 1f9d2c00 00004a01 102bbbf0 MSVCR90!wcscpy_s+0x49 (FPO: [Non-Fpo])
0015d1cc 6ba2ea3c 102bbbf0 00004a00 83cc72d1 HCellBook!CBookBase::SetDefPivotStyle+0x3a
0015d40c 717a3c3a 8377dbaa 6c178628 00000000 HCellApp!CHclUndoCommand::AddRef+0x57a1c
0015d444 ffff0600 00051001 00000000 1e318ff8 MSVCR90!free+0xec (FPO: [Non-Fpo])
0015d44c 00000000 1e318ff8 80030002 0015d4f4 0xffff0600

0:000> !heap -p -a 1f9d2c00
    address 1f9d2c00 found in
    _DPH_HEAP_ROOT @ 3301000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                1ee12478:         1f9d2520             8ae0 -         1f9d2000             a000
    73f88e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
    779a628e ntdll!RtlDebugAllocateHeap+0x00000030
    7796a6cb ntdll!RtlpAllocateHeap+0x000000c4
    77935d20 ntdll!RtlAllocateHeap+0x0000023a
    717a3db8 MSVCR90!malloc+0x00000079
    717a3eb8 MSVCR90!operator new+0x0000001f
    6b63e267 HCellApp!CHclDoc::InitBook+0x00000087

0:000> ? 1f9d2c00 + 4a01*2
Evaluate expression: 530432002 = 1f9dc002

0:000> ? 1f9d2c00 + 83*4
Evaluate expression: 530394636 = 1f9d2e0c

0:000> ? 1f9d2c00 + 4a01*2 > 1f9d2520 + 8ae0
Evaluate expression: 1 = 00000001

Description of the proof-of-concept

The Hangul HCell document format utilizes the Compound Document format that is available via Microsoft’s API. This file format is documented by Microsoft as part of their Document Interoperability Initiative. The format is similar to the FAT file format and contains a table describing where each file stream is stored within the file. Within each Hcell file is a stream labeled “Worbook” which is where the contents of the document is stored at.

The overall structure of an Hcell document can be described as a list of arrays of smaller type-length-value structures. Each record within the stream is prefixed by a header described as the following.

struct {
    uint16 type
    uint16 size
    byte[size] data
} record

Each array is terminated by an element of type 0x000a. Within the proof-of-concept that should’ve been provided, this leaves 6 substreams. The element containing the style names is identified by type 0x088e and is located at offset 0xa11 of the provided proof-of-concept. This can also be located as record 67 of the 1st stream.

<class RecordGeneral> '67'
[a11] <instance uint16 'type'> 0x088e (2190)
[a13] <instance uint16 'length'> 0x0076 (118)
[a15] <instance record088e 'data'> "\x00\x29\x00\x3f\x00\x37\x00  ..skipped ~98 bytes.. \x00\x33\x00\x35\x00\x30\x00"

The 0x088e record can be located at offset 0xa15 within the proof-of-concept and has the following structure. The first few fields don’t appear to be used for anything. However, at offset 0x10 and 0x12 within the structure are the string lengths that are used by this vulnerability. Both of these are of type uint16_t and are used to determine the lengths of the Table style and Pivot style strings that follow the fields within the file. The amount of space allocated in the data structure where these Style strings (plus a null byte) are copied to is 0x83*4 (524) bytes in length. If either of the length fields in this structure are larger than 522, then this vulnerability is being triggered. Within the provided proof-of-concept, the Table style length is 0x3b00 and the Pivot style length is 0x4a00.

<class record088e>
[a15] <instance uint16 'unused_0'> 0x2900 (10496)
[a17] <instance uint16 'unused_2'> 0x3f00 (16128)
[a19] <instance block(8) 'skipped_4'> "\x00\x37\x00\x32\x00\x3a\x00\x36"
[a21] <instance uint32 'loop_terminator_c'> 0x29003500 (687879424)
[a25] <instance uint16 'table_style_length_10'> 0x3b00 (15104)
[a27] <instance uint16 'pivot_style_length_12'> 0x4a00 (18944)
[a29] <instance wstring 'table_style'> ???
[a29] <instance wstring 'pivot_style'> ???


Discovered by Cisco Talos


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