Web Application Security Memo

ウェブセキュリティに関するメモ書き

OWASP ZAPの「Cross Site Scripting (Persistent)」(持続型クロスサイト・スクリプティング)診断は何をしているのか?

※当サイトにはプロモーションが含まれています。

公開日: 更新日:

OWASP ZAP

OWASP ZAP の Active Scanで実行される脆弱性診断に「Cross Site Scripting (Persistent)」という項目(別名 Stored XSS)があります。日本語だと持続型(格納型)クロスサイト・スクリプティングです。この項目はバージョン 2.2ではbeta扱いだったのですが、バージョン2.3から正式版扱いになりました。ここではこの診断が何をしているのか説明します。

※ 脆弱性を自動診断して何らかの脆弱性が報告された場合、本当にその脆弱性が存在するのか調査すると思いますが、どういう診断処理が行われたのかが分かっていないと、非効率な調査しかできません。

ZAP 2.3 が行うXSS診断の種類

ZAP 2.3のスキャンポリシーにはXSSに関する項目がデフォルトで4つ用意されています。

  1. Cross Site Scripting (Reflected)
  2. Cross Site Scripting (Persistent) - Prime
  3. Cross Site Scripting (Persistent) - Spider
  4. Cross Site Scripting (Persistent)

今回説明するのは、2から4の3つです。この3つで1セットです。

「Cross Site Scripting (Persistent)」は「Cross Site Scripting (Persistent) - Spider」に依存しており、「Cross Site Scripting (Persistent) - Spider」は「Cross Site Scripting (Persistent) - Prime」に依存しています。スキャンポリシー で「Cross Site Scripting (Persistent)」だけ選択しても何も診断できません。診断できないどころか、現時点だと依存性が解決できずActive Scan内で処理が無限ループしてしまい終わらなくなります。これについては開発者の方も認識されてまして、そのうち修正されるのだろうと思います。

1つ目の「Cross Site Scripting (Reflected)」については、以下の記事を参照して下さい。

診断対象の脆弱性

CWE

WASC

ソースコード

以下の3つのメソッドについて解説します。

  1. Cross Site Scripting (Persistent) - Prime
  2. Cross Site Scripting (Persistent) - Spider
  3. Cross Site Scripting (Persistent)

※ これらのソースコードは変更されていきますので、ここで説明している内容がソースコードの内容と一致しなくなる可能性があります。

処理概要

前提

  • 大まかには以下のように処理が進みます。
    1. ターゲットになっている全てのURL(と付随するそれぞれのパラメータ)に対して、「Cross Site Scripting (Persistent) - Prime」の診断処理が行われる。
    2. ターゲットになっている全てのURLに対して、「Cross Site Scripting (Persistent) - Spider」の診断処理が行われる。
    3. ターゲットになっている全てのURL(と付随するそれぞれのパラメータ)に対して、「Cross Site Scripting (Persistent)」の診断処理が行われる。
  • 3つある診断のそれぞれのscanメソッドが実行される時点で、診断対象となるURLが1つ決まっています。
  • TestPersistentXSSPrime.java と TestPersistentXSSAttack.java のscanメソッド
    • Active Scanを実行する前に、このURLに対してスパイダリングもしくは手動でアクセスしているはずであり、その時に送信した各パラメータ(URLからのパラメータ, Formからのパラメータ等)毎にこのscanメソッドが実行されます。
    • 以下の引数となります。
      1. 基のアクセスデータ
      2. パラメータ名
      3. パラメータ値
  • TestPersistentXSSSpider.java のscanメソッド
    • こちらは、パラメータ別に実行されるわけではなく全体に対して1回だけ実行されます。

ポイント

  • URLのペアが作成されます。
    • 以下のペア(但し、後者は複数あり)です。
      1. 送信されたパラメータ値がサーバに保存されるページのURL(とパラメータ名)
      2. 1で送信されたパラメータ値がHTML上に出力されるページのURL
        • こちらは1つとは限りません。
    • このペアとなるデータは、PersistentXSSUtilsクラスの sourceToSinks変数(スタティック変数)に保持されます。

処理概要

  1. TestPersistentXSSPrime.java の scanメソッド
    1. 対象パラメータに対して試験用文字列(例: “zApPX17sS”)をセットして、対象URLにアクセスします。
      • これが対象URLに付随する全てのパラメータに対して実行されます。
      • 試験用文字列は送信される毎に違う文字列が使用されます。
    2. ※ 以上のscan処理を、ターゲットなっている全てのURLに対して行います。
  2. TestPersistentXSSSpider.java の scanメソッド
    1. 対象URLにアクセスし、TestPersistentXSSPrime で送信したパラメータ値がレスポンスボディ内に存在しているかチェックし、存在していればスタティックな変数に保持しておきます。
      • つまり「サーバに対しこれまでに送信されたきたパラメータ値が保存されており、それが今回の対象URLにアクセスした画面上に表示されている」ことをチェックします。
      • この時の対象URLに対して送信した試験用文字列だけでなく、別のURLに対して送信した試験用文字列もチェックします。
      • この処理は各パラメータ毎にそれぞれ行う必要はないため、対象URLに1度だけアクセスしてそのレスポンスボディに今まで送信してきた試験用文字列が出力されているかまとめてチェックしています。
      • 最初に見付けたパラメータ値に関するデータがスタティックな変数に追加されたら TestPersistentXSSSpider.java の処理は終了します。
      • 試験用文字列が見つかった場合、以下のスタティックな変数に関連データが保持されます。
        • org.zaproxy.zap.extension.ascanrules.PersistentXSSUtils.sourceToSinks
        • この変数の型は HashMap になっており、その内容は以下です。
        • キー:パラメータ値を送り込んだ時のURL + パラメータ名
        • 要素:(そのパラメータの値がHTMLに出力されたURLのHttpMessageデータ)のHashSet
          • 複数ありえます。
    2. ※ 以上のscan処理を、ターゲットなっている全てのURLに対して行います。
  3. TestPersistentXSSAttack.java の scanメソッド
    1. 対象URLとパラメータに対するデータが、PersistentXSSUtilsのsourceToSinks変数に保持されていなければ、ここで処理を終えて次のパラメータの処理に進みます。

    2. 対象パラメータに “0W45pz4p” をセットして、対象URLにアクセスします。

    3. PersistentXSSUtilsのsourceToSinks変数に保持されているデータの中の、ここでの対象URLとパラメータに対するデータ部分を取得し(つまり、上の3-2で送信したパラメータ値が出力される側のページデータです。複数の場合があります)、その数だけループ処理します。

      1. パラメータ値が出力される側のページのURLにアクセスします。
        • ここでのアクセスは、パラメータに入力した値がHTML上のどこに出力されるのかを調べるためだと思われます。
        • こちらのURLに対しても同じパラメータに、”0W45pz4p” をセットしてアクセスしていますが、この理由は分かりませんでした。( 2014/08/01: これはバグであり必要ない処理だったことが分かりました→ OWASP ZAP のバグを見付けてから修正されるまでの例 )
      2. そのレスポンスボディに、”0W45pz4p” が見つかった箇所毎にループ処理します。
        1. HTML上の見つかった位置によって異なる攻撃用入力文字列(主に JavaScriptのコードです)を生成し、それを対象パラメータにセットして対象URLにアクセスします。
        2. パラメータ値が出力される側のページのURLにアクセスします。
          • こちらのURLに対しても同じパラメータに、”0W45pz4p” をセットしてアクセスしていますが、この理由は分かりませんでした。
        3. そのレスポンスボディに、攻撃用入力文字列が見つかれば脆弱性有りと判定します。
    4. ※ 以上のscan処理を、ターゲットなっている全てのURLに対して行います。

メモ

  • 各ページ(URL)を診断する順番によっては脆弱性を検出できないことがありえるのではないかと思ったのですが、そんなことはありませんでした。TestPersistentXSSPrime.java → TestPersistentXSSSpider.java → TestPersistentXSSAttack.java のそれぞれの段階でターゲットなっているURLを全て検査した上で次に進むので、送信したパラメータ値が対象サイトのどのページに出力されても本脆弱性検査が処理されます。

その他

  • 間違っているところがあるかもしませんので参考ということでお願いします。間違っているところがあれば、ご指摘頂けるとありがたいです。

更新履歴

  • 2014/04/26 - 新規公開
  • 2014/04/27 - 「処理概要」と「この自動診断処理の限界」を修正
  • 2014/04/27 - 「この自動診断処理の限界」を「メモ」に変更
  • 2014/04/28 - 「処理概要 - 前提」を分かりやすくするために修正
  • 2014/04/29 - タイトルを変更
  • 2014/08/01 - バグであった部分についての記述を追加

[最終更新日: 2014年8月1日]