ぶるーたるごぶりん

UI, UX, セキュリティとか😘

XSStrikeを読む part1

はじめに

めちゃくちゃイケてて最高なXSStrike の中身を読もうという記事です。

github.com

最近カメ並のスピードで最強のXSSスキャナーを目指して開発をしているのですが、 さすがに既存のXSSスキャナーが何をやってるのか把握していないのはまずいだろうということで、 今回は3、4回に分けてXSStrikeのロジックを読んでまとめていこうと思います。

ZAPは過去に読んだのですが、XSStrikeは未読なのでワクワクです。

ちなみに昨年ZAPのXSSルールを読んだ時は、こちらの記事の内容とほぼほぼ一緒でしたのでお勧めです。 OWASP ZAPのXSS(Cross-site scripting)診断は何をしているのか? – Web Application Security Memo

最強のXSSスキャナーを作るのであれば、 Burp, ZAP, Arachni, Nikto などのスキャナーも読む必要があるのでは?と思われるかもしれませんが、 Burpは有償なのでペイロードくらいしか見れないですし、 Arachni はサポート切れですし(かなり読みやすいのでお勧め)、 Nikto は汎用スキャナー且つ Perl なので読む気力が・・・ 

ということで、XSStrike以外はちゃんと読むきあまりなしです。

では行ってみましょう

ファイル一覧

読んでいくにあたり、 ひとまずファイル一覧を眺めつつ、 main関数から派生していく処理をみていきましょう。 ではまずファイル一覧から

重要ファイル (.py のみ)

  • xsstrike.py (main file)

/modes * bruteforcer.py * crawl.py * scan.py * singleFuzz.py

/core * arjun.py * checker.py * colors.py * config.py * dom.py * encoders.py * filterChecker.py * fuzzer.py * generator.py * htmlParser.py * jsContexter.py * log.py * photon.py * prompt.py * requester.py * updater.py * utils.py * wafDetector.py * zetanize.py

/plugins * retireJs.py

その他ファイル

/db * definitions.json * wafSinatures.json

コードを読む

main 関数

メイン関数は以下の行から、大きく処理が別れます。 (以下のURLの行よりも前の部分は、パラメータとかデータの初期化とかそういう処理ばかりなので無視)

XSStrike/xsstrike.py at 0ecedc1bba149931e3b32e53422d5b7c089ba9dc · s0md3v/XSStrike · GitHub

main 処理は以下の4つに大きく分岐します。

  • singleFuzz()
  • bruteforcer()
  • scan()
  • photon() ( + crawl())

今回の記事では singleFuzz() をみていきます。

singleFuzz()

シングルファズは文字通り Fuzzing をするもので、 スキャンなどの脆弱性検知までは行われません。

主な目的は FireWall のテストで、 ランダム遅延を行いつつリクエストを送っていくという処理を行います。

ここには --fuzzer パラメータをONにすると入ってきます。

XSStrike/singleFuzz.py at 0ecedc1bba149931e3b32e53422d5b7c089ba9dc · s0md3v/XSStrike · GitHub

singleFuzz() のフロー

  1. paramData ( e.g. --data q=123 などのパラメータ) が存在するかで GET, POST どちらかを選択する

  2. protocol(http, https) の決定。 target URLが https だった場合、httpsのリクエストを送って対応しているか確認。 https がだめだったら以後のリクエストは http ベースになる。

  3. wafDetector()

    1. /db/wafSignatures.json を読み込む。 これはレスポンスの Status, header, page(htmlなど?) から何製のWAFかを判断するためのデータ
    2. ?xss=<script>alert("XSS)</script> を送る
    3. response の status code が 400 <= status 場合、 WAF の可能性があると考え、更に評価
    4. WAF Signature からステータスコード、ページデータなどとの一致度でScoreを+していく。
    5. WAFで一番マッチ度が高いやつを検知したWAFだとし、返す
  4. リクエストパラメータ(複数)を forEach みたいな感じでループ。 ループ時に、その index 番目のパラメータの値を v3dm0s に変更(あとでペイロードに置換するための足跡)

    (インデントが足らないので囲む)

    
    https://github.com/s0md3v/XSStrike/blob/0ecedc1bba149931e3b32e53422d5b7c089ba9dc/core/config.py#L66
    にあるペイロード(複数)を、対象のリクエストパラメータ(単体)に変えてく感じでループ(以下がその処理)

       (ペイロードを対象(単体)のパラメータに埋め込んで送り込む所:)
        1. ペイロードの文字列数・処理の中で変動する数値をベースに sleep をかける
        2. ペイロードをデコードしたあとにエンコードする
        3. 前もって置換しておいた `v3dm0s` (ペイロードの置換用の足跡)をペイロードに置換
        4. リクエストを送る
            1. エラーが起きた時はしばらくsleepしてから再送。
            2. 再送で失敗した場合は IP がブロックされたと判断して停止
            3. 再送が成功した場合は、sleepが功を奏したとして、 `5.` (次の行)に移動
        5. レスポンスにペイロードがないかをレスポンス, ペイロード共に lower してマッチング
        6. あった場合は [pass],  
           status code が 2xx 系以外の場合は [block],
           その他の場合は [filtered] というログレベルで吐き出して終わり。

終わりに

今回は singleFuzz() の中身を読んだ。 次回は bruteforce() を読む

補足

以下のファイルには、 XSStrike における重要なペイロードや、 多分今後出てきそうなXSSの有無をチェックするためのタグ一覧などが格納されている。

XSStrike/config.py at master · s0md3v/XSStrike · GitHub

主な内容はいかが格納されてる。

  • delay などのプロパティ値
  • 特別な { 属性, タグ }
  • 普通の { タグ }
  • js, tag, handler, space のセパレーターとなる文字列
  • event handler
  • POP UP を出現させる関数のペイロードパターン (confirm, prompt 各3パターン)
  • Filter / WAF を回避する 20パターン
  • Fuzz strings to test WAFs
  • WAF をテストするためのPayloads 30種
  • default request header (UA, Upgrade-Insecure-Request, Accept など)
  • パラメータ発見のために利用される総当たり用の一般的なパラメータ名 95種類