Overview
To create a general way to execute local and remote code, we designed a relatively obscure method of code execution, which we internally refer to as RpcCraft (Self) and RpcExec (Remote Process). This technique leverages a methodology well-known among exploit developers, abusing RPC (Remote Procedure Call) server calls such as NdrServerCall2
or NdrServerCallAll
to execute arbitrary code.
Abusing Server Calls for Execution
Within RPCRT4.dll
, functions like NdrServerCall2
, NdrServerCallAll
, and NdrServerCallNdr64
(an alias of NdrServerCallAll
) are implemented as wrappers to dynamically invoke functions pertaining to server functionalities. These functions take a single argument, a pointer to an RPC_MESSAGE
structure.
RPC_MESSAGE Structure:
typedef struct _RPC_MESSAGE { RPC_BINDING_HANDLE Handle; unsigned long DataRepresentation; void *Buffer; unsigned int BufferLength; unsigned int ProcNum; PRPC_SYNTAX_IDENTIFIER TransferSyntax; void *RpcInterfaceInformation; void *ReservedForRuntime; RPC_MGR_EPV *ManagerEpv; void *ImportContext; unsigned long RpcFlags; } RPC_MESSAGE, *PRPC_MESSAGE;
Initialization and Execution
To initialize the runtime without binding to a service, the PerformRpcInitialization
function is used. This function internally initializes necessary structures without requiring manual binding.
Known Issues
This public version of the technique has been developed as POC to showcase the feasibility, and it currently generates an exception on NdrGetBuffer due to a missing Binding Handle. This can be dealt with in several ways, but the current implementation does:
- Performs a patch to ntdll (RaiseException -> RtlExitUserThread)
- Recovers return value via VEH
int FetchReturnValue(const PEXCEPTION_POINTERS ExceptionInfo) { ExceptionInfo->ContextRecord->EFlags |= (1 << 16); g_ReturnValue = (PVOID)ExceptionInfo->ContextRecord->Rax; return EXCEPTION_CONTINUE_EXECUTION; }
Limitations and Patching
RPC invocation is CFG protected, meaning that in order to achieve full, unrestricted code execution, it is necessary to either mark the target valid with SetProcessValidCallTargets
or patching RpcInvokeCheckICall
.
Conclusion
The RpcProxyInvoke project demonstrates an alternate technique that can be abused to implement a RailGun style library. Although the public implementation is not perfect, it can serve as a basis for further development.
License
This project is licensed under the MIT License - see the LICENSE file for details.