デジタルペンテスト部でペネトレーションテストを担当している小松奈央です。
ペネトレーションテストを実施する中で、ほぼ必ずと言ってよいほど検出される問題に「パスワードの強度に関する指摘事項」があります。 これは一言で言えば弱いパスワードが使用されているという問題であり、ペンテスター(攻撃者)の観点からすれば非常に悪用が容易、かつシナリオの達成(攻撃目的の達成)に直結することも多いことから真っ先に狙う脆弱性です。
しかし、ペネトレーションテストの中でパスワードの強度を確認する際には、気をつけなければならないことがあります。 それは、アカウントロックです。
これは、本番環境で実施することが多いペネトレーションテストにおいて、アカウントロックを発生させてしまうと、テスト対象組織の実業務に影響を及ぼしてしまう可能性があるためです。
アカウントロックは、一定の回数認証に失敗するとアカウントがロックされサインインできなくなる機能です。 しかし、Windows(Active Directory)の場合、認証の方法によっては(見かけ上)1回の認証試行でも内部の認証失敗回数カウンタが2以上増加し、想定より少ない回数の認証試行でもアカウントロックが発生することがあります。 そこで本記事では、ペネトレーションテストで用いられる認証方法とActive Directoryにおけるアカウントロックの関係1について調査した結果を解説します。
注意:本記事の内容によってトラブルなどが発生した場合でも、当社は一切の責任を負いかねます。また、本情報の悪用はしないでください。
Active Directoryにおけるアカウントロック
アカウントロックの設定方法
まず、Active Directoryにおけるアカウントロックの設定方法や、設定の確認方法について簡単に説明します。
Active Directoryにおけるアカウントロックはグループポリシーから設定します。
Computer Configuration > Policies > Windows Settings > Security Settings > Account Policies > Account Lockout Policy
以下の3つの設定が可能です。
- Account lockout duration
- アカウントロックが解除されるまでの時間(分)。0の場合、時間経過でロック解除されないため、システム管理者によるロック解除が必要。
- Account lockout threshold
- アカウントロックが発生するサインイン試行失敗回数のしきい値。0の場合、アカウントロックは無効。
- Reset account lockout counter after
- サインイン試行失敗回数がリセットされるまでの時間(分)。
これらの設定はクライアント端末からgpresult.exe
などを用いて確認することができます。
なお、アカウントロック関連の設定を確認するためには管理者権限が必要です。
PS C:\> gpresult.exe /h gpo.html
サインイン試行失敗回数の確認方法
ドメインアカウントによるサインインに失敗すると、当該ドメインアカウントのbadPwdCount属性の値が加算されていきます。
この値が上記Account lockout threshold
の値に到達すると、アカウントがロックされる仕組みになっています。
各ドメインアカウントのbadPwdCount属性の値は以下のコマンドで確認できます。
PS C:\> $User = "<UserName>" PS C:\> (([adsisearcher]"samaccountname=$User").FindAll().Properties).badpwdcount
ペネトレーションテストにおけるパスワード強度の確認方法
ペネトレーションテストでは、単一のドメインアカウントに対してパスワードを推測し、手動による認証でサインインを試みることはもちろん、複数のドメインアカウントに対してツールやスクリプトを使ってブルートフォース攻撃(MITRE ATT&CK:T1110.001)やパスワードスプレー攻撃(MITRE ATT&CK:T1110.003)と呼ばれる手法を用いることも多いです。
以下に手動による認証の方法や、有名なツールの例を記載します。
- Kerberos認証
- runas.exe
- Wndowsに標準で組み込まれているプログラムであり、他のユーザの権限でプログラムを実行することが可能です。Linuxにおける
su
コマンドに似た機能を提供します。
- Wndowsに標準で組み込まれているプログラムであり、他のユーザの権限でプログラムを実行することが可能です。Linuxにおける
- Kerbrute(GitHub)
- Kerberos事前認証を用いて、ドメインアカウントに対してブルートフォース攻撃やパスワードスプレー攻撃を行うGo言語製のツールです。
- runas.exe
- LDAP認証
- System.DirectoryServices.DirectoryEntryクラス
- PowerShellからDirectoryEntryクラスを呼び出すことでLDAP認証を行い、Active Directoryに対してLDAPによる検索・問い合わせを行うことが可能です。
- DomainPasswordSpray(GitHub)
- LDAP認証を用いて、ドメインアカウントに対してパスワードスプレー攻撃を行うPowerShellスクリプトです。内部ではDirectoryEntryクラスを使っています。
- System.DirectoryServices.DirectoryEntryクラス
各認証方法におけるbadPwdCountの増加数調査
調査に使用した環境
調査にあたって、Hyper-V上に以下のような検証環境を用意しました。
構築にはAutomatedLabを使用しており、グループポリシーなどの設定はデフォルトの状態から変更していません。
AutomatedLabについては過去に当ブログでも解説しています。 興味のある方はぜひこちらも読んでみてください。
調査結果
runas.exe(Kerberos認証)
- /netonlyオプションなし
runas.exeの実行1回(誤ったパスワードを入力)につき、badPwdCountは1ずつ増加しました。
通信を確認してみると、実際にKerberos事前認証に1度だけ失敗していることがわかります。
- /netonlyオプションあり
runas.exeに/netonly
オプションを付与して実行してみます。この場合、runas.exeを実行したタイミングでは認証は行われず、ネットワーク経由で何かしらのリソースへアクセスする際に認証が発生します。
dirコマンドによってドメインコントローラの管理共有へアクセスすることで認証情報の正誤を確認した場合、badPwdCountが3~12程度増加しました。
badPwdCountの増加量が変動する正確な理由は分かりませんでしたが、通信を確認する限り少なくとも6回Kerberos事前認証に失敗していました。
Kerbrute(Kerberos認証)
Kerbruteは1つのユーザ名とパスワードの組み合わせに対して、Kerberos事前認証を1度だけ行う仕様になっているため、badPwdCountは1ずつ増加しています。
DirectoryEntryクラス(LDAP認証)
PowerShellからDirectoryEntryクラスを呼び出す方法は少しやっかいで、その呼び出し方によって結果が異なりました。
本記事では例として以下の2つのパターンを記載していますが、方法によってはまた別の結果になるものもありました。
- 直接インスタンスを作成する
以下のコマンドでPowerShellからNew-Object
によって直接インスタンスを作成した場合、インスタンス作成のタイミングで認証が発生し、badPwdCountが3ずつ増加しました。
PS C:\> $User = "<UserName>" PS C:\> $InvalidPass = "<InvalidPassword>" PS C:\> $CurrentDomain = [string](([adsisearcher]"objectclass=domain").FindAll().Properties).adspath PS C:\> New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain, $User, $InvalidPass)
通信を確認してみても、LDAP認証に3回失敗していることがわかります。
- インスタンスを変数に格納し、変数のプロパティへアクセスする
以下のコマンドでNew-Object
によって作成したインスタンスを1度変数に格納し、変数のプロパティへアクセスする方法で認証を行いました。
PS C:\> $User = "<UserName>" PS C:\> $InvalidPass = "<InvalidPassword>" PS C:\> $CurrentDomain = [string](([adsisearcher]"objectclass=domain").FindAll().Properties).adspath PS C:\> $Check = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain, $User, $InvalidPass) PS C:\> $Check.Name
直接インスタンスを作成する方法とは異なり、インスタンスを変数に格納したタイミングでは認証は行われず、変数のプロパティへアクセスしたタイミングで認証が発生し、badPwdCountは1ずつ増加しました。
DomainPasswordSpray(LDAP認証)
DomainPasswordSprayはDirectoryEntryクラスのインスタンスを変数に格納し、変数のプロパティへアクセスするという上記と同様の方法を採用しているため、結果も上記と同様でbadPwdCountは1ずつ増加しました。
調査結果のまとめ
調査結果をまとめると以下のようになります。
認証プロトコル | 認証方法 | オプション等 | badPwdCount増加数 |
---|---|---|---|
Kerberos | runas.exe | /netonlyなし | 1 |
/netonlyあり | 3~12 | ||
Kerbrute | 1 | ||
LDAP | DirectoryEntry | 直接インスタンスを作成 | 3 |
インスタンスを変数に格納 | 1 | ||
DomainPasswordSpray | 1 |
上記の結果から、パスワードの簡単な確認方法としてはrunas.exe /noprofile
(/netonlyなし)か、DirectoryEntryクラスのインスタンスを変数に格納し、プロパティの変数へアクセスする方法のどちらかが良さそうです。
逆にパスワードの確認方法としてのrunas.exe /noprofile /netonly
はかなり危険で、インタラクティブシェルを起動した時点ではパスワードの正誤がわからない上に、アカウントロックのしきい値が小さい場合1発でロックされてしまう可能性があります。
なお、本調査の結果はあくまで上記検証環境での結果をまとめたものであり、別の環境では結果が異なる可能性があります。 実際の業務でパスワード強度を確認する際は、badPwdCount属性の値を都度確認しながら慎重に認証を試行することが重要です。
おわりに
本記事では、異なる認証方法におけるbadPwdCountの増加数について調査した内容を解説しました。
ペネトレーションテストにおいてアカウントロックの可能性を完全にゼロにすることは難しいものの、弊社ペネトレーションテストサービスでは本記事のようにWindowsの挙動を調査し、アカウントロックの可能性を少しでも減らすための工夫をしています。
また、本記事が世の中のセキュリティエンジニアやペンテスターの参考になり、アカウントロックによるインシデントが1件でも減れば幸いです。
- ペネトレーションテストにおいてパスワードの強度を確認する方法は、大きく分けて「実際に認証を行う方法」と「パスワードハッシュ値を入手して解析する方法」の2つがあります。本記事では前者の方法を扱います。後者の方法は実際の認証を行わないため、アカウントロックが発生することはありません。↩