Binary Pulsar

技術寄りなセキュリティの話題について書きます

Structured Exception Handlingとセキュリティ

概要

Structured Exception Handling (SEH)は、Windows OSに実装されている、プログラムの例外を処理する機構です。本記事では、SEHの概要とともに、SEHに関するセキュリティの話題について解説します。

SEHの概要

SEHはWindows OSのプログラムの例外を処理するために実装されている処理です。以下の図にその概要を表しています。SEHのエントリの低位アドレスに次のSEHのエントリのアドレスを、上位アドレスに例外を処理するためのハンドラのアドレスを格納することにより構成されています。

f:id:binary-pulsar:20190117003541p:plain
SEHの処理の概要

SEHはプログラムにおけるtry-catchの例外処理に例えられます。最初のSEHエントリのアドレスは、セグメントレジスタFSに格納されています。例外が発生すると、セグメントレジスタFSに登録されているアドレスのSEHエントリに実行を移し、SEHエントリに指定されているハンドラのアドレスに記述されている処理を実行します。ハンドラにより例外の処理に成功した場合は例外処理を終了しますが、失敗した場合はSEHエントリに指定されているアドレス情報に従って次のSEHハンドラで例外処理を試みます。同様の手続きを継続して、例外の捕捉に成功するまで例外処理を試行します。すべてのSEHハンドラの処理がすべて失敗した場合は、ntdll.dllに定義されているFinalExceptionHandlerで例外を処理して例外処理を終了します。

Buffer Overflowの脆弱性をついた攻撃におけるSEH

SEH Overwrite

SEH Overwriteは、Windows OSのプログラムにスタックベースのBuffer Overflowの脆弱性が存在していた場合に、悪用される可能性がある手法の一つです。Windowsのプログラムは、コンパイル時に/GSオプションを設定することにより、Stack Canaryを設定することが可能です。Stack Canaryが設定されている場合、単純なスタックベースのBuffer Overflowで実行ポインタを書き換えてもStack Canaryの値の整合性が崩れるため、攻撃者による悪意のあるコードの実行を防ぐことが可能となります。しかし、SEH Overwriteを悪用することにより、攻撃者はStack Canaryによる防御が有効なプログラムに任意のコードが実行できることがあります。 SEHのハンドラはBuffer Overflowにより書き換える対象となる実行ポインタよりも高位のアドレスに存在します。SEH Overwriteでは、名前の通り、スタックベースのBuffer Overflowの脆弱性を悪用する際に、SEHのハンドラを書き換えてしまいます。SEHのハンドラはStack Canaryやリターンアドレスよりも高位アドレスに存在するため、SEHを書き換える際に当然Stack Canaryが破壊されてしまいます。しかし、Stack Canaryの破壊により発生した例外は、SEHにより例外処理されるため、SEHのハンドラが格納されているアドレスを書き換えることにより、Stack Canaryが破壊された状態でも悪意のあるコードが実行可能となります。

SEH Overwriteによる攻撃への対策機構

SEH Overwriteにより、Stack Canaryが設定されていたとしても、スタックベースのBuffer Overflowによる任意のコード実行が可能となります。Windows OSではSEH Overwriteによる任意のコード実行を防ぐために、いくつかの保護機能を実装しています。

SafeSEH

SafeSEHはSEH Overwriteに対する防御機構の一つです。SEHのハンドラが格納されているアドレスのリストを保持することにより、攻撃者によって上書きされた不正なSEHのアドレスを検出します。しかし、プログラムのイメージ内のアドレスに存在するハンドラにのみ有効であり、プログラムのイメージの外のアドレスは有効な例外ハンドラとして扱われるという欠点があります。また、プログラムをすべて/SAFESEHオプションをつけて再ビルドする必要があるため、SafeSEHによる対策状況はプログラムの開発者に依存します。

Software DEP

Software DEPはSafeSEHを拡張した防御機構です。Windows XP SP2から導入されました。DEP (Data Execution Protection)という文言が含まれていますが、Hardware DEPのように特定のメモリ領域のコードをすべて実行禁止にするものではありません。 Software DEPでは、プログラムのKPROCESS構造体内の_KEXECUTE_OPTIONS構造体に定義されている、ImageDispatchEnableフラグとExecuteDispatchEnableフラグでSEHハンドラの実行制御をします。それぞれ値が「0」に設定されている場合は有効、「1」に設定されている場合は無効です。ImageDispatchEnableフラグが有効に設定されている場合は、プログラムのイメージの外部のアドレスを例外ハンドラとして取り扱いません。ExecuteDispatchEnableフラグが有効に設定されている場合は、実行可能属性がついていない例外ハンドラを呼び出さないことで、攻撃者により上書きされたSEHハンドラの実行を防止するというものです。

SEHOP

SEH Overwrite Protection (SEHOP)は、Windows Vista SP1およびWindows Server 2008から導入された保護機構です。SEHハンドラを辿り、最後に処理される例外ハンドラのアドレスがntdll.dllのFinalExceptionHandlerのアドレスを指していない場合は、不正なSEHが混入されたとしてプログラムの実行を停止します。FinalExceptionHandlerのアドレスがわかっている場合は、SEHOPの防御機構を回避して任意のコードを実行できる可能性が有りますが、Address Space Layout Randomization (ASLR)によるアドレスのランダム化と併用することで堅牢な防御機構となります。 SEHOPは、Windows Vista SP1では初期状態で無効、Windows Server 2008では初期状態で有効に設定されており、レジストリキーHKLM\SYSTEM\CurrentControlSet\Control\Session Manager\kernel\DispatchExceptionChainValidationの値を0に設定することで有効化することができます。

マルウェアの自己防衛におけるSEH

マルウェアには、マルウェア解析者による解析を困難にする目的で、SEHを悪用することがあります。悪用手順は以下の通りです。

  1. マルウェアが実行したいコードが配置されているアドレスをSEHのハンドラとするSEHのエントリを作成
  2. 意図的に例外を発生させて例外処理として悪意のあるコードを実行

挙動を確認する目的でアセンブリ言語を用いて解説します。以下のアセンブリ言語は、上述の手法でSEHを悪用する処理を例示したものです。

mov   eax, maliciousCodeAddress
push  eax
push  dword ptr fs:[0]
mov   dword ptr fs:[0], esp
xor   eax, eax
mov   dword ptr ds:[eax], ecx

maliciousCodeAddressは、マルウェアが実行したいコードが配置されているアドレスであるとします。まず冒頭の以下の処理ですが、マルウェアが実行したいコードが配置されているアドレスを、スタックに格納しています。

mov   eax, maliciousCodeAddress
push  eax

Windowsのプログラムでは、fs:[0]にはSEHエントリの最初のアドレスが格納されています。よって、続く処理は、SEHハンドラの最初のアドレスをスタックに格納しています。

push  dword ptr fs:[0]

以上までの処理で、マルウェア開発者が作成したSEHエントリが完成しました。続く以下の処理では、fs:[0]にスタックポインタを格納することにより、マルウェア開発者が作成したSEHエントリが最初のSEHエントリとして登録されます。こうして作成されたSEHエントリで示されている次のSEHエントリのアドレスは、そもそものSEHハンドラのアドレスとなり、最終的にはFinalExceptionHandlerのアドレスに到達するため、SEHOPの規則に違反しません。

mov   dword ptr fs:[0], esp

最後に、以下の処理で適当な値をNULLポインタに代入することになるため、Null Pointer Dereferenceによる例外が発生します。

xor   eax, eax
mov   dword ptr ds:[eax], ecx

例外が発生することにより、マルウェア開発者が作成したSEHハンドラが最初に処理されるため、マルウェア開発者が意図したコードが実行されます。下図に概要を示します。

f:id:binary-pulsar:20190117144348p:plain
SEHを悪用したマルウェアの動作の概要

まとめ

本記事では、Windows OSにおける例外処理機構であるSEHの概要について解説しました。また、SEHに関連したセキュリティの技術について解説しました。

Net-LTLMv1認証の危険性

概要

前回の記事では、Pass-the-Hashの手法について解説しました。

binary-pulsar.hatenablog.jp

その際にNet-NTLMv2認証について解説しましたが、v2があるということはv1も存在します。Net-NTLMv1認証については、Pass-the-Hashの解説をする上ではそこまで必要ではないため、前回の記事ではその解説を割愛しました。しかし、Net-NTLMv1認証が用いられている環境は安全性に欠けるため、本記事ではNet-NTLMv1認証の実装とその弱点について解説します。

Net-NTLMv1認証

Net-NTLMv1認証は、古いWindows OSに用いられていた認証方式です。その実装の弱さから、Windows Server 2008およびWindows Vistaからは、LMハッシュ値とともに初期状態で無効化されました。しかし、古いWindows OSとの互換性のため、グループポリシーを操作することにより、有効化することは可能となっています。 Net-NTLMv1認証はチャレンジレスポンス方式であり、前回解説したNet-NTLMv2認証と大差ありません。ただし、Net-NTLMv1認証では、チャレンジ値はサーバ側でのみ生成され用いられます。Net-NTLMv1認証は以下の手順で行われます。

  1. クライアントからサーバに対して認証を要求する。
  2. サーバからクライアントへ、8バイトのチャレンジ値を送信する。
  3. クライアントが、認証情報とチャレンジ値を用いてNet-NTLMv1応答値を生成して、Net-NTLMv1応答値をサーバに送信する。
  4. クライアントから受信したNet-NTLMv1応答値をサーバが検証して、整合性を確認することにより認証する。

Net-NTLMv1応答値の生成手順は以下に従います。

  1. ユーザの平文パスワードのLMハッシュ値またはNTLMハッシュ値のどちらかを用いる。
  2. パスワードハッシュ値(LMおよびNTLMのいずれでも16バイト)の末尾にNULLバイトを5バイト追加することにより、データ長を21バイトに調整する。
  3. パスワードハッシュ値から作成した21バイトを、7バイトごとに分割し、それぞれ暗号鍵として利用する。
  4. 作成した3つの暗号鍵を用いることにより、サーバから受信した8バイトのチャレンジ値をDESで暗号化したものを3つ作成して連結する。

f:id:binary-pulsar:20181211010318p:plain
Net-NTLMv1応答値の生成手順

以上の手順で作成したNet-NTLMv1応答値が、サーバに送信されます。Net-NTLMv1認証では、LMハッシュ値を用いて作成されたNet-NTLMv1応答値と、NTLMハッシュ値を用いて生成されたNet-NTLMv1応答値の両方がサーバに送信され、検証されることになります。先述の通り、Net-NTLMv2認証とは異なり、Net-NTLMv1認証ではチャレンジ値を生成するのはサーバのみであるため、サーバ側でもNet-NTLMv1応答値を生成するために必要な情報をすべて保有しています。よって、クライアントから受信したNet-NTLMv1応答値をサーバで検証することにより、認証することが可能となります。

Net-NTLMv1応答値の弱点と攻撃手法

上述の通り、Net-NTLMv1応答値は56ビット(7バイト)の鍵をもちいてDESで暗号化された、8バイトのチャレンジ値を3つ連結したものです。よって、Net-NTLMv1応答値を3つに分割してそれぞれ解析することが可能です。56ビットという鍵長は、暗号学において十分な強度があるとは言えません。現代の計算機の性能では、チャレンジ値(DESの平文)がわかっている状況において現実的な時間で必ず解析することが可能と考えて良いでしょう。

Active Directoryで構成された組織のネットワークへの侵入に成功した攻撃者は、いくつかの手法によりネットワークの通信を盗聴することが可能です。攻撃者がネットワークの通信を盗聴した場合、当然ながら認証の全通信内容を取得することが可能であるため、サーバとクライアントの間でやり取りされるチャレンジ値と、認証の応答値を取得することが可能です。よって、Net-NTLMv1認証が有効である環境では、制圧に成功したホスト以外のホストを利用しているユーザのパスワードハッシュ値を、以下の手順で入手することが可能となります。

  1. 制圧に成功したホストからネットワーク上の通信を盗聴する。
  2. 他のホストとサーバの認証通信から、チャレンジ値とNet-NTLMv1応答値を盗聴により取得する。
  3. 盗聴により取得したチャレンジ値とNet-NTLMv1応答値を解析することにより、パスワードハッシュ値を取得する。

Active Directoryで構成された組織のドメインネットワークへの侵入に成功した攻撃者は、以上の手順を踏むことによりパスワードハッシュ値を取得して解析することにより、平文のパスワードを取得されてしまう可能性も考えられます。また、解析したパスワードハッシュ値を用いられて、Pass-the-Hashにより侵入範囲の拡大されてしまう可能性があります。

対策

Net-NTLMv1およびLMハッシュ値に関するセキュリティ対策について、Microsoftから公式文書が公開されています。以下のリンク先の公式文書を参考に、サーバおよびクライアントの両方で、Net-NTLMv1認証を無効化することで対策しましょう。

https://support.microsoft.com/ja-jp/help/2793313/security-guidance-for-ntlmv1-and-lm-network-authentication

Pass-the-Hashの仕組み

概要

近年、Active Directoryで構築されたネットワークを侵害する上で、もっとも悪用されている手法の一つはPass-the-Hashと言えるでしょう。組織のActive Directoryドメインのネットワークへの侵入に成功した攻撃者は、Pass-the-Hashの手法を用いることで、取得に成功したパスワードハッシュ値を平文に復号することなく認証することが可能となります。本記事では、Pass-the-Hashの仕組みを解説することで、読者がその手法を理解できるようにすることを目標としています。

パスワードハッシュ値

Windows OSにおいてパスワードハッシュ値は、ユーザのパスワードを安全に保存するのみではなく、主にサーバやクライアントホストへの認証に用いられます。Pass-the-Hashという手法は、Windows OSがパスワードハッシュ値を用いて認証を実施する過程を悪用するものです。よって、Pass-the-Hashの手法を理解する上ではWindows OSのハッシュ値について理解する必要があります。

LMハッシュ値

LMハッシュ値Windows Vistaよりも古いWindows OSで用いられていたパスワードハッシュ値です。ソルト化はされておらず、ハッシュ値の長さは16バイトです。パスワードの最大長として許可されているバイト数は14バイトであり、パスワードを安全に守るには実装が弱いため、Windows Vista以後のWindows OSでは初期設定で無効化されています。LMハッシュ値の生成は以下の手順に従います。

  1. パスワードを大文字に変換する。
  2. パスワードが14バイトになるように、末尾をNULLバイトで埋める。
  3. パスワードを7バイト単位に分離してDESの鍵とする。
  4. パスワードの前半を用いて生成されたDESの鍵で文字列「KGS!@#$%」を暗号化したものと、パスワードの後半を用いて生成されたDESの鍵で文字列「KGS!@#$%」を暗号化したものを連結する。

f:id:binary-pulsar:20181206151556p:plain
LMハッシュ値生成の概要

以上の手順からわかる通り、LMハッシュ値を用いている場合はパスワードに用いるアルファベットの大文字と小文字は区別されません。よってその分だけハッシュ値の衝突による平文パスワードの推測が容易になります。さらに、LMハッシュ値を前半と後半に分けて解析することで、平文パスワードの前半の7文字と後半の7文字を分割して解析することが可能です。また、パスワードの長さが7バイト以下である場合は、後半の7バイトはNULLバイトが7つ並んだものとなり、ハッシュ値の後半は固定値(AAD3B435B51404EE)となるため、パスワードの長さが7バイト以下であることが容易に推測できてしまいます。LMハッシュ値では平文パスワードに含まれるアルファベットの大文字と小文字の区別ができないとはいえ、7バイトという長さは現実的な時間で解析できる長さであるため、パスワードのLMハッシュ値が漏洩してしまった場合は必ず解析されてしまうと言っても良いでしょう。

NTLMハッシュ値

NTLMハッシュ値は、前述のLMハッシュ値の弱点を克服するために実装されました。Windows Vista以後のWindows OSでは、NTLMハッシュ値をパスワードハッシュ値の標準として用いています。ハッシュ化の手順としてはあまり複雑ではありません。平文パスワードをUnicodeに変換し、MD4によりハッシュ化したものです。ソルト化はされていませんが、LMハッシュ値とは異なり、大文字と小文字はしっかり区別されます。ハッシュ値の長さはLMハッシュ値と同じく16バイトですが、パスワードの長さは128文字(256バイト)まで許されています。

f:id:binary-pulsar:20181205151222p:plain
NTLMハッシュ値生成の概要

Net-NTLMv2認証

Net-NTLMv2認証は現行のWindows OSで認証に用いられている方式です。以下の手順に従い、サーバとクライアント間で認証します。

  1. クライアントからサーバに対して認証を要求する。
  2. サーバからクライアントに対してチャレンジ値を送信する。
  3. クライアントが、認証情報とチャレンジ値を用いてNet-NTLMv2応答値を生成して、Net-NTLMv2応答値をサーバに送信する。
  4. サーバがクライアントから送信されたNet-NTLMv2応答値の内容を検証して、整合性を判断して認証する。

Net-NTLMv2応答値の生成アルゴリズムは以下の手順に従います。

  1. 平文パスワードからNTLMハッシュ値を生成する。
  2. NTLMハッシュ値を鍵として、ドメイン名とユーザ名を連結したデータを、HMAC-MD5でハッシュ化する。
  3. NTLMハッシュ値とユーザ情報から生成したHMAC-MD5ハッシュ値を鍵として、サーバから送信されたチャレンジ値とクライアントで生成したチャレンジ値を連結したデータを、HMAC-MD5でハッシュ化する。
  4. チャレンジ値から生成したHMAC-MD5ハッシュ値に、クライアントで生成したハッシュ値を付加する。

f:id:binary-pulsar:20181205151125p:plain
Net-NTLMv2認証値生成の概要

クライアントが生成するチャレンジ値を除き、サーバも同じ情報を保有しているため、こうして生成されたNet-NTLMv2応答値からクライアントが生成したチャレンジ値を抽出することにより、Net-NTLMv2応答値と同じものをサーバ側でも生成することが可能です。よって、クライアントから送信されたNet-NTLMv2応答値と、サーバが生成したNet-NTLMv2応答値を比較することにより、認証情報の整合性を確認することが可能となります。

Pass-the-Hash

Pass-the-HashはNet-NTLMv2認証の実装を悪用した手法です。Pass-the-Hashの手法により、NTLMハッシュ値を平文パスワードに戻すことなく認証することが可能となります。先述のNet-NTLMv2認証の手順を追うとわかりますが、Net-NTLMv2認証においては平文パスワードから生成したNTLMハッシュ値のみを用いており、平文パスワード自体は直接的にNet-NTLMv2応答値に含まれていません。よって、NTLMハッシュ値のみでNet-NTLMv2応答値を生成して認証することが可能です。

f:id:binary-pulsar:20181205151028p:plain
Pass-the-Hashの仕組みの概要

上の原理で、パスワードハッシュ値を平文に戻すことなく認証を実行する手法が「Pass-the-Hash」と呼ばれています。 Pass-the-Hashは家庭用環境のようにホストが独立している場合はあまり脅威とはなりませんが、Active Directoryによって構成された組織が管理するドメインネットワークで大きな力を発揮します。Windows OSには、初期状態で登録される管理者権限のアカウント(通称「ビルトイン管理者」。初期設定のアカウント名はAdministrator)が存在しますが、Active Directoryで管理されている組織のネットワークに所属するホストの場合は、ネットワーク管理者による管理を円滑にするために、複数の端末で共通のパスワードが設定された状態でアカウントが有効化されている場合が多いです。よって、組織のネットワークのいずれかのクライアントホストに侵入し、そのホストでの管理者権限の掌握に成功した攻撃者は、ホストのメモリ上やレジストリからビルトイン管理者のパスワードのNTLMハッシュ値を抽出してPass-the-Hashを実行することにより、同一のドメインネットワークに所属するホストを連鎖的に制圧することが可能となる場合があります。

検知

これまでの説明からわかるように、Pass-the-Hashにより最終的に生成されるNet-NTLMv2応答値は、正規の手順で生成されたNet-NTLMv2応答値と区別がつかないため、「Pass-the-Hashを悪用してNTLM認証を試行されてしまった」という事象を検知することは難しいと考えられます。Pass-the-Hashによる認証が成功した後の攻撃者の動作に関しては検知できると考えられるものがありますが、本記事の題材とは異なるため割愛します。

対策

Pass-the-HashはWindowsの認証の仕組み上、仕方がないものです。攻撃者に侵入されてしまい権限昇格されてしまった前提で対策するべきでしょう。読者である皆様が利用しているホストが攻撃者に侵入されなかったとしても、同じドメインネットワークに所属する別の誰かのホストが攻撃者に制圧されてしまい、Pass-the-Hashにより自身のホストに被害が拡大してしまうという事態は充分に考えられます。よって、Pass-the-Hashによる攻撃者の侵入領域の拡大を防ぐ対策が求められます。 ドメインネットワークに所属する各ホストのアカウントの認証情報を強化することはもちろんですが、それぞれのホストのビルトイン管理者のパスワードを共通にしないという対策が有効でしょう。Microsoftでは、ドメインネットワークの管理者が、ビルトイン管理者のパスワードを円滑に管理するためのツールであるLocal Administrator Password Solution (LAPS)を無償で公開しています。

マイクロソフト セキュリティ アドバイザリ 3062591 | Microsoft Docs

以下のURLにLAPSの使用方法の解説ビデオが公開されているため、組織のネットワークの管理を管理するために参考とすると良いでしょう。

channel9.msdn.com