URL Parserに起因する脆弱性
ma.la
概要
URLパーサに起因する脆弱性について
いくつかはまだ未修正
1. URL Parserとは
URLの解釈に関する話
ブラウザやライブラリによって異なるURLと認識される
RFC通りに実装されているとは限らないし、RFCが正しいとは限らない
互換性のため、相互運用性のためにinvalidなURLを許容することがある
例えば
厳格なparserではerror
Java: new URI
Ruby: URI.parse
2. URL誤認による脆弱性
URL Parser自体にバグが有るもの
チェックするタイミングによって問題が起きるもの
SOP bypass
Android でのUXSS
\u0000javascript:xxx でUXSSが可能だった問題
問題の箇所
Open Redirect
WordPressの事例
Bypass A: http:example.com
ホスト名の一致を確認する必要がある
parse_url(url).host == “example.com”
Bypass B: otherprotocol:example.com
javascript://example.com%0A alert(1);
XSS with href, iframe, js refresh, etc.
Oops!
じゃあ、protocolもチェックしましょう
url.protocol == “http” || url.protocol == “https”
Bypass C:
非常に深刻な問題
origin = scheme + host + port
正しい方法でのsame origin判定が失敗する!!
SOP bypass on server-side
host名を誤認するURL
いくつかのライブラリ、言語の標準実装で問題あり
PHP, ■■■■, ■■■■■■■ (reported by mala)
PHP 5.6.28 / 7.0.13 で直っています
cURL (自分の報告ではない)
UPDATE 2017-02
この問題は知られている?
オフレコ
バグか脆弱性かの問題
複数実装に問題があったときの公表方法
正しい実装は?
https://tools.ietf.org/html/rfc3986#section-3.2
The authority component is preceded by a double slash ("//") and is
terminated by the next slash ("/"), question mark ("?"), or number
sign ("#") character, or by the end of the URI.
Authority component
バグが起こりやすい原因
絶対URLと相対パスの両方を同じライブラリで処理
http urlとそれ以外のprotocolも同列に処理
歴史的経緯、相互運用性、互換性のための寛容な処理
user:pass には本来、予約文字が使えない
authority = [ userinfo "@" ] host [ ":" port ]
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
3. 実世界での問題
URL Parserのバグがどのように脆弱性になるか
A: DOM based XSS(client side)
B: Open Redirector → XSS
client side + server side
jQuery mobile + open redirector
最近報告したものがある
jQuery mobileまだ使ってるの?
yes.
CMS製品、デフォルトでjQuery mobile使用+open redirectorあり
非常に広範なwebサイトでXSSが可能だった
オフレコ
C: Open Redirector → Auth bypass
server side.
URL parserバグ起因のものは実際の事例は見つけていない
危なっかしい状態だったものはあり
validation of callback url
OAuth, OpenIDなどのredirect url
domainのみ一致でcheckしていると危険
URL parserがバグっていると。。。
そもそも「ドメイン」丸ごと安全とは限らない
Why?
ホスト名誤認を使って別ドメインに認証コードを送る
オープンリダイレクタとの組み合わせ
referrerで外部に認証コードが漏洩するPathを指定する
Provider実装側
D: SSRF / TOCTOU attack
イントラネットのURLにHTTP requestを送る
管理画面に攻撃コード送る
変換系処理のAPIで内容を取得する
SSRF with URL Parser's bug
URLがintranetのhostではないか確認
→ hostname誤認問題があるparserを使っていると。。。
解釈の違いによって問題が起きる場合がある
そもそも
check と use は異なる実装で行ってはいけない
Time-of-check Time-of-use problem
URLをcheckするタイミング、fetchするタイミング
DNSが変更されている可能性がある
バグをなくすための考え方
check / use で可能であれば同じ実装を使いましょう。
check / use は同じデータを使いましょう。
"Normalize strings before validating them"
HTML parserの問題
以前発表した
<!--> -->
の解釈の違いを使ったXSS
ブラウザの実装と、jsやサーバーサイドで解釈が違う
TinyMCE, etc.
URL Parserの場合
client / server / language 複数の実装が混在するのは必然
need more test case.
終わり
おまけ
各言語のURL Parserの実装について
Ruby
コアモジュール、URI class.
https://github.com/ruby/ruby/blob/trunk/lib/uri/rfc2396_parser.rb
https://github.com/ruby/ruby/blob/trunk/lib/uri/rfc3986_parser.rb
RFCをそのまま正規表現に。
厳格。
Perl
URI moduleの中の URI::_generic を見ると良い
http://cpansearch.perl.org/src/ETHER/URI-1.71/lib/URI/_generic.pm
各partごとに正規表現で定義
内部的には単に文字列で保持
呼び出されたタイミングで指定されたパートを取り出している
Python
https://github.com/python-git/python/blob/master/Lib/urlparse.py
PHP
バグあり。レポート済み。