制御フローガード。 Adobe Flash Playerの例を使用した動作と回避策



マイクロソフトは、アプリケーションを保護するための新しいテクノロジを何度も実装することで、エクスプロイト記述子を使った終わりのない戦争に勝つ試みを放棄しません。 今回、Windowsオペレーティングシステムの開発者は、この問題に根本的に取り組み、問題の根本に視点を移しました。 何らかの形でのほぼすべてのエクスプロイトの作業は、アプリケーション実行のフローを傍受することを目的としているため、この瞬間を監視するためにアプリケーションを「教える」ことは害になりません。

制御フローの整合性の概念は、2005年に説明されました。 そして今、10年後、Microsoftの開発者は、このコンセプトの不完全な実装であるControl Flow Guardを発表しました。







制御フローガードとは何ですか?



制御フローガード(Guard CF、CFG)は、ユーザーおよびカーネルモードアプリケーションのバイナリ脆弱性を悪用するプロセスを複雑にすることを目的とした比較的新しいWindowsエクスプロイト緩和メカニズムです。 このメカニズムの機能は、間接呼び出しを検証することです。これにより、攻撃者が実行スレッドを傍受するのを防ぎます(たとえば、仮想関数のテーブルを上書きすることにより)。 以前の防御メカニズム( SafeSEHASLRDEPなど)と組み合わせることで 、エクスプロイトの作成者にとっては頭痛の種です。

このセキュリティ機能は、Microsoft Windows 8.1(Update 3、KB3000850)およびWindows 10のユーザーが利用できます。

CFGをサポートするプログラムのコンパイルは、Microsoft Visual Studio 2015で利用できます( 有効にする方法は? )。







LinuxファミリのOSの制御フロー整合性の概念に基づく保護メカニズムの同様の実装は、 PaX拡張で利用できます。


制御フローガードの仕組み



ユーザーモードでのCFGの原理を考慮してください。 このメカニズムには、2つの主要なコンポーネントがあります。アドレスのビットマップ(カーネルによって制御される)と、呼び出された関数のポインターをチェックする手順(ユーザーアプリケーションによって使用される)です。

すべてのCFG IMAGE_LOAD_CONFIG_DIRECTORY



は、コンパイル時にIMAGE_LOAD_CONFIG_DIRECTORY



実行可能ファイルに記録されます。











IMAGE_DLLCHARACTERISTICS_GUARD_CF



フラグがIMAGE_NT_HEADERS.OptionalHeader.DllCharacteristics



ヘッダーに入力され、この実行可能ファイルがCFGメカニズムをサポートしていることを示します。







すべてのサービス情報は、 /loadconfig



実行することにより、Microsoft Visual Studio 2015のdumpbin.exe



ツール( Microsoft Visual Studio 14.0 \ VC \ bin \ dumpbin.exe )を使用して/loadconfig



ます。

















ガードフラグ



Windows 10(1511)のwinnt.h



ヘッダーファイルには、次のCFGフラグが含まれています(後者はフラグであり、マスクではありません)。









これは、既存のフラグの不完全なリストであることに注意してください。 最も完全なリストは、 link.exe



ファイル(リンカー)の内部から取得できます。









また、いくつかの興味深いフラグの存在に注意を払う価値がありますが、その公式情報は入手できません。 マイクロソフトの開発者は、書き込みアドレス( IMAGE_GUARD_CFW_INSTRUMENTED



)を確認するために、追加のCFGメカニズムをテストしているようです。







ビットマップ



カーネルがOS( nt!MiInitializeCfg



)をnt!MiInitializeCfg



と、 nt!MiInitializeCfg



ビットマップが作成されます。これは、すべてのプロセスの共有セクションです。 CFGをサポートするプロセスを開始すると、プロセスのアドレス空間へのビットマップのマッピング(マッピング)が発生します。 その後、アドレスとビットマップサイズがntdll!LdrSystemDllInitBlock



入力されます。

関数アドレスとビットマップのビットとの比較は、実行可能ファイルローダー( nt!MiParseImageCfgBits



)によって実行されます。 ビットマップの各ビットは、8バイトのユーザープロセスアドレス空間を担当します。 すべての有効な関数の先頭のアドレスは、ビットマップ内の対応するオフセットの単一ビットに関連付けられており、それ以外はすべて0です。

















呼び出された関数のポインターを確認する手順



コンパイル段階でのプログラム内の暗黙的な呼び出しは、呼び出された関数のアドレスをチェックすることによりフレーム化されます。 検証手順のアドレスは、空の手順のアドレスが最初に設定されたため、実行可能ファイルのローダーによって設定され、それにより下位互換性が維持されます。

わかりやすくするために、CFGなしでコンパイルされた同じコードを見てみましょう。







元のC ++コード:







 class CSomeClass { public: virtual void doSomething() { std::cout << "hello"; } }; int main() { CSomeClass *someClass = new CSomeClass(); someClass->doSomething(); return 0; }
      
      





ASMリスト(クリッピング):







 mov eax, [ecx] ; EAX = CSomeClass::vftable call dword ptr [eax] ; [EAX] = CSomeClass::doSomething()
      
      





コンパイルキー/ガードを使用:cf:







 mov eax, [edi] ; EAX = CSomeClass::vftable mov esi, [eax] ; ESI = CSomeClass::doSomething() mov ecx, esi call ds:___guard_check_icall_fptr ; checks that ECX is valid function pointer mov ecx, edi call esi
      
      





最初のケースでは、コードは仮想関数テーブルスプーフィング手法を使用した攻撃を受けやすくなります。 攻撃者がこの脆弱性の悪用中にオブジェクトのデータを上書きできる場合、関数someClass->doSomething()



を呼び出すと、攻撃者が制御するコードを実行するように仮想関数テーブルを置き換え、アプリケーション実行フローをインターセプトできます。

制御フローガードを使用する場合は、呼び出された関数のアドレスが最初にビットマップで検証されます。 対応するビットがゼロの場合、ソフトウェア例外が発生します。







Guard CFメカニズムをサポートするOSでこのアプリケーションを起動すると、実行可能ファイルローダーがビットマップを作成し、チェックプロシージャのアドレスをntdll!LdrpValidateUserCallTarget





Windows 10(ビルド1511)のこの機能は、次のように実装されています。











入力アドレス0x0B3385B0の例を使用して、この関数のアルゴリズムを研究します。







B3385B0 16 = 10110011001110000101 10110 000 2







この関数は、 ecx



介して検証済みアドレスを受け取りecx



。 ビットマップアドレスは、 edx



入力edx



ます。 私の場合、ビットマップは0x01430000にあります。











3バイト(24ビット)の上位(下線付き)アドレスは、ビットマップのオフセットに対応します。 この場合、オフセットは0xB3385



ます。 ビットマップの単位は4バイト(32ビット)であるため、目的のセルを取得するに + * 4



を計算する必要があります。 この例では、 0x01430000 + 0xB3385 * 4 = 0x16FCE14



ます。 ビットマップセル値はedx



書き込まedx



ます。









ターゲットセルを取得しました。次に、興味のあるビットの数を決定する必要があります。 数値は、アドレスの次の5ビットの値です(太字で強調表示)。 ただし、チェック対象のアドレスが16バイトの境界で整列されていない場合( address & 0xf != 0



)、奇数ビットが使用されることに注意してください( offset | 0x1



)。 この場合、アドレスは整列され、ビット番号は10110 2 = 22 10になります。







現在は、ビットテストを実行してビット値をチェックするだけです。 bt



命令は、最初のレジスタのビット値をチェックします。そのシーケンス番号は、2番目のレジスタの最下位5ビット(モジュロ32)から取得されます。 ビットが1の場合、 Carry Flag (CF)



が設定され、プログラムは通常モードで実行され続けます。







それ以外の場合、 ntdll!RtlpHandleInvalidUserCallTarget



関数が呼び出され、プログラムはスタック上の0xAパラメーターを持つ29番目の割り込みで終了しますnt!_KiRaiseSecurityCheckFailure(FAST_FAIL_GUARD_ICALL_CHECK_FAILURE)



つまり、 nt!_KiRaiseSecurityCheckFailure(FAST_FAIL_GUARD_ICALL_CHECK_FAILURE)











22ビット目をチェックすることにより、呼び出された関数のアドレスが有効であることを確認できます。







Pythonでのこのアルゴリズムの実装は次のとおりです。







 def calculate_bitmap_offset(addr): offset = (addr >> 8) * 4 bit = (addr >> 3) % 32 aligned = (addr & 0xF == 0) if not aligned: bit = bit | 1 print "addr = 0x%08x, offset = 0x%x, bit index = %u, aligned? %s" % (addr, offset, bit, "yes" if aligned else "no") calculate_bitmap_offset(0x0B3385B0)
      
      





スクリプトの結果:







 addr = 0x0b3385b0, offset = 0x2cce14, bit index = 22, aligned? yes
      
      





例外



すべての場合において、無効な関数の呼び出しが29番目の割り込みで終了するわけではありません。 ntdll!RtlpHandleInvalidUserCallTarget



関数では、次のチェックが行われます。









この関数の擬似コードは次のとおりです。











「抑制された」コールに関する公式情報はありません。 これらの呼び出しにはコンパイラーのサポートが必要であるとしか言えませんGuardFlags



フラグでIMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK



マスクを設定し、コンパイラーが拡張テーブルを生成する必要があります。 このマスクに対応するバイトには、 GuardCFFunctionTable



テーブルの要素の追加サイズの値が格納されます。 関数のアドレスが「抑制」されている場合、アドレスに続くバイトは1に等しくなければなりません。

たとえば、必要なアプリケーションのCFGOptions



パラメーターを1に設定することにより、レジストリブランチHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\



を使用して、「抑制された」呼び出しを解決できます。







制御フローガードの弱点



他の防御メカニズムと同様に、CFGにはいくつかの弱点があります。









Adobe Flash Playerの例を使用した制御フローガードバイパスの実装



Windows 8以降、Adobe Flash PlayerプラグインはInternet Explorerに統合され、Windows 8.1(Update 3)ではCFGサポートが付属しています。 Adobe Flash Playerのエクスプロイトには、コントロールフローガードバイパスの実装がいくつかありますが、そのいくつかは現在でも関連しています。

















ダイナミックコードバイパス



Adobe Flash PlayerはJITコンパイルを広範囲に使用するため、ActionScriptコードの解釈などのリソースを大量に消費する操作を回避できます。 ただし、前述のように、動的に生成された関数には、開発者による追加の注意が必要です。 以下に説明する2つの回避策は、メモリ割り当てに関する開発者の省略の結果です。







動的コードでの暗黙的な呼び出しチェックの欠如



この方法は、Core Securityの研究者であるFranciscoFalcónによるCVE-2015-0311のエクスプロイト分析で提案および実装されました。 元の記事では、回避策のプロセスについてかなり詳細に説明しています。 このメソッドの本質は、特定のActionScriptクラスの仮想関数の内部テーブルを変更することです。 その後、このクラスのメソッドの1つを、動的に生成された関数の本体から呼び出す必要があります。 ByteArray



クラスは、この目的に適しています。

ByteArray



オブジェクトの構造:









オフセット$ + 8には、クラスVTable



オブジェクトへのポインターがあります。











VTable



クラスは、ActionScriptクラスの仮想関数テーブルの内部表現です(つまり、C ++が生成するものではありません)。

このクラスのオブジェクトには、 MethodEnv



クラスのオブジェクトへのポインターが含まれています。









このクラスはActionScriptメソッドの説明であり、メモリ内のオフセット$ + 4にある関数本体へのポインターが含まれています。







オフセット$ + D4のVTable



オブジェクトには、 ByteArray::toString()



メソッドの説明が含まれています。 メモリへの任意の読み取りおよび書き込みが可能なため、攻撃者はByteArray::toString()



実行することで、関数ポインターを関数本体( MethodEnv + 4



)に変更し、アプリケーション実行フローを安全にインターセプトできます。







これは、このクラスのメソッドがJITコードから呼び出されるという事実により可能になります。











上記のスクリーンショットでわかるように、この関数は動的に生成されたため、最初に呼び出されたアドレスをチェックせずに暗黙的な呼び出しが発生します。







このCFGの回避策は、Adobe Flash Playerバージョン18.0.0.160(KB3065820、2015年6月)のリリースで修正されました。 修正の構成は次のとおりです。JIT関数に暗黙的な呼び出しが含まれている場合、JITコンパイラは暗黙的な呼び出しの直前にテストプロシージャ呼び出しを挿入します。







動的関数の本文内のアドレスはすべて有効です。



以前の回避策は、暗黙的な呼び出しを行う関数の欠陥のために可能でした。 そして、このメソッドは、暗黙的に呼び出される関数の欠陥のために可能です。

Center of Vulnerability ResearchのYuri DrozdovとLyudmila Drozdovaの研究者は、 Defcon Russia Conference(St. Petersburg、2015)でこのCFGバイパス手法を発表しましたプレゼンテーション記事 )。 彼らの方法は、実行可能メモリを割り当てるときに、カーネルがすべての割り当てられたメモリのCFGビットマップに単一ビットを設定するという事実に基づいています。 この動作が何につながるかを見てみましょう。







アドレス0x69BC9080に特定のJIT関数があり、その本文に次のコードが含まれているとします。









この関数が正確に何をするのかは興味がありません;アドレス0x69BC90F0のFF D0



命令の2バイトに注意するだけです。 機能の開始がこの命令の途中に突然移動するとどうなりますか? ここに何があります:









FF D0



call eax



ことに他なりません! これは、一見無害な機能が攻撃者にとって優れた標的になった方法です。つまり、制御フローガードをチェックしない暗黙的な呼び出しです。 必要なバイトシーケンスを達成する方法と、必要なアドレスをレジスタに書き込む方法の2つだけの質問に対処する必要があります。







必要なシーケンスは、ActionScriptコードを試すだけで生成できます。 Nanojit( AVM JITコンパイラー)が生成されたコードを難読化するという事実を考慮するだけでよいため、簡単な方法はありません。 Nanojitがこの機能をどのように変えるかを見てみましょう。







 public static function useless_func():uint { return 0xD5EC; }
      
      





結果:









まったく期待していなかった。 経験的に、たとえば、このバージョンのコードにアクセスできます。







 public static function useless_func():void { useless_func2(0x11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26); } public static function useless_func2(arg1:uint, arg2:uint, arg3:uint, a, b, c, d, e, f, g, h, i, j, k, l, m, n, p, q, r, s, t, u, v, w, x, y, z):void { }
      
      





最初の関数の本体には、次の指示が含まれます。









興味のあるFF 11



バイトはcall [ecx]



命令です:











暗黙の呼び出しがありました。今、 ecx



制御されたアドレスを入力する必要があります。 useless_func()



関数がuseless_func()



れたときに、このレジスタに何が格納されているかを確認します。









関数が呼び出された時点で、 MethodEnv



クラスのオブジェクトはecx



レジスタにあります。 このクラスの最初のDWORDは 、仮想関数テーブル(C ++コンパイラーによって生成されたもの)へのポインターです。 このテーブルはuseless_func()



メソッドの呼び出し時には使用されないため、メソッドが呼び出される前に攻撃者がポインターを自分の権利に置き換えることを妨げるものは何もありません。

このアルゴリズムの実装は次のとおりです。







 var class_addr:uint = read_addr(UselessClass); var vtable:uint = read_dword(class_addr + 8); var methodenv:uint = read_dword(vtable + 0x54); // $+54 = useless_func var func_ptr:uint = read_dword(methodenv + 4); write_dword(methodenv + 4, func_ptr + offset_to_call_ecx); write_dword(methodenv, rop_gadget); // ecx <- pointer to rop gadgets UselessClass.useless_func(); // call [ecx]
      
      





したがって、アプリケーションの実行フローをインターセプトし、この場合はROPガジェットの実行に移動することができました。







このCFGの回避策は、バージョン18.0.0.194(KB3074219、2015年6月)で修正されています。 修正は、新しいフラグを使用することです

PAGE_TARGETS_INVALID/PAGE_TARGETS_NO_UPDATE



(0x40000000)は、新しいWinAPI関数SetProcessValidCallTargets



と組み合わせたVirtualAlloc



およびVirtualProtect



関数用です。

実行可能メモリを割り当てるときのPAGE_TARGETS_INVALID



フラグは、メモリロケーション全体にPAGE_TARGETS_NO_UPDATE



し、メモリタイプを実行可能に変更するときはPAGE_TARGETS_NO_UPDATE



フラグにより​​、ターゲットメモリロケーションのビットマップが変更されません。

この修正は、AVMカーネルソースコードAVMPI / MMgcPortWin.cpp )のAVMPI_makeCodeMemoryExecutable



関数で確認できます。











SetProcessValidCallTargets



関数の呼び出しSetProcessValidCallTargets



AVMPI_makeTargetValid



AVMPI / MMgcPortWin.cpp )で実装されていAVMPI_makeTargetValid













このことから、CFG条件下で動的に生成されたコードをメモリに配置するときのアクションの正しいシーケンスは次のようになると結論付けることができます。









そして、もちろん、動的コード内の暗黙的な呼び出しを忘れないでください。







WinAPIの回避策



制御フローガードの確認では、着信アドレスの検証が行われますが、ユーザー機能の開始だけが有効なアドレスではありません。 すべてのWinAPI関数は、インポートテーブルの他の関数と同様に、暗黙的な呼び出しの有効な宛先です。 攻撃者が実行スレッドを直接ライブラリ関数に変換し、シェルコードまたはROPガジェットをバイパスすることを妨げるものは何もありません。 これに適した候補は、WinAPI関数kernel32!WinExec



です。







Yuki Chen Qihoo 360 Vulcan Team SyScan (, 2015) , Internet Explorer 11 . BlackHat (, 2015) Francisco Falcón Adobe Flash Player.

Francisco Falcón toString()



Vector



, , .

, WinExec



. , , 2 : LPCSTR lpCmdLine



UINT uCmdShow



.









:









3 . . , 0 = SW_HIDE



( ). MethodEnv



.









, 4 , ActionScript- . 4 , WinExec



.

, 4 . , , cmd\0



( Windows). , , , .







:







 var class_addr:uint = read_addr(UselessClass); var vtable:uint = read_dword(class_addr + 8); var methodenv:uint = read_dword(vtable + 0x50); // $+50 = useless_func var winexec:uint = get_proc_addr("kernel32.dll", "WinExec"); write_dword(methodenv + 4, winexec); // useless_func() --> WinExec() write_dword(methodenv, 0x00646d63); // '\0', 'd', 'm', 'c' UselessClass.useless_func();
      
      





WinAPI Flash- . , , Flash Exploiter Metasploit.

, :











, , , .









Flash- (payload) HackingTeam. . WinAPI kernel32!VirtualProtect



, , , Control Flow Guard.

apply()



Function



( core/FunctionClass.cpp )









core->exec->apply(get_callEnv(), thisArg, (ArrayObject*)AvmCore::atomToScriptObject(argArray));



, , ActionScript.











, GitHub . 64- Flash Metasploit .







Control Flow Guard



CFG Adobe Flash Player. Flash, , Control Flow Guard Internet Explorer 11.









おわりに



, Control Flow Guard Windows. Microsoft , , Control Flow Integrity, , . , Microsoft .

, CFG.







. Intel, , , ROP- — CET (Control-flow Enforcement Technology) ( ). , CET Control Flow Guard.




Jack Tang, Trend Micro Threat Solution Team. Exploring Control Flow Guard in Windows 10.

mj0011, Qihoo 360 Vulcan Team. Windows 10 Control Flow Guard Internals.

Source code for the Actionscript virtual machine, GitHub.

Francisco Falcon, Core Security. Exploiting Adobe Flash Player in the era of Control Flow Guard.








All Articles