【論文紹介】HEIST: HTTP Encrypted Information can be Stolen through TCP-windows

この記事は情報セキュリティ系論文紹介 Advent Calendar 2016の20日目の記事です。厳密には「ローカルネットワークでのHTTPSについて関心のある人の間でやっているセキュリティ勉強会」(not正式名称)の8月の回の発表ネタのrewriteです。rewriteで書けそう、とは思ったけれどよく見たら周りはセキュリティ方面で名が知られてる強い人ばっかりだし内容もいわゆる学術論文ばっかりでちょっと間違えたかなーという感じですがまあやってみます。まあセキュリティ研究者がどこらへんを投稿の目標にしているかの指標がわかったのはでかい。


というわけでタイトルの通り、Black Hat USA 2016で発表されたHTTPS脆弱性HEIST: HTTP Encrypted Information can be Stolen through TCP-windows のoverviewです。

TL;DR

  • HTTP, SSL/TLS, TCPとそれに対するブラウザのインターフェースを利用して、cross-origin responseの長さを割り出す手法
  • 圧縮を利用したTLSへの攻撃手法(CRIME, BREACH)をman-in-the-middleなし、ブラウザのみで実行することができる
  • HTTP/2でも同様の攻撃が可能、さらにHTTP/2のほうが攻撃しやすくなる条件もある
  • (とはいえ、「HTTPSは死んだ」とするのは過大広告気味)

何がすごいの?

今までの圧縮ベースのTLS攻撃手法はman-in-the-middleが取れることを前提として成立していた(*厳密には違う)。

  • CRIME - "1st requirement: the attacker can sniff on your network traffic"
  • BREACH - "The Setup. We assume the attacker has the ability to view the victim's encrypted traffic."

この手法はその前提を緩和するための手法。

CRIME攻撃

Compression Ration Info-leak Made Easyの略。

データ圧縮を行うHTTPS/SPDY上を流れるCookieの内容を復元し、セッションハイジャックを実現する。

  • 攻撃者が暗号文の長さを見れること + 同時にブラウザから複数の操作されたリクエストを送れることを前提に、暗号文の長さを利用して平文を割り出す手法

DEFLATE圧縮はLZ77とハフマン符号化を使う。これらは共通の部分文字列があると圧縮が効く。

LZ77の例: Google is so googley -> Google is so g(-13, 5)y

この性質を用いて、「実際のCookie」+「予想」の組み合わせをリクエストし、圧縮が効いたら「予想」の内容は実際のCookie内に存在する!→繰り返して全体を「予想」!

(ほんとはもうちょっと複雑)

BREACH攻撃

Browser Reconnaissance and Exfiltration via Adaptive Compression of Hypertextの略。よく思いつくなあ

CRIME攻撃のHTTPS + HTTP compression(gzip, DEFLATE)に対するヴァリエーション。

CRIME攻撃がHTTP requestに対して攻撃したのに対し、BREACH攻撃はHTTP responseに対して攻撃をする。リクエストの一部がレスポンスに反映される(reflected)ことを利用する。

HEIST攻撃に使われる道具

  • Service WorkersのFetch API : XMLHttpRequestと違い(Eventの代わりに)Promiseを用いる。Promiseの解決はレスポンスの第1バイトが帰ってきた時点。まだストリーミング中のレスポンスに対して操作ができる。
  • TCP Slow Start Algorithm : レスポンスはMaximum Segment Size(MSS)単位に分割され、最初はinitial congestion windowの個数のセグメント分(だいたいの場合10)だけ送信され、ACKが来るごとにcongestion windowを少しずつ大きくして帯域を増やしていく

f:id:sylph01:20161213161136p:plain

(こちらの図は原論文から)

手法の大雑把な概要

  • Promiseの解決と終了のタイミングがわかる(Resource Timing APIを使うと便利)ので、レスポンスにかかった通信時間がわかる
  • これによって、レスポンスが1 windowに収まったか、2 window以上になったかがわかる
  • なので、レスポンスにreflectされるような値の長さを少しずついじって境界値を探ることで、本来のレスポンスの長さがわかる

f:id:sylph01:20161213161125p:plain

2 window以上の場合は?

  • TCP Slow Startにはwindow sizeを増やす方法がある。ACKされたパケット1つにつきcongestion windowは1大きくなる。
  • なので、パケット数xになるよう制御されたリクエストをあらかじめ送っておき、あらかじめcongestion windowの大きさを操作しておくことができる
  • なんとこうすると長さの探索空間は1 window(>= 10 MSS)ではなく1MSS(=1460 bytes)になる

HTTP/2の場合は?

  • HTTP 1.1とはパケットのフレームが違う/送られ方が違うのでオーバーヘッドの計算がちょっと違う
  • settingsフレーム : Apache, nginxのそれぞれの場合で数と長さが予想可能
  • headersフレーム: HPACKによって既に送られた値が1バイトのindexに圧縮されることによって、HTTP 1.1よりも長さが予想しやすいほんとかなあ
  • HTTP/2では複数のリソースを並列にリクエストすることができるため、「ターゲットのリソース」と「reflectionを含むリソース」を並列にリクエストすることができる
  • これらは同じTCP connectionで行われTCP windowを共有する
  • よって、reflectionを含むリソースでTCP windowを消費するよう長さ調整をすることでターゲットリソースの長さを割り出せる

そもそもreflectionがまずいんじゃないの?

  • BREACHで紹介されているOutlook Web Accessの例ではquery stringに入っているidの値がbody中に現れることを利用している
  • 正直この前提がかなり無理やりな気もするが…URLの一部、もしくはリクエストしたURLがbodyに入るのはありがち

実際の攻撃例

  • BREACH攻撃につなげる
  • 検索エンドポイントに対してHEIST + BREACH攻撃をすることで、検索対象にパスワードとかクレジットカード情報が入ってたらそれを抜き出せる
    • クレカ情報をメールに含めるなよという話はさておき…

対策

  • 最も有効な対策は3rd-party Cookieの無効化。攻撃者のサイトを踏んだら3rd-party Cookieの内容を反映するcross-origin requestの中身が抜かれてた、という状況を防げる。
  • そのほかにもいくつかの手法が提示されているが、どれも「完全ではない」とのこと。

私見

  • 既存の攻撃手法の前提を緩めることでその手法が再度注目を浴びる、というのがすごい。特に、"man-in-the-middleが必須です"と紹介されがちなところ、本当は「長さ知るだけで十分」だった、という、既存の攻撃手法の本質を掘り返したのがさらにすごい
  • でもパラメータのreflectionがどれくらいのサイトに有効なのかは微妙な気も。過大広告のきらいあり?

参考文献