
Librería POC simple para ejecutar llamadas arbitrarias haciendo proxy de ellas a través de NdrServerCall2 o similar.
Para crear una forma genérica de ejecutar código local y remoto, diseñamos un método de ejecución de código relativamente oscuro, al que internamente nos referimos como RpcCraft (Self) y RpcExec (Remote Process). Esta técnica aprovecha una metodología bien conocida entre los desarrolladores de exploits: abusar de las llamadas de servidor RPC (Remote Procedure Call), como NdrServerCall2 o NdrServerCallAll, para ejecutar código arbitrario.
Dentro de RPCRT4.dll, funciones como NdrServerCall2, NdrServerCallAll y NdrServerCallNdr64 (un alias de NdrServerCallAll) están implementadas como wrappers para invocar dinámicamente funciones relacionadas con las funcionalidades del servidor. Estas funciones toman un único argumento: un puntero a una estructura RPC_MESSAGE.
Estructura RPC_MESSAGE:
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;
Para inicializar el runtime sin vincularse a un servicio, se utiliza la función PerformRpcInitialization. Esta función inicializa internamente las estructuras necesarias sin requerir un binding manual.
Esta versión pública de la técnica se ha desarrollado como POC para demostrar su viabilidad, y actualmente genera una excepción en NdrGetBuffer debido a la falta de un Binding Handle. Esto puede resolverse de varias maneras, pero la implementación actual hace lo siguiente:
int FetchReturnValue(const PEXCEPTION_POINTERS ExceptionInfo) {
ExceptionInfo->ContextRecord->EFlags |= (1 << 16);
g_ReturnValue = (PVOID)ExceptionInfo->ContextRecord->Rax;
return EXCEPTION_CONTINUE_EXECUTION;
}
La invocación RPC está protegida por CFG, lo que significa que, para lograr una ejecución de código completa y sin restricciones, es necesario marcar el objetivo como válido con SetProcessValidCallTargets o parchear RpcInvokeCheckICall.
El proyecto RpcProxyInvoke demuestra una técnica alternativa que puede ser abusada para implementar una librería estilo RailGun. Aunque la implementación pública no es perfecta, puede servir como base para un desarrollo posterior.
Este proyecto está licenciado bajo la Licencia MIT; consulte el archivo LICENSE para más detalles.