はじめに
ironCTF 2024のWebセクションに挑戦した記録です。初の表彰台(チーム内)で非常に嬉しい経験となりました。一部の問題は知識重視の「唐」な出題もありましたが、学びが多くありました。
順位表
| ユーザー名 | スコア |
|---|---|
| LamentTyphon | 2468 |
| Jerrythepro123 | 2610 |
| Dragonkeep | 483 |
問題一覧
- JWT Hunt
- Mango
- Loan App
- b64SiteViewer
- cerealShop
- MovieReviewApp
JWT Hunt: シークレット復元チャレンジ
JWTトークンの署名鍵が4つの部分に分割され、それぞれ異なる場所に隠されていました。スキャナ使用禁止という制約がありましたが、手動探索が求められます。
- パート1:
/robots.txt内に記載 - パート2: HTTPレスポンスのCookieヘッダー
- パート3:
/sitemap.xmlの中に存在(スキャナ不要だが発見が難しい) - パート4: 直接
curl /secretkeypart4を実行して取得
全パートを結合すると、完全なシークレットキーが得られます:
6yH$#v9Wq3e&Zf8LpRt1%Y4nJ^aPk7Sd2C@mQjUwEbGoIhNy0T!BxlVz5uMKA#Yp
このキーを使って、以下のペイロードを持つ管理者用JWTを生成します:
{
"username": "admin",
"exp": 1728200262
}
最終的なトークンをCookieに設定しアクセスすることで、フラグを獲得。
フラグ: ironCTF{W0w_U_R34lly_Kn0w_4_L07_Ab0ut_JWT_3xp10r4710n!}
Mango: 誘導と誤解
タイトルからMongoDBインジェクションを連想させますが、実際は単純な罠でした。脆弱性テストを行う前に、/admin/index に直接アクセスすると、フラグが即座に表示されます。
フラグ: ironCTF{I_Said_M@nG0_Not_M0ngo!}
Loan App: HAProxy 組み合わせ攻撃
HAProxyの設定ファイルを確認すると、/admin パスへのアクセスがブロックされています。しかし、CVE-2021-40346 として知られるHTTPリクエストスメラッシュ(Request Smuggling)の脆弱性を利用可能です。
ただし、本問ではより簡便な別解が存在しました。UUID検証関数に関するStack Overflowの記事を検索し、特定の形式のUUID(例: fbd3036f-0f1c-4e98-b71c-d4cd61213f90)を入力すると、バックエンドのチェックを通過してフラグが返却されました。これは非予期されたショートカットでしたが、現実のCTFではよくあることです。
b64SiteViewer: SSRF + RCE 環境構築
提供されたFlaskアプリケーションにはSSRFおよびRCEの脆弱性があります。特に/adminエンドポイントは、ループバックアドレスからのアクセスに限りOSコマンド実行が可能。
SSRFフィルタを回避するため、IPv4アドレス127.0.0.1を16進表記0x7f.0.0.1に変換して利用します。
RCE側では、コマンド名にシングルクォートやダブルクォートが含まれないよう制限されています。また、cmd_blacklistにより特定の文字列もブロックされます。このフィルタはバックスラッシュによるエスケープで簡単にバイパス可能です。
以下のURLにアクセス:
http://0x7f.0.0.1:5000/admin?cmd=en\\v
Base64エンコードされた応答をデコードすると、環境変数に格納されたフラグが含まれています。
フラグ: ironCTF{y0u4r3r0ck1n6k33ph4ck1n6}
cerealShop: PHP反シリアル化脆弱性
ソースコードは?file=../../../../../sourceで取得可能。PHPのunserialize()関数を使用しており、Adminクラスに__toString()マジックメソッドが定義されています。
目標は、is_admin == 0かつyour_secret === my_secretという条件を満たすオブジェクトを送信することです。ここで、is_adminはmd5ハッシュですが、比較時に整数0と評価される文字列(例: "0")を使うことで、文字列と整数の弱い比較(==)を悪用できます。
さらに、your_secretとmy_secretを同じ参照(ポインタ)にすることで、値の一致を保証します。以下のようなPoCコードでペイロードを生成します:
<?php
class Admin {
public $is_admin = "0";
public $your_secret;
public $my_secret;
public function __construct() {
$this->my_secret = 'dummy';
$this->your_secret = &$this->my_secret; // 参照で連結
}
}
echo base64_encode(serialize(new Admin()));
?>
得られたBase64文字列をcan_you_get_meという名前のCookieに設定し、ページを再読み込みするとフラグが表示されます。
フラグ: ironCTF{D353r1411Z4710N_4T_1T5_B35T}
MovieReviewApp: .gitディレクトリからの情報収集
サイトルートに.gitディレクトリが公開されており、git cloneやgit logなどの操作が可能。履歴を確認すると、過去のコミットに管理者の認証情報がプレーンテキストで含まれていました。
ADMIN_USERNAME=admin_user
ADMIN_PASSWORD=secure_pass_123
これらの資格情報を使用して/adminにログイン後、/admin_panelに移動します。ここにはping機能があり、内部でsubprocess.check_output()が使われています。
IPアドレスは正規表現で厳密に検証されていますが、countパラメータにはサーバーサイドのバリデーションがありません。Burp Suiteなどでリクエストを捕捉し、countを1; cat /flag.txtに書き換えます。
これによりOSコマンドインジェクションが成功し、フラグを取得できます。
フラグ: ironCTF{4lways_b3_c4ar3ful_w1th_G1t!}