2016/04/08

EasyXDM 2.4.20で修正されたXSS

Update: English version is here: http://mksben.l0.cm/2016/04/easyxdm-xss-docmode-inheritance.html
------------------

EasyXDM というクロスドメインでのあれこれを便利にしてくれるライブラリの 2.4.20 で、自分の報告したXSS脆弱性が修正されています。使っている人はアップデートしましょう。

Release Security update - 2.4.20 · oyvindkinsey/easyXDM · GitHub
https://github.com/oyvindkinsey/easyXDM/releases/tag/2.4.20

以前にも脆弱性が指摘されていますが、それとは別の問題です。

http://blog.kotowicz.net/2013/09/exploiting-easyxdm-part-1-not-usual.html
http://blog.kotowicz.net/2013/10/exploiting-easyxdm-part-2-considered.html
http://blog.kotowicz.net/2014/01/xssing-with-shakespeare-name-calling.html


これ以下は技術的な説明です。
このバグはDOM based XSSなのですが、再現方法が少し変わっているので紹介します。

このXSSはIEでのみ動作します。おまけにドキュメントモードがIE7モード以下でないと起こりません。なぜかというと、XSSのある場所が、バグった挙動があると判断されたブラウザだけが通過する箇所にあり、その条件を満たすのが、IE7モード以下だけだからです。

次のcreateElement()の箇所でXSSが起きます。

https://github.com/oyvindkinsey/easyXDM/blob/2.4.19/src/Core.js#L507-509
    if (HAS_NAME_PROPERTY_BUG) {
        frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");
    }

このif文の条件のHAS_NAME_PROPERTY_BUGという値が、バグった挙動があると判定されたブラウザだけtrueになります。設定しているのは、以下の部分です。

https://github.com/oyvindkinsey/easyXDM/blob/2.4.19/src/Core.js#L474-482
function testForNamePropertyBug(){
    var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input"));
    input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues
    HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name];
    document.body.removeChild(form);
    // #ifdef debug
    _trace("HAS_NAME_PROPERTY_BUG: " + HAS_NAME_PROPERTY_BUG);
    // #endif
}
formと名前付きのinputを作って、名前からinput要素にアクセスできるかテストしています。どうやら、IE7モード以下では、動的に作った名前付きの要素に、名前経由でアクセスできないバグがあるらしく、その回避策として、このようなコードで一度検証を行っているようです。

このテスト部分だけを実行できるページを以下に用意しました。IEでアクセスすることで、HAS_NAME_PROPERTY_BUGの値がtrueになることを確認できます。

http://vulnerabledoma.in/easyxdm/name_property_test.html

それでは、実際に脆弱なEasyXDMで、XSSが起きることを確認してみます。以下にIEでアクセスして、IEのF12開発者ツール( F12 → エミュレーション )から、ドキュメントモードをIE7以下にしてみてください。アラートが出るはずです。

http://vulnerabledoma.in/easyxdm/2.4.19_index.html?xdm_e=http%3A%2F%2Fvulnerabledoma.in&xdm_c=%22onload%3dalert(document.domain)//&xdm_p=0

これで、IE7モード以下でXSSが可能なことがわかりました。しかし、IE7モード以下でEasyXDMを利用しないとXSSが起こらないのでは、攻撃できる条件がかなり限られてしまいます。

そこで、最近公開した資料にも書いた、「ドキュメントモードの継承」というテクニックを使います。

ドキュメントモードを変更した親のフレームに埋め込むと、フレーム内のドキュメントモードも変更されるというテクニックでした。これを使ってみましょう。

http://l0.cm/easyxdm/poc.html
<meta http-equiv="x-ua-compatible" content="IE=5">
<iframe src="//vulnerabledoma.in/easyxdm/2.4.19_index.html?xdm_e=http%3A%2F%2Fvulnerabledoma.in&xdm_c=%22onload%3dalert(document.domain)//&xdm_p=0"></iframe>
<script>document.write("document.documentMode: "+document.documentMode)</script>
どうでしょうか?まだアラートは動かないはずです。親はIE=5指定により、IE5モードで動いているはずなのに、フレームの中のドキュメントモードは8までしか下がっていません。これは、フレーム内のページの先頭に<!DOCTYPE html>があるからです。この宣言がある場合、IE11では、フレームに埋め込んでも降格されるのは8までが限度になっています。XSSを成功させるにはなんとか7まで下げなければいけません。

ご安心ください。実は、さらに強力な継承方法があります。以下にIE11でアクセスしてみてください。

http://l0.cm/easyxdm/poc.eml

どうですか?今回はアラートが出たと思います。1つ前のページとの違いは、このページは、text/html ではなく、Content-Type: message/rfc822形式のページだということです。スライド中でも触れたのですが、IE11/Edgeは、今もmessage/rfc822形式のドキュメントをブラウザ内で開くことができます。(mhtml:という文字列はなくても開けます。)

message/rfc822形式のページは、デフォルトでIE5モードで表示されるようです。そしてどうやら、そこに埋め込んだフレームに対するドキュメントモードの継承の力が通常のtext/htmlよりも強いようなのです!例え、先頭に<!DOCTYPE html>があろうとも7までは降格させることができます。実際に、フレーム内のドキュメントモードをみると7まで下がっており、このおかげで、脆弱な箇所への到達に成功したことがわかります。

この手法を使えば、EasyXDMのXSSのように、IE7のドキュメントモードでしか再現しない問題を、脆弱性のあるページのドキュメントモードにかかわらず、また、ユーザによるドキュメントモードの切り替え操作なしに、攻撃可能な問題に発展させることができる、という訳です。

ちなみに、もう1つ強力な継承が起きる場所があります。それは、CVリスト(互換表示リスト)でIE7のドキュメントモードで表示指定しているサイトのフレームです。
CVリストはWindowsの以下の場所に保存されています。ここにリストされているドメインは、リストで指定したドキュメントモードで表示されるようになります。

%LOCALAPPDATA%\Microsoft\Internet Explorer\IECompatData\iecompatdata.xml

ここにリストしてもらうには、面倒な手続きが必要ですが、XSSのためにそんなことをする必要はありません。なぜなら、既にここにリストされているドメインのXSSを探してきてそのページ内にフレームを作ればいいだけだからです。めちゃくちゃなことを言っているように聞こえるかもしれませんが、その方がMicrosoftを騙して手続きするよりもはるかに簡単で現実的です。

実験してみましょう。CVリストに載っている以下のMicrosoftのドメインのページを開いて(※Under Construction と表示されますがそれでOKです )、

http://epim.partners.extranet.microsoft.com/
<domain docMode="EmulateIE7" versionVector="7" uaString="7">epim.partners.extranet.microsoft.com</domain>
F12開発者ツールのコンソール上で、以下を実行してみてください。フレーム内のページのドキュメントモードは7まで降格され、message/rfc822の時と同様にEasyXDMの脆弱箇所に到達し、アラートが出ると思います。
document.write('<iframe src="//vulnerabledoma.in/easyxdm/2.4.19_index.html?xdm_e=http%3A%2F%2Fvulnerabledoma.in&xdm_c=%22onload%3dalert(document.domain)//&xdm_p=0"></iframe>')
message/rfc822の強い継承に気付くまではこの方法で攻撃可能なことを証明していました。今となってはmessage/rfc822の方が簡単なので、あえてこっちを使う理由はありません。

以上、EasyXDMのXSSの技術的な部分を説明しました。

今月は余力があれば(2月、3月書いてない分)もう1つか2つ記事を書く予定です。

0 件のコメント:

コメントを投稿