
NdrServerCall2 などを介して任意のコールをプロキシとして実行するシンプルな POC ライブラリ
ローカルおよびリモートコードを実行する一般的な方法を作成するために、私たちは比較的目立たないコード実行方法を設計しました。これを内部ではRpcCraft(Self)およびRpcExec(Remote Process)と呼んでいます。この手法は、エクスプロイト開発者の間でよく知られている方法論を活用し、NdrServerCall2やNdrServerCallAllなどのRPC(リモートプロシージャコール)サーバーコールを悪用して任意のコードを実行します。
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ファイルを参照してください。