Instantly share code, notes, and snippets.
Save mala/f86a849d15b2d60d7119e05f33b4b885 to your computer and use it in GitHub Desktop.
This is src doc of my presentation on shibuya.xss #8 (2016-11-14)
The main topic is vulnerabilities related to url parser.
Java/OpenJDKhttp://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/cd0585378c46 (CVE-2016-5552)
Androidhttps://android.googlesource.com/platform/libcore/+/4b3f2c6c5b84f80fae8eeeb46727811e055715ea%5E%21/ (CVE-2016-5552)
cURLhttps://curl.haxx.se/docs/adv_20161102J.html (CVE-2016-8624)
ma.la
- Flash and CORS
- URL Parser
- Malicious Chrome Extensions
- Hmm, I can't choose one.
- There is many differences JS and Flash about crossdomain policy.
- Many developers don't know exactly CORS policy.
- Crossdomain image loading as "data" without crossdomain.xml is vuln, but Flash developers say it is "Hack".
- Today, it is clear whether it is a spec or bug by CORS.
- 1 year ago, I've reported BAD spec of Flash as vulnerability.(not fixed yet)
- SOP bypass that can leak content-length, redirect or not.
- https://gist.github.com/mala/8e822f2e292d8db68e288ac935025c71
- Some people making noise "Chrome extension became malware!", so I've investigated.
- I've downloaded TOP5000 extensions and investigated it.
- Malicious extension load external script by obfuscated js
- 0.7% of TOP 5000, some were already removed from webstore.
- Some were destroying CSP header by webRequestBlocking permission.
- https://gist.github.com/mala/e87973df5029d96c9269d9431fcef5cb
ma.la
----# Summary- vulnerabilities regarding URL parsers- not fixed yet in some libraries- see My URL isn't your URL
- https://daniel.haxx.se/blog/2016/05/11/my-url-isnt-your-url/
- the same url brings different result depend on browsers and libraries
- some implementations follow RFC but the others are not
- RFC is different from the real implementations
- for compatibility reason, browser/server may accept invalid URLs.
- http://example.com/#hash#in#hash
#
in location.hash- valid or invalid?
- Java: new URI
- Ruby: URI.parse
- bugs in URL parser itself
- bugs regarding the time of check
- https://android.googlesource.com/platform/external/webkit/+/7e4405a7a12750ee27325f065b9825c25b40598c%5E%21/
- check logic for #"noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5f7b6ce58ec86b2c761565a148b3d74c9741e9c4b2bc2362dc68936b8a2f367f/68747470733a2f2f692e6779617a6f2e636f6d2f62386163383139623864303562333862663537373166323064653731383830652e706e67">
- http://homakov.blogspot.jp/2014/01/evolution-of-open-redirect-vulnerability.html
- //example.com
- /\example.com
- http:example.com
- CVE-2016-2221
- https://core.trac.wordpress.org/changeset/36444
- Open redirect vulnerability in the wp_validate_redirect
- parse_url doesn't return hostname
- browsers returns the same result ashttp://example.com
- parse_url(url).host == “example.com”
- then, check protocol!
- url.protocol == “http” || url.protocol == “https”
- http://evil.example.com#@example.com/
- hostname of this url is
- browsers: evil.example.com
- PHP 5.6: example.com
- origin = scheme + host + port
- your code is not wrong, but "origin" may be failure
- SOP bypass on server-side
- I found same bugs on the default URL parser of major languages/platforms
- PHP, ■■■■, ■■■■■■■ (reported by mala)
- fixed: PHP 5.6.28 / 7.0.13
- cURL (not my work, but got hint from bug report of PHP?)
- Java/Android (java.net.URL) has been fixed CVE-2016-5552
- Java : 2017-01http://www.oracle.com/technetwork/security-advisory/cpujan2017-2881727.html
- Android : 2017-02https://source.android.com/security/bulletin/2017-02-01.html
- http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/cd0585378c46
- https://android.googlesource.com/platform/libcore/+/4b3f2c6c5b84f80fae8eeeb46727811e055715ea%5E%21/
- caution! not fixed yet in major implementations
- but, disclosed already, PHP and cURL
- https://curl.haxx.se/docs/adv_20161102J.html CVE-2016-8624
- this is a bug of INTERNET
- bugs or vulns?
- disclosure timing?
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.
- user:pass@example.com part.
- should be terminated always / or ? or #
- always!
- they handle absolute URLs and relative URLs in a same library
- they handle http URLs and other schemes in a same library
- historical reason, compatibility, fuzzy liberal parser
- originally, user:pass can't contain reserved chars
authority = [ userinfo "@" ] host [ ":" port ]userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
- URL parser's bug → vulnerability
- CVE-2012-3695
- http://masatokinugawa.l0.cm/2012/08/safari-location.href.html
- location.href of WebKit based browsers
- http://siteA.example.com%2F@siteB.example.com/
- percent decoded in host. location.href returns different host
- same origin detection fails, and loads external resources
- client side + server side
- jQuery mobile + open redirector
- http://jqm-site.example.com/#!/path/to/redirect_other_website
- Too old problem, I've reported/blogged this issue at 2011
- but I found the same case recently
- Certificate Transparency log of my domain
- https://www.google.com/transparencyreport/https/ct/?hl=ja#domain=ma.la&incl_exp=false&incl_sub=true
- let's encrypt for open redirector, example.com.evil.com case
- server side
- I've never seen any cases in the real world
- but there would be cases
- redirect url of OAuth, OpenID
- check only hostname is dangerous
- with URL parser's bug
- and "trusted by domain" is dangerous
- with vulnerable parsers and crafted URL, sending authentication code to wrong host is possible
- if there is an open redirector.
- if callback url contains external resources/links, referrer header leaks auth code/token
- do not use "startWith" for verifying urls. Use exact match.
- redirect_uri=http://example.com/auth/callback/../../../
- normalize and compare it strictly
- ignore user:pass@, remove query string
- send HTTP request to internal network
- send attack code to http based old CMS, admin console
- fetch intranet URLs via proxy API
- check hostname by buggy parse_url
- fetch url by other implementation
- Time-Of-Check Time-Of-Use problem
- DNS record can be changed
- You should use the same implementation for checking and use whenever possible
- You should use same data for checking and use
- "Normalize strings before validating them"
- I've talked about it on AppSec
- XSS with
<!--> -->
- TinyMCE, etc
- client / server / language, there are too many implementations.
- need more test cases
- Fin.
ma.la
- URLパーサに起因する脆弱性について
- いくつかはまだ未修正
- My URL isn't your URL
- cURLの作者によるURLの仕様と実装についての苦言
- https://daniel.haxx.se/blog/2016/05/11/my-url-isnt-your-url/
- ブラウザやライブラリによって異なるURLと認識される
- RFC通りに実装されているとは限らないし、RFCが正しいとは限らない
- 互換性のため、相互運用性のためにinvalidなURLを許容することがある
- http://example.com/#hash#in#hash
#
in location.hash- valid or invalid?
- Java: new URI
- Ruby: URI.parse
- URL Parser自体にバグが有るもの
- チェックするタイミングによって問題が起きるもの
- https://android.googlesource.com/platform/external/webkit/+/7e4405a7a12750ee27325f065b9825c25b40598c%5E%21/
- URLをcheckする箇所でprotocolを確認している
- 正規化前のURLで、#"auto">
Open Redirect
- http://homakov.blogspot.jp/2014/01/evolution-of-open-redirect-vulnerability.html
- //example.com
- /\example.com
- http:example.com
- CVE-2016-2221
- https://core.trac.wordpress.org/changeset/36444
- Open redirect vulnerability in the wp_validate_redirect
- hostが取れないけど相対パスじゃない
- ブラウザではhttp://example.com と解釈
- parse_url(url).host == “example.com”
- じゃあ、protocolもチェックしましょう
- url.protocol == “http” || url.protocol == “https”
- http://evil.example.com#@example.com/
- host of this url is
- Browser: evil.example.com
- PHP 5.6: example.com
- origin = scheme + host + port
- 正しい方法でのsame origin判定が失敗する!!
- SOP bypass on server-side
- いくつかのライブラリ、言語の標準実装で問題あり
- PHP, ■■■■, ■■■■■■■ (reported by mala)
- PHP 5.6.28 / 7.0.13 で直っています
- cURL (自分の報告ではない)
- Java/Android (java.net.URL) has been fixed CVE-2016-5552
- Java : 2017-01http://www.oracle.com/technetwork/security-advisory/cpujan2017-2881727.html
- Android : 2017-02https://source.android.com/security/bulletin/2017-02-01.html
- http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/cd0585378c46
- https://android.googlesource.com/platform/libcore/+/4b3f2c6c5b84f80fae8eeeb46727811e055715ea%5E%21/
- 未修正の事例はまだ公開できないが、問題自体はcURLのケースで公知
- https://curl.haxx.se/docs/adv_20161102J.html CVE-2016-8624
- 複数の実装で同様の問題がある、インターネットのバグ!
- WordPressの事例のテストケースにあり
- PHPのバグなので上流に報告しましょう
- バグか脆弱性かの問題
- 複数実装に問題があったときの公表方法
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.
- user:pass@example.com の部分
- / or ? or # で問答無用で終わるのが正しい
- 絶対URLと相対パスの両方を同じライブラリで処理
- http urlとそれ以外のprotocolも同列に処理
- 歴史的経緯、相互運用性、互換性のための寛容な処理
- user:pass には本来、予約文字が使えない
authority = [ userinfo "@" ] host [ ":" port ]userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
- URL Parserのバグがどのように脆弱性になるか
- CVE-2012-3695
- http://masatokinugawa.l0.cm/2012/08/safari-location.href.html
- location.href of WebKit based browser
- http://siteA.example.com%2F@siteB.example.com/
- ホスト名部分がdecodeされて返ってくる → location.hrefが異なるhostの値を返す。
- same originの判定に失敗して外部ドメインのリソースを読み込み
- client side + server side
- jQuery mobile + open redirector
- 最近報告したものがある
- yes.
- CMS製品、デフォルトでjQuery mobile使用+open redirectorあり
- 非常に広範なwebサイトでXSSが可能だった
- https://www.google.com/transparencyreport/https/ct/?hl=ja#domain=ma.la&incl_exp=false&incl_sub=true
- https なサイトのオープンリダイレクタの検証のためにlet's encryptを使った
- Certificate Transparency logに残るぞ!
- server side.
- URL parserバグ起因のものは実際の事例は見つけていない
- 危なっかしい状態だったものはあり
- OAuth, OpenIDなどのredirect url
- domainのみ一致でcheckしていると危険
- URL parserがバグっていると。。。
- そもそも「ドメイン」丸ごと安全とは限らない
- ホスト名誤認を使って別ドメインに認証コードを送る
- オープンリダイレクタとの組み合わせ
- referrerで外部に認証コードが漏洩するPathを指定する
- Pathは先頭一致にしないで「完全一致」にすべき
- redirect_uri=http://example.com/auth/callback/../../../
- これが通ってしまうと別Pathに認証コードを送ることが可能
- そもそもuser:passが入ってるのとおかしいので、正規化して完全一致にしましょう。
- query string部分のみ除去して登録済みURLと比較
- イントラネットのURLにHTTP requestを送る
- 管理画面に攻撃コード送る
- 変換系処理のAPIで内容を取得する
- 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"
- 以前発表した
<!--> -->
の解釈の違いを使ったXSS- ブラウザの実装と、jsやサーバーサイドで解釈が違う
- TinyMCE, etc.
- client / server / language 複数の実装が混在するのは必然
- need more test case.
おまけ
各言語のURL Parserの実装について
Ruby
コアモジュール、URI class.
https://github.com/ruby/ruby/blob/trunk/lib/uri/rfc2396_parser.rbhttps://github.com/ruby/ruby/blob/trunk/lib/uri/rfc3986_parser.rb
RFCをそのまま正規表現に。厳格。
- fragmentの中に # が使えない。
- URI.parse("http://example.com#foo#bar") → error
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バグあり。レポート済み。