SSTエンジニアブログ

SSTのエンジニアによるWebセキュリティの技術を中心としたエンジニアブログです。

DOM Invader触ってみた

はじめに

ゼルダの伝説 スカイウォードソード HDやりたくて仕事する気が起きない岩間です。女神転生Vも待ち遠し…。

今回は、先日リリースされたBurpの新機能であるDOM Invaderの紹介です!

DOM Invaderは、Burp ProfessionalおよびCommunityの2021.7のバージョンでリリースされました!
Early Adopterでの提供のため、Stable(安定版のことです)はもう少し先になるかと思います。またEarly Adopterなので今後、機能追加や変更も頻繁に行われる可能性があります。

DOM Invader

DOM Invaderとは、DOMの操作によって引き起こるXSS(以下、DOM XSS)のテストを支援する新たなツールです。Burpに組み込まれた内蔵ブラウザの拡張機能として追加されており、有効にすることでターゲットとなるサイトのDOMを解析し、Javascriptのソースとシンクをツリービューで表示します。

カナリアと呼ばれるユーザが設定可能な文字列を使用して、Javascriptのソースにカナリアを挿入し、シンクでカナリアを検出することで脆弱性の有無をテストしています。

その他にもリリースノートにはWeb Messageの傍受や脆弱性をテストすることができるとの記載があります。
ここで言うところのWeb Messageは、一般用語の意味ではなくWHATWG HTML5仕様に含まれるCross Document Messaging APIのことを指しています。Cross Document Messagingは安全にクロスドメイン通信を可能にするためのもので、実装としてはpostMessageメソッドを使った通信方法があります。
DOM Invaderでは、このpostMessageによる通信を傍受し、脆弱性テストを行います。

起動と設定オプション

Burpを起動して内蔵ブラウザを開きます。
最初はメニューバーにエクステンションが表示されていないので、拡張機能→固定化でメニューバーに固定表示しておきましょう。

次に拡張機能をクリックします。デフォルトでは、DOM InvaderはOFFになっています。 postmessageのインターセプトを有効にしたい場合はPostmessage interceptionをONにします。 カナリアを設定する際も、この設定画面から行います。以下の画像だとカナリアはydgi5bsfになっています。もちろんユーザが自由に設定することもできます。

f:id:wild0ni0n:20210715142222p:plain
初期の設定画面

ソースとシンクの確認方法は、開発者ツールから確認することができます。 開発者ツールを開くと、Augmented DOMPostmessage のメニューが追加されています。

f:id:wild0ni0n:20210715143506p:plain
Augmented DOM画面

f:id:wild0ni0n:20210715143549p:plain
Postmessage画面

シンクの表示順序は重要度順となっており、シンクランキングと呼ばれる値が小さいほど重要度が高いようです。 2021/6/30時点で検出できるソースやシンク、およびシンクランキングはIntroducing DOM Invader: DOM XSS just got a whole lot easier to findの記事のList of sources and sinksに記載されています。(※リストが長いのでここでは割愛します)

試してみる

では、実際にDOM Invaderによるソースとシンクの検出を確認してみます。

確認のため以下のようなhtmlを用意しました。

<html>
    <body>
        <div id="target"></div>
        <script>
            const message = location.href;
            document.getElementById('target').innerHTML = unescape(message);
        </script>
    </body>
</html>

エクステンションのDOM InvaderをONにし、開発者ツールからAugemented DOMを開きます。 Injection canary into URLをクリックすると、x=[カナリア]1\<>'":をクエリパラメータに自動的に差し込みます。

f:id:wild0ni0n:20210715142956p:plain
ソースとシンクのツリービュー

画像から、カナリア(ydgi5bsf)を使ってソースとシンクが確認できていることが分かります。 ちなみに既に他のクエリパラメータがある場合は、パラメータ値をx=[カナリア]1\<>'":に全て書き換えて送信します。

クエリパラメータへの自動挿入の他には、フォームへ自動挿入を行うInject canary into formsがあり、これはHTML内の全てのフォームの値をカナリアに書き換えます。

ソースがURLやフォームではない時(例えば、フラグメント取得するlocation.hashなど)で、自動的にソースにカナリアを挿入してほしい場合は、設定のInject canary into all sourcesをONにすることで、ページの読み込み時に全てのソースにカナリアを挿入します。 ただし、全てのソースにカナリアを入れるのでサイトの挙動がおかしくなる場合があります。

f:id:wild0ni0n:20210715144146p:plain
設定変更後のreloadをお忘れなく。

検出されたソースやシンク、後述するpostmessageは、スタックトレースを使ってコードの中のどこで発見されたのかを知ることができます。

f:id:wild0ni0n:20210715144503p:plain
スタックトレースのログからソースやシンク箇所が分かる

画像では、poc2.htmlの7行目でinnerHTMLが使われていることが分かります。

次にpostmMessageを確認してみます。 確認のため以下のようなhtmlを用意しました。

<html>
    <body>
        <div id='target'></div>
        <script>
            window.addEventListener('message', function(e) {
                document.getElementById('target').innerHTML = e.data;
            });
        </script>
    </body>
</html>

自動的にカナリアの挿入から検出まで行いたい場合は、設定のGenerate automated messagesをONにします。 この設定をONにし、開発者ツールからPostmessageを開いて確認した結果、postmessageの送信を検出していることが分かります。

f:id:wild0ni0n:20210715144814p:plain

検出された結果をクリックすると、Replay Postmessage画面が表示されます。

f:id:wild0ni0n:20210715144953p:plain

重大度(Severity)や、検出の信頼度合(Confidence)などといった情報のほかに、検出結果の説明(Description)が記載されています。

Sendボタンをクリックすることで、もう一度同じpostmessageを送ることができます。 また、Build PoCボタンをクリックすることで、PoC用のHTMLがクリップボードにコピーされます。 例として、この画像結果のPoCを生成してみました。

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Postmessage PoC</title>
        <script>
            function pocLink() {
                let win = window.open('http://localhost:8000/poc3.html');
                let msg = "ydgi5bsf0-\\\u003c\u003e'\":";
                
                setTimeout(function(){
                    win.postMessage(msg, '*');
                }, 5000);
            }
            function pocFrame(win) {           
                let msg = "ydgi5bsf0-\\\u003c\u003e'\":";
                
                win.postMessage(msg, '*');          
            }
        </script>
    </head>
    <body>
        <a href="#" onclick="pocLink();">PoC link</a>          
        <iframe src="http://localhost:8000/poc3.html" onload="pocFrame(this.contentWindow)"></iframe>                    
    </body>
</html>

CSRF PoCのようにすぐに確認できますし、仮にうまくPoCが動作しなかったとしても、スタックトレースのログやソースシンクの情報を参考に原因を突き詰めやすいのがいいですね。

不便に感じたところ

現時点で非常に便利ですが、いくつかちょっと不便だなと感じた部分を紹介します。

  • Chrome ウェブストアで拡張機能が提供されていない

    診断では、自分でカスタマイズしたブラウザを使う事が多いです。 内蔵ブラウザを使いなさいということなのでしょうが、拡張機能として提供されると嬉しいですね。

  • Issuesに表示されない

    ソースやシンクの確認やDOM XSSと疑われる挙動が確認できた場合には、Issuesに表示されるようにして欲しいなと感じました。

  • Scannerで使えない

    厳密に確認したわけではありませんが、スキャンオプションやリリース内容から、現時点のScannerではDOM Invaderは使っていないように見えます。 私は暇つぶしでscannerを使う程度なのでそれほど困るわけではないのですが、おそらくメインで使ってる人には一定の需要がありそうなので不便な点として記載しました。

まとめ

触ってみて、手動診断の支援ツールの位置付けだと感じました。 なので手動を中心とした診断なのか、自動スキャンツールを中心とした診断なのかによって評価が変わりそうです。
手動の場合、これまでDOM XSSを探すのが非常に大変でしたのでDOM Invaderのようなソースとシンクが分かるツールがあることで、より効率的に探し出せるかと思います。UIもわかりやすく、パッと見て理解しやすいのも非常に良い点だと思います。

一方で、自動スキャンツールを中心とした診断での評価では、そもそもScannerに搭載されているかも分からないという点もありますが、仮にScannerで動作していたとしても、Issuesに登録されないのでレポートに出力されず見逃すケースは多いと思います。 とはいえ、まだEarly Adopter提供なので、今後のアップデートで変わる可能性は大いにあり得ます。

Community版でも提供されているので、試してみようかなと思ったときに試せるのも良いですね。
この記事を読んで興味が出た方は是非試してみてください。