CVE-2016-4294
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 property record within the Workbook stream, the application will attempt to allocate space for an element using a length from the file. When copying user-supplied data to this buffer, however, the application will use a different size which leads to a heap-based buffer overflow. This vulnerabiltiy 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.
When parsing the Workbook stream, the application will perform 3 passes over each record. The third pass is assumed by the author to parse record types that depend on cell data that is parsed during the second pass. During the third pass, the application will read the record type of 0x00ec. This record type is the same as OfficeArt’s (Escher) record and utilizes the exact same format. Once this type is identified, the application will then enter a function that deals with OfficeArt records.
HCellApp!CNexPTViewDefine::SetColLast+0x20be7:
69738067 8b13 mov edx,dword ptr [ebx]
69738069 8b92e4010000 mov edx,dword ptr [edx+1E4h]
6973806f 8d442434 lea eax,[esp+34h]
69738073 50 push eax
69738074 57 push edi ; worksheet
69738075 8d8c2480000000 lea ecx,[esp+80h]
6973807c 51 push ecx
6973807d 8bcb mov ecx,ebx
6973807f ffd2 call edx ; XXX: office art records
69738081 8bf0 mov esi,eax
Inside this function is a loop that will take the recordheader and use it to determine which case should be used to handle which record type. If the recordtype is 0xf004, which defines the record OfficeArtSpContainer, then the application will execute the following code. This code is responsible for reading information from the file that is used to define a Shape.
HCellApp!CHclUndoCommand::AddRef+0x56809:
6979d829 8b442444 mov eax,dword ptr [esp+44h]
6979d82d 50 push eax ; worksheet
6979d82e 8d4c242c lea ecx,[esp+2Ch]
6979d832 51 push ecx ; recordheader
6979d833 8d54241c lea edx,[esp+1Ch]
6979d837 52 push edx
6979d838 55 push ebp
6979d839 e862fbffff call HCellApp!CHclUndoCommand::AddRef+0x56380 (6979d3a0) ; XXX
6979d83e 8bf0 mov esi,eax
Inside this function, the application will read the contents of the container into a buffer. After reading the file data into a buffer, the function call at 6979d455 is responsible for initializing an object containing a number of associative arrays that are used to reference file data related to the shape. Each of these arrays are a map-like-object that store the offsets to the various record types that compose a Microsoft Office shape container. When creating the associative array for each property, if the property has it’s fComplex bit set, then the associative-array’s value is mapped to the out-of-band data associated with the property. This allows the application to quickly find the IMsoArray data that is used by the pVertices and pSegmentInfo properties when rendering the shape. After populating this object with it’s lookup tables, the object will then get passed to the function call at 6979d477.
HCellApp!CHclUndoCommand::AddRef+0x563c1:
6979d3e1 8bbc2480000000 mov edi,dword ptr [esp+80h]
6979d3e8 8b4f14 mov ecx,dword ptr [edi+14h]
6979d3eb 8b11 mov edx,dword ptr [ecx]
6979d3ed 8b5204 mov edx,dword ptr [edx+4]
6979d3f0 8bf0 mov esi,eax ; heap buffer
6979d3f2 8b4504 mov eax,dword ptr [ebp+4]
6979d3f5 83c404 add esp,4
6979d3f8 50 push eax ; size
6979d3f9 56 push esi ; buffer to read file data into
6979d3fa 89742428 mov dword ptr [esp+28h],esi
6979d3fe ffd2 call edx
...
HCellApp!CHclUndoCommand::AddRef+0x5642c:
6979d44c 8b4504 mov eax,dword ptr [ebp+4]
6979d44f 50 push eax ; recordLength
6979d450 56 push esi ; recordData
6979d451 8d4c2434 lea ecx,[esp+34h] ; container of sub-records
6979d455 e826d43900 call HCellApp!NXDeleteArcObj+0xe390 (69b3a880) ; initialize a structure for sub-records
...
HCellApp!CHclUndoCommand::AddRef+0x5643a:
6979d45a 8b942488000000 mov edx,dword ptr [esp+88h]
6979d461 8d4c242c lea ecx,[esp+2Ch]
6979d465 51 push ecx ; mapcontainer
6979d466 52 push edx ; worksheet
6979d467 8bf7 mov esi,edi
6979d469 e812ef0600 call HCellApp!CHclUndoManager::AddRef+0x43410 (6980c380) ; takes one argument. allocates a 0x64 and 0x2c byte object
6979d46e 50 push eax
6979d46f 8d84248c000000 lea eax,[esp+8Ch] ; recordHeader
6979d476 50 push eax
6979d477 e894453a00 call HCellApp!NXDeleteArcObj+0x15520 (69b41a10) ; XXX: takes 3 arguments
6979d47c 83c40c add esp,0Ch
Inside the function at 69b41a10, the application will process the different sub-records that are within the OfficeArtSpContainer. After processing record types such as 0xf122 or 0xf00b which contains information such as the coordinate system for the shape, the application will use the flags for the 0xf00a record type. This record type is named OfficeArtFSP and contains a list of flags that describe conditions of the shape. Eventually, the application will execute the code at 69b42009. This function call is specifically responsible for acting on the list of properties that were read from the 0xf00b record. It is within the 0xf00b record that information such as the vertices and the segment-info of our shape are processed.
HCellApp!NXDeleteArcObj+0x15907:
69b41df7 8b8c2480000000 mov ecx,dword ptr [esp+80h] ; shape structure
69b41dfe 8b74241c mov esi,dword ptr [esp+1Ch] ; shapeCoordinateSystem
69b41e02 8b9c2484000000 mov ebx,dword ptr [esp+84h] ; map/set container
69b41e09 51 push ecx
69b41e0a 8d442440 lea eax,[esp+40h] ; flags from 0xf00a record
69b41e0e 8bce mov ecx,esi
69b41e10 896c2440 mov dword ptr [esp+40h],ebp
69b41e14 e8b7010000 call HCellApp!NXDeleteArcObj+0x15ae0 (69b41fd0) ; \
69b41e19 83c404 add esp,4
\
HCellApp!NXDeleteArcObj+0x15b14:
69b42004 57 push edi ; recordData(f00a)
69b42005 56 push esi ; shapeCoordinateSystem
69b42006 55 push ebp
69b42007 8bc3 mov eax,ebx ; map-container
69b42009 e862920000 call HCellApp!NXDeleteArcObj+0x1ed80 (69b4b270) ; \
69b4200e 8b431c mov eax,dword ptr [ebx+1Ch]
\
HCellApp!NXDeleteArcObj+0x1ed83:
69b4b273 8b4810 mov ecx,dword ptr [eax+10h] ; map (f00b)
69b4b276 8b5014 mov edx,dword ptr [eax+14h]
69b4b279 890c24 mov dword ptr [esp],ecx
69b4b27c 8b4818 mov ecx,dword ptr [eax+18h] ; map (f122)
69b4b27f 89542404 mov dword ptr [esp+4],edx
69b4b283 33d2 xor edx,edx
69b4b285 894c2408 mov dword ptr [esp+8],ecx
...
69b4b2b4 8b4c241c mov ecx,dword ptr [esp+1Ch] ; shapeCoordinateSystem
69b4b2b8 50 push eax
69b4b2b9 8b44241c mov eax,dword ptr [esp+1Ch] ; shape object
69b4b2bd 8d542404 lea edx,[esp+4] ; map (f00b)
69b4b2c1 52 push edx
69b4b2c2 8b542428 mov edx,dword ptr [esp+28h]
69b4b2c6 50 push eax
69b4b2c7 e804000000 call HCellApp!NXDeleteArcObj+0x1ede0 (69b4b2d0) ; XXX: process the list of shape properties
Inside this function, the application will process our vulnerable OfficeArtFOPTE properties specifically. The function call at 0x69b4b316 will return a pointer to the file-data given a property identifier in the %esi register. With the provided proof-of-concept, which does not include a philShape property, the application will execute until it finally hits the function call at 69b4b4ac. This function call checks to see if the shape is to be drawn in Black and White mode (bWMode).
HCellApp!NXDeleteArcObj+0x1ee0c:
69b4b2fc 8b4510 mov eax,dword ptr [ebp+10h]
69b4b2ff 8b7d0c mov edi,dword ptr [ebp+0Ch] ; map (f00b)
69b4b302 8b5d08 mov ebx,dword ptr [ebp+8]
69b4b305 be82030000 mov esi,382h ; pihlShape property
69b4b30a 89442418 mov dword ptr [esp+18h],eax
69b4b30e 894c2414 mov dword ptr [esp+14h],ecx ; shapeCoordinateSystem
69b4b312 89542410 mov dword ptr [esp+10h],edx
69b4b316 e805aeffff call HCellApp!NXDeleteArcObj+0x19c30 (69b46120) ; return a fileRecordProperty
69b4b31b 85c0 test eax,eax
69b4b31d 742a je HCellApp!NXDeleteArcObj+0x1ee59 (69b4b349) ; XXX
69b4b31f 83780200 cmp dword ptr [eax+2],0 ; op
69b4b323 7424 je HCellApp!NXDeleteArcObj+0x1ee59 (69b4b349)
69b4b325 b900800000 mov ecx,8000h ; fComplex bit
69b4b32a 668508 test word ptr [eax],cx ; opid
69b4b32d 741a je HCellApp!NXDeleteArcObj+0x1ee59 (69b4b349)
...
HCellApp!NXDeleteArcObj+0x1ee7d:
69b4b36d c744245800000000 mov dword ptr [esp+58h],0
69b4b375 8b442430 mov eax,dword ptr [esp+30h]
69b4b379 85c0 test eax,eax
69b4b37b 7424 je HCellApp!NXDeleteArcObj+0x1eeb1 (69b4b3a1)
...
HCellApp!NXDeleteArcObj+0x1efb8:
69b4b4a8 57 push edi ; map (f00b)
69b4b4a9 53 push ebx
69b4b4aa 8bce mov ecx,esi
69b4b4ac e88f000000 call HCellApp!NXDeleteArcObj+0x1f050 (69b4b540) ; XXX
69b4b4b1 83c408 add esp,8
Inside the function at 69b4b540, the application will map the value of the bWMode property to an enumeration described as MSOBWMODE. After this is determined, the application will finally grab the value of the pVertices property and then make a call to the function at 69b4fb45 with the file data as it’s parameter. Once in this function, the application will continue on to the call at 69b55f60 which will actually use the property’s values in a vulnerable manner.
HCellApp!NXDeleteArcObj+0x1f0b8:
69b4b5a8 8bc3 mov eax,ebx ; shapeCoordinateSystem
69b4b5aa 8bcf mov ecx,edi ; map (f00b)
69b4b5ac e85f450000 call HCellApp!NXDeleteArcObj+0x23620 (69b4fb10) ; \
\
HCellApp!NXDeleteArcObj+0x23644:
69b4fb34 be45010000 mov esi,145h ; pVertices
69b4fb39 e83266ffff call HCellApp!NXDeleteArcObj+0x19c80 (69b46170) ; return the FOPTE header
69b4fb3e 85c0 test eax,eax
69b4fb40 740b je HCellApp!NXDeleteArcObj+0x2365d (69b4fb4d)
69b4fb42 53 push ebx
69b4fb43 8bcf mov ecx,edi
69b4fb45 e866180000 call HCellApp!NXDeleteArcObj+0x24ec0 (69b513b0) ; \
69b4fb4a 83c404 add esp,4
\
HCellApp!NXDeleteArcObj+0x24eed:
69b513dd 8d442454 lea eax,[esp+54h]
69b513e1 50 push eax
69b513e2 e8794b0000 call HCellApp!NXDeleteArcObj+0x29a70 (69b55f60) ; XXX
Inside the function call at 69b55f60, the application will process the pVertices and pSegmentInfo properties. Earlier, when the application created an associative array for the properties within this container, an the array was made to store the out-of-band data parts of each property. This out-of-band data will be referred to as the complexData field. For these properties, the complexData field is organized in a structure known as IMsoArray. It as at this point in execution, that the application copies an IMsoArray structure out of the complexData field within the file. At address 0x69b56031, the application processes the pVertices’ IMsoArray. A little bit later, at address 69b5607f, the application will call the vulnerable function using the IMsoArray from the pSegmentInfo property. Although both properties are vulnerable, the provided proof-of-concept triggers the vulnerability using the pSegmentInfo property.
HCellApp!NXDeleteArcObj+0x29b36:
69b56026 46 inc esi
69b56027 b950010000 mov ecx,150h
69b5602c 663bf1 cmp si,cx
69b5602f 76bf jbe HCellApp!NXDeleteArcObj+0x29b00 (69b55ff0)
69b56031 8d71f5 lea esi,[ecx-0Bh] ; 0x150-0xb == 0x145 == pVertices
69b56034 e83701ffff call HCellApp!NXDeleteArcObj+0x19c80 (69b46170) ; return property record
69b56039 85c0 test eax,eax
69b5603b 7418 je HCellApp!NXDeleteArcObj+0x29b65 (69b56055)
69b5603d 8b10 mov edx,dword ptr [eax] ; IMsoArray.nElems
69b5603f 8d7520 lea esi,[ebp+20h]
69b56042 8916 mov dword ptr [esi],edx
69b56044 668b4804 mov cx,word ptr [eax+4] ; IMsoArray.cbElem
69b56048 83c006 add eax,6 ; IMsoArray.data
69b5604b 50 push eax ; XXX: pointer to file data
69b5604c 66894e04 mov word ptr [esi+4],cx
69b56050 e86b010000 call HCellApp!NXDeleteArcObj+0x29cd0 (69b561c0) ; XXX: call vulnerable function
...
HCellApp!NXDeleteArcObj+0x29b8f:
69b5607f be51010000 mov esi,151h ; pSegmentInfo
69b56084 e8e700ffff call HCellApp!NXDeleteArcObj+0x19c80 (69b46170)
69b56089 85c0 test eax,eax
69b5608b 7418 je HCellApp!NXDeleteArcObj+0x29bb5 (69b560a5)
69b5608d 8b10 mov edx,dword ptr [eax] ; IMsoArray.nElems
69b5608f 8d7538 lea esi,[ebp+38h]
69b56092 8916 mov dword ptr [esi],edx
69b56094 668b4804 mov cx,word ptr [eax+4] ; IMsoArray.cbElem
69b56098 83c006 add eax,6 ; IMsoArray.data
69b5609b 50 push eax
69b5609c 66894e04 mov word ptr [esi+4],cx
69b560a0 e81b010000 call HCellApp!NXDeleteArcObj+0x29cd0 (69b561c0) ; XXX: calls vulnerable function
Within the function 69b561c0, the application will then perform an allocation by multiplying the constant 8 by the value of the IMsoArray.nElems field. Later, at address 69b56231, the application copies data into this buffer using the value of the IMsoArray.cbElem field for each element. Due to the application using a different size (8) for the cbElem field during allocation than what is used to copy data from the file into the allocated buffer, a heap-based buffer overflow can be made to occur. This can allow for one to corrupt the heap which can lead to code-execution under the context of the application.
HCellApp!NXDeleteArcObj+0x29cd0:
69b561c0 55 push ebp
69b561c1 8b6c2408 mov ebp,dword ptr [esp+8]
69b561c5 b8f0ff0000 mov eax,0FFF0h
69b561ca 57 push edi
69b561cb 66394604 cmp word ptr [esi+4],ax ; IMsoArray.cbElem
69b561cf 7509 jne HCellApp!NXDeleteArcObj+0x29cea (69b561da)
...
69b561da 0fb706 movzx eax,word ptr [esi] ; IMsoArray.nElems
69b561dd 33c9 xor ecx,ecx
69b561df ba08000000 mov edx,8 ; XXX: cbElem == 8
69b561e4 f7e2 mul eax,edx ; XXX: nElems * 8
69b561e6 0f90c1 seto cl
69b561e9 f7d9 neg ecx
69b561eb 0bc8 or ecx,eax
69b561ed 51 push ecx ; nElems * 8
69b561ee e864790200 call HCellApp!CHclDoc::IsPrinting+0x53c7 (69b7db57) ; heap allocation
...
HCellApp!NXDeleteArcObj+0x29d24:
69b56214 0fb74604 movzx eax,word ptr [esi+4] ; XXX: IMsoArray.cbElem
69b56218 53 push ebx
69b56219 8da42400000000 lea esp,[esp]
69b56220 d1e8 shr eax,1 ; XXX: divide by 2
69b56222 50 push eax
69b56223 8b4608 mov eax,dword ptr [esi+8]
69b56226 8d1cfd00000000 lea ebx,[edi*8]
69b5622d 03c3 add eax,ebx ; index into destination by constant size
69b5622f 55 push ebp
69b56230 50 push eax ; XXX: destination heap buffer
69b56231 e828ff0300 call HCellApp!CHclDoc::IsPrinting+0x1d9ce (69b9615e) ; XXX: memcpy
After corrupting the heap buffer, the application will eventually have to return 5 times to get to the address 0x69b4b5bf. It as at this point the application will use a 0x2c byte object to call a virtual method.
HCellApp!NXDeleteArcObj+0x1f0b8:
69b4b5a8 8bc3 mov eax,ebx ; shapeCoordinateSystem
69b4b5aa 8bcf mov ecx,edi ; map (f00b)
69b4b5ac e85f450000 call HCellApp!NXDeleteArcObj+0x23620 (69b4fb10) ; return
...
69b4b5bf 8bf3 mov esi,ebx ; 0x2c byte object
69b4b5c1 8bcf mov ecx,edi
69b4b5c3 e8c8930000 call HCellApp!NXDeleteArcObj+0x284a0 (69b54990) ; \
\
HCellApp!NXDeleteArcObj+0x284c3:
69b549b3 8b16 mov edx,dword ptr [esi] ; dereference a virtual table
69b549b5 50 push eax
69b549b6 8b4224 mov eax,dword ptr [edx+24h] ; dereference a code pointer
69b549b9 6a08 push 8
69b549bb 8bce mov ecx,esi
69b549bd ffd0 call eax
0:000> lm
692d0000 69fb5000 HCellApp (export symbols) HCellApp.dll 00CB6449
eax=00000200 ebx=001bcba0 ecx=00000000 edx=00000008 esi=001bcbd8 edi=001bcd20
eip=69b561e4 esp=001bcaf4 ebp=1d126b2e iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
HCellApp!NXDeleteArcObj+0x29cf4:
69b561e4 f7e2 mul eax,edx
0:000> ? @eax*@edx
Evaluate expression: 4096 = 00001000
0:000> u .
HCellApp!NXDeleteArcObj+0x29cf4:
69b561e4 f7e2 mul eax,edx
69b561e6 0f90c1 seto cl
69b561e9 f7d9 neg ecx
69b561eb 0bc8 or ecx,eax
69b561ed 51 push ecx
69b561ee e864790200 call HCellApp!CHclDoc::IsPrinting+0x53c7 (69b7db57)
0:000> g 69b56220
eax=00006040 ebx=001bcba0 ecx=00000000 edx=00000000 esi=001bcbd8 edi=00000000
eip=69b56220 esp=001bcaf0 ebp=1d126b2e iopl=0 nv up ei ng nz na pe cy
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000287
HCellApp!NXDeleteArcObj+0x29d30:
69b56220 d1e8 shr eax,1
0:000> p
eax=00003020 ebx=001bcba0 ecx=00000000 edx=00000000 esi=001bcbd8 edi=00000000
eip=69b56222 esp=001bcaf0 ebp=1d126b2e iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
HCellApp!NXDeleteArcObj+0x29d32:
69b56222 50 push eax
0:000> ? @eax
Evaluate expression: 12320 = 00003020
0:000> u .
HCellApp!NXDeleteArcObj+0x29d32:
69b56222 50 push eax
69b56223 8b4608 mov eax,dword ptr [esi+8]
69b56226 8d1cfd00000000 lea ebx,[edi*8]
69b5622d 03c3 add eax,ebx
69b5622f 55 push ebp
69b56230 50 push eax
69b56231 e828ff0300 call HCellApp!CHclDoc::IsPrinting+0x1d9ce (69b9615e)
(184.d78): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=1d129b4e ebx=00000000 ecx=00000ad4 edx=00000000 esi=1d126ffe edi=201db4d0
eip=71b3ae7a esp=001bcad4 ebp=001bcadc iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
MSVCR90!memcpy+0x5a:
71b3ae7a f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
0:000> kv L2
ChildEBP RetAddr Args to Child
001bcadc 69b56236 201db000 1d126b2e 00003020 MSVCR90!memcpy+0x5a
001bcaf8 69b560a5 1d126b2e 91c83667 001bcd20 HCellApp!NXDeleteArcObj+0x29d46
0:000> db 1d126b2e
1d126b2e 20 00 80 61 00 61 00 08-00 69 9a 0c 00 28 90 19 ..a.a...i...(..
1d126b3e 00 d7 9e 0d 00 9a 8f 1a-00 03 17 0f 00 97 a8 1b ................
1d126b4e 00 81 fe 0f 00 db 41 1c-00 71 1b 10 00 db 41 1c ......A..q....A.
1d126b5e 00 ce 3c 11 00 39 f5 1b-00 da ee 12 00 b1 c2 1a ..<..9..........
1d126b6e 00 c1 a9 16 00 ba 77 17-00 e5 bf 1b 00 3a fa 12 ......w......:..
1d126b7e 00 4e 93 1e 00 40 c8 10-00 a2 52 23 00 02 fd 0d .N...@....R#....
1d126b8e 00 2c ec 25 00 90 fd 0c-00 f2 e0 29 00 90 fd 0c .,.%.......)....
1d126b9e 00 f1 ff 30 00 a1 62 0f-00 45 bf 35 00 f6 60 12 ...0..b..E.5..`.
0:000> !heap -p -a 201db000
address 201db000 found in
_DPH_HEAP_ROOT @ 33b1000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
18013514: 201db000 1000 - 201da000 3000
744e8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
77d6628e ntdll!RtlDebugAllocateHeap+0x00000030
77d2a6cb ntdll!RtlpAllocateHeap+0x000000c4
77cf5d20 ntdll!RtlAllocateHeap+0x0000023a
71b63db8 MSVCR90!malloc+0x00000079
71b63eb8 MSVCR90!operator new+0x0000001f
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, this leaves 5 Worksheets.
The Escher record is used by Hangul Hcell to draw Office Art records. This record can be identified by the type 0x00ec and is located at offset 0x129e6 of the provided proof-of-concept. This can also be located as record 72 of the 2nd sheet. The documentation for this format [1] has been released as part of Microsoft’s Open Specification promise and is named [MS-ODRAW].
<class RecordGeneral> '72'
[129e6] <instance uint16_t 'type'> 0x00ec (236)
[129e8] <instance uint16_t 'length'> 0x0e74 (3700)
[129ea] <instance unknown 'data'> "\x0f\x00\x04\xf0\x6c\x0e\x00 ..skipped ~3680 bytes.. \x11\xf0\x00\x00\x00\x00"
Within this record, the application abides by the format described in Microsoft Office’s Office Art file-format. This format prefixes each record with an 8-byte header. This particular vulnerability is located within an OfficeArtSpContainer identified by the record type of 0xf004. This specific record type is used for describing a shape in the OfficeArt format and actually contains multiple records.
<class VersionInstance>
[129ea.0] <instance type 'Instance'> (0x000, 12)
[129eb.4] <instance type 'Version'> (0xf, 4)
<class Header> 'Header'
[129ea] <instance VersionInstance 'Version/Instance'> (0x000f, 16)
[129ec] <instance RecordType 'Type'> FT_OfficeArtSp(0xf004)
[129ee] <instance uint32_t 'Length'> 0x00000e6c (3692)
[129f2] <instance OfficeArtSpContainer 'data'> RecordGeneral[4] "\x02\x00\x0a\xf0\x08\x00\x00 ..skipped ~3672 bytes.. \x11\xf0\x00\x00\x00\x00"
This shape record, OfficeArtSpContainer, is used to describe shapes which will be drawn onto the spreadsheet. Within this record is a list of subrecords which begins at offset 0x129f2. Another record, identified by the recType 0xf00b, is named OfficeArtFOPT and specifically holds the property table that contains the fields that are used by this vulnerability. Within the proof-of-concept, this record begins at offset 0x12a02.
<class VersionInstance>
[12a02.0] <instance type 'Instance'> (0x011, 12)
[12a03.4] <instance type 'Version'> (0x3, 4)
<class Header> 'Header'
[12a02] <instance office.VersionInstance 'Version/Instance'> (0x0113, 16)
[12a04] <instance office.RecordType 'Type'> FT_OfficeArtFOPT(0xf00b)
[12a06] <instance uint32_t 'Length'> 0x00000e2e (3630)
<class RecordGeneral> '1'
[12a02] <instance Header 'Header'> Version/Instance=0113 type=0xf00b length=0x00000e2e
[12a0a] <instance OfficeArtFOPT 'data'> "\x7f\x00\x10\x02\x10\x02\x42 ..skipped ~3610 bytes.. \x49\x00\x67\x11\x1d\x00"
[13838] <instance undefined 'extra'> ...
The 0xf00b record contains a list of properties for a particular shape. The number of properties in this record is identified by the Instance field within the record’s header. Within the provided proof-of-concept, this value is 0x11 which states that there’s 17 properties within the container. Each property is 6-bytes in length and has the following structure. If any of the properties has it’s fComplex bit set, then immediately following the list of properties is out-of-band data associated with the property. It is prudent to note that n order to determine where the out-of-band data begins, the number of propertes will need to be multiplied by 6 and for each property that has it’s fComplex bit set, the ‘op’ field of that property contains the length within the complexData.
<class OfficeArtFOPTEOPID> 'opid'
[12a22.0] <instance type 'fComplex'> (0x1, 1)
[12a22.1] <instance type 'fBid'> (0x1, 1)
[12a22.2] <instance type 'id'> (0x0145, 14)
In order to trigger this vulnerability any of the properties must have an id of 0x145 (pVertices) or 0x151 (pConnectionSites). Within the provided proof-of-concept a pVertices property is located at 12a22. This property has an op value of 0x90e which states that the size of it’s data within the complexData field is 0x90e bytes. At offset 0x12a23 the complexData field has 0x30e bytes which is the next number of bytes that contains the complexData.
; At offset 0x12a22 is an example pVertices property.
<class OfficeArtFOPTE> '4'
[12a22] <instance OfficeArtFOPTEOPID 'opid'> (0xc145, 16)
[12a24] <instance pVertices 'op'> 0x0000090e (2318)
; At offset 0x12a23 is the pConnectionSites property that this proof-of-concept utilizes.
<class OfficeArtFOPTE> '6'
[12a2e] <instance OfficeArtFOPTEOPID 'opid'> (0xc151, 16)
[12a30] <instance pConnectionSites 'op'> 0x0000030e (782)
Each piece of data is indexed by whichever properties have it’s fComplex bit set. Within the proof-of-concept the pConnectionSites property’s complexData field begins at offset 0x1338a. This is the 3rd property that has it’s fComplex bit set. The other properties that prefix the complexData are the pVertices propetty at offset 0x12a22 and the pSegmentInfo property at offset 0x12a28.
; pConnectionSites complexData field
<class block(782)> '2'
1338a 00 02 00 00 40 60 20 00 80 61 00 61 00 08 00 69 ....@` ..a.a...i
1339a 9a 0c 00 28 90 19 00 d7 9e 0d 00 9a 8f 1a 00 03 ...(............
133aa 17 0f 00 97 a8 1b 00 81 fe 0f 00 db 41 1c 00 71 ............A..q
133ba 1b 10 00 db 41 1c 00 ce 3c 11 00 39 f5 1b 00 da ....A...<..9....
Both the pVertices and pSegmentInfo properties’ complexData field have the following structure. This structure contains the fields that are utilized by the vulnerability. The expected size of the pVertices and pSegmentInfo fields is supposed to be 8. The application uses the value of 8 multiplied by the nElems field to calculate the size of the buffer. However, when copying file-data into this buffer, it explicitly trusts the value in the cbElem field. If any of the pVertices or pSegmentInfo properties’ complexData contains a cbElem value other than 8, then this vulnerability is being triggered. Within the provided proof-of-concept, the IMsoArray structure is at offset 0x1338a and uses the cbElem value of 0x6040.
<class IMsoArray>
[1338a] <instance uint2 'nElems'> 0x0200 (512)
[1338c] <instance uint2 'nElemsAlloc'> 0x0000 (0)
[1338e] <instance uint2 'cbElem'> 0x6040 (24640)
2016-03-28 - Discovery
2016-04-19 - Vendor Notification
2016-08-04 - Public Disclosure
[1] http://download.microsoft.com/download/2/4/8/24862317-78F0-4C4B-B355-C7B2C1D997DB/[MS-ODRAW].pdf
Discovered by Cisco Talos.