Exploit-DB #49541
Description: Microsoft Internet Explorer 11 32-bit - Use-After-Free
Type: local
Platform: windows
Date: 2021-02-08
Author: Forrest Orr

Exploit:
# Exploit Title: Microsoft Internet Explorer 11 32-bit - Use-After-Free
# Date: 2021-02-05
# Exploit Author: deadlock (Forrest Orr)
# 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 and Windows 7 x86
# CVE: CVE-2020-0674
# Bypasses: DEP, ASLR, EMET 5.5 (EAF, EAF+, stack pivot protection, SimExec, CallerCheck)
# Original (64-bit) exploit credits: maxpl0it

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=EmulateIE8" />
<script language="JScript.Compact">

/*

  ___ _   _  ___  ___ __ ___ __      __   ___ ___ _  _
 / _/| \ / || __|(_  /  (_  /  \ __ /  \ / __|_  | || |
| \__`\ V /'| _|__/ / // / / // |__| // | ,_ \/ /`._  _|
 \__/  \_/  |___||___\__/___\__/    \__/ \___/_/    |_|

Overview

This is a 32-bit re-creation of CVE-2020-067, a vulnerability in the legacy
Javascript engine (jscript.dll) in Windows. It was used in historic versions
of Internet Explorer but its load/usage can still be coerced (and thus exploited)
in all versions of IE up to 11.

A high quality description of this exploit can be found on F-Secure's blog at:
https://labs.f-secure.com/blog/internet-exploiter-understanding-vulnerabilities-in-internet-explorer/

The original public 64-bit variation of this exploit was written by maxspl0it
and can be found at https://github.com/maxpl0it/CVE-2020-0674-Exploit

Maxspl0it's variation of this exploit works on IE 8-11 64-bit. It is using a
ret2libc style attack with a RIP hijack to NTDLL.DLL!NtContinue which then
calls KERNEL32.DLL!WinExec. Since it is on 64-bit (the first 4 parameters are in
RCX, RDX, R8 and R9) no stack pivot is needed, and this drastically simplifies
the creation of the exploit (especially as it relates to exploit mitigation
protections such as EMET).

My motivation in creating my own variation of this exploit was threefold:

1. I wanted to write an exploit that woulld work on 32-bit (as this is the
   default IE used on Windows 7 and 8.1 and thus makes the exploit more practical).
2. I wanted it to bypass the advanced exploit mitigation features such as stack
   pivot protection, EAF+, SimExec and CallerCheck (EMET 5.5 in Windows 7 but built
   into Windows Defender Exploit Guard today).
3. I wanted it to execute a shellcode payload rather than simply a command via
   a ret2libc style sttack.

The first point was a relatively easy one to deal with. The sizes and offsets of
various internal Windows and Javascript structures had to be adjusted for 32-bit.
The other two points significantly complicated the exploit beyond what is found in
maxspl0it's version of the exploit: executing a payload as shellcode requires a
DEP bypass, which in turn requires a stack pivot. Stack pivots are perhaps the
most scrutinized part of a modern exploit attack chain targeted by the exploit
mitigations in EMET 5.5 and Windows Defender today. Furthermore, EAF+ prevents the
resolution of key DEP bypass APIs (such as in my case NtProtectVirtualMemory)
originating from within jscript.dll, which meant API resolution had to be done
via import instead.

Design

The UAF aspect of the exploit itself is best explored in the aforementioned F-Secure
blog, but in summary, the legacy JS engine contained a bug which would not track
variables passed as arguments to the "sort" method of an array. This meant that
GcBlock structures (which store the VAR structs underlying vars in JS) could be
freed by the garbage collector despite still containing active variables in the JS
script. From here, it was just a matter of re-claiming these freed  GcBlocks and
manipulating the VAR struct underlying the saved untracked vars (into BSTR for
arbitrary read attacks for example).

In both my variation and maxspl0it's the instruction pointer hijack is performed by
manipulating the VAR struct underlying one of these untracked vars to point to
a class object in another region of memory we control with the UAF re-claim. The first
field of this class object will be the vtable pointer, and thus we can place a pointer
at a method offset of our choice within this fake vtable. In this case, the "typeof"
method is used, and when the typeof the var is queried through the JS script it will
trigger execution of a pointer of our choice.

In my variation, this hijack takes the instruction pointer to a XCHG EAX, ESP gadget
within MSVCRT.DLL. There are only three gadgets in the ROP chain which need to be
scanned for in memory in order to dynamically generate the chain (this exploit does
not rely on static offsets within MSVCRT.DLL and should be reliable on any version of
this module):

1. XCHG EAX, ESP ; RET
2. POP EAX ; RET
3. ROPNOP (derived from either of the previous gadgets by doing a +1 on their address)

The goal of the ROP chain is to make a call to NtProtectVirtualMemory and change
the protections of the shellcode (stored within a BSTR) in memory from +RW to +RWX.
The issue with this, is that EMET hooks NtProtectVirtualMemory and will detect the
stack pivot. To solve this issue, I designed a syscall ROP chain which manually
populates EAX with the NtProtectVirtualMemory syscall number and triggers the syscall
itself using an unhooked region withinh NTDLL.DLL.

Payload

The payload is a simple message box shellcode, the source of which can be found here:
https://github.com/forrest-orr/ExploitDev/blob/master/Shellcode/Projects/MessageBox/EAF/MessageBox32.asm

There is one very significant detail to this shellcode which needs to be replicated in any
other shellcode substituted into this exploit if it is going to bypass EMET: the
shellcode makes a stack pivot using the stack base pointer stored in the TEB. This is
essential, as any call (even indirectly such as in the initialization user32.dll does
before popping a MessageBoxA) to a sensitive API hooked