
임의의 호출을 NdrServerCall2 또는 유사한 API를 통해 프록시하여 실행하는 간단한 POC 라이브러리
로컬 및 원격 코드를 실행하는 일반적인 방법을 만들기 위해, 우리는 내부적으로 RpcCraft(자체) 및 RpcExec(원격 프로세스)라고 부르는 비교적 난해한 코드 실행 방법을 설계했습니다. 이 기법은 익스플로잇 개발자들 사이에서 잘 알려진 방법론을 활용하며, RPC(원격 프로시저 호출) 서버 호출(예: NdrServerCall2 또는 NdrServerCallAll)을 남용하여 임의 코드를 실행합니다.
RPCRT4.dll 내에서 NdrServerCall2, NdrServerCallAll, NdrServerCallNdr64(NdrServerCallAll의 별칭) 같은 함수는 서버 기능과 관련된 함수를 동적으로 호출하는 래퍼로 구현됩니다. 이 함수들은 단일 인수, 즉 RPC_MESSAGE 구조체에 대한 포인터를 받습니다.
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;
서비스에 바인딩하지 않고 런타임을 초기화하려면 PerformRpcInitialization 함수가 사용됩니다. 이 함수는 수동 바인딩 없이 필요한 구조체를 내부적으로 초기화합니다.
이 기법의 공개 버전은 실현 가능성을 입증하기 위한 POC로 개발되었으며, 현재 바인딩 핸들 누락으로 인해 NdrGetBuffer에서 예외가 발생합니다. 이는 여러 가지 방법으로 처리할 수 있지만, 현재 구현은 다음과 같이 처리합니다:
int FetchReturnValue(const PEXCEPTION_POINTERS ExceptionInfo) {
ExceptionInfo->ContextRecord->EFlags |= (1 << 16);
g_ReturnValue = (PVOID)ExceptionInfo->ContextRecord->Rax;
return EXCEPTION_CONTINUE_EXECUTION;
}
RPC 호출은 CFG로 보호됩니다. 즉, 완전하고 제한되지 않은 코드 실행을 달성하려면 SetProcessValidCallTargets로 대상을 유효하게 표시하거나 RpcInvokeCheckICall을 패치해야 합니다.
RpcProxyInvoke 프로젝트는 RailGun 스타일 라이브러리를 구현하는 데 남용될 수 있는 대체 기법을 보여줍니다. 공개 구현은 완벽하지 않지만, 추가 개발의 기반이 될 수 있습니다.
이 프로젝트는 MIT 라이선스에 따라 라이선스가 부여됩니다. 자세한 내용은 LICENSE 파일을 참조하세요.