Search code examples
c++cwindowswinapirpc

Why an RPC call would return access denied when running as a local admin?


I am just getting started with Windows RPC programming. I am trying to interact with the Windows Event log system through ms-even6. Microsoft does not cover secure RPC calls in its tutorials, and I couldn't find much about it anywhere. So far, I have the following code ...

#include <stdlib.h>
#include <iostream>
#include <ctype.h>
#include "ms-even6_h.h"
#include <windows.h>

#pragma comment(lib, "rpcrt4.lib")

int main()
{
    RPC_STATUS status;
    RPC_WSTR pszUuid = NULL;
    RPC_WSTR pszProtocolSequence = reinterpret_cast<RPC_WSTR>(const_cast<PWSTR>(L"ncacn_np"));
    RPC_WSTR pszNetworkAddress = NULL;
    RPC_WSTR pszEndpoint = reinterpret_cast<RPC_WSTR>(const_cast<PWSTR>(L"\\pipe\\eventlog"));
    RPC_WSTR pszOptions = NULL;
    RPC_WSTR pszStringBinding = NULL;
    unsigned long ulCode;

    status = RpcStringBindingCompose(pszUuid,
        pszProtocolSequence,
        pszNetworkAddress,
        pszEndpoint,
        pszOptions,
        &pszStringBinding);
    if (status) {
        std::cerr << "[-] RpcStringBindingCompose failed [" << status << "]" << std::endl;
        exit(status);
    }

    status = RpcBindingFromStringBinding(pszStringBinding, &client_IfHandle);

    if (status) {
        std::cerr << "[-] RpcBindingFromStringBinding failed [" << status << "]" << std::endl;
        exit(status);
    }

    status = RpcBindingSetAuthInfo(client_IfHandle,
        0,
        RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
        RPC_C_AUTHN_WINNT,
        0,
        0
    );

    if (status) {
        std::cerr << "[-] RpcBindingSetAuthInfo failed [" << status << "]" << std::endl;
        exit(status);
    }

    RpcTryExcept // This block always throw an Access Denied runtime exception
    {
        EvtRpcVariantList props;
        status = EvtRpcGetChannelConfig(L"Application", 0, &props);
        if (status)
        {
            std::cerr << "[-] EvtRpcGetChannelConfig failed [" << status << "]" << std::endl;
            exit(status);
        }
        std::cout << "[+] EvtRpcGetChannelConfig worked!" << std::endl;

    }
        RpcExcept(1)
    {
        ulCode = RpcExceptionCode();
        printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);
    }
    RpcEndExcept

        status = RpcStringFree(&pszStringBinding);

    if (status) {
        std::cerr << "[-] RpcStringFree failed [" << status << "]" << std::endl;
        exit(status);
    }

    status = RpcBindingFree(&client_IfHandle);

    if (status) {
        std::cerr << "[-] RpcBindingFree failed [" << status << "]" << std::endl;
        exit(status);
    }
    std::cout << "[+] Done." << std::endl;
    return 0;
}

/******************************************************/
/*         MIDL allocate and free                     */
/******************************************************/

void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
{
    return (malloc(len));
}

void __RPC_USER midl_user_free(void __RPC_FAR* ptr)
{
    free(ptr);
}

I tried calling different RPC functions, and they all throw an access denied exception. My client process is running as a local admin, and I am targeting my local machine.

Any thoughts on what I am doing wrong here?

All help is appreciated!

#UPDATE

After reviewing windows_protocols ms-even6, I changed the protocol sequence to ncacn_ip_tcp. Now the ACCESS DENIED error seem to be gone but now I get a Runtime reported exception 0x6f7 = 1783 (The stub received bad data.) error.

/* file: helloc.c */
#include <stdlib.h>
#include <iostream>
#include <ctype.h>
#include "ms-even6_h.h"
#include <windows.h>
#include <thread>

#pragma comment(lib, "rpcrt4.lib")

int main()
{
    RPC_STATUS status;
    RPC_WSTR pszUuid = NULL;
    RPC_WSTR pszProtocolSequence = reinterpret_cast<RPC_WSTR>(const_cast<PWSTR>(L"ncacn_ip_tcp"));
    RPC_WSTR pszNetworkAddress = reinterpret_cast<RPC_WSTR>(const_cast<PWSTR>(L"localhost"));
    RPC_WSTR pszEndpoint = NULL;
    RPC_WSTR pszOptions = NULL;
    RPC_WSTR pszStringBinding = NULL;
    unsigned long ulCode;

    status = RpcStringBindingCompose(pszUuid,
        pszProtocolSequence,
        pszNetworkAddress,
        pszEndpoint,
        pszOptions,
        &pszStringBinding);
    if (status) {
        std::cerr << "[-] RpcStringBindingCompose failed [" << status << "]" << std::endl;
        exit(status);
    }

    status = RpcBindingFromStringBinding(pszStringBinding, &client_IfHandle);

    if (status) {
        std::cerr << "[-] RpcBindingFromStringBinding failed [" << status << "]" << std::endl;
        exit(status);
    }

    status = RpcEpResolveBinding(
        client_IfHandle,
        IEventService_v1_0_c_ifspec
    );

    if (status) {
        std::cerr << "[-] RpcEpResolveBinding failed [" << status << "]" << std::endl;
        exit(status);
    }

    status = RpcBindingSetAuthInfo(client_IfHandle,
        0,
        RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
        RPC_C_AUTHN_WINNT,
        0,
        0
    );

    if (status) {
        std::cerr << "[-] RpcBindingSetAuthInfo failed [" << status << "]" << std::endl;
        exit(status);
    }

    RpcTryExcept
    {
        EvtRpcVariantList props;
        status = EvtRpcGetChannelConfig(L"Application", (INT32)0, &props);
        if (status)
        {
            std::cerr << "[-] EvtRpcGetChannelConfig failed [" << status << "]" << std::endl;
            exit(status);
        }
        std::cout << "[+] EvtRpcGetChannelConfig worked!" << std::endl;

    }
        RpcExcept(1)
    {
        ulCode = RpcExceptionCode();
        std::cerr << "[-] Runtime reported exception 0x"
            << std::hex << ulCode
            << " = "
            << std::dec << ulCode
            << std::endl;
    }
    RpcEndExcept

        status = RpcStringFree(&pszStringBinding);

    if (status) {
        std::cerr << "[-] RpcStringFree failed [" << status << "]" << std::endl;
        exit(status);
    }

    status = RpcBindingFree(&client_IfHandle);

    if (status) {
        std::cerr << "[-] RpcBindingFree failed [" << status << "]" << std::endl;
        exit(status);
    }
    std::cout << "[+] Done." << std::endl;
    return 0;
}

/******************************************************/
/*         MIDL allocate and free                     */
/******************************************************/

void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
{
    return (malloc(len));
}

void __RPC_USER midl_user_free(void __RPC_FAR* ptr)
{
    free(ptr);
}

Solution

  • After reviewing windows_protocols ms-even6, I changed the protocol sequence to ncacn_ip_tcp. Once that was done, the ACCESS DENIED error was gone, but I was still unable to call the remote procedures. The app would always fail either with Runtime reported exception 0x6f7 = 1783 (The stub received bad data.) or Runtime reported exception 0x6c6 = 1734 (The array bounds are invalid.).

    The reason? Uninitialized pointers! Once I properly initialized my pointers and DWORDs, everything worked!

    Here is a working example.

    /* file: helloc.c */
    #include <stdlib.h>
    #include <iostream>
    #include <ctype.h>
    #include <windows.h>
    #include "ms-even6_h.h"
    
    #pragma comment(lib, "rpcrt4.lib")
    
    int main()
    {
        RPC_STATUS status;
        RPC_WSTR pszUuid = NULL;
        RPC_WSTR pszProtocolSequence = reinterpret_cast<RPC_WSTR>(const_cast<PWSTR>(L"ncacn_ip_tcp"));
        RPC_WSTR pszNetworkAddress = reinterpret_cast<RPC_WSTR>(const_cast<PWSTR>(L"localhost"));
        RPC_WSTR pszEndpoint = NULL;
        RPC_WSTR pszOptions = NULL;
        RPC_WSTR pszStringBinding = NULL;
        unsigned long ulCode;
    
        status = RpcStringBindingCompose(pszUuid,
            pszProtocolSequence,
            pszNetworkAddress,
            pszEndpoint,
            pszOptions,
            &pszStringBinding);
        if (status) {
            std::cerr << "[-] RpcStringBindingCompose failed [" << status << "]" << std::endl;
            exit(status);
        }
    
        status = RpcBindingFromStringBinding(pszStringBinding, &client_IfHandle);
    
        if (status) {
            std::cerr << "[-] RpcBindingFromStringBinding failed [" << status << "]" << std::endl;
            exit(status);
        }
    
        status = RpcEpResolveBinding(
            client_IfHandle,
            IEventService_v1_0_c_ifspec
        );
    
        if (status) {
            std::cerr << "[-] RpcEpResolveBinding failed [" << status << "]" << std::endl;
            exit(status);
        }
    
        status = RpcBindingSetAuthInfo(client_IfHandle,
            0,
            RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
            RPC_C_AUTHN_WINNT,
            0,
            0
        );
    
        if (status) {
            std::cerr << "[-] RpcBindingSetAuthInfo failed [" << status << "]" << std::endl;
            exit(status);
        }
    
        RpcTryExcept
        {
            PCONTEXT_HANDLE_LOG_HANDLE hLog;
            RpcInfo error;
            status = EvtRpcOpenLogHandle(L"Application", 1, &hLog, &error);
            if (status)
            {
                std::cerr << "[-] EvtRpcOpenLogHandle failed [" << status << "]" << std::endl;
                exit(status);
            }
            std::cout << "[+] EvtRpcOpenLogHandle worked!" << std::endl;
    
    
            status = EvtRpcClose(&hLog);
            if (status)
            {
                std::cerr << "[-] EvtRpcClose failed [" << status << "]" << std::endl;
                exit(status);
            }
            std::cout << "[+] EvtRpcClose worked!" << std::endl;
    
            EvtRpcVariantList props;
            props.count = 0;
            props.props = NULL;
            status = EvtRpcGetChannelConfig(L"Application", 0, &props);
            if (status)
            {
                std::cerr << "[-] EvtRpcGetChannelConfig failed [" << status << "]" << std::endl;
                exit(status);
            }
            std::cout << "[+] EvtRpcGetChannelConfig worked!" << std::endl;
            for (size_t i = 0; i < props.count; i++)
            {
                std::cout << "\tChannelConfig[" << i << "]:"
                    << "\n\t\ttype: " << props.props[i].type
                    << std::endl;
            }
            PCONTEXT_HANDLE_REMOTE_SUBSCRIPTION hSub;
            PCONTEXT_HANDLE_OPERATION_CONTROL hOpCtrl;
            DWORD dwQueryChannelInfoSize = 0;
            EvtRpcQueryChannelInfo* queryChannelInfo = NULL;
            status = EvtRpcRegisterRemoteSubscription(
                L"Application",
                L"*",
                NULL,
                0x00000002 | 0x00001000,
                &hSub,
                &hOpCtrl,
                &dwQueryChannelInfoSize,
                &queryChannelInfo,
                &error);
            if (status)
            {
                std::cerr << "[-] EvtRpcRegisterRemoteSubscription failed [" << status << "]" << std::endl;
                exit(status);
            }
            std::cout << "[+] EvtRpcRegisterRemoteSubscription worked!" << std::endl;
            std::cout << "\tdwQueryChannelInfoSize: " << dwQueryChannelInfoSize << std::endl;
            for (size_t i = 0; i < dwQueryChannelInfoSize; i++)
            {
                std::wcout << L"\tqueryChannelInfo[" << i << "]: "
                    << queryChannelInfo[i].name
                    << L" ("
                    << queryChannelInfo[i].status
                    << L")"
                    << std::endl;
    
            }
    
            DWORD numRequestedRecords = 1;
            DWORD flags = 0;
            DWORD numActualRecords = 0;
            DWORD* eventDataIndices = NULL;
            DWORD* eventDataSizes = NULL;
            DWORD resultBufferSize = 0;
            BYTE* resultBuffer = NULL;
            status = EvtRpcRemoteSubscriptionNextAsync(
                hSub,
                numRequestedRecords,
                flags,
                &numActualRecords,
                &eventDataIndices,
                &eventDataSizes,
                &resultBufferSize,
                &resultBuffer
            );
            if (status)
            {
                std::cerr << "[-] EvtRpcRemoteSubscriptionNextAsync failed [" << status << "]" << std::endl;
                exit(status);
            }
            std::cout << "[+] EvtRpcRemoteSubscriptionNextAsync worked!" << std::endl;
        }
            RpcExcept(1)
        {
            ulCode = RpcExceptionCode();
            std::cerr << "[-] Runtime reported exception 0x"
                << std::hex << ulCode
                << " = "
                << std::dec << ulCode
                << std::endl;
        }
        RpcEndExcept
    
            status = RpcStringFree(&pszStringBinding);
    
        if (status) {
            std::cerr << "[-] RpcStringFree failed [" << status << "]" << std::endl;
            exit(status);
        }
    
        status = RpcBindingFree(&client_IfHandle);
    
        if (status) {
            std::cerr << "[-] RpcBindingFree failed [" << status << "]" << std::endl;
            exit(status);
        }
        std::cout << "[+] Done." << std::endl;
        return 0;
    }
    
    /******************************************************/
    /*         MIDL allocate and free                     */
    /******************************************************/
    
    void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
    {
        return (malloc(len));
    }
    
    void __RPC_USER midl_user_free(void __RPC_FAR* ptr)
    {
        free(ptr);
    }