⛓️

【CODEBLUE2025 recap】SSRFの連鎖によるAzureテナント侵害

に公開

この記事は?

CODEBLUE2025の公演内容のrecap記事。

気になった公演の詳細を振り返る。

Azureに深刻なSSRF脆弱性が見つかった件

今回のrecap対象は

クラウド全体への汚染拡大:SSRFの連鎖によるAzureテナント侵害 (CVE-2025-29972)

SSRF(Server Side Request Forgery) といえば内部ネットワークの信頼を逆手にとり、外部から内部情報を参照させることができてしまうという脆弱性。

例えば内部サーバーからのリクエストであることHTTPヘッダ X-Internal-Request: true の有無によって識別し、

内部リクエストであると判断された場合にユーザー機密情報をレスポンスするという作りになっていた場合、これを外部からリクエストしても同じようなレスポンスが帰ってくる際にサーバーはSSRFに対して脆弱となってしまう。

外部からその内部情報を参照することができれば、攻撃が成立し、「機密情報の漏洩」や「権限昇格」に繋がる恐れがあり、この脆弱性が発覚した際には影響度は大きく評価される。

公演の内容はこれがAzureにあることが発見されたというもの。

Vladimir Tokarev 氏により、発見過程とその先でどこまで影響があるか調査したものが語られた。

本記事では

  • 要点のまとめ
  • それぞれのステップの解説

を行い、いかにAzureのサービス間信頼が乗っ取られたか見ていこうと思う。

脆弱性の要点

どのサービス/コンポーネントに存在した脆弱性か

Azure Storage Resource Provider (以降SRP) に存在する、外部入力を信頼しすぎた内部サービスプロキシ機能における SSRF の脆弱性(CVE-2025-29972)である。

漏洩した情報

SSRFを通じて、SRPが信頼するコンテキストで生成されたテナントのAAD (Azure Active Directory) アクセストークンを獲得した。

影響範囲

マルチテナント環境にわたる境界越え攻撃が可能となった。

低権限の認証済みプリンシパルから開始して任意テナントに対する侵害が確認され、最終的にSFTPサービスのパスワード再生成を外部から実行できた。

発表者が強調していたポイント

外部入力を用いたアイデンティティ解決プロセスにおける過剰な信頼の危険性

管理系操作(パスワード再生成、キー再発行)の権限・監査体制の重要性

詳しい説明に入る。

Step.0 Azureサービスの概要

登場する Azure サービスについて整理する。

ARM(Azure Resource Manager)

ARM は、Azure 全体で リソースを作成・更新・削除するための統一 API を提供するレイヤー。
ユーザーや CLI/Portal からの操作はすべて ARM を経由し、ARM が裏側で各 Resource Provider(RP)に処理を振り分ける。

SRP(Storage Resource Provider)

SRP は ARM の裏側で動く バックエンドの Resource Provider。
ストレージアカウントというリソースを実際に 作成・変更・管理する実体 が SRP になる。

SRP の主な役割:

  • ARM からの要求を受け取り、ストレージアカウントを作成する
  • 冗長性、アクセス層、ネットワーク制限などの設定変更を処理する
  • ストレージリソースに関わる管理 API を提供する

つまり「ARM の指示に従ってストレージアカウントを動かす下位サービス」が SRP

Encryption Scope

Azure Storage(主に Blob Storage)に対して、暗号化キーの適用範囲を細かく制御できる仕組み

Storage Accountは複数の Encryption Scope を持てる

SRPが作成や更新を処理する

IRP(Identity Resource Provider)

IRP は、Azure 内部で Identity に関するメタデータやトークン取得を担当する RP。

Step.1 SSRFの誘発

静的解析

まず静的解析でコードを調査をする中で、SRPのEncryption Scopeに関する実装に問題が見つかった。

(研究者がSRPのコード内部を調査できたのは、彼がMicrosoftに在籍中にネットワークセキュリティ研究チームに所属していたからだそう)

ProcessEncryptionScopeという関数にてリソースプロバイダーから渡される引数の検証が抜けていたという

この実装は当時以下のようになっていた。

  • encryptionScopeというオブジェクトが渡される
  • Storage Accountのメタデータ取得のためこのプロパティからidentityUrlを取り出す

メタデータ取得の関数は以下のようになっていた

  • リクエストして401かつWWW-Authenticateヘッダーがあればその内容をパースしてauthorizationとresorceの二つのパラメータを抽出。これはトークン生成に用いる。
    • authorization: トークンを発行する認証機関(オーソリティ)のURIとテナントIDを含んでいる
    • resorce: 生成されるAADトークンのオーディエンス(トークンを受け付けるサービスエンドポイント)、OAuth2のaudに似ている
  • パラメータからトークンを取得
  • トークンをAuthorizationヘッダーに追加して改めてメタデータをリクエスト
  • 取得したメタデータをデシリアライズして呼び出し元に返す

ここで攻撃者視点に立つとどんなことができると予想されるだろうか。

identityUrlに攻撃者が自身のURLをインジェクションできる場合、攻撃者自身が用意したドメインへSRP内部からのリクエストを漏洩させることができるかもしれない。

また、自身のサーバーからの401レスポンスにてauthorizationをテナントIDを侵害対象にしたり、resorceを広範囲のオーディエンスに設定できそうだ。

トークンの漏洩

実際に発見者はIRPを模したサーバーを用意し、作成したEncryption ScopeのidentityUrlを自身のドメインにする不正リクエストを送信した。

受け付けるサーバーでは前述のようなレスポンスを返すようにしたところ以下のフローとなった

  1. SRPは指定されたURLに対して最初のGETリクエストを送信
  2. 攻撃者が制御するサーバーで、IRPの動作を模倣し、ステータスコード401と細工されたのWWW-Authenticateヘッダーを応答として返す。
  3. SRP内部のロジックは、このWWW-Authenticateヘッダーからパラメータを抽出し、それに基づき、AADトークンを生成
  4. SRPは、生成したこのAADトークンをAuthorizationヘッダーに含め、2回目のGET/POSTを攻撃者の用意したサーバーに送信してしまう。

これで内部のAADトークンを容易に取得できてしまった。

静的解析で予想された動きは動的解析でも再現し、SSRFの攻撃が成功している。

これは内部ネットワークを前提とした認証フローであるのに対して実装が外部エンドポイントにも送信できるようになっていたことに起因している。

ここまでがSSRFの脆弱性であるが、問題は取得できたAADトークンがどこまでクラウド内部を侵害できるかというところ。

研究者は次のステップとして、このAADトークンを使用して内部のサービスにどこまでアクセスできるかということになる。

Azureのインフラストラクチャは、ネットワーク信頼境界 (Network Trust Boundary)によって厳重に保護されている。Azure内部のコンポーネントは、一般のテナントや外部インターネットから直接アクセスできないようにネットワーク隔離とセグメンテーションがなされているため、

外部の攻撃者がこの強力なトークンを使ってAzure内部のエンドポイントを叩こうとしても、リクエストがブロックされてしまう。

このネットワークの壁を突破するため、攻撃者はトークンを外部から内部へ利用するのではなく、SRP自身に内部から内部へリクエストを送信させる必要がある

この手法として攻撃者のタイミングで内部リクエストを発生させる方法である DNSリバインディング を試行することとなる。

Step.2 DNSリバインディング

DNSリバインディングとは

この攻撃手法の詳しい解説はUnit42の記事を参考にするとして、簡単な解説をすると、

DNS問い合わせにTTL=0での応答をするとキャッシュが行われずに、リクエストの度にDNS問い合わせが発生する。

この時に2回のリクエストで違うIPを応答させるというものだ。

1回目ではDNSがattacker.comのIPで返され、HTTPレスポンスの内容では再度attacker.comにリクエストを発生させるようなものにする。

TTL=0のため再度DNS問い合わせがくるが、そのIPをリクエスト元ネットワークの内部IPにする。

すると内部リクエストが攻撃者のタイミングで発生してしまうというものだ。

内部情報の漏洩はどうするのかという疑問があるが、この攻撃では攻撃者が内部ネットワークのリクエストをトリガーできるという部分に意味がある。

attacker.comのレスポンスに2回目以降のリクエスト内容を外部に漏洩させるスクリプトを混入すれば漏洩の可能性もある。

一筋縄では行かない理由

発表ではIRPサーバーのドメインに独自実装のDNSサーバーも用意している

先ほどのSSRF時にAADトークンをSRPが送るタイミングでDNSを内部IPに切り替え応答し、SRPからの内部リクエストを発生させるようになっている

実際これが次の攻撃ステップにつながりそうだが、発表内のデモにもある通り、これは失敗した

DNSリバインディングを阻んだもの

これはDNSキャッシュの影響になる。

DNSキャッシュは、クライアント(ブラウザ・OS)やネットワーク機器が、一度解決したDNS応答を一定時間保持し再利用する仕組み

DNSが毎回インターネット全体へ問い合わせると遅延や負荷が増えるため、ほとんどの実装は積極的にキャッシュを行う

しかし DNSリバインディング攻撃は本質的に 「短時間で同一ホスト名に対し異なるIPアドレスを返す」 ことを前提としている。

攻撃者は初回アクセス時には外部IPを返し、SSRFが発生する瞬間だけ内部IPへ返答を切り替える必要があるが、最初のDNS応答をキャッシュしてしまうと、どれだけDNSを内部IPへ切り替えても、クライアント側は新しいIPへ再解決しない。結果として、SRPは内部IPに対してリクエストを送らず、攻撃チェーンはそこで途切れてしまう。

DNSキャッシュの回避策

DNS レコードの TTL は短く設定できても、クライアント側のキャッシュ保持タイミングまではコントロールできない。このため、研究者はDNSクエリをSRPへ一定間隔で送信し続け、そのうちのどれかがTTL切れの瞬間に当たるかを調査した。

この手法はDNSリバインディング対策の回避策として

  • TTLを短く設定(数秒未満)
  • バックエンドのリゾルバに対して高頻度のAレコード照会を連打
  • どこかのタイミングで「キャッシュが切れる時」に内部IPをリバインドさせる

というものだ。

15秒間隔で、SSRFを誘発するリクエストを送ることでキャッシュ時間を推測する。

キャッシュが有効ならば2回とも攻撃者のサーバーにリクエストが届くが、キャッシュが切れたタイミングで内部IPにリバインドできた場合は攻撃者のサーバーに1回目のリクエストしか届いていないことから検知ができる。

ここから研究者はキャッシュが5分であることを割り出すことができており、最初のSSRFを起点に5分後に SRP to 内部エンドポイント のリクエストを成功させられることが示されていた

この方法は発表ではSpray&Pray4Bindと呼ばれていた。

説明がなかったので調べたところ、Spray&Prayとは、壁にスパゲッティを投げて何がくっつくかを見る方法のこと。「大量にぶっ放して、祈る」、つまり日本語で言うと「数うちゃ当たる」

Pray4Bindなのでバインド成功を祈るものだ。しかしキャッシュ期間が固定なので運任せなものではなく、立派な攻撃試行である。ちなみに15秒ではSprayしている感覚はない。

Step.3 SRPを踏み台に

SRP to SRP

AADトークン付きの内部ネットワークにSRPからリクエストを発行する。これを攻撃者が実行できるという環境が整ったことで、

外部テナントへの不正リクエストを攻撃者が行えるになってしまった。

公演ではほかテナントのSFTPパスワード再生成を実行することが可能となった。

これには事前にAzure Storageの アカウント名・サブスクリプションID・リソースグループ名・ユーザー名などを取得して置く必要があり、実現性は低い

さらにSRPを踏み台にし、「Azure全体を好き放題」... とはならず

侵害は SRP to SRP のストレージ間レベルで止まったという。

この“食い止めた要因”は、Azureの複数の境界・制約の多層防御にあると解説されている

多層防御

  • トークンスコープの制約
    漏洩させたAADトークンは「SRP用(特定リソース用)」として発行されていた。
    つまり「同じAADトークンでも、サービスごとに期待される audience やスコープが違うため、他RPの管理APIの多くは弾かれ、SRP→NRP→他サービス…と芋づるにすることは不可能であった

  • ネットワークの分離とアクセス制御
    Azure内部では、RPごとにネットワークセグメントやファイアウォールルールが細かく引かれており、「SRPから見えている世界」はかなり限定されている
    そのため、「とりあえず何でも叩ける」状況ではなく、SRPから到達可能な範囲のうち、かつトークン的にも受け入れられるサービスにしか攻撃は広げられない

  • エンドポイントごとの追加バリデーション
    各リソースプロバイダーや各エンドポイントには、呼び出し元やリクエスト内容に対する個別の検証ロジックが多層に入っており、「形式上はHTTPが届いても、条件が揃わないと実際の危険な操作には至らない」ケースが多い

脆弱だったのはどこか

1. 外部URLを ID/メタデータ解決にそのまま流し込む設計

SRP は本来、IRPから暗号化スコープ単位でメタデータを取得する前提で設計されていた。

そのため、メタデータのURLは内部的に高い信頼を置く場所だったが、

テナントが制御可能なURLをそのまま渡す仕様になっていた。外部入力がメタデータ解決処理に直結する構造となっており、ここにドメインの検証が抜けていたと言える

2. DNS・キャッシュ前提の IP ベース防御への過信

古典的なDNSリバインディングはDNSキャッシュで防げたが、IPフィルタを導入していた。しかし Spray&Pray4Bind によって、リバインドが成功するようになってしまった。

ここから、DNSリバインディング対策としてキャッシュは根本解決になっていないことがわかる。

修正

修正が行われ、以上に示した脆弱箇所に対策が行われた。

  • 外部入力URLに対して、SRP内部の「想定されるIRPエンドポイント」との形式・構造比較を厳密化し、任意ホストへのSSRFをブロック

  • キャッシュTTLのランダム化

    (これでリバインドが成功したのかキャッシュ中なのか判別ができなくなる)

  • SRP特化のテレメトリ・ログ監視を追加し、不正SSRF試行を早期検知(追加対策)

この中でも根本的なのは最初の項目だろう。

まとめ

外部入力の検証不備に始まるSSRFの解説と、DNSリバインディング対策の回避まで、侵入範囲が徐々に広がる発表であった。

たった1つの関数のURL検証が抜けていただけで、サービスを踏み台にされ、信頼されている内部ネットワークにリクエストを投げられるため、守る側は常に不備だ。

しかし、これがAzure全体に被害が及ばなかったのは多層防御が効いたからであり、

多階層の防御アーキテクチャは、守る側の不備を補完する最後の安全網と言えるかもしれない

Discussion