stuart attacking http2 implementations truefinal-jp
TRANSCRIPT
HTTP/2実装を攻撃
Stuart Larsen & John Villamil Yahoo! ペンテスト チーム
本日の内容
▪ HTTP2とは ▪ なぜHTTP2は強い? ▪ http2fuzz ▪ ATS ▪ Firefox ▪ NodeJS ▪ まとめ
Stuart Larsen ▪ https://c0nrad.io John Villamil ▪ @day6reak
自己紹介
HTTP/1.1 は1999年に登場
その後に・・・ ▪ HTML と Java Script は進化した ▪ Webサイトは遥かに複雑になった ▪ ISPの回線速度は改善されてより広い帯域幅が提供されている ▪ Web上では遥かに多くのコンテンツが提供されている ▪ SSL は今ではより当たり前に使われている
▪ “HTTP/2よこんにちは、さようならSPDY” http://blog.chromium.org/2015/02/hello-http2-goodbye-spdy-http-is_9.html
▪ HTTP/2 はSPDYおよびSPDY/2から進化したもの ▪ 機能:
› TCP使用の改善 › バイナリプロトコル
• フレームとストリーム › マルチプレキ゚シング (ストリーム)
• かねてから認識されていた遅延を緩和 › サーバからのプッシュ (PUSH_PROMISE) › データ圧縮 (HPACK) › フレーム › その他いろいろ
▪ 大きな攻撃の可能性
HTTP/2 はパフォーマンスのため
HTTP/1.1からのアップグレード
▪ http:// および https:// というURIのスキームを維持 ▪ TLS はオプションとしての位置づけ
› Chrome と Firefox では必須としている › Internet Explorer と curlを含む他のクライアントはオプションのまま
▪ http:// のヘッダーをアップグレード › ラウンドトリップの原因になるが、HTTP/2 接続はより安定している
▪ マイナーバージョン番号は無し
HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: h2c
GET /index.html HTTP/1.1 Host: example.com Connection: Upgrade, HTTP2-Settings Upgrade: h2c HTTP2-Settings: <SETTINGS payload>
HPACK
▪ HTTP はステートレス › リクエストのサイズ (cookies その他のヘッダー) は大きな影響を与える › 圧縮は自然な解決策
▪ “Hpack was designed to make it difficult for a conforming implementation to leak information, to make encoding and decoding very fast/cheap, to provide for receiver control over compression context size, to allow for proxy re-indexing (i.e. shared state between frontend and backend within a proxy), and for quick comparisons of huffman-encoded strings.”
› Roberto Peon, http://lists.w3.org/Archives/Public/ietf-http-wg//2014AprJun/1044.html
▪ レシーバが使用メモリサイズの最大値をコントロール › 最少が0 で最大が 2^32 › SETTINGS フレームで指定
▪ SPDY は圧縮アルゴリズムを使用 › CRIME(Compression Ratio Info-leak Made Easy)攻撃に対して脆弱
HPACK ▪ name:value のペアをインデックスに割り付け
› 双方のエンドポイントにおいてダイナミックテーブルを作成
▪ 差分符号化 › スピードとサイズ圧縮に大きく寄与 › リファレンス・テーブルはヘッダーのためにつくられる
› 現在のヘッダーと直前のものの差分のみが符号化される
› 無駄を除去
▪ ハフマン符号化 › 固定ハフマンテーブル › 文字列リテラル
HPACK 攻撃の可能性
▪ インデックス・テーブルのサイズとオフセット ▪ 文字列リテラルの例
› 1つのビットがハフマン符号化されているかどうかを決定 › 整数はサイズを示す › 文字列データが続く › オクテットの境界まで積み重ねていく
▪ コンテキスト更新 ▪ ヘッダーテーブルのサイズ変更
› デフォルトでは、動的テーブルのサイズは4k ▪ https://tools.ietf.org/html/rfc7541
ATSで手始め
▪ Yahoo ペンテストチームはATS (Apache Traffic Server)を見ることに決定した
Http2ConnectionState.cc
ATS 2 ▪ RFCより - http://tools.ietf.org/html/rfc7541#section-4.3
› 4.3. 動的テーブルサイズ変更時のエントリの削除 動的テーブルの最大サイズが減少するたびに、動的テーブルのサイズが最大サイズ以下になるまで動的テーブルの末尾からエントリが削除されます。
▪ 予期しないパケットの順序のために、 headers テーブルが空の時にテーブルサイズを更新するバグが発生
▪ HTTP/1.1はパイプライン化で複数のリクエストを送ることができる▪ ヘッドオブラインブロッキング
› レスポンスは送信された順に行われなくてはならない
クライアント
サーバ
HTTP/1.1
クライアント
サーバ
HTTP/2
1 34 2
12 3 4
12 3 4
1 2 3 4
マルチプレキ゚シング
フレーム
▪ 通信の基本ユニット
Length (24 bits)
Type (8 bits) Flags (8 bits)
R Stream Identifier (31 bits)
Payload (0+ bits)
▪ フレームタイプ › Headers › Data › Priority › Reset › Settings › Push › Ping › Goaway › Update › Continuation
サーバプッシュ
▪ リソースをクライアントにプッシュする新機能 ▪ 例えば、もし、クライアントが index.html をWebサーバへリクエストしたら、Webサーバは「クライアントは恐らく logo.png も欲しがるだろう」と推測する
› クライアントが logo.png を要求するのを待つ代わりに、サーバは先回りして logo.png をプッシュするので、ユーザはリクエスト全てを待つ必要が無い
HTTP/2 の新しい攻撃の可能性
▪ HPACK▪ アップグレード・ダウングレード▪ つじつまの合わないマルチプレキ゚シング▪ 不正なフォーマットのフレーム▪ クライアントに任意のデータをプッシュ▪ サーバに任意のデータをプッシュ▪ ストリーム依存▪ 無効なフレームの記述
ファジング
▪ ランダムなデータ(バイナリ・アスキー)をアプリケーションに送信して、予期せぬ動きをしないかをモニターする behavior
HTTPをファジング
メソッド
ホスト
パス クエリー フラグメント
ヘッダー
ボディ
http2fuzz ▪ 最初に公開された http2 ファジングツール
▪ golangで開発されている ▪ クライアント・サーバ両方で使用可能
• テストケースの最小化のためのリプレイモード
• 高度なコンカレント機能
http2fuzz: クライアントモード
1. クライアントはWebサーバにhttp接続を確立 2. ALPN セクションでは h2 もしくは h2-14 を指定 3. 初期設定フレームはクライアント・サーバ間を往復する 4. ランダムに生成されたフレームがサーバに送信される 5. テスト対象のサーバがクラッシュしてもリスタートさせてテストを継続
http2fuzz: サーバモード
1. サーバはローカルホストの証明書鍵をTLSようにロード 2. サーバはポートをバインドして接続を待つ 3. コネクションが確立されると、ランダムに生成されたフレームを、ブラウザが接続を終了するまで送信し続ける
▪ ブラウザのファジングに使うスクリプトの例:
› setInterval(function() { $.get(‘https://localhost:8000’) }, 2000)
▪ 正常なフレームと、半分正常なものと、完全に異常なものを混ぜる
▪ 各々のストラテジは異なったフレームを生成する
▪ ストラテジは組み合わせると「ミニ・ファジングツール」になる
ストラテジ http2fuzz
ファジング ツール
ファジング ツール
ファジング ツール
ストラテジ 1
ストラテジ 2
ストラテジ 3
ストラテジ 1
ストラテジ 3
ストラテジ 4
ストラテジ 2
ストラテジ 3
ストラテジ 4
ストラテジ
SettingsFuzzer: ▪ 0から5の間のランダムな値を選ぶ ▪ ランダムな値で構成された多くのランダムな設定をSettingsFrameに付け加える
HeaderFuzzer: ▪ 0から5の間のランダムな値を選ぶ ▪ ランダムな値で構成された多くのランダムなHTTPヘッダーを
HeadersFrameに付け加える
ストラテジ PriorityFuzzer: ▪ PriorityフレームにランダムなstreamDependencysteamId、weight、および、 exclusive valueを設定して送信する
PingFuzzer: ▪ pingフレームにランダムな8 バイトペイロードを設定して送信する
ResetFuzzer: ▪ RSTフレームにランダムな streamIdとerrorCodeを設定して送信する
ストラテジ WindowUpdateFuzzer: ▪ Window Update Frameにランダムな streamId とincr valueを設定して送信する
RawFrameFuzzer: ▪ ランダムなframeType (0-12)、randomFlags (0-256)、
streamId(2**31)、および、 0から10000までの長さのランダムなバイ配列を生成
▪ 上記によって構成された異常なフレームを送信
ストラテジ
DataFuzzer: ▪ Data Frameにランダムな streamIdとendStream bool、そして、0から10000バイトのランダムな長さのペイロードを設定して送信
PushPromiseFuzzer: ▪ PushPromise Frameに0から10000バイトのランダムな長さのペイロード、streamId、promiseId、endHeaders bool、およびpadLengnth (0-256)を設定して送信
ストラテジ
ContinuationFuzzer: ▪ Continuation Frameにランダムな streamIdとendStream bool、そして、
0から10000バイトのランダムな長さのペイロードを設定して送信 RawTCPFuzzer: ▪ TLS接続を確立して完全なガーベージを送信。ぺイロードは0から
10000バイトのランダムな長さの配列。
リプレイモード
▪ ファジングツールがクラッシュを検出したら原因を突き止めなくてはならない
▪ ファジングに使われた各々のペイロードはreplay.jsonに保存される ▪ クラッシュするとファジングツールは停止してファイルも閉じられる ▪ ./http2fuzzを実行 –リプレイはフレームを同じ順序でサーバに送信 ▪ そのため、いくつかのフレームを削除してそれでもなおサーバがクラッシュするかどうかを確かめたり、必要なフレームを見つけ出すまでフレームのセットを絞り込んだりすることができる。
FireFoxにおける不正なHTTP2ヘッダーフレームによるDoS
▪ 不正なhttp2ヘッダーフレームがブラウザに送られる ▪ 通常は、ヘッダーフレームはpad length、steam dependency
identifier、weight、header block fragmentそしてpaddingによって構成される
▪ しかし、たったの1バイトのみが送信される ▪ これによって整数値のアンダーフローが発生し、結果として
nsCStringが約2^32バイトのメモリ割り当てを試みることになる
FireFoxにおける不正なHTTP2ヘッダーフレームによるDoS
Http2Session.cppの1226行目において、圧縮から復元されたフレームを圧縮から復元されたフレームバッファに追加するコールが行われる:
FireFoxにおける不正なPushPromiseアンダーフローによるDoS Http2Session.cppの1634行目において、圧縮から復元されたフレームを圧縮から復元されたフレームバッファに追加するコールが行われる:
= 4294967292
node-http2
▪ バグは見つかったが、状態を確定させるのが難しい
› どのフレームをいつ送るのか
▪ 全てのフィールドを検証する必要がある › 値と大きさ
まとめ
▪ HTTP2とは ▪ なぜHTTP2は強い? ▪ http2fuzz ▪ ATS ▪ Firefox ▪ NodeJS
終わり
質問?