Windows の HiveNightmare バグによるパスワード漏洩の対処法

** 本記事は、Windows “HiveNightmare” bug could leak passwords – here’s what to do! の翻訳です。最新の情報は英語記事をご覧ください。**

Windows のプリンターのバグ (PrintNightmare) が公開されてからまだ日が浅いにもかかわらず、マイクロソフト社は 2021 年 7 月 20 日に Windows レジストリから重要な秘密を漏洩する可能性のある新たなバグを公開しました。

CVE-2021-36934 と呼ばれるこのバグは、HiveNightmareSeriousSAM とも呼ばれています。

HiveNightmare という通称は、Windows がレジストリデータを、マイクロソフトの専門用語でハイブまたはハイブファイルと呼ばれる少数の独自データベースファイルに保存していることに由来しています。

これらのハイブファイルには、SAMSECURITYSYSTEM と呼ばれる 3 つのファイルが含まれており、これらのファイル間には、パスワードやセキュリティトークンなど、一般ユーザーがアクセスできないような秘密のデータが含まれています。

これらのファイルは、Windows ディレクトリの下にある C:\Windows\System32\config と呼ばれる特別なフォルダに保存されています (下図参照) 。

C:\Windows\System32\config> dir
[. . .]
Directory of C:\Windows\System32\config
[. . .]
21/07/2021  12:57           524,288 BBI
25/06/2021  06:21            28,672 BCD-Template
21/07/2021  14:45        32,768,000 COMPONENTS
21/07/2021  12:57           786,432 DEFAULT
21/07/2021  12:32         4,194,304 DRIVERS
[. . .]
21/07/2021  12:57            65,536 SAM       <--some system secrets included
21/07/2021  12:57            32,768 SECURITY  <--some system secrets included
21/07/2021  12:57        87,556,096 SOFTWARE
21/07/2021  12:57        11,272,192 SYSTEM    <--some system secrets included
[. . .]

SeriousSAM という通称は、ファイル名の SAM から来ています。 SAM は Security Account Manager の略で、ファイルの内容と同様いかにも重要そうな響きです。

パスワードクラックツールやハッキングツールを使用したことがある方 (または、攻撃を検知した後にネットワーク上にその痕跡を見つけたことがある方) なら、サイバー攻撃者がネットワーク上を移動するために必要な管理者認証情報を探す際、真っ先に探るのが SAM データベースであることはご存知のことでしょう。

幸いなことに、メモリ上の SAM データを入手するためには、管理者権限が必要であり、また、管理者であったとしても Windows の実行中にディスク上の SAM レジストリハイブを入手することはできません。

ここまでは問題ありません。

どのような情報が誰に漏洩するのか?

私たちは、システム上のあらゆるファイルの「アクセシビリティインジケータ」を得るために使用できる簡単な C プログラムを書きました。このプログラムは、単に、コマンドラインに入力されたファイル名を開こうと試み、ファイルが読み取りアクセスのために開かれなかった場合には、Windows のエラーコードを報告します。

(以下のコードはパブリックドメインに公開していますので、ご自身の責任においてご自由にお使いください。)

コンパイルには Windows 用のヘッダーファイルも必要ありません。単純に、コンパイラやリンカに kernel32.dllmsvcrt.dll が必要であることを伝えるだけでよいのです。

/* --- CHKIT.C --- */

void     *CreateFileA(char *name,unsigned mode,unsigned share,void *sec,unsigned disp,unsigned attr,void *tmpl);
int      CloseHandle(void *hnd);
unsigned GetLastError(void);
int      printf(char *fmt, ...);

int main(int argc, char **argv) {
   for (int i = 1; i < argc; i++) {
      printf("Opening file [%s]\n",argv[i]);
      void *hnd = CreateFileA(argv[i],0x80000000L,0,0,3,0x80,0);
      if ((long int)hnd == -1) {
         printf("Failed (GetLastError=0x%08X)\n",GetLastError());
      } else {
         printf("Worked (handle=%ld)\n",(long int)hnd);
         CloseHandle(hnd);
      }
   }
   return 0;
}

昇格したコマンドプロンプト (管理者権限で実行しているもの) から、次のような結果が得られます。

C:\Users\duck> chkit C:\Windows\System32\config\SAM C:\Windows\System32\config\SYSTEM C:\Windows\System32\config\SECURITY
Opening file [C:\Windows\System32\config\SAM]
Failed (GetLastError=0x00000020)
Opening file [C:\Windows\System32\config\SYSTEM]
Failed (GetLastError=0x00000020)
Opening file [C:\Windows\System32\config\SECURITY]
Failed (GetLastError=0x00000020)

Error 0x20 は ERROR_SHARING_VIOLATION の略で、マイクロソフトの公式な説明では 「別のプロセスが使用しているため、そのプロセスがファイルにアクセスできない状態」 とされています。

ここまでは通常の動作です。

では、権限のないコマンドプロンプトから、通常のユーザーとして実行してみましょう。

C:\Users\duck> chkit C:\Windows\System32\config\SAM
Opening file [C:\Windows\System32\config\SAM]
Failed (GetLastError=0x00000020)

ここで、予想外の動作が起こりました。

本来であれば、ERROR_ACCESS_DENIED を意味する Error 0x05 とすぐに表示されるはずです。

Error 0x20 が表示されたということは、ファイルへのアクセスがブロックされたのではなく、プログラムがファイルを開くことは許可されており、ファイルを開くことに失敗したということを意味します。

ICACLS ユーティリティーを使用して、例として SAM ハイブファイルの ACL (アクセスコントロールリスト) を確認すると、この動作はセキュリティ上の過失によるものであることがわかります。

C:\Windows\System32> icacls config\SAM
config\SAM BUILTIN\Administrators:(I)(F)
           NT AUTHORITY\SYSTEM:(I)(F)
           BUILTIN\Users:(I)(RX)    <-- this is wrong - regular users should not have read access!
           APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)
           APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX)

Successfully processed 1 files; Failed processing 0 files

つまり、SAM レジストリデータ (および SECURITYSYSTEM のハイブファイルも) は、ファイルが別の場所で使用されているため一般ユーザーによるアクセスに対して実行時に保護されているのであって、最初から一般ユーザーがアクセスできないようになっているわけではないということです。

この脆弱性を修正する必要がありますが、マイクロソフトの公式な回避策は、CONFIG ディレクトリ以下のすべてのファイルのアクセス制御リスト (ACL) を制限することです。

それを行うためには管理者として次のようなセキュリティ上の変更を行う必要があります。

C:\Users\duck> icacls %windir%\system32\config\*.* /inheritance:e
processed file: C:\Windows\system32\config\BBI
[. . .]
processed file: C:\Windows\system32\config\SAM
[. . .]
processed file: C:\Windows\system32\config\SECURITY
[. . .]
processed file: C:\Windows\system32\config\SYSTEM
[. . .]
Successfully processed 45 files; Failed processing 0 files

さて、上記のように SAM ファイルの ACL は、正常に近づきました。

C:\Windows\System32> icacls config\SAM
config\SAM NT AUTHORITY\SYSTEM:(I)(F)
           BUILTIN\Administrators:(I)(F)

Successfully processed 1 files; Failed processing 0 files

また、管理者以外のコマンドプロンプトから SAM レジストリハイブファイルを再度開いても、Error 0x20 が表示されなくなりました。

代わりに ACCESS_DENIED を意味する Error0x05 と表示されました。セキュリティは強化されました。

C:\Users\duck> chkit C:\Windows\System32\config\SAM
Opening file [C:\Windows\System32\config\SAM]
Failed (GetLastError=0x00000005)

さらなる問題

しかし、問題はこれだけではありません。

システムの復元ポイント (ボリュームシャドウコピーとも呼ばれる) がコンピューターにある場合、その復元ポイントには、古く安全ではないアクセスコントロール設定を持つ、オリジナルの SAMSECURITYSYSTEM レジストリハイブファイルのコピーが含まれています

つまり、特権を持たないユーザーでも Windows のアクセス制御の秘密やパスワードのハッシュ値などのデータをシャドウコピーから読むことができるのです。

ちなみに、「システムの保護」メニューから「作成」ボタンをクリックしてシャドウコピーを作成しなくても、シャドウコピーが 1 つ以上コンピューターにすでに存在している可能性があります。

(復元ポイントとは、オンラインのスナップショットや一時的なバックアップのようなもので、アップデートに失敗して不具合が生じた際などにハードディスクの内容を「巻き戻す」ことで、古いバージョンのシステムを復元することができます)

IT 部門がさまざまなタイミングで復元ポイントを作成している可能性があります。また、システムのアップグレードや一部のセキュリティソフトウェアが、自分自身で使用するために自動的に復元ポイントを作成することもあります。

ボリュームシャドウコピーサービスの管理用コマンドラインツールである vssadmin を使えば、お使いのコンピューター上にシャドウコピーがあるかどうかを調べることができます。

下図は、この記事のためにあえて作成したシャドウコピーです。

C:\Users\duck> vssadmin list shadows

vssadmin 1.1 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001-2013 Microsoft Corp.

Contents of shadow copy set ID: {. . .}
   Contained 1 shadow copies at creation time: 21/07/2021 14:58:05
      Shadow Copy ID: {. . .}
         Original Volume: (C:)\\?\Volume{. . .}\
         Shadow Copy Volume: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2  <--this is the directory tree where the shadow file copies can be found
         Originating Machine: W10
         Service Machine: W10
         Provider: 'Microsoft Software Shadow Copy provider 1.0'
         Type: ClientAccessibleWriters
         Attributes: Persistent, Client-accessible, No auto release, Differential, Auto recovered

この出力は、復元ポイントとシャドウコピーを作成した時点でのレジストリハイブファイルのコピーが、このシャドウディレクトリにあることを示しています。

\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2\Windows\System32\config

シャドウコピーボリュームのルートディレクトリ名を取り、そこにドライブレターを除いた元の Windows ファイル名を追加するだけです。

(ちなみに、上記のプレフィックス \\?\ は、Windows がこのファイル名に「ワイド文字」を使用することを示しており、1 文字あたり 1 バイトの通常の ASCII テキスト文字列として書かれているにもかかわらず、各文字に 2 バイトを使用します。これにより、通常の ASCII ファイル名の制限である 260 文字ではなく、32KB までの長さのファイル名をつけること可能になります)

それでは、上記の SHARING_VIOLATION エラーや ACCESS_DENIED エラーが発生したライブコピーではなく、レジストリハイブファイルのシャドウコピーで chkit プログラムを試してみましょう。

管理者ではないユーザーとしてコマンドプロンプトを使用すると、次のような結果が得られました。

C:\Users\duck> chkit \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2\Windows\System32\config\SAM
Opening file [\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2\Windows\System32\config\SAM]
Worked (handle=136)

簡単に言うと、(a) システムが稼動していて、(b) 管理者権限がないにもかかわらず、SAM ファイル (および同様にシャドウコピーディレクトリ内の他のレジストリハイブバックアップ) へのアクセスを取得できました。

対策

マイクロソフトが公開している回避策はとても簡単です。

  • ICACLS コマンドを使って、上記のようにライブレジストリのハイブファイルの ACL をリセットします。これにより、それ以降はシステムが保護されます。  
  • 既存の復元ポイントまたはシャドウコピーをすべて削除します。 これにより、誤って保護されたファイルがシャドウコピーのディレクトリに残らないようにします。
  • 必要に応じて、新しい復元ポイントを再作成します。

もちろん、マイクロソフト社が苦々しげに述べたように「シャドウコピーを削除すると、サードパーティ製のバックアップアプリケーションでデータを復元する機能を含む、復元操作に影響を与える可能性がある」ことを忘れるわけにはいけません

攻撃者が、ネットワークを破壊する直前にほとんどいつも復元ポイントをすべて削除して、復旧を遅らせたり困難にしたりするのはこうした理由によります。

因みに、すべての復元ポイントを削除する手っ取り早い方法は、管理者として以下のコマンドを使用することです。

C:\Users\duck> vssadmin delete shadows /all
vssadmin 1.1 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001-2013 Microsoft Corp.

Do you really want to delete 1 shadow copies (Y/N): [N]? y

Successfully deleted 1 shadow copies.

理論的には、安全でないレジストリハイブのバックアップをシャドウコピーディレクトリ内で見つけるスクリプトやプログラムを作成し、それらの個別ファイルに ACL を設定することで、残りの復元ポイントをそのまま残すことができると思われます。

しかし、我々も実際に試したことはなく、復元ポイントの内容を「非公式に」変更しても、復元ポイントが正しく機能するかどうかはわかりませんので、お勧めはできません。