ShadowHashはMac OS X 10.3 Pantherにて採用されたパスワードの管理方法で、Jaguarにて使われていたLocalWindowsHashを引き継ぐものである(注3)。

LocalWindowsHashおよびShadowHashの特徴は、通常のログインの認証に加えて、Windowsとのファイル共有で使われる認証方式であるNTLM認証に利用できるという点にある。

WindowsのSMBによる共有では、LANMANやWindows for Workgroupの時代から存在する古いLM認証と、Windows NTと共に導入されたより新しいNTLM認証(注4)が存在する。

WindowsのNTLM認証では、生パスワードから生成したMD4によるダイジェスト値と、認証の度に生成されるランダムなチャレンジ値を用いてチャレンジレスポンス式の認証を行う。

UNIXの/etc/passwd/etc/shadowにはパスワードをcrypt、もしくはMD5で変換したダイジェスト値しか格納されておらず、仮にこのダイジェスト値を読まれても、すぐに生のパスワードは計算では導けるわけではない(注5)。

逆に言えば、生のパスワードを取得できないため、NTLM認証をしたくても、/etc/shadowの情報だけでは行えないのだ。

このため、Sambaではsmbpasswdというファイル、あるいはtdbとよばれるデータベースに生パスワードから計算したLM認証用ないしはNTLM認証用のダイジェスト値が格納されている。

この値は認証時に「直接」利用される。言い換えれば生パスワードそのものと同じ重要度を持っている。

/etc/shadowが漏洩しても、そこに記載された値から生パスワードを手に入れるには総当たり攻撃で試していくしかない。しかし、smbpasswdはそんな必要がない。この値さえ分かっていれば生のパスワードを知らずとも認証を通せるからだ。これは非常に危険な情報である。

Mac OS Xでは、この危険な情報を含め、認証に必要なパスワード情報を/var/db/shadow/hash以下に格納している。このディレクトリに格納されているファイルが、ShadowHashの実体だ(図5)。

図5: /var/db/shadow/hash以下に格納しているファイルがShadowHashの実体

このディレクトリはrootだけがアクセス可能なようパーミッションが制限されており、1ユーザごとユーザのUUIDを付けたファイルと、UUIDに拡張子.stateがついたファイルの2つが置かれている(図6)。

図6: 1ユーザごとユーザのUUIDを付けたファイルと、UUIDに拡張子.stateが付いたファイルが存在

UUIDのみのファイルにパスワードのダイジェスト値が記録されており、.stateの方は「作成日時」「ログインに失敗した回数」「先後にログインした日時」や「次回ログイン時に新しいパスワードを作成するか」といった付随情報がバイナリ形式のplistで記録されている(図7)。

図7: .stateファイルには、付随情報がバイナリ形式のplistで記録されている

では、実際のパスワードの格納されているファイルを見てみよう。

通常、先頭はNULデータが羅列されている。Leopardの場合(注6)は168バイトの00データが並んだ後に、48バイトのバイナリデータが存在する(図8)。

図8: Leopardの場合は168バイトの00データが並んだ後に、48バイトのバイナリデータが存在する

この48バイトのバイナリデータは「8バイトのsalt」+「40バイトのSHA1によるダイジェスト値」でできている。8文字の16進数の文字を4バイトのバイナリデータと見なし、この4バイトをパスワードの前に接続、SHA1でダイジェスト値を取ると、この40バイトのダイジェストになる(図9図10)。

図9: SALTED-SHA1 の計算方法

図10: SHA1によるダイジェスト値の取得方法

Leopardでは、通常はこのSALTED-SHA1の値を用いることで、ログイン時などに行われるパスワード認証を処理する。

一方、システム環境設定にある「共有」のファイル共有でのオプションで、SMBによるファイル共有が設定された場合、先の168バイトのNULデータの先頭に、32バイトのダイジェスト値が格納される(図11)。

図11: SMBによるファイル共有が設定された場合、先の168バイトのNULデータの先頭に、32バイトのダイジェスト値が格納される

これは、NTLM認証で利用されるダイジェスト値になる。計算方法は、図12にあるように、パスワードをUnicode(UCS-2)に変換した後に、MD4でダイジェストをとるというもの(図13)。なお、NT-Hashとも呼ばれるこの方式ではsaltは存在せず、1つのパスワードはかならず1つのダイジェスト値に対応付けられる。そもそもMD4はダイジェスト値としての有効性に懸念がもたれる上、パスワードが1対1に対応するとなればrainbow table(注7)によるパスワードの発見すら可能になる。

図12: NT-Hash計算方法

図13: NT-Hashの実際の取得方法。パスワードをUnicode(UCS-2)に変換した後に、MD4でダイジェストをとる

加えて言うならば、そもそもこのダイジェスト値さえ分かればNTLM認証のチャレンジに対する正確なレスポンスが生成できる。わざわざ生パスワードを求めなくても、NTLM認証をパスしてファイル共有にアクセスすることが可能なのだ。

このため、システム環境設定の「共有」では、SMBによるファイル共有を利用する際に、ユーザを限定できる上、「パスワードが安全性の低い方法で保存されます」という警告が記載されている。これは、このNT Hashの保存を行うことを指す(図14)。

図14: ファイル共有のオプションにてSMBによるファイル共有を許可するユーザ一覧が設定できるが、ここには「安全性の低い方法で保存されます」という警告がある。これは NT-Hash で保存していることを意味する

なお、システム環境設定の上でSMB認証を行うユーザに加えない、あるいは加えていたユーザからチェックを外すと、このNT Hashは消されて、NULデータで上書きされる(図15)。

図15: システム環境設定の上でSMB認証を行うユーザに加えない、あるいは加えていたユーザからチェックを外すと、このNT Hashは消されて、NULデータで上書きされる

これがShadowHashファイルの実態である。

注3: ShadowHashはMac OS X 10.3 Pantherにて採用されたパスワードの管理方法で、Jaguarにて使われていたLocalWindowsHashを引き継ぐもの
10.0、10.1および10.2でSMBによるファイル共有を行わないユーザについては、NetInfoに格納されたUNIXと同じCryptによってハッシュされたパスワードを利用していた。

注4: NTLM認証
実際にはNTLM認証にはバージョン1とバージョン2という2つの認証があるが、ここではバージョン2であるNTLMv2を想定している。

注5: すぐに生のパスワードは計算では導けるわけではない
もちろん、このダイジェスト値が盗まれれば、より高速かつ効率的な攻撃が可能となるため、この値を読まれないようにすることはセキュリティを保つためには必須となる。

注6: Leopardの場合
ShadowHashはPanther、Tiger、Leopardで若干内容が異なっている。この説明はLeopard、それも10.5.0ないしは10.5.1でしか確認されていないことに気を付けよう。

注7: rainbow table
rainbow tableとは、あらかじめパスワードのダイジェスト値を計算しておき、それと比較することで生パスワードを手に入れようというもの。事前のテーブルの作成は非常にコストがかかるが、クラッキング時は単なるテーブル参照で済むため極めて高速になる。saltがある場合は、例え同じパスワードでもsaltの値でダイジェスト値が変わりうるため、より大きなテーブルが必要になる。SALTED-SHA1の場合、4バイトのため2の32乗の範囲、同じパスワードでも約43億通りのダイジェスト値が存在しうる。