CVE-2016-4293
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.
Hancom Office 2014 VP Trial HCell.exe Product version: 9.1.0.2176 HCellApp.dll Product version: 9.1.0.2176 HCellBook.dll Product version: 9.1.0.2176
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 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.
HCellApp!CNexPTViewDefine::SetColLast+0x1fd31:
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.
HCellApp!CHclUndoManager::AddRef+0xb210:
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.
HCellApp!CHclUndoCommand::AddRef+0x57850:
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.
HCellApp!CHclUndoCommand::AddRef+0x579ec:
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)]
...
HCellApp!CHclUndoCommand::AddRef+0x57a0d:
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.
HCellBook!CBookBase::SetDefPivotStyle:
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.
HCellBook!CBookBase::CBookBase:
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
(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
MSVCR90!wcscpy_s+0x49:
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
HCellApp!CBook::`vftable'
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
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'> ???
2016-03-28 - Discovery
2016-04-19 - Vendor Notification
2016-08-04 - Public Disclosure
Discovered by Cisco Talos.