Windows カーネルグラフィック ドライバの攻撃面 イリヤ・ファン・スプルンデル ペネトレーションテスト ディレクター IOActive, Inc. Copyright ©2014. All Rights Reserved. 自己紹介 • • • • • • イリヤ・ファン・スプルンデル [email protected] ペネトレーションテスト ディレクター at IOActive ペネトレーションテスト コードレビュー 趣味と実益のコード破壊☺ IOActive, Inc. Copyright ©2014. All Rights Reserved. アジェンダ • • • 今回お話すること Windows グラフィックドライバ WDDM kmd ドライバ – – • • • 排他制御 エントリポイント これらと通信するためのユーザーランドで完結したプログラム プライベートデータの探索と窃取 まとめ – – ファジング リバースエンジニアリング IOActive, Inc. Copyright ©2014. All Rights Reserved. 今回お話すること • Windows® WDDM ドライバ – – • 実装上のセキュリティ カーネルドライバに関して 想定される聴衆 – – 解析者(どこを解析すべきか) グラフィックドライバの開発者 (すべきでないこと、注意を払うべき箇所) – ドライバの内部構造に興味を持った奇人変人 • 前提知識 – Windows ドライバに関する基礎知識(IRP、イベントハンドラ、データの受け渡し…) IOActive, Inc. Copyright ©2014. All Rights Reserved. Windows グラフィックドライバ • 過去のモデル – – – – • XDDM /XPDM Windows 2000/XP Windows 8 ではサポートされていない 本セッションでは対象としない WDDM (Windows Display Driver Model) – – Vista 以降のモデル • v1 – vista • v1.1 – win 7 • v1.2 – win 8 • V1.3 – win 8.1 セキュリティの観点から興味深い箇所について紹介する IOActive, Inc. Copyright ©2014. All Rights Reserved. Windows グラフィックドライバ • 誰が、何のためにドライバを開発しているのか? – – – – – 独立系ハードウェアベンダ (Intel, NVIDIA, AMD, Qualcomm, PowerVR, VIA, Matrox, …) • 非常に高機能なドライバ 基本的なフォールバック (基本レンダラ、基本ディスプレイ) • 最小限の実装 仮想化 (VMware, Virtual Box, Parallels guest drivers) • 特殊な目的のためのドライバ リモートデスクトップの実現 (XenDesktop, RDP, …) • 特殊な目的のためのドライバ 仮想ディスプレイ (intelligraphics, extramon, …) • 特殊な目的のためのドライバ IOActive, Inc. Copyright ©2014. All Rights Reserved. Windows グラフィックドライバ • • WDDM モデルはユーザーモードとカーネルモードに分けられている 安定性と信頼性のために、ユーザーモードへとコンポーネントが分割された – • Vista 以前のブルースクリーンは、その原因の大部分をグラフィックドライバに負っていた (MSDN から引 用): “Windows XP のグラフィックドライバは巨大かつ複雑で、システムを不安定にする原因でもあった。 これらのドライバは完全にカーネルモードで動作するものであり(i.e., システムの深部)、したがって、ドライ バの内部で問題が発生した場合、システムは再起動を余儀なくされる。Windows XP が主流だった時期 に収集されたクラッシュダンプ解析によると、ブルースクリーンにおける原因の最大 20 パーセント はグラ フィックドライバによるものだった。 ユーザーモードにおいては、プロセスに読み込まれるDLLとして実行される – • こちらについても、興味深い攻撃面が見受けられる • エンコーダ/デコーダ • バイナリプランティング • いくつかのAPIは、部分的に(間接的に)リモートからの攻撃に晒されうる (e.g. WebGL) 本発表はユーザーモードを対象とせず、カーネルモードにおける攻撃面を取り上げる IOActive, Inc. Copyright ©2014. All Rights Reserved. IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ • では、WDDM kmd ドライバとはどのようなものか? NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { ... DRIVER_INITIALIZATION_DATA DriverInitializationData; ... DriverInitializationData.DxgkDdiEscape = DDIEscape; ... Status = DxgkInitialize(DriverObject, RegistryPath, &DriverInitializationData); ... } IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ • • DriverEntry() はあらゆるカーネルドライバのエントリポイントである DRIVER_INITIALIZATION_DATA 構造体を埋める – – 無数のコールバック関数を含む 「動的な」構造体 • • • • • • win7 では肥大化 (vs vista) win8 ではより肥大化 win 8.1 ではさらに肥大化 末尾に新たな要素が追加されていく DxgkInitialize() の呼び出し – dxgkernel にドライバ自身とそのコールバック関数を通知する WDM のような IRP や IOCTL といった構造は存在せず、IoManager を介さない IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ • • • • これまでのものとよく似ている DxgkInitialize() の代わりに DxgkInitializeDisplayOnlyDriver() を呼び出す PKMDDOD_INITIALIZATION_DATA 構造体を利用 これまでのものと似ているが、カーネルモードの display only driverのみが用 いる IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ • • DRIVER_INITIALIZATION_DATA はあらゆるコールバック関数を含む 攻撃面の観点から、大きく3つのグループに分けることができる – – – • 攻撃者が全く制御できない、あるいは少ししか制御できない箇所 攻撃者が(間接的に)制御できる箇所 攻撃者がコールバック関数への重要な入力を制御できる箇所 我々は後者を問題視している IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – 排他制御 • • WDDM はスレッドモデルであり、そのコールバック関数は4つのレベルで構 成される(コールバック関数はこれらのいずれかに属する): レベル3 – – – – • 単一スレッドのみ GPU はアイドル状態である必要がある DMA バッファは処理されない ビデオメモリは CPU 側のメモリに追い出される レベル2 – ビデオメモリの追い出しを除き、上記と同じ IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – 排他制御 • • レベル1 – クラスに分類された呼び出し。各クラスにつき 1 つのスレッドのみ、同 時にコールバック関数を呼び出すことができる レベル0 – • • リエントラント(再入可能) マルチスレッドの実行が許可される場合であっても、2 つのスレッドが同時に 単一のプロセスに属することはできない レースコンディションによる攻撃シナリオを考えるにあたっては、このことを念 頭に置いておく必要がある IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント • ユーザーランドから重要な入力を受け取るコールバック関数は、かなり少数である: – – – – エスケープ機能 描画 メモリ割り当て クエリアダプタ • 興味深いコールバック関数に辿り着く前に、我々はドライバを適切に初期化しなければならない • – まずは初期化の部分を見てみよう それから、コールバック関数を見てみよう IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 初期化 • • • ユーザーランドからエントリポイントに到達する前に、デバイスを初期化しなけ ればならない 我々はHDC(デバイスコンテキストのハンドル)を持ってGDI(グラフィックデバ イスインターフェイス)の世界からやってくると仮定する 簡潔に、これらは3つのステップを伴う – – – HDC を WDDM が扱えるハンドルとして変換する 変換したハンドルから WDDM のデバイスハンドルを取得する デバイスのためのコンテキストを作成する IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 初期化 – HDC を WDDM が扱えるハンドルとして変換する – D3DKMT_OPENADAPTERFROMHDC 構造体を埋める – D3DKMTOpenAdapterFromHdc の呼び出し D3DKMT_OPENADAPTERFROMHDC oafh; memset(&oafh, 0x00, sizeof(oafh)); oafh.hDc = GetDC(NULL); D3DKMTOpenAdapterFromHdc(&oafh); IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 初期化 – 変換したハンドルからデバイスハンドルを取得する – D3DKMT_CREATEDEVICE 構造体を埋める – D3DKMTCreateDevice の呼び出し D3DKMT_CREATEDEVICE cdev; memset(&cdev, 0x00, sizeof(cctx)); cdev.hAdapter = oafh.hAdapter; D3DKMTCreateDevice(&cdev); IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 初期化 – デバイスのためのコンテキストを作成する – 先程取得したデバイスハンドルは、WDDM ドライバに通信するためのユーザーラン ド API の殆どに渡されるハンドルである – 何をするにもまずデバイスコンテキストを作成する必要がある • WDDM ドライバに渡すことができるコマンドバッファを設定する • ここに攻撃面がある。ユーザーランドから任意のデータ (pPrivateDriverData) (とその ポインタが指すデータ長 PrivateDriverDataSize) を WDDM ドライバに渡すことができ るのだ – とはいえ、これは完全にドライバ依存であり、時と場合によるものである IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 初期化 – デバイスのためのコンテキストを作成する – D3DKMT_CREATECONTEXT 構造体を埋める – D3DKMTCreateContext の呼び出し D3DKMT_CREATECONTEXT cctx; memset(&cctx, 0x00, sizeof(cctx)); cctx.hDevice = cdev.hDevice; r= pfnKTCreateContext(&cctx); – DxgkDdiCreateContext カーネルエントリポイント IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _D3DKMT_CREATECONTEXT { D3DKMT_HANDLE hDevice; UINT NodeOrdinal; UINT EngineAffinity; D3DDDI_CREATECONTEXTFLAGS Flags; VOID *pPrivateDriverData; UINT PrivateDriverDataSize; D3DKMT_CLIENTHINT ClientHint; D3DKMT_HANDLE hContext; VOID *pCommandBuffer; UINT CommandBufferSize; D3DDDI_ALLOCATIONLIST *pAllocationList; UINT AllocationListSize; D3DDDI_PATCHLOCATIONLIST *pPatchLocationList; UINT PatchLocationListSize; D3DGPU_VIRTUAL_ADDRESS CommandBuffer; } D3DKMT_CREATECONTEXT; WDDM kmd ドライバ エントリポイント – 初期化 – デバイスのためのコンテキストを作成する – 構造体が出力する興味深い要素 – コマンドバッファや patchlocationlist は、いずれもあ なたに代わって WDDM によって割り当てられる – ユーザーモードでは WDDM ドライバとの通信に用 いられる IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _D3DKMT_CREATECONTEXT { D3DKMT_HANDLE hDevice; UINT NodeOrdinal; UINT EngineAffinity; D3DDDI_CREATECONTEXTFLAGS Flags; VOID *pPrivateDriverData; UINT PrivateDriverDataSize; D3DKMT_CLIENTHINT ClientHint; D3DKMT_HANDLE hContext; VOID *pCommandBuffer; UINT CommandBufferSize; D3DDDI_ALLOCATIONLIST *pAllocationList; UINT AllocationListSize; D3DDDI_PATCHLOCATIONLIST *pPatchLocationList; UINT PatchLocationListSize; D3DGPU_VIRTUAL_ADDRESS CommandBuffer; } D3DKMT_CREATECONTEXT; WDDM kmd ドライバ エントリポイント – 初期化 • • • • • • • • DxgkDdiEscape グラフィックドライバにおける IOCTL に相当する 「過去の」 extEscape に酷似している しかしながら、 エスケープ機能が呼ばれることはない プライベートデータへのポインタとそれが指すデータ長が格納される MSDN は「DxgkDdiEscape 関数は、ユーザーモードとディスプレイドライバが情報を共有する ためのものである」と述べている ドライバは、どのような方式でも、この仕組みを実装して構わない データは全くと言って標準化されていない – • めちゃくちゃなデータであっても、ドライバ間で送受信することができる スレッドレベル 2 IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – エスケープ機能 • では、 DxgkDdiEscape とはどのようなものか? NTSTATUS APIENTRY DxgkDdiEscape( __in const HANDLE hAdapter, __in const DXGKARG_ESCAPE *pEscape ) { ... } IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _DXGKARG_ESCAPE { HANDLE hDevice; D3DDDI_ESCAPEFLAGS Flags; VOID *pPrivateDriverData; UINT PrivateDriverDataSize; HANDLE hContext; } DXGKARG_ESCAPE; WDDM kmd ドライバ エントリポイント – エスケープ機能 • • • • pPrivateDriverData はハンドリングされ、キャプチャされる 長さの制限なし (e.g. 4 ギガバイトまで可能) ユーザーランドから完全に制御することができる 埋め込まれたポインタは全て try/except によってハンドリングされる必要があ る IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – エスケープ機能 • どのようにしてユーザーランドから通信するか? NTSTATUS D3DKMTEscape( _In_ const D3DKMT_ESCAPE *pData ); • typedef struct _D3DKMT_ESCAPE { D3DKMT_HANDLE hAdapter; D3DKMT_HANDLE hDevice; D3DKMT_ESCAPETYPE Type; D3DDDI_ESCAPEFLAGS Flags; VOID *pPrivateDriverData; UINT PrivateDriverDataSize; D3DKMT_HANDLE hContext; } D3DKMT_ESCAPE; システムコールとして正式に文書化されている IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – エスケープ機能 IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 描画 • • • DxgkDdiRender このコールバック関数はレンダリングの心臓部である ユーザーモードから GPU に対し、コマンドバッファから描画させる – コマンドバッファから DMA バッファを生成する IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 描画 • では、DxgkDdiRender とはどのような ものか? NTSTATUS APIENTRY DxgkDdiRender( _In_ const HANDLE hContext, _Inout_ DXGKARG_RENDER *pRender ) { ... } IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _DXGKARG_RENDER { const VOID CONST *pCommand; const UINT CommandLength; VOID *pDmaBuffer; UINT DmaSize; VOID *pDmaBufferPrivateData; UINT DmaBufferPrivateDataSize; DXGK_ALLOCATIONLIST *pAllocationList; UINT AllocationListSize; D3DDDI_PATCHLOCATIONLIST *pPatchLocationListIn; UINT PatchLocationListInSize; D3DDDI_PATCHLOCATIONLIST *pPatchLocationListOut; UINT PatchLocationListOutSize; UINT MultipassOffset; UINT DmaBufferSegmentId; PHYSICAL_ADDRESS DmaBufferPhysicalAddress; } DXGKARG_RENDER; WDDM kmd ドライバ エントリポイント – 描画 • • • • pCommand バッファはユーザーランドから送られるポインタである pPatchLocationListIn はユーザーランドから送られるポインタである MSDN はこのように述べている: 「サブシステムとしてユーザーモードで動作するディスプレイドライバが生成するデータである pCommand コマンドバッファと patch-location list の入力 pPatchLocationListIn は、いず れもユーザーモードのアドレス空間に割り当てられ、手を加えられないまま、ディスプレイミニ ポートドライバを経由する。ディスプレイミニポートドライバはバッファやリストを参照するにあ たって必ず __try/__except を用いる必要があり、それぞれのカーネルバッファにバッファやリス トをコピーする前に、その内容をバリデーションする必要がある」 それでは、バリデーション例を見てみよう IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 描画 __try { for (Index = 0; Index < AllocationListInSize; AllocationTable++, AllocationListIn++, AllocationListOut++, Index++) { D3DKMT_HANDLE AllocationHandle = AllocationListIn->hAllocation; ... } } __except(EXCEPTION_EXECUTE_HANDLER) { Status = STATUS_INVALID_PARAMETER; SAMPLE_LOG_ERROR( "Exception occurred accessing … Status=0x%I64x", Status); goto cleanup; } IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 描画 • • • • • ユーザーランドが実際にコマンドバッファやパッチリストのアドレスを指定してい るわけではない D3DKMTCreateContext を呼び出す際に、Dxgkernel はあなたに代わってバ アドレスをユーザーランドに割り当てる そのため、ドライバのバックグラウンドで(VirtualFree によって)アンマップするこ とができる したがって、try/except が必要とされる コマンド、パッチリストのアドレスともユーザーランドに存在していることを考える と、ダブルフェッチに気をつけなければならない – – – フェッチ 1: デリファレンスとバリデーション ユーザーランドからのデータ改変 フェッチ 2: デリファレンスとデータの利用、ダブルフェッチのバグ、先ほどのバリ デーションの無効化 IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 描画 • try /except が存在しない例 static NTSTATUS APIENTRY DxgkDdiRenderNew( CONST HANDLE hContext, DXGKARG_RENDER *pRender) { if (pRender->CommandLength < sizeof (VBOXWDDM_DMA_PRIVATEDATA_BASEHDR)) { return STATUS_INVALID_PARAMETER; } PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pInputHdr = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender>pCommand; NTSTATUS Status = STATUS_SUCCESS; VBOXCMDVBVA_HDR* pCmd = (VBOXCMDVBVA_HDR*)pRender->pDmaBufferPrivateData; switch (pInputHdr->enmCmd) ← try/except が存在しない { ... } ... return STATUS_SUCCESS; } IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 描画 • ダブルフェッチの例 static NTSTATUS APIENTRY DxgkDdiRenderNew( CONST HANDLE hContext, DXGKARG_RENDER *pRender) { … PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR pInputHdr = (PVBOXWDDM_DMA_PRIVATEDATA_BASEHDR)pRender->pCommand; ... PVBOXWDDM_DMA_PRIVATEDATA_UM_CHROMIUM_CMD pUmCmd = pInputHdr; … PVBOXWDDM_UHGSMI_BUFFER_UI_SUBMIT_INFO pSubmUmInfo = pUmCmd->aBufInfos; … if (pSubmUmInfo->offData >= pAlloc->AllocData.SurfDesc.cbSize || pSubmUmInfo->cbData > pAlloc->AllocData.SurfDesc.cbSize || pSubmUmInfo->offData + pSubmUmInfo->cbData > pAlloc->AllocData.SurfDesc.cbSize) { WARN(("invalid data")); return STATUS_INVALID_PARAMETER; } … pSubmInfo->cbBuffer = pSubmUmInfo->cbData; …IOActive, Inc. Copyright ©2014. All Rights Reserved. return STATUS_SUCCESS; } バリ デート 使用 WDDM kmd ドライバ エントリポイント – 描画 • どのようにしてユーザーモードから通 信する? NTSTATUS APIENTRY D3DKMTRender( _Inout_ D3DKMT_R ENDER *pData ); IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _D3DKMT_RENDER { union { D3DKMT_HANDLE hDevice; D3DKMT_HANDLE hContext; }; UINT CommandOffset; UINT CommandLength; UINT AllocationCount; UINT PatchLocationCount; VOID *pNewCommandBuffer; UINT NewCommandBufferSize; D3DDDI_ALLOCATIONLIST *pNewAllocationList; UINT NewAllocationListSize; D3DDDI_PATCHLOCATIONLIST *pNewPatchLocationList; UINT NewPatchLocationListSize; D3DKMT_RENDERFLAGS Flags; ULONGLONG PresentHistoryToken; ULONG BroadcastContextCount; D3DKMT_HANDLE BroadcastContext[D3DDDI_MAX_BROADCAST_CONTEXT]; ULONG QueuedBufferCount; D3DGPU_VIRTUAL_ADDRESS NewCommandBuffer; VOID *pPrivateDriverData; UINT PrivateDriverDataSize; } D3DKMT_RENDER; WDDM kmd ドライバ エントリポイント – 描画 IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – メモリ割り当て • • • DxgkDdiCreateAllocation Dxgkernel は、ユーザーランドからのメモリ割り当て要求に対し、このコール バック関数を呼び出す これは、フラグに応じてシステムまたはビデオメモリのいずれかを割り当てる IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – メモリ割り当て • では、DxgkDdiCreateAllocation とはどのようなものか? NTSTATUS APIENTRY DxgkDdiCreateAllocation( const HANDLE hAdapter, DXGKARG_CREATEALLOCATION *pCreateAllocation ) { ... } IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _DXGKARG_CREATEALLOCATION { const VOID *pPrivateDriverData; UINT PrivateDriverDataSize; UINT NumAllocations; DXGK_ALLOCATIONINFO *pAllocationInfo; HANDLE hResource; DXGK_CREATEALLOCATIONFLAGS Flags; } DXGKARG_CREATEALLOCATION; WDDM kmd ドライバ エントリポイント – メモリ割り当て • では、DxgkDdiCreateAllocation とはどのようなものか?(cont.) typedef struct _DXGK_ALLOCATIONINFO { VOID *pPrivateDriverData; UINT PrivateDriverDataSize; UINT Alignment; SIZE_T Size; SIZE_T PitchAlignedSize; DXGK_SEGMENTBANKPREFERENCE HintedBank; DXGK_SEGMENTPREFERENCE PreferredSegment; UINT SupportedReadSegmentSet; UINT SupportedWriteSegmentSet; UINT EvictionSegmentSet; UINT MaximumRenamingListLength; HANDLE hAllocation; DXGK_ALLOCATIONINFOFLAGS Flags; DXGK_ALLOCATIONUSAGEHINT *pAllocationUsageHint; UINT AllocationPriority; IOActive, Inc. Copyright ©2014. All Rights Reserved. } DXGK_ALLOCATIONINFO; WDDM kmd ドライバ エントリポイント – メモリ割り当て • • • • プライベートドライバデータは、カーネルがユーザーランドから取得する ユーザーランドから渡すための NumAllocations DXGK_ALLOCATIONINFO 構造体がある DXGK_ALLOCATIONINFO のプライベートデータは、カーネルがユーザーラ ンドから取得する DxgkDdiOpenAllocation を直接ユーザーランドから呼び出すことはできない が、 そのプライベートドライバデータはここで提供されるものと同じである IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – メモリ割り当て • どのようにしてユーザーランドから通信す typedef struct _D3DKMT_CREATEALLOCATION { る? NTSTATUS APIENTRY D3DKMTCreateAllocation( D3DKMT_CREATEALLOCATION *pData ); IOActive, Inc. Copyright ©2014. All Rights Reserved. D3DKMT_HANDLE hDevice; D3DKMT_HANDLE hResource; D3DKMT_HANDLE hGlobalShare; const VOID *pPrivateRuntimeData; UINT PrivateRuntimeDataSize; const VOID *pPrivateDriverData; UINT PrivateDriverDataSize; UINT NumAllocations; D3DDDI_ALLOCATIONINFO *pAllocationInfo; D3DKMT_CREATEALLOCATIONFLAGS Flags; HANDLE hPrivateRuntimeResourceHandle; } D3DKMT_CREATEALLOCATION; WDDM kmd ドライバ エントリポイント – メモリ割り当て IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – クエリアダプタ • • • • • • 実際の nr の型はユーザーとドライバで異 なっている Dxgkernel は何らかの変換を行う いずれのフォーマットも定義されている データ長についても定義されている DXGKQAITYPE_UMDRIVERPRIVATE を除いて、 ドライバはこれらをどのように扱っても良い typedef enum _DXGK_QUERYADAPTERINFOTYPE { DXGKQAITYPE_UMDRIVERPRIVATE = 0, DXGKQAITYPE_DRIVERCAPS = 1, DXGKQAITYPE_QUERYSEGMENT = 2, #if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN7) DXGKQAITYPE_ALLOCATIONGROUP = 3, DXGKQAITYPE_QUERYSEGMENT2 = 4, #endif #if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WIN8) DXGKQAITYPE_QUERYSEGMENT3 = 5, DXGKQAITYPE_NUMPOWERCOMPONENTS = 6, DXGKQAITYPE_POWERCOMPONENTINFO = 7, DXGKQAITYPE_PREFERREDGPUNODE = 8, #endif #if (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM1_3) DXGKQAITYPE_POWERCOMPONENTPSTATEINFO = 9, DXGKQAITYPE_HISTORYBUFFERPRECISION = 10 #endif } DXGK_QUERYADAPTERINFOTYPE; IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – クエリアダプタ • では、DxgkDdiQueryAdapterInfo とはどのようなものか? NTSTATUS APIENTRY DxgkDdiQueryAdapterInfo( HANDLE hAdapter, DXGKARG_QUERYADAPTERINFO *pQueryAdapterInfo ) { ... } IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _DXGKARG_QUERYADAPTERINFO { DXGK_QUERYADAPTERINFOTYPE Type; VOID *pInputData; UINT InputDataSize; VOID *pOutputData; UINT OutputDataSize; } DXGKARG_QUERYADAPTERINFO; WDDM kmd ドライバ エントリポイント – クエリアダプタ • • 興味深いエントリ- イグジットポイントを持っている エントリポイント: – ユーザーランドを経由してきたデータ – このための最も興味深い型は DXGKQAITYPE_UMDRIVERPRIVATE で ある • イグジットポイント: – ユーザーからカーネルに巨大な構造体を返すクエリ API が存在しており、情報が漏 洩する可能性がある • 構造体がスタック/ヒープ領域にあり、かつ memsetが行われておら ず、かつ 1 つ以上のメンバが初期化されていないとき(e.g. NULL 終 端文字列) IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – クエリアダプタ • どのようにしてユーザーランドから通信する? NTSTATUS D3DKMTQueryAdapterInfo( D3DKMT_QUERYADAPTERINFO *pData ); IOActive, Inc. Copyright ©2014. All Rights Reserved. typedef struct _D3DKMT_QUERYADAPTERINFO { D3DKMT_HANDLE hAdapter; KMTQUERYADAPTERINFOTYPE Type; VOID *pPrivateDriverData; UINT PrivateDriverDataSize; } D3DKMT_QUERYADAPTERINFO; WDDM kmd ドライバ エントリポイント – クエリアダプタ IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ エントリポイント – 最善の方法 • 境界外の読み取り ← 極めて一般的 – – • デバッグコードを出荷するな – – – • これはカーネルでのブルースクリーンを意味する 境界外のたった 1 バイトを読み取った場合でも発生しうる DbgPrint の除去 および周辺のコード (e.g. 書式指定文字列によって出力されうるデータ) • DbgPrint を除去したところで、周辺のコードはバイナリに含まれるため、悪 用されうるバグが含まれてしまうかもしれない #ifdef debug の除去 カーネル用の安全な整数ライブラリ関数を用いること (e.g. RtlUIntAdd) – 我流のコードを書かないように… IOActive, Inc. Copyright ©2014. All Rights Reserved. これらと通信するためのユーザーランドで完結したプログラム • • • • 少しばかり見た目より難しい API は MSDN で文書化されており、 gdi32.dll からエクスポートされている データ構造についても MSDN で文書化されている OpenGL ICD (インストール可能なクライアントドライバ) ドライバのためのもの – これらのためのヘッダが存在しない: • LoadLibrary/GetProcAddress が必要となる • 開発キットはあるものの…MSDN は述べている:「OpenGL ICD 開発キット のライセンスを得る際には OpenGL Issues に連絡するよう 注意してくださ い」 • 文書化されていることを考えると、動作している(部分的な)実装を把握する ことは容易い • あるいは COM API を呼ぶこともできる ☺ IOActive, Inc. Copyright ©2014. All Rights Reserved. プライベートデータの探索と窃取 • • • umd から kmd に送信されるデータは標準化されておらず、ドライバの実装に 依存するため、正常系におけるデータの送信を解析することによって、プロトコ ルの構造を推測する必要がある 任意のドライバがどのようなプロトコルで通信しているか知るためには API フック: – – – – D3DKMTEscape D3DKMTRender D3DKMTCreateAllocation D3DKMTQueryAdapterInfo IOActive, Inc. Copyright ©2014. All Rights Reserved. プライベートデータの探索と窃取 • • • ツール/デモ 公開! PowerPoint に対して実行しているが、かなり良い結果を与えているようだ IOActive, Inc. Copyright ©2014. All Rights Reserved. まとめ • • ファジング リバースエンジニアリング IOActive, Inc. Copyright ©2014. All Rights Reserved. まとめ – ファジング • • • • • ミューテーションファザー 送受信データの傍受(ドライバごとにテンプレートを作成) テンプレートをもとに改変したデータを送信 ループ リバースエンジニアリングとの連携 – – • If (embedded_len != PrivateDataSize) bail; Checksums ➔ バグ! IOActive, Inc. Copyright ©2014. All Rights Reserved. まとめ – リバースエンジニアリング Bruce Dang 曰く、 「Windows ドライバのリバースエンジニアリングを職業として捉えるな らば、その工程の 90% は Windows の仕組みを理解することであり、残 り 10% はアセンブリコードを理解することだと言えるだろう」 IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • • • • 先に示したように、あらゆるドライバは初期化の一環として、DxgkInitialize() あ るいは DxgkInitializeDisplayOnlyDriver() を呼び出す そしてコールバックテーブル (DRIVER_INITIALIZATION_DATA) に渡す 逆アセンブラによる静的解析では、これらの関数への call が発見できなかった なぜなら、これらの関数はインライン展開されるからである IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • では、シンボルとともに、どのようなものか見てみよう IOActive, Inc. Copyright ©2014. All Rights Reserved. IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • • • • • Dxgkrnl.sys のロード(これは既にロードされているべきである) デバイスオブジェクトへのポインタを取得する ioctl 0x230043 を発行 (video device, function 10, method neither, FILE_ANY_ACCESS) 返された関数ポインタは、コールバック関数の登録に用いられる 関数ポインタの呼び出しには、 DRIVER_INITIALIZATION_DATA または PKMDDOD_INITIALIZATION_DATA 構造体を引数として与える IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • テーブル自身はいくつかの異なった方法で作成/記録される – – – • • • グローバル空間 スタック上 特定の関数が DRIVER_INITIALIZATION_DATA に記録する あるいは DxgkInitialize() を呼び出す前にローカルスタックに書き込まれたバッ ファ これらのコードの発見は非常に簡単である。これらの処理は、ドライバの早い 段階で行われるためである(通常は DriverEntry() か、それが呼び出す関数) このように見える傾向がある: IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • C 言語によって表現した構造体を示す: typedef struct _DRIVER_INITIALIZATION_DATA { ULONG Version; PDXGKDDI_ADD_DEVICE DxgkDdiAddDevice; PDXGKDDI_START_DEVICE DxgkDdiStartDevice; PDXGKDDI_STOP_DEVICE DxgkDdiStopDevice; PDXGKDDI_REMOVE_DEVICE DxgkDdiRemoveDevice; ... } DRIVER_INITIALIZATION_DATA, *PDRIVER_INITIALIZATION_DATA; • IDA の逆アセンブルコードに構造体を反映させることで、名前マングリングが 容易になる IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • ユーザーランドから渡されたデータ(プライベートデータ) – – ドライバは任意のプロトコル仕様に従ってデータを処理する 通常時: • (簡単な)ネットワークプロトコルのリバースエンジニアリングのようなもの • 通常、ヘッダと共にやってくる – 型 – 長さ – 値 • これらを処理するための switch case やネストした if/else が見つかるだろう IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • 典型的な例: IOActive, Inc. Copyright ©2014. All Rights Reserved. WDDM kmd ドライバ – リバースエンジニアリング • DxgkDdiEscape などの関数は、ユーザーランドから渡されたデータを処理で きなかった場合 STATUS_INVALID_PARAMETER (0xc000000d) を返そうと する – – 戻り値はドライバによって指定される ファジング中、頻繁に/常にこれが発生する場合、これは通常、バリデーション/ チェックサム処理を検出した兆候である • 周辺のアセンブリを読み解いて理由を把握し、それに応じてファザーを調整 しよう IOActive, Inc. Copyright ©2014. All Rights Reserved. まとめ • Vista 以降の WDDM ついて • 信頼境界やエントリポイントにおける興味深い要素 – – – – エスケープ機能 描画 メモリ割り当て クエリアダプタ • umd <-> kmd 間で送受信されるデータは標準化されておらず、ドライバの 実装に依存する(e.g. IRP として構造化されていない) • 他のドライバからも類似のバグが見つかるかもしれない IOActive, Inc. Copyright ©2014. All Rights Reserved. おわりに • 未だ知られていない攻撃面は無数にある • 今回お話した内容はほんの一部 IOActive, Inc. Copyright ©2014. All Rights Reserved. Q&A IOActive, Inc. Copyright ©2014. All Rights Reserved.
© Copyright 2024 ExpyDoc