Hello there, ('ω')ノ
ねらい
このLABは、登録時のメールドメイン制限(@ginandjuice.shopのみ)を、メールアドレスのパース処理の食い違いを突いて突破します。クライアント(アプリ側)とメールサーバ/ライブラリ側の“どの文字列を本当のアドレスとみなすか”がズレるポイントを使い、検証では@ginandjuice.shopに見せかける一方、実際の送信先は自分の(Exploit Serverの)アドレスにさせます。届いた検証メールのリンクを踏んでアカウントを有効化し、carlosを削除してクリアします。
全体像(ストーリー)
- 登録フォームで@ginandjuice.shop縛りがあるのを確認
- encoded-word(RFC 2047)を使ったエンコード表現でフィルタの“反応”を確かめる(ISO-8859-1、UTF-8はブロックされる)
- UTF-7のencoded-wordはブロックされないことを発見
- UTF-7で@とスペースを埋め込み、見かけは @ginandjuice.shop、実際の送信先は attacker@[自分のExploitサーバ] となる文字列を登録
- メール受信→確認リンクをクリック→ログイン→Admin panelからcarlos削除
事前知識(超圧縮)
- encoded-word:
=?charset?enc?encoded_text?=の形で、メールヘッダ中の非ASCIIを表現(encはQまたはB)。 - パーサ差:アプリ側の“許可ドメイン判定”と、MUA/MTA/メールライブラリ側の“最終的に送る先の決定”が一致しないと、検証は通るが送信先は別という状況が生まれる。
- UTF-7:歴史的事情から一部の処理系が危険性の検出を見落とす。PortSwiggerのホワイトペーパーで詳述。
実践:一手ずつ「なぜそうするか」を添えて
1) 制限の確認(基準線づくり)
- 操作:「Register」から foo@exploit-server.net で登録を試す。
- 観察:ginandjuice.shopでないとエラー。
- なぜ:サーバがドメインチェックしていることを把握(どこをすり抜ければ良いかの基準)。
2) エンコード差の実験(どこまで拒否される?)
操作:以下を順に試す(ユーザ名・パスワードは任意)。
=?iso-8859-1?q?=61=62=63?=foo@ginandjuice.shop(abcfoo\@... をQエンコード)=?utf-8?q?=61=62=63?=foo@ginandjuice.shop
- 観察:いずれも“Registration blocked for security reasons.”
- なぜ:サーバは一般的なencoded-wordを警戒してブロックしている模様。
3) UTF-7の手応えを見る
- 操作:
=?utf-7?q?&AGEAYgBj-?=foo@ginandjuice.shopを試す。 - 観察:今回はブロックされない。
- なぜ:サーバ側の検出ロジックがUTF-7には無頓着。ここが突破口。
4) 本攻撃:検証は@ginandjuice.shop、送信は自分宛に
- 使う文字列(メール欄にそのまま貼る):
=?utf-7?q?attacker&AEA-[YOUR-EXPLOIT-SERVER_ID]&ACA-?=@ginandjuice.shop
- これは人間可読では attacker@[YOUR-EXPLOIT-SERVER_ID] ␠ に相当(&AEA- が「@」、&ACA- がスペースのUTF-7表現)。
- 後ろにプレーンな @ginandjuice.shop を付けることで、アプリのドメイン判定はパスします。
一方で、メール側のパーサはencoded-wordをデコードし、スペースまでを実アドレス attacker@[YOUR-EXPLOIT-SERVER_ID]として扱うため、確認メールはExploitサーバに届くことになります。
操作:フォームでこのメール、任意のユーザー名・パスワードで登録 → 画面のEmail clientを開く。
観察:検証メールがExploitサーバの受信箱に届いている。
次:本文の確認リンクをクリック → アカウント有効化完了。
5) 管理操作でクリア
- 操作:「My account」で今作ったアカウントにログイン → Admin panelへ → carlos削除。
- ゴール:ラボがSolvedに。
仕組みの理解(なぜ起きる?)
- アプリ側:メール文字列の末尾が
@ginandjuice.shopかを緩く判定(あるいは単純な正規表現)。encoded-wordのデコードを十分しない。 - メール側:ヘッダ生成時にencoded-wordを復号→ 途中の@(&AEA-)とスペース(&ACA-)でアドレス区切りとして解釈 → 前半だけが実送信先に。
- 結果:検証は通るが、メールは攻撃者宛に飛ぶ=確認フローを乗っ取れる。
つまずきポイント&対処
登録が弾かれる
- 文字列をそのまま貼っているか(余計な空白や改行、全角化に注意)。
- クライアントサイド検証が邪魔なら、BurpでIntercept→サーバ側に投げる値だけ差し替え。
メールが来ない
- YOUR-EXPLOIT-SERVER_ID を正しく置き換えたか。
- ExploitサーバのEmail clientを開き直す(自動更新されない場合あり)。
リンクを踏んでも未有効
- 一度登録やり直し(同じユーザー名が使えない場合は末尾に数字)。
- アクセス時にCookieやセッションが切れていないか確認。
防御の勘どころ
- ヘッダ前提のエンコードを“アドレス入力”で許さない(
=?...?=を拒否)。 - 検証は正規化後に実施:encoded-word/各種エンコード(UTF-7含む)をまず完全にデコードし、単一の正規表現で
local-part@allowed-domainを厳格判定。 - メール送信側でも検証:最終的に送る直前のアドレスに対して、許可ドメイン再チェック。
- ライブラリ差異のテスト:実際のMTA/MUA/言語ライブラリでプロパティベーステストを回す。
- UTF-7の全面無効化:受入力のUTF-7検知と拒否。
コピペ用ペイロード
手応え確認(UTF-7でブロックされないか)
=?utf-7?q?&AGEAYgBj-?=foo@ginandjuice.shop
本攻撃(検証パス+実送信は攻撃者)
=?utf-7?q?attacker&AEA-[YOUR-EXPLOIT-SERVER_ID]&ACA-?=@ginandjuice.shop
※ [YOUR-EXPLOIT-SERVER_ID] を自分のIDに置換。
まとめ
肝は、“アプリの検証”と“メールの最終送信先決定”の解釈差を作ること。今回はUTF-7のencoded-wordを使い、@ とスペースを“見えにくい形”で埋め込んで、検証は@ginandjuice.shopに見せ、送信は攻撃者宛に分岐させました。
手順は、制限確認 → エンコード差の実験 → UTF-7で成功する形を確立 → 攻撃ペイロードで登録 → メール確認 → ログイン → carlos削除。 この“パーサの差異”は想像以上に頻出。入力は正規化してから検証、送信直前にも再検証を徹底することが防御の基本です。
Best regards, (^^ゞ