2024年9月18日

SHIM Me What You Got: Shimとコードインジェクション用Officeの操作

Deep InstinctのセキュリティリサーチャーであるRon Ben-YizhakとDavid Shandalovが、DEF CON 32で発表したリサーチについて解説します。それは2つの異なる攻撃方法の詳細な調査です。彼らが発表した方法について調べ、その仕組みを説明しながら追っていきましょう。

サイバーセキュリティの専門家にとって、好奇心というのは必要な性格の特性です。多くの人にとって、それは、これまで培ってきたセキュリティ側の知識を武器として活用することを意味します。そして攻撃手法と攻撃者の思考方法を理解することが、攻撃をうまく防御するための鍵となります。

サイバーセキュリティの専門家にとって、好奇心というのは必要な性格の特性です。多くの人にとって、それは、これまで培ってきたセキュリティ側の知識を武器として活用することを意味します。そして攻撃手法と攻撃者の思考方法を理解することが、攻撃をうまく防御するための鍵となります。

本ブログは、DEF CON 32での講演の補足となります。講演では、サイバーセキュリティベンダーが「とうの昔に対処済み」と考えていたアタックサーフェスが復活したことについて説明しました。私たちは、2つのユニークなアタックサーフェスの研究に焦点を当てました。

最初のリサーチは、Officeに関連するRPCサーバーを対象としたものでした。単一のRPCメソッドを分析したところ、コードのインジェクションと特権昇格の両方を実現するために複数の操作を組み合わせた注目すべき攻撃につながりました。

2つ目のリサーチは、App Compatibilityフレームワークとその文書化されていない構造のリバースエンジニアリングに焦点を当てたものでした。レジストリの変更やSDBファイルを必要としないプロセスに悪意のあるシムを適用し、ディスク上に痕跡を残さないという、新しいステルス性の高い手法を発見しました。

OfficeのRPCインターフェース 

Microsoft Officeは世界で最も普及しているソフトウェアのひとつです。 OSに関係なく、ほぼすべてのWindowsマシンにインストールされています。 その動作に必要な多くのコンポーネントで構成された複雑なツールです。Microsoft Officeには、COMオブジェクト、スクリプトエンジン、クラウド同期機能、および多くの機能に対する下位互換性があり、これらはすべて、攻撃対象領域の研究には最適な候補となります。

私たちは、Officeがインストールされたマシン上で稼働しているRPCサーバーを探すことから調査を始めました。私たちは、サービスClickToRunSvcをホストするプロセスOfficeClickToRun.exeを発見しました。OfficeClickToRun.exeは、以下のRPCファイルで実装されている複数のインターフェースを公開しています: 

  • OfficeClickToRun.exe 

  • AppVIsvVirtualization.dll 

  • AppVIsvSubsystemController.dll 

ClickToRunSvcのRPCインターフェースがRPC Investigatorで表示

AppVIsvVirtualization.dll 内の文字列が目に留まりました。「サブシステムDLLを子プロセス(プロセスID %3%、モジュール %2%)に注入できませんでした。エラーコード %1%」これは、DLLが公開するRPCメソッドの1つによって表示されるデバッグ文字列です。

AppVIsvVirtualization.dll内の文字列で、コードインジェクションを示している

この方法でDLLインジェクションが実行されることを確認するため、サービスをデバッグし、コードインジェクション用のWinAPIにブレークポイントを設定しました。Officeプログラムの起動中に、このRPCメソッドがWriteProcessMemoryにつながっていることが分かりました。これは有用そうに見えたので、このDLLについてさらに詳しく調べることにしました。 

AppVIsvVirtualization.dll 

AppVIsvVirtualization.dllの説明は「Microsoft Application Virtualization Client Virtualization Manager Component」となっています。実際には、これは2つの文書化されていないメソッドを公開するRPCサーバーです。2番目のメソッドがDLLインジェクションを実行します。PowerShellを使用してRPCクライアントを探したところ、AppvIsvSubsystems64.dllというファイルに行き当たりました。クライアントの公開シンボルから、RPCコールを実行する関数の名前が判明しました。

    a. virtman_notification_server_notify_new_process 

    b. virtman_notification_server_notify_new_child_process 

PowerShell を使用した RPC クライアントの検索
インジェクションプロセス

インジェクションプロセスを理解するために、まず初めにクライアントがサーバーに送信するものを確認しました。ソフトウェアのデバッグ中に、Word によって、RPC メソッドが呼び出される前に子プロセスが作成されることが示されました。プログラム ai.exe が一時停止状態で起動します。その後、2つのパラメータとともにサーバーにリクエストが送信されます。1つ目は ai.exe の PID です。2つ目は、文字列「AppvIsvSubsystems64.dll」と、その長さ(つまり、その文字列に含まれる文字数)を含む構造体です。

次に、リバースエンジニアリングを開始する前に、サーバーとアプリケーション仮想化プラットフォームに関連するファイルを調べました。system32ディレクトリで見られるような名前のファイルがあることが分かりました。

system32内のアプリケーション仮想化ファイル

これらのファイルには、Detoursライブラリが使用されていることを示すシンボルが含まれています。「Detours」は、Windows上のAPIコールの監視およびインストルメント化のためにMicrosoftが開発したオープンソースライブラリです。また、他のプロセスにコードを注入する機能も提供しています。AppVIsvSubsystemController.dll は、DetourUpdateProcessWithDll およびDetourCopyPayloadToProcessの関数を呼び出すことで、この機能を使用しています。これは、BinDiffでOfficeファイルとsystem32ファイルを比較すると確認できます。

BinDiff による Office ファイルと system32 ファイルの比較

Detours のソースコードは、DLL インジェクションがどのように実行されるかを明らかにしています。オプションのヘッダーは、インジェクションされた DLL への追加のインポート記述子を含むインポートテーブルの新しいコピーを指すように変更されます。WinDbg を使用してインジェクションされたプロセスのヘッダーを表示すると、インジェクションされた DLL へのフルパスが表示されます。

WinDBGで表示された注入されたプロセスのヘッダー

中断されたプロセスが再開されます。プロセスはまだ完全に初期化されていないため、OSのローダーは変更されたインポートテーブルを使用し、AppvIsvSubsystems64.dll がプロセスに注入されます。 OfficeClickToRun.exe が 32 ビットプロセスに DLL を注入するコマンドを受信すると、同じ注入を実行する mavinject32.exe を起動します。

ClickToRunSvcの悪用

人気のソフトウェアは、誤検知を避けるために、セキュリティ製品の振る舞い分析の対象から除外されることがよくあります。このことを知った上で、OfficeClickToRun.exe に DLL の注入を強制すると、検出を回避できる可能性があります。

virtman_notification_server_notify_new_child_process によって実行される呼び出しを模倣し、一時停止中のプロセスに AppvIsvSubsystems64.dll を注入することは可能でしたが、別の DLL を注入するにはどうすればよいのでしょうか? この関数が文字列を受け取ることは分かっているので、注入するDLLの名前を変更することはできますが、DLLファイルをOfficeディレクトリに書き込むには管理者権限が必要であり、非常に疑わしい行為です。

文字列をAppvIsvSubsystems64.dllからC:\Temp\Injected.dll に変更すると、C:\Program Files\CommonFiles\microsoftshared\ClickToRun \C:\Temp\Injected.dll をロードしようと試みます。

文字列が何のチェックも行われずに単にディレクトリに追加されているように見えるので、古いテクニックであるディレクトリトラバーサルを使用することができます。ドット・ドット・スラッシュ(..\)の連続は、ファイル検索が親ディレクトリを参照するようにします。ドット・ドット・スラッシュの連続を複数回使用すると、ファイル検索がまったく異なるディレクトリを参照するように操作することができます。次のインポート記述子は、最終的にファイル C:\temp\Injected.dllをロードします。

注入方法を操作した後のプロセスのヘッダー

この時点で、私たちはすでに、良性のアプリケーションを使用してDLL注入を実行する新たなテクニックを発見しています。それだけでも立派な成果ですが、私たちはさらに多くのことを知りたいと思いました。

注入は、NT AUTHORITY\SYSTEMとして実行されるプロセスによって実行されます。クライアントは低い権限で実行されますが、このサービスを特権昇格のために悪用できるでしょうか?

ClickToRunSvcのセキュリティメカニズム

ClickToRunSvcは、インジェクションを行う前に、リモートプロセスへのアクセスが許可されていることを確認するために、RPCクライアントを偽装します。つまり、中程度の整合性レベルで実行されているRPCクライアントは、高整合性レベルのプロセスにDLLをインジェクションすることはできません。RPCリクエストを処理するスレッドはクライアントと同じトークンを使用し、ターゲットプロセスへのハンドルを取得しようとすると、OpenProcessへの呼び出しはエラーコードERROR_ACCESS_DENIEDで失敗します。

クライアントの権限でClickToRunSvcセキュリティチェックを実行

結論として、非管理者特権から管理者特権への昇格は不可能でした。しかし、ここで別の疑問が生じます。管理者特権から NT AUTHORITY\SYSTEM 特権への昇格は可能なのでしょうか?

システム権限で中断されたプロセスを起動する

API モニタリングを使用して、NT AUTHORITY システムとして実行され、CREATE_SUSPENEDフラグとともに CreateProcessを呼び出すプロセスを探したところ、タスクスケジューラサービスにたどり着きました。

このサービスは悪用される可能性が非常に高いものです。多くのスケジュールされたタスクがSYSTEMとして起動され、その中にはOfficeに属するものも含まれています。ClickToRunSvcが別のOfficeプロセスにDLLを注入することは、Wordが起動されるたびにai.exeにDLLが注入されるため、アラームが鳴る可能性はさらに低くなります。私たちが選んだタスクは「Office Automatic Updates 2.0」です。

Officeによって作成され、「NT AUTHORITY SYSTEM」として実行するように構成されたスケジュールされたタスク

問題は、タスクスケジューラサービスが起動後まもなくプロセスを再開してしまうことです。IATを変更できるように、プロセスを再開する前にタスクスケジューラサービスの実行を保留する方法を見つける必要があります。そのために、便宜的ロックを使用することができます。

便宜的ロック 

便宜的ロック(OpLock)は、ネットワークファイルシステムでファイルアクセスを最適化し、パフォーマンスを向上させるために使用されるメカニズムです。クライアントアプリケーションがファイルにアクセスすると、サーバーはクライアントに便宜的ロックを付与します。このロックにより、クライアントは他のクライアントからの干渉を受けずにファイルの操作を実行できます。クライアントが便宜的ロックを保持している間、そのクライアントはデータをローカルにキャッシュします。別のクライアントが同じファイルにアクセスしようとした場合、サーバーは最初のクライアントが保持している便宜的ロックを解除することができます。これにより、データの整合性が確保され、クライアント間の競合が防止されます。ロックが解除されると、サーバーは通常、最初のクライアントに通知し、キャッシュされたデータをすべて消去し、必要に応じてロックを再設定します。

アプリケーションは、他のアプリケーションやプロセスによるファイルの破損を防ぐために、ローカルファイルにアクセスする際にOpLockを要求することもできます。アプリケーションは、ローカルファイルシステムからOpLockを要求し、その後、ファイルをローカルにキャッシュすることができます。このような場合、ローカルサーバーはセマフォのようなOpLockを使用し、その主な目的はデータの不整合を防ぎ、プロセスにファイルアクセスを通知することです。

プロセスが作成された後、再開される前にタスクスケジューラサービスによってアクセスされたファイルが見つかり、ローダーがIATを解析する場合には、このファイルに対してOpLockを要求し、インジェクションが完了するまでプロセスの再開を停止することができます。 スケジュールされたタスクの実行中のファイルアクセスを監視したところ、ファイルC:\Windows\apppatch\sysmain.sdb が読み込まれていることが分かりました。 このファイルは、シムデータベースです。アプリケーションの互換性設定を保存しています。

API CreateProcess がシムデータベースを開いていることを示すコールスタック

アプリケーション互換性 

アプリケーション互換性フレームワークは、Microsoft によって提供されるツール、ライブラリ、および技術のセットであり、古いバージョンの Windows アプリケーションが新しいバージョンの Windows オペレーティングシステム上でもスムーズに動作することを保証します。 このフレームワークには、さまざまな互換モード、シム、およびその他のメカニズムが含まれています。

Windows App Compatibility フレームワークの目的は、古いソフトウェアとの互換性を維持することで、Windows の新しいバージョンにアップグレードする際のユーザーや企業への影響を最小限に抑えることです。このフレームワークは、API、セキュリティ機能、システム構成の変更など、既存のアプリケーションの動作に影響を与える可能性があるオペレーティングシステムの変更に関連する問題の解決に役立ちます。

このフレームワークは、解像度の変更やファイルのリダイレクトなどの単一の修正、およびまとめて適用される修正のセットとして機能するモード(レイヤーとも呼ばれる)を提供します。

ファイルのプロパティから利用可能なアプリケーション互換性の修正

このフレームワークでは、互換性修正を保存するために.sdbファイル、または“Shim Database”ファイルも使用します。 .sdbファイルは、Windows Assessment and Deployment Kit (ADK) の一部である互換性管理ツールによって管理されます。 管理者は、このツールを使用して、組織内のアプリケーション全体で互換性の問題に対処するために、.sdbファイルに保存された互換性修正を作成、変更、および展開することができます。

私たちの目標は、アプリケーション互換性設定ファイルを実行するスケジュールされたタスクを見つけることです。そのために、すべてのタスクを実行し、どのタスクがサービスによる sdb ファイルの読み取りを引き起こすかを調べました。見つかったタスクは、Microsoft Edge の更新に関連するものだけでした。それらはC:\Program Files (x86)\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe を実行し、Microsoftの互換性管理ソフトウェアを使用して互換性設定を行っていることが確認できました。 “Update”という文字列を含むすべてのプロセスは、“GenericInstaller“の修正を受け取ります。

“update”という語を含むファイルに関するシムデータベースのエントリ

これは、32ビットプロセスにDLLを注入するのに適したターゲットとなり得えますが、64ビットのターゲットも見つけなければなりません。

この件について調査している際に、奇妙な挙動に気づきました。 マシンが起動して以来、実行可能ファイルが最初に実行された際に、たとえアプリケーションの互換性設定が一致していなくても、sdbファイルが読み込まれていました。 その後、それ以降の実行では、sdbファイルは読み込まれませんでした。 そこで私たちは、実行可能ファイルが実行されるたびに、sdbファイルが確実に読み込まれる方法を見つけたいと考えました。そしてファイルの互換性を設定することで、合法的にそれを実現することができました。

  1. ツールsdbinstは、以下のレジストリ値を設定することで、カスタムsdbファイルをシステムにインストール:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVe:rsion\AppCompatFlags\CustomHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\InstalledSDB

  2. ファイルのプロパティの互換性ウィンドウ 

SDBファイルは既知の攻撃ベクトルであり、コードインジェクションやAPIフックに悪用される可能性があります。つまり、エンドポイント検出・対応(EDR)ツールは、たとえ悪意のないものであっても、新しいアプリの互換性構成を検出する可能性があるということです。また、これが、組織を保護するには EDRだけでは不十分 である理由でもあります。レジストリの変更は避け、ディスクに触れることなくこの構成を作成したいと考えています。

アプリケーションの互換性に関連するファイルを探したところ、apphelp.dllに行き着き、その主なAPIはNtApphelpCacheControlであることが分かりました。

NtApphelpCacheControl 

これはntdllによってエクスポートされる、文書化されていないAPIです。このAPIは、整数と不明な構造体へのポインタという2つのパラメータを受け取ります。GitHubでこのAPIの使用例を探したところ、Windows SDKの以前のバージョンに含まれていたahcache.hファイルに行き当たりました。このヘッダーファイルには、関数のパラメータに関する詳細な情報が記載されています。

さらに、他のOSコンポーネントによるAPIの使用例も調べました。このAPIは、kernel32.dllsxssrv.dllapphelp.dllなど、複数のDLLファイルで使用されています。

DLLファイル内のWinAPI呼び出しに定義を適用したところ、矛盾が見つかりました。構造体に割り当てられたメモリのサイズが定義よりも大きかったのです。いくつかの関数では、最初のパラメータの値がEnumの可能な値よりも高くなっていました。これは、ahcache.hを含むSDKが公開されてから、これらの定義が変更されたことを意味します。

NtApphelpCacheControl が不明なパラメータとともに呼び出される

私たちは引き続きNtApphelpCacheControl の使用法を調べ、combase.dllのシンボルにAPIに関する情報が含まれていることを発見しました。シンボルの関連定義を抽出すると、ahcache.hの更新版が作成されました。これにより、APIで実行できるさまざまな操作が示されます。

NtApphelpCacheControlの最初のパラメータの定義を更新

これらの定義を理解すると、他のDLLファイルのAPIへの呼び出しがより明確になります。CreateProcessは、パラメータApphelpCacheServiceLookupProcess:とともに、このAPIを裏で呼び出します:

APIのCreateProcessがキャッシュ内の値をどのように検索するかを示したコールスタック

オペレーティングシステムがシャットダウンすると、キャッシュはレジストリにフラッシュされ、起動時に読み込まれてアクティブなキャッシュデータベースとして「ロード」されます。プロセスが初めて起動された際にキャッシュがクリアされている場合、そのプロセスに関する情報は何もありません。そのため、sdbファイルが読み込まれ、ファイルにアプリケーション互換性の修正があるかどうかを指定するエントリがキャッシュに追加されます。これが、プロセスが2回目に起動された際にsdbファイルが読み込まれない理由です。

このキャッシュのエントリを削除すると、sdbファイルが再び読み込まれます。

NtApphelpCacheControlへの相互参照を確認したところ、kernel32.dllapphelp.dllの両方が「削除」操作を実行することが分かりました。また、これらのファイルには、ファイル名とファイルハンドルのみを受け付けることで構造体の作成を簡素化するエクスポート関数も用意されています。

kernel32.dllの機能で、シムキャッシュから値を削除

“remove”パラメータとともにNtApphelpCacheControlを呼び出すと、ファイルの実行により再びsdbファイルの読み込みが開始されます。このプロセスを中断したままにしておくために、このファイルをロックすることができます。その後、DLLを注入することができます。

攻撃 #1 ワークフロー 
  1. 注入するDLLをディスクに書き込む
  2. 任意のスケジュールされたタスクが実行するファイルのパスを見つける(例えば「Office Automatic Updates 2.0」)
  3. kernel32.dllから BaseUpdateAppcompatCacheWorkerを呼び出すことで、このファイルのシムキャッシュを削除
  4. C:\windows\apppatch\sysmain.sdb に対して oplock を要求
  5. 「Office Automatic Updates 2.0」を実行するようスケジュールされたタスクサービスにメッセージを送信
  6. このプロセスにより、SYSTEMが一時停止状態に作成
  7. スケジュールされたタスクサービスがC:\windows\apppatch\sysmain.sdb を読み取ろうとし、その後待機状態に入り、プロセスを再開しない
  8. oplockからのコールバックが呼び出される
  9. OfficeClickToRunサービスにRPCを送信し、一時停止中のプロセスにDLLを注入
  10. oplockを解除すると、スケジュールされたタスクサービスがプロセスを再開
  11. 修正されたIATが使用され、DLLがSYSTEMプロセスにロード

最初の攻撃の紹介

攻撃 #1 の概要

この攻撃には以下の利点があります: 

  1. EDRソリューションでは監視されていない技術を使って実行することで、良性で既知のプロセスが代わりにインジェクションを実行します。そのため、アラームが鳴る可能性は低いでしょう
  2. 良性のプロセスにDLLをインジェクションしますが、そのプロセスは我々とは無関係なものです。タスクスケジューラの子プロセスとして生成されます
  3. NT AUTHORITY」SYSTEM.」としてコード実行を実現します
  4. その後、NtApphelpCacheControlの呼び出しやOpLockの要求など、その他の動作を実行しますが、これらの動作はセキュリティ製品によってほとんど監視されていません

この攻撃はコードの注入と特権昇格の両方を実現します。また、脆弱性を探すプロセスも示しています。悪用可能なRPCメソッドを見つけましたが、それだけでは重要な攻撃を実行するには不十分でした。障害にぶつかった際には、それを克服するためにOSの別のコンポーネントを調べました。すべての操作を連鎖させることによってのみ、最初のRPCコールから何かを得ることができます。

Apphelpキャッシュの調査 

私たちは、NtApphelpCacheControlを呼び出した際に何が起こるのか、またそれによって何ができるのかについて、より深い理解を得たいと考えました。

この API への呼び出しがカーネルに到達すると、ntoskrnl.exeはデバイス IO 要求を「Device」>「ahcache」に送信します。これは、ahcache.sysによって制御されています。

NtApphelpCacheControlのコールスタックの表示

ahcache.sysがロードされると、以下のレジストリ値が読み込まれます。\Registry\MACHINE\System\CurrentControlSet\Control\Session Manager\AppCompatCache : a. AppCompatCache b. CacheMainSdb c. SdbTime 

キャッシュ操作に使用されるレジストリ値

これらの値には、ドライバがAVLテーブルにソートするバイナリデータが含まれています。

ドライバエントリからAVLテーブルの初期化まで

NtApphelpCacheControlによって実行されるさまざまな操作により、テーブル内のエントリの検索、挿入、または削除が行われます。

シム処理されるべき値の AVL テーブル内の各エントリには、EXE TAG が含まれています。

すべてのエントリには、エントリのサイズ、データのサイズ、データバッファ、および NtImagePath が含まれています。

シャットダウン/再起動時に、メモリ内のテーブルのデータがレジストリ値にダンプされます。 

AVLテーブルの中身を見る

例えば、VRCHAT.exeのエントリを取り上げて、9CCC20を取得してみましょう。リトルエンディアン形式から変換すると、0x20cc9cが得られます。sdb-explorerを使用すると、変換した値をsysmain.sdbの読み取り可能なバージョンで検索することができます。 

sdb-explorerによるsysmain.sdbエントリーの読み取り可能なバージョン

実際のsysmain.sdbファイルの0x20cc9cアドレスの中身を見ると、上記のTAGを含むエントリーを確認できます。

sysmain.sdb内のエントリーの生々しい内容

AVLテーブルのエントリからsysmain.sdbまで

\Device\ahcacheのディスパッチルーチンを見ていると、ApphelpCacheServiceInitProcessDataのリクエストを処理する関数がAVLテーブルにアクセスしていないことに気づきました。代わりに、別のプロセスのメモリに書き込みを行っているのです!

他のプロセスのメモリに書き込む

プロセスデータの初期化 

NtApphelpCacheControlをパラメータ ApphelpCacheServiceInitProcessDataと共に呼び出す場合、入力が必要な構造体は以下の通りです:

ApphelpCacheServiceInitProcessDataの文書化されていない構造

ReactOSのリバースエンジニアリングと古い定義に基づくと、文書化されていないデータフィールドは次のようになります:

文書化されていないシムデータ構造

この要求を処理するahcache.sys内の関数は、AhcApiInitProcessDataです。別のプロセスのメモリに書き込む前に、いくつかのチェックが行われます:

a. ProcessHandleがNULLではない

b. DataSizeが0x11C0以上である

c. Data.Magicが0xAC0DEDABである

d. Data.Sizeが0x11C0である

e. 呼び出し元のプロセスが NT AUTHORITY\SYSTEM として実行されており、SeTcbPrivilege 権限を持っている

f. 対象プロセスで PsGetProcessProtection を呼び出すと 0x81 が返される(以下で説明)

g. 対象プロセスの PEB がチェックされる。BitField にフラグ IsPackagedProcess (0x10) がオンになっている必要がある。 PsGetProcessProtection が呼び出されると、呼び出しは失敗する。この関数は、EPROCESS構造体のフィールド「Protection」を返します。このフィールドはユーザーモードから取得でき、ZwQueryInformationProcessで文書化されている。値0x81は、PS_PROTECTION.TypePsProtectedTypeProtectedLight(0x1)であり、PS_PROTECTION.SignerPsProtectedSignerApp(0x8)であることを意味する

EPROCESS構造体からのPsProtectedTypeProtectedLight

EPROCESS構造体からのPsProtectedSignerApp

Windows 11のすべてのプロセスを調べた結果、この種の保護機能を持つWindowsアプリは存在しないという結論に達しました。

つまり、ターゲットがないということです。

この呼び出しではコードのインジェクションは発生しないと結論付けましたが、この種の要求を調査し、悪用する方法を見つけるのはコミュニティに委ねます。

それでも、この文書化されていない構造は私たちの興味をそそり、それが何を意味するのかを理解したいと思いました。そこで、システム上のすべてのDLLファイルでマジック値を探し、kernel32.dllとapphelp.dllのいくつかの関数がそれを参照していることが分かりました。SdbUnpackAppCompatDataSdbPackAppCompatDataSdbGetAppCompatDataSizeBaseReadAppCompatDataForProcessWorkerBasepGetAppCompatData、そしてSbpGetShimDataです。

マジック値の検索結果

互換性の修正 初期化

このマジック値を参照する関数のリバースエンジニアリングにより、この構造体がプロセスに適用する必要のあるシム修正を表していることが判明しました。新しいプロセスが作成されると、kernelbase!CreateProcessInternalWの一部として以下の手順が実行されます。

a. 親プロセスがapphelpキャッシュを照会し、子プロセスにシム修正が必要かどうかを確認

b. 親プロセスはsysmain.sdbを読み取り、修正に関する完全な情報を取得

c. 親プロセスは、これらの特定の修正に従って構造体を構築し、子プロセスのメモリに書き込む

d. 親プロセスは、PEB->pShimDataの値を修正し、構造体を指す

PEB構造体からpShimDataを調べる

e. ntdll pShimData が空でない場合、apphelp.dll をロード

f. apphelp.dllは構造体に従ってシム修正を適用

新しいプロセスが作成された際の概要

SHIM_DATAの作成 

シムキャッシュが照会された後、親プロセスはCreateProcessの呼び出しの一部としてSHIM_DATA構造体を構築します。

   

親プロセス内の Shim Data ビルドフロー

pShimData インジェクション 

目的を達成するには、PEB->pShimDataに書き込まれる非公開構造体のフィールドを理解する必要があります。

「互換性管理者」ツールを使用して、システム上のさまざまなシム用のカスタムルールをインストールしました。 

「Compatibility Administrator」ツール内のInjectDll Fix

カスタムルールがプロセスに適用されると、SHIM_DATAの生データがプロセスのメモリからダンプされました。この生データは、プロセスにシムが適用された他のインスタンスと比較することでファジングされました。異なるファイル名に対して特定のルールが作成され、フィールドの値の差異を比較することで構造が分析されました。

カスタムルールに加え、sysmain.sdbの既存のルールもテストされました。ファイル名、バージョン、会社名など、ルールの仕様を満たすプロセスが作成されました。カスタムルールを記述する構造とデフォルトルールを記述する構造を比較することで、追加のフィールドが明らかになりました。

この方法により、カスタムおよび標準のsysmain.sdbエントリ内のパターンを識別し、ダンプ内の特定のアドレスにおける完全一致、類似性、完全な相違を強調表示することができます。

最後に、類似したアドレスを統合し、どのフィールドが重要でないかを決定するための排除プロセスを開始し、当社の用途に合わせた構造の合理化を図ります。

sysmain.sdbのエントリー

Custom sdbエントリー

これはリバースエンジニアリング後の構造の定義です:

今回公開したリバースエンジニアリングされたSHIM_DATA構造

カスタムのSDBファイルを登録することは、セキュリティ製品に検出される可能性があるため避けたいので、Fix ”Inject DLL”を適用するsysmain.sdb内の既存のエントリを見つける必要があります。この作業には、sdb-explorerというツールが役立ちます。

攻撃対象のsysmain.sdbエントリ

このエントリによると、プロセス名がGLJで始まり、テンポラリ拡張子で終わる場合、正しい会社名と製品名を持つ場合に、RTvideo.dllが注入されることになります。幸いにも、これらのチェックは親プロセスによって実行されます。SHIM_DATA->ExeTagがこのエントリを指すと、apphelp.dllは条件をチェックせずに修正を適用します。

制限事項 

a. 注入されたプロセスは中断状態で起動されなければなりません。すでに実行中のプロセスに注入することはできません。LoadLibraryにつながるコールスタックは、エクスポートされた関数であるapphelp!SE_InstallAfterInitを通過します。実行中のプロセスに対して攻撃を実行しようと試みたところ、カスタムの SHIM_DATA を書き込んでから、そのプロセス上でリモートスレッドを起動し、再び apphelp!SE_InstallAfterInitを実行しました。この試みは失敗しました。なぜなら、apphelp!SE_InstallAfterInitはグローバル変数をチェックし、プロセスがすでに初期化されている場合、チェックは失敗し、シムデータは処理されないからです。

b. 注入されたプロセスはシステムファイルであることはできません。AcGenral!NS_InjectDll::NotifyFnはDLLを注入する前にAcGenral!ShimLib::IsSystemExeFromSelfを呼び出します。ファイルが C:\Windows\WinSXS 以下にある場合、または「信頼されたインストーラ」に属する場合は、注入はスキップされます。

c. このシム修正は64ビットプロセスでは利用できません。Microsoftがこの機能を隠していないことを確認するには(実際には不可能ですが)、AcGenral.dllの64ビットバージョンのコードを確認します。このコードには、NS_InjectDllというクラスがありません。

これらの制限事項を念頭に置き、適切な実行可能ファイルを探し始めました。

そして、前述の「友人」であるC:\Program Files (x86)\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe が、3つの制限すべてを満たしているため、このファイルが標的となります。

攻撃 #2 フロー   

現時点では、App Compatibility メカニズムを悪用するのに十分な知識が得られています。以下の手順を実行することで、DLL を注入することができます。

a. RTvideo.dllという名前の DLL をディスクに書き込む

b. サスペンドされたプロセスを起動し、カレントディレクトリをRTvideo.dllと同じものに設定

c. SHIM_DATA構造体を構築し、ExeTagを0x4ed54に設定す

d. 構造体を子プロセスのメモリに書き込む

e. PEB->pShimDataを構造体に設定

f. 子プロセスを再開

g. apphelp.dll が InjectDll の修正を適用し、我々の DLL がロードされる

2回目の攻撃の例示

攻撃 #2 の概要 

悪意のあるシムは、多くのセキュリティ製品によって検出される既知の攻撃ベクトルです。このインフラストラクチャをリバースエンジニアリングすることで、私たちはそれを改良することができました。この攻撃をファイルレスおよびレジストリレスにする新しい方法を見つけました。私たちは、システム上にSDBファイルを登録することなく、プロセスに悪意のあるシムを適用しました。EDR 検出を回避するために、子プロセスに書き込み、EDR フックが確立される前に中断された子プロセスからターゲットの DLL をロードしました。 「InjectDll」シムを選択しましたが、この攻撃は他の悪意のあるシム修正にも適用できます。

検出 
  1. 最初の攻撃:
  2. 2番目の攻撃:
さらなる調査 - アプリケーションの互換性 
  1. AhcApilnitProcessDataのターゲットを見つける
  2. SHIM_DATAをリバースエンジニアリングして、apphelp.dllを操作する他の方法を見つける
  3. キャッシュを汚染して、別のプロセスに悪意のあるSHIMを適用 
結論

私たちは、2つの異なるOSコンポーネントを悪用することで実現可能な、新しいステルスインジェクションおよび特権昇格技術につながる攻撃面調査の方法論を提示しました。サービス、オプロック、互換性メカニズムを含むさまざまなシステムコンポーネントを活用し、悪用することで、これらの要素を単一のまとまった攻撃戦略に統合する方法を示しました。オプロックと互換性メカニズムは、他の複数のコンポーネントから成る高度で複雑な攻撃の不可欠な要素となり得ます。オプロックは多くのシナリオでビルディングブロックとして使用でき、64ビットプロセスでも悪意を持って使用できるシムフィックスはさらに多く存在します。私たちの広範な調査により、ステルスインジェクションと特権昇格のための新たなテクニックが発見され、これらの攻撃の有効性が向上しました。私たちは、EDRで監視されない2つの攻撃を実証しました。インジェクションは、EDRがフックを確立できない非常に初期の段階で発生します。未文書化のAPIおよび関連構造のリバースエンジニアリングを通じて、これらの手法の開発に役立つ貴重な洞察を得ることができました。さらに、以前から知られていた悪意のある手法を改良し、より見つけにくく、ファイルレスでレジストリレスの攻撃に変えました。私たちは、コミュニティ全体が私たちの研究を基にしてさらなる発展を遂げるよう、研究が継続されることを望みます。一方で、侵害の検出と対応にEDRのみに頼っている場合は、EDRだけでは不十分な理由について詳しく知り、デモをリクエストして、Deep Instinctがサイバーセキュリティ専用に構築された唯一のディープラーニングAIプラットフォームを活用して、他のツールでは検出できない脅威をどのようにして防ぐのかを確認してください。

Githubリポジトリ