
Freezeは、サスペンドプロセス、ダイレクトシステムコール、および代替実行方法を使用してEDRをバイパスするためのペイロードツールキットです。
Freezeの最新バージョンを確認したり、問題を報告するには、https://github.com/Tylous/Freeze を参照してください。
このフレームワークで使用されている手法について詳しく知りたい場合は、SourceZeroブログをご覧ください。
Freezeは、EDRセキュリティ制御を回避してシェルコードをステルスに実行するためのペイロード作成ツールです。Freezeは、ユーザーランドのEDRフックを除去するだけでなく、他のエンドポイント監視制御を回避する方法でシェルコードを実行するために、複数の手法を利用しています。
プロセスが作成されると、最初にロードされるDLLはNtdll.dllです。これは、EDR DLLがロードされる前に発生します。つまり、EDRがロードされ、システムDLLのアセンブリのフックや変更を開始するまでに少し遅延があります。Ntdll.dll内のWindowsシステムコールを見ると、まだ何もフックされていないことがわかります。プロセスをサスペンド状態(時間的に凍結された状態)で作成すると、Ntdll.dll以外のDLLはロードされていないことがわかります。また、EDR DLLがロードされていないことから、Ntdll.dllにあるシステムコールが変更されていないこともわかります。
このクリーンなサスペンドプロセスを使用してFreezeローダーからフックを除去するには、プログラムでクリーンなサスペンドプロセスのメモリを見つけて読み取る方法が必要です。ここでアドレス空間配置のランダム化(ASLR)が活躍します。ASLRは、スタックメモリの破壊に基づく脆弱性を防ぐセキュリティメカニズムです。ASLRはプロセス内のアドレス空間をランダム化し、メモリマップされたオブジェクト、スタック、ヒープ、実行可能プログラム自体が一意になるようにします。ここからが興味深いところです。ASLRは機能しますが、DLLのような位置独立コードに対しては機能しません。DLL(特に既知のシステムDLL)では、アドレス空間はブート時に一度だけランダム化されます。つまり、ntdll.dllのベースアドレスを見つけるためにリモートプロセスの情報を列挙する必要はありません。なぜなら、それは自分たちが制御するプロセスを含むすべてのプロセスで同じだからです。すべてのDLLのアドレスはブートごとに同じ場所であるため、この情報を自分自身のプロセスから取得でき、サスペンドプロセスを列挙してアドレスを見つける必要はありません。
この情報を使用して、API ReadProcessMemoryを使ってプロセスのメモリを読み取ることができます。このAPI呼び出しは、資格情報ベースの攻撃の一環としてLSASSを読み取ることと一般的に関連付けられていますが、それ自体は本質的に悪意があるわけではありません。特にメモリの任意のセクションを読み取るだけならなおさらです。ReadProcessMemoryが怪しいものとしてフラグされるのは、読み取るべきでないもの(LSASSの内容など)を読み取る場合だけです。EDR製品はReadProcessMemoryが呼び出されたという事実だけをフラグすることは決してないはずです。なぜなら、この関数には正当な運用上の使用例があり、多くの誤検出を引き起こすからです。
さらに一歩進んで、Ntdll.dllのすべてのシステムコールが保存されているセクション(その.textセクション)のみを読み取ることで、DLL全体を読み取る必要はありません。
これらの要素を組み合わせることで、シェルコードを実行する前に、既存のフックされた.textセクションを上書きするために、Ntdll.dllの.textセクションのコピーをプログラムで取得できます。
ETWは組み込みのシステムコールを利用してこのテレメトリを生成します。ETWもWindowsに組み込まれたネイティブ機能であるため、セキュリティ製品は情報にアクセスするためにETWシステムコールを「フック」する必要はありません。その結果、ETWを防ぐために、Freezeは複数のETWシステムコールにパッチを当て、レジスタをフラッシュして実行フローを次の命令に戻します。ETWパッチングは現在すべてのローダーでデフォルトになっています。
Ntdll.dllのみが復元されるため、シェルコードを実行するための後続の呼び出しはすべてNtdll.dll内に存在する必要があります。Goを使用すると(他の言語でもできますが、Goでは実装が非常に簡単です)、シェルコードの割り当て、書き込み、保護に必要なNTシステムコールを定義して呼び出すことができ、kernel32.dllやKernelbase.dllにある標準的な呼び出しを効果的にスキップできます。これらのDLLはまだフックされている可能性があるためです。
FreezeはGolangで開発されました。
Freezeをインストールするには、以下のコマンドを実行するか、コンパイル済みバイナリを使用してください:
go build Freeze.go
___________
\_ _____/______ ____ ____ ________ ____
| __) \_ __ \_/ __ \_/ __ \\___ // __ \
| \ | | \/\ ___/\ ___/ / /\ ___/
\___ / |__| \___ >\___ >_____ \\___ >
\/ \/ \/ \/ \/
(@Tyl0us)
やがて彼らは、復讐とは…冷やして食べるのが一番の料理だと知るだろう…
Usage of ./Freeze:
-I string
生の64ビットシェルコードへのパス。
-O string
出力ファイルの名前(例: loader.exe または loader.dll)。定義されたファイル拡張子に応じて、Freezeがdllまたはexeを作成するかが決まります。
-console
バイナリペイロードのみ - ペイロード実行時に詳細なコンソール情報を生成します。これにより、非表示ウィンドウ機能が無効になります。
-encrypt
AES 256暗号化を使用してシェルコードを暗号化します。
-export string
DLLローダーのみ - ローダーが持つ特定のエクスポート関数を指定します。
-process string
生成するプロセスの名前。このプロセスはC:\Windows\System32\に存在する必要があります。例: 'notepad.exe' (デフォルト "notepad.exe")
-sandbox
サンドボックス回避を有効にします。以下をチェックします:
エンドポイントがドメインに参加しているか?
エンドポイントが2つ以上のCPUを持っているか?
エンドポイントが4GB以上のRAMを持っているか?
-sha256
ローダーのSHA256値を提供します(追跡に便利です)
Freezeは.exeまたは.dllファイルのいずれかを生成できます。これを指定するには、-Oコマンドラインオプションの末尾がバイナリの場合は.exe、DLLの場合は.dllで終わるようにしてください。他のファイルタイプは現在サポートされていません。DLLファイルの場合、Freezeは追加のエクスポート機能を追加することもできます。これを行うには、-exportオプションを使用して特定のエクスポート関数名を指定します。
Freezeは、まずプロセスを作成してからバックグラウンドに移動する手法を利用しています。これにより、2つのことが行われます。第一に、プロセスを隠し続けるのに役立ち、第二に、EDR製品による検出を回避します。すぐにバックグラウンドでプロセスを生成することは非常に疑わしく、悪意の指標となる可能性があります。Freezeは、プロセスが作成されEDRのフックがロードされた後、'GetConsoleWindow'および'ShowWindow' Windows関数を呼び出し、ウィンドウの属性を非表示に変更することでこれを実現しています。Freezeは、従来の-ldflags -H=windowsguiを使用するのではなく、これらのAPIを利用しています。これは、ほとんどのセキュリティ製品で侵害の指標として強くシグネチャされ分類されているためです。
-consoleコマンドラインオプションが選択された場合、Freezeはプロセスをバックグラウンドに隠しません。代わりに、ローダーが何をしているかを表示するいくつかのデバッグメッセージを追加します。
aahmad097によるAlternativeShellcodeExecの開発に特に感謝します。
mvdanによるGarbleの開発に特に感謝します。