この記事はIPFactory Advent Calendar 2021 25日目の記事です。
こんにちは、futabatoです。
先日、MBSD Cybersecurity Challenges 2021の最終審査会を終えました。
y0d3n, okodayon, l7elVliと出場したチーム「After_the_CM」は第三位でした。
MBSD Cybersecurity Challenges 2021 第3位でした。
— ふたばと (@01futabato10) 2021年12月17日
ひよってばかりの僕に背中を押してくれたチームメイトにはとても感謝しています。幸せな5ヶ月間でした🌻
MBSD Cybersecurity Challenges 2021 最終審査会 After_the_CM 発表スライド https://t.co/0HmMLZvUq3
5カ月間の振り返りはこちらの記事で行っています。
チームメンバーのy0d3nの記事も併せてご覧ください。
今回のコンテストの課題は「脆弱性診断ツールの開発」でした。
私たちはGo製の脆弱性診断ツール「Himawari」を開発しました。
コンテストが終わっても開発を続けたい想いから、先日リポジトリを公開しました。
一からWebセキュリティを学んで脆弱性診断ツールの開発を行った私たちの5カ月間の軌跡を、機能説明書のようなものとしてHimawariというプロダクトの面から世に残しておきます。
- 1. 概要
- 2. Sitemap
- 3. Crawl機能
- 4. Scan機能
- 5. Report機能
- 6. その他機能
- 7. 精度評価
- 8. 結果と考察
- 9. Himawariの限界
- 10. おわりに
1. 概要
HimawariはWebアプリケーションに存在する脆弱性を自動的に発見し、ユーザに診断結果を報告することができる脆弱性診断ツールです。
HimawariはBlack Box型の診断ツールなので、Himawariを使った診断において、診断するWebアプリケーションの実装に関する詳細な知識やソースコードは不要です。診断に必要なのは診断対象となるWebアプリケーションのURLです。HimawariにURLを入力すれば診断対象のWebアプリケーションに対して自動的にクローリングを行ってサイトマップを構築した上で診断を行うことができます。
診断結果は脆弱性の解説とその解決策を含む、検証に使われた一連のデータをまとめたレポートを出力してユーザに提示します。
HimawariはWeb User Interface(WebUI)を用意しています。WebUIを利用することでユーザが行う一連の操作をWebブラウザを介して簡単に行うことができます。
図1に示すように、Himawariは大きくCrawlerとScannerとReportの3つのモジュールによって構成されています。
順に解説していきますが、まずはHimawariの真髄である独自のデータ構造を持つSitemapについて解説します。
2. Sitemap
Himawariで診断を行うためには、診断対象のWebアプリケーションのSitemapが必要になります。理想的なSitemapには、診断するにあたって必要になるページと攻撃に必要なパラメータ等の情報が漏れなく格納されている状態です。
どこにどのようなリクエストを送信すればよいのかという問題を解決するのがSitemapになります。
SitemapはJSONというデータの形式で管理されており、ファイルとしてDownload / Uploadが可能です。
診断を実施したくない部分があればSitemapの一部を切り取る、特定のページに診断を実施したければSitemapの一部を残してすべて切り取る、後に説明するCrawlerで収集ができないようなページはユーザがJSONを記述することで診断が可能になる等、Sitemapの編集により任意のSitemapが構築できます。
2.1. サイトマップのデータ構造
サイトマップのデータ構造についての説明をしていきます。
Himawariはサイトマップを木構造で保持します。そのデータ構造をここでは「JsonNode
」と呼び、以下のように定義します。
type JsonNode struct { Path string `json:"path"` Messages []JsonMessage `json:"messages"` Children []JsonNode `json:"children"` URL string `json:"url"` } type JsonMessage struct { URL string `json:"url"` Time float64 `json:"time"` Referer string `json:"referer"` GetParams url.Values `json:"getParams"` PostParams url.Values `json:"postParams"` }
構造体JsonNode
はPath
, Messages
, Children
, URL
の4つのフィールドを持ちます。
Messages
フィールドは構造体JsonMessage
型の配列です。
構造体JsonMessage
はURL
, Time
, Referer
, GetParams
, PostParams
の5つのフィールドを持ちます。
構造体JsonMessage
のTime
フィールドはレスポンスタイムを指します。これを通常時のレスポンスタイムとしてTime Basedな検出アプローチで利用します。
ここで、図2で示すようないくつかのPHPファイルで構成される簡単なWebアプリケーションを考えてみます。
このアプリケーションの構造を木構造で表現しようとすれば、以下の図3のようになるかと思います。
上記の定義に従ってWebアプリケーションの情報を格納したSitemapのJSONをPlantUMLで表現してみると、以下の図4のようになっています。
Webアプリケーションの情報を定義通りに格納することで、たしかにWebアプリケーションの構造を木構造で表現することができており、後に説明するScannerでは、このSitemapから情報を取り出してリクエストを生成・送信していきます。
2.2 診断時間の概算
Sitemapの情報から診断を実施するパラメータの数が割り出せるため、Sitemapが構築された段階で診断時間の概算が可能です。
3. Crawl機能
1つ目のモジュールはCrawl機能です。
SitemapはJSONファイルを一から手書きで構築することができますが、HimawariではSitemapを自動で構築できるCrawlerを用意しています。
HimawariのCrawl機能を使えば、診断対象のWebアプリケーションのURLを入力するだけでHTML内のハイパーリンクを辿って自動的にクロールを行い、診断するWebアプリケーションに関連する同一オリジン内の全てのページと、攻撃に必要な全てのパラメータ等の情報がサイトマップに保存されていきます。
3.1. アルゴリズム
HimawariのCrawl機能のアルゴリズムについて説明していきます。
HimawariのCrawlerは、入力されたURLから辿って発見したページのHTMLの内容を見てサイトマップを順次構築していきます。
ハイパーリンクやフォーム等の情報から次のページを追いかけて、その次のページをすべて確認し終えると、追いかけに行った地点に戻ってきてそのページの下に進むことを繰り返します。
これは単純なWebアプリケーションであれば深さ優先探索の振舞いをすることになります。Webアプリケーションの規模が大きくなって複雑な遷移をする場合であっても、このアルゴリズムは一貫したアプローチでクロールを遂行できます。
先ほどの簡単なWebアプリケーションの場合でCrawlを行うアルゴリズムをトレースしてみると、以下の図5のようになります。
このようなアルゴリズムでHTMLに存在する内容をすべて確認し終えるとCrawlは終了となり、Sitemapが構築されたことになります。
3.2. 診断のスコープ
Himawariではスコープの基準として、オリジンを採用しています。
オリジンとは、Webコンテンツにアクセスするために使われるURLのスキーム(プロトコル)、ホスト名(ドメイン)、ポートによって定義されます。
それら3つが全て一致した場合のみCrawl及びScan(診断)の対象となり、オリジン外の範囲に影響を与えることを防ぎます。
3.3. ユーザ入力による最適な入力値のセット
後述するWebUIのCrawlの設定画面ではユーザ入力による最適な入力値のセットができるようになっています。
入力されるデータはKey, Valueの形で入力を受け付けています。
例えばemail等の指定された形式の入力しか受け付けていない入力欄が存在した場合にCrawlの設定画面にて「key: email
, value: himawari@email.com
」を入力してCrawlを始めると、その「email=himawari@email.com
」という情報を利用してCrawlを行います。
この機能によって、フォーム等の画面で入力される値に間違いがあるためにその先のページをCrawlすることができないことを避けることができます。
3.4. JSONのImport / Exportによるサイトマップの編集
2.Sitemapにて言及はされていますが、HimawariのサイトマップはJSONで管理をしていて、Scanを開始する前にサイトマップのJSONをダウンロードして編集することができます。
JSONの編集によってHimawariのアルゴリズムでCrawlすることができなかったページの追加及び、データ削除や問い合わせ機能等といった診断を実施してほしくないページの削除を実現できます。
ユーザの手でJSONを編集できるということは漏れのないサイトマップが構築ができるということになります。
これにより、事実上すべてのページをクロールできている状態でScanに進むことができます。
4. Scan機能
2つ目のモジュールはScan機能です。
構築されたSitemapをもとにして診断を実施します。
Himawariが現在検出できる脆弱性は以下の8種類です。
- Cross-Site Scripting(Reflected・Stored)
- SQL Injection
- Cross-Site Request Forgery
- OS Command Injection
- Directory Traversal
- Open Redirect
- HTTP Header Injection
- Directory Listing
以下では各種脆弱性検出アルゴリズムについて解説していきます。
4.1. アルゴリズム
4.1.1. 概要
Scan機能を主として担うScan
関数は、サイトマップのJSONを参照し、JsonNodeのループを回してi
番目のJsonNode
を引数に各脆弱性診断アルゴリズムの関数を呼び出します。
JsonNode
がChildren
を持つ場合は再帰的にScan
関数を呼び出します。
audit
というprefixが付いた各種脆弱性検出アルゴリズムの関数の中では、JsonMessage
のループを回してj
番目のJsonMessage
からリクエストを生成し、攻撃を行います。このアルゴリズムはサイトマップで構築されたJSONを元にした深さ優先探索のアルゴリズムでJsonMessageを取り出し、診断を順に行います。
4.1.2. 攻撃用リクエストの生成
JsonMessage
に保持されている情報をもとに、Payloadと呼ばれる悪意のあるコマンドやバグを引き起こさせるための文字列を付与してリクエストを作成し、送信します。
Payloadを挿入している箇所は、JsonMessage
のGETパラメータ
, POSTパラメータ
, User-Agent
, Referer
, Path
, Cookie
です。
4.1.3. 検出アプローチ
Himawariの脆弱性判断機能は大きく、応答時間比較と文字列の部分一致の2パターンに分かれます。
4.1.3.1 応答時間比較
応答時間比較は、攻撃のリクエストに対するレスポンスタイムがJsonMessage
のTime
フィールドに保持されているCrawl時のレスポンスタイムと比較して一定時間(Payloadで設定した時間 - 誤差)以上遅くなっていた場合に脆弱性と判断するアルゴリズムです。
4.1.3.2 文字列の部分一致
文字列の部分一致は、攻撃のリクエストに対するレスポンスに特定の文字列が存在するかどうかを判断するアルゴリズムです。
比較の対象がレスポンスのヘッダかボディのどちらになるのかは検出したい脆弱性によって異なります。
4.2. 各種脆弱性診断アルゴリズム
4.2.1. Cross-Site Scripting
Cross-Site Scripting(XSS)は、攻撃者によって仕掛けられた悪意のあるスクリプトをサイトに訪れたユーザのブラウザ上で実行させることができる脆弱性です。
XSS脆弱性の検出には、Landmark
と名づけられた目印となる文字列をPayloadに含めます。
デフォルトであればScan開始時のLandmarkの数字は0で、genLandmark
関数を呼び出すごとにLandmark
の数字がインクリメントされていくようになっています。
Wapitiを始めとする多くの診断ツールはLandmarkの数字をインクリメントさせるのではなく、乱数を生成するようにしています。
私たちはLandmark
番号が衝突することを恐れて絶対に被らないインクリメントの方式で実装しましたが、結果的には実装が若干複雑になってしまいました。
4.2.2.1. Reflected Cross-Site Scripting
Reflected(反射型) XSSはPayloadを仕込んだリクエストに対するレスポンスボディの中でPayloadがscript
タグとして解釈されているかどうかを判断しています。
単なる文字列の部分一致ではtextarea
タグの中に出力されている状況等に対応できないが故にFalse Positiveとなってしまう問題がありましたが、この問題はgoqueryというgo言語の外部packageを利用して、script
タグを解釈することにより解決されました。
scriptタグとして解釈されているものの中で、注入したPayloadの文字列が存在すればReflected XSSの脆弱性が存在すると判断しています。
4.2.2.2. Stored Cross-Site Scripting
Stored(持続型) XSSの脆弱性が存在すると攻撃者によって書き込まれた悪意のあるスクリプトがサイトのDB等に保存されます。攻撃用のスクリプトがDBに保存されているとWebアプリケーションにアクセスするたびにスクリプトが実行されてしまうのがReflected XSSとの違いです。
Stored XSSの検出のためには、まずメッセージを格納できる候補となるページの探索から始まります。
j
番目のJsonMessage
に対するXSS攻撃のタイミングでPayloadの代わりにLandmarkを載せたリクエストを送信します。
リクエストを送信後、すべてのJsonMessage
に対してリクエスト送信・レスポンス取得を行い、レスポンスボディにj
番目のJsonMessage
で送信したLandmark
が含まれていれば、Candidate
と名づけたStored XSSの攻撃対象となるページとして記録します。
Candidate
はJsonMessage
型のポインタ配列で定義しています。
j
番目のJsonMessage
が1つ以上Candidate
を保持していれば、Stored XSSの検出アルゴリズムへ移行します。
Stored XSSの検出アルゴリズムの中で改めてLandmark
を発行して、PayloadにLandmark
を含ませた上でCandidate
にリクエスト送信・レスポンスを取得します。
レスポンスボディの中でscriptタグとして解釈されているものの中で、注入したPayloadの文字列が存在すればStored XSSの脆弱性が存在すると判断しています。
Candidate
が1つも無い場合はStored XSSの検出アルゴリズムではなくReflected XSSの検出アルゴリズムへ移行するため、Stored XSSが検出される箇所でReflected XSSが検出されることはないようになっています。
4.2.2. SQL Injection
SQL Injectionは、DBと連携したWebアプリケーションでSQLの呼び出し方に不備があると発生する脆弱性です。
SQL Injectionの検出は2段階になっています。
1段階目では文字列の部分一致を利用したError BasedなアプローチのSQL Injection攻撃、
2段階目は応答時間比較を利用したTime BasedなアプローチのBlind SQL Injection攻撃です。
4.2.2.1. SQL Injection (Error Based)
SQL Injection検査の1段階目のフェーズでは、SQLがエラーを起こすような値をPayloadとしてリクエストを送り、レスポンスボディにある特定のエラーメッセージが含まれているかどうかを判断します。
この時点で特定のエラーメッセージがレスポンスボディに含まれていればSQL Injectionの脆弱性が存在すると判断し、2段階目の検査は行わずに次のJsonMessage
の検査を行います。
エラーベースのPayloadで一通り検査が終了して脆弱性が発見できなかった場合は、Blind SQL Injectionの攻撃を実施します。
4.2.2.2. Blind SQL Injection (Time Based)
SQL Injection検査の2段階目のフェーズでは、SQLのエラーメッセージを含む出力結果がHTML上に表示されない場合であっても、レスポンスの差異から脆弱性が存在するかどうかを判断します。
具体的な攻撃手法としてはsleep
という、返されるメッセージのタイミングを遅らせるコマンドを使ったPayloadを含むリクエストを送り、レスポンスタイムが一定の時間(Payloadで指定したsleepの時間 - 誤差)以上であれば、SQL Injectionの脆弱性が存在すると判断するアルゴリズムです。
SQLのエラーメッセージ直接表示されていなくてもSQL Injectionの脆弱性を検出できる場合があるため、Time BasedのBlind SQL Injectionの攻撃手法は有効ですが、返されるメッセージのタイミングを遅らせることが基本なので、他の脆弱性検出アルゴリズムに比べて検査にかかる時間が長くなってしまいます。そのため、SQL Injection検出アルゴリズムは2段階に分けて、Error Basedの攻撃手法で検出できるものに関しては検出してしまうというアプローチを取っています。
4.2.3. Cross-Site Request Forgery
Cross-Site Request Forgery(CSRF)は、ログインした利用者の意図したリクエストであるかの確認ができていないと発生する脆弱性で、CSRFの脆弱性が存在するとアカウントの不正利用、アカウント内情報の改ざんなどが発生する可能性があります。
CSRFの検出は診断対象のWebアプリケーションがPOSTリクエストを受け取った際にReferer
のチェックを行っているかどうかのみを確認しています。
POSTパラメータ
を持つJsonMessage
に対して、Referer
を改ざんしてリクエストを送信したレスポンスのステータスコードが400番台500番台である場合にCSRF対策がされていると判断しています。
しかし、これだけでは偽陽性が多くなってしまう可能性が十分にあります。商品検索のようなどのユーザがリクエストを送信しても問題がない機能に関しては、脆弱性になり得ない場合があります。
4.2.2.2.で説明したStored XSS用のCandidate
はJsonMessage
に用意されているので、同様にCSRF用のCandidate
を用意して重要な処理が行われる部分をユーザにOnにしてもらうことが現在案に上がっています。
4.2.4. OS Command injection
OS Command Injectionは、シェルの不適切な呼び出し方をしている場合に意図しないOSコマンドの実行が可能になる脆弱性です。
OS Command Injection検出アルゴリズムは応答時間比較のアプローチを採用しています。
Blind SQL Injectionの検出手法同様、sleep
という返されるメッセージのタイミングを遅らせるコマンドを使ったPayloadを含むリクエストを送り、レスポンスタイムが一定の時間(Payloadで指定したsleepの時間 - 誤差)以上であれば、OS Command Injectionの脆弱性が存在すると判断するアルゴリズムです。
4.2.5. Directory Traversal
Directory Traversalは、攻撃者によって制限されたディレクトリ外の任意のファイルに対して、閲覧をはじめとする開発者の意図しない処理が行える脆弱性です。
文字列の部分一致で脆弱性が存在するかどうかを判断していくため、Unix系OSとWindowsOSのどのコンピュータにでも統一的なメッセージが表示される/etc/passwd
とwin.ini
のファイルパスを指定するPayloadに採用して判断できるようにしてあります。
4.2.6. Open Redirect
Open Redirectは、攻撃者が任意の外部ドメインにリダイレクトさせるURLを作成できる脆弱性です。
Open Redirect脆弱性の検出アルゴリズムはPayloadを載せたリクエストを送り、返ってきたレスポンスのLocation
ヘッダがhttp://example.com
を指していればとOpen Redirectの脆弱性が存在すると判断するアルゴリズムです。文字列の部分一致を用いてLocation
ヘッダの判断をしています。
4.2.7. HTTP Header Injection
HTTP Header Injectionは、レスポンスヘッダの出力処理に問題がある場合に発生する脆弱性です。
改行コードを含むPayloadとHimawariによってセットされたCookie
値をリクエストヘッダに載せたリクエストを送り、レスポンスのSet-Cookie
ヘッダにHimawariがセットしたCookie
値が存在するかどうかを文字列の部分一致で判断しています。
4.2.8. Directory Listing
Directory Listingとは、Webサーバのディレクトリ内容をリスト表示するものです。
特定のWebサイトディレクトリにインデックスファイルがない場合にディレクトリの内容を表示するWebサーバーの機能がオンになっていることで、Directory Listingが発生します。
Directory Listingそれ自体は脆弱性とは言い難いですが、この機能がオンになっていることによって意図せずファイルが公開され、攻撃者が攻撃を仕掛けるのに十分な情報を与えてしまう可能性があります。
Directory Listingの検出アプローチは文字列の部分一致です。
Directory Listingが存在するページでは、ApacheでもNginxでも同じメッセージがレスポンスボディに表示されるので、その文字列が存在しているかどうかで判断しています。
JsonNode
が持つURLごとに、URLの末尾に/
を付与する場合と付与しない場合の2つのURLに対してリクエストを送り、レスポンスボディに判断基準となるという文字列が含まれているかどうかを判定しています。
4.3. 非破壊な診断
Himawariは非破壊な診断を心がけてScan部分のアルゴリズムを実装したうえで、Payloadを選定しています。
危険なリクエストを送信したが故に診断対象のWebアプリケーションが壊れてしまうことがない攻撃手法を採用しています。
5. Report機能
3つ目のモジュールはReport機能です。 Himawariが診断を行った結果をわかりやすい形で利用者にレポートを表示します。
レポートには、検出した脆弱性の名前, 脆弱性の重要度(severity), CWE番号, 発見した脆弱性の件数, 脆弱性の説明, 脆弱性を防ぐための必須対策, 保険的対策を載せています。
レポートは脆弱性ごとにまとめられており、各脆弱性の情報として、脆弱性を検出した際に利用したPayload, 脆弱性が存在すると判断をした証拠となるEvidence, 脆弱性を検出したParameter, 脆弱性を検出したページのURL, 脆弱性を検出した際にHimawariからWebサーバへのリクエストおよびサーバからのレスポンスの情報が含まれています。
5.1. WebUI上でのレポート提示
診断中に検出された脆弱性は随時WebUIのレポート画面にて表示されます。 以下の図8に示すように見やすい形でユーザに提示します。
5.2. レポートのファイル出力
診断終了後、WebUIで表示されるレポートと同様の内容をファイルとして出力し、ダウンロードすることができます。
コンテストの関係でファイル形式をMarkdownにしていましたが、より見やすい形があればそのファイル出力にも対応していきたいと思います。
6. その他機能
6.1. Web User Interface
HimawariはNuxt.jsで実装されたシンプルなWebUIを搭載しています。
URLを入力してCrawl、Scan、レポート確認までのフローをWebUIで完結できるようになっています。
3.4で述べたサイトマップのJSONのImport / ExportはWebUIを通じて行います。サイトマップのJSONがアップロードされた場合はCrawlは行わずにScanの設定画面へ遷移します。
Scan中に検出された脆弱性は随時WebUIのReport画面に反映されます。
診断終了後のレポートはWebUIで確認できる他、Markdownファイルとしてレポートのファイル出力機能を備えています。
6.2.リクエストとレスポンスのログの保存
WebUI上ではすべてのログを表示しませんが、HimawariはCrawl及びScanで発生したすべてのリクエストとレスポンスのログを保存しています。
診断中に想定外のエラーが発生して中断してしまった場合等はログが大いに役立ちます。
6.3. ログイン機能
HimawariのCrawl設定画面とScan設定画面ではログイン情報の入力ができます。
例えば、「username=hoge
, password=fuga
」 という情報でアカウントを作成している場合は、ログイン情報入力欄に「username=hoge
, password=fuga
」のログイン情報とリクエストメソッドを指定してCrawlやScanを実行すればそのusername
とpassword
を利用してログインを試行します。
Crawl中やScan中にセッションが切れてしまうことを防ぐために、図9で示すようにリクエストを送信するごとにログインを試みるようにしています。この方法であれば、リクエストの数が単純に倍になってしまいますが、セッションが切れないことを優先した結果です。
6.4. Scanのオプション選択
HimawariはQuick ScanモードとFull Scanモードの2種類の診断方法を用意しています。
もとは以下の理由から分けていましたが、計算量の大幅な改良により、Quick ScanとFull Scanの診断時間の差分はほとんど無くなっています。
Stored XSS 検出アルゴリズムの中で実行されるStored XSSの候補となるページをすべての
JsonMessage
から探す処理にとても時間がかかってしまうため、主にStored XSSの検出を行わないようにするためにQuick Scanモードを用意しています。
6.5. Landmarkの開始番号の指定
診断対象のWebアプリケーションは環境をリセットすることが難しい場合があります。
Scan中に想定外のエラーが発生して診断が中断されてしまった場合に診断をやり直すことができるようLandmarkの開始番号を指定できるようになっています。この機能はデフォルトでは隠されていて、デバッグオプションとして用意しています。
Landmarkのデフォルトの初期値は0になっているので、そのままスキャンをやり直すとlandmarkを利用しているXSS等の脆弱性の検出を正しく行うことができません。
6.2. で説明したログファイルを確認することでLandmark番号がどこまで使われたかを知ることができるので、未使用のLandmark開始番号を指定して再スキャンを実行できます。
7. 精度評価
Himawariの有効性を示すには、精度を算出して他の診断ツールとあらゆる角度から比較を行う必要があります。
7.1. 評価指標
以下で定義される混合行列を用いて評価関数を作成し、精度を算出しました。
- TP (True Positive): 診断ツールが検出した脆弱性が、実際に脆弱性が存在したもの。
- FP (False Positive): 診断ツールが検出した脆弱性が、実際には脆弱性が存在していなかったもの。
- FN (False Negative): 実際には脆弱性が存在していたが、診断ツールが検出しなかったもの。
- TN (True Negative): 実際には脆弱性が存在しない箇所を、診断ツールが検出しなかったもの。
以上4つの値から3つの評価指標を算出します。
これらの評価指標を用いてベンチマークによる比較を行うことで精度を数値として算出することはできます。
しかし、これらの指標を用いて診断ツールの性能比較を行うことは少し注意が必要だと考えております。1つ1つの脆弱性には重みがあると考えており、検出の難しさや脆弱性の重要度、現実世界での脆弱性の発生しやすさ等によって変わってくる隠れたパラメータが存在していると考えられます。つまり、一概に精度を算出だけして「この診断ツールはRecallが高いから他の診断ツールよりFNが少なくて優秀だ」等と判断することは難しいと考えています。
まずは精度比較のための診断対象の選定には注意が必要で、さらに算出された精度を確認した上でどのような場合にFPやFNが発生してしまったのかの考察をする必要があると考えられます。
また、診断にかかる時間も比較材料の1つであると考えられます。
同じような精度であれば診断時間は短いほうが好ましいですが、FP・FNが多く発生してしまうようではいけません。検出しようとする脆弱性の種類の数やPayloadのバリエーションの豊富さによって診断時間は伸びてしまうので、診断時間と精度は正の相関の傾向が見られる可能性はありますが、無駄なアルゴリズムのせいで診断時間が伸びてしまっている場合も考えれるので、診断にかかる時間のみが診断ツールの優位性を獲得するとは考えにくいです。
7.2 診断対象の脆弱なWebアプリケーション
診断ツールの精度を比較するためには診断対象となるWebアプリケーションが必要となります。
私たちのチームは以下のいくつかの脆弱なWebアプリケーションを利用して脆弱性診断の概念検証(PoC)及び精度比較を行いました。
診断対象のWebアプリケーションにはまず箱庭BadStoreが候補に上がりました。
箱庭BadStoreをHimawariを使ってクロールを実行したところHTMLが崩れている箇所が見つかり、正常にクロールができずにエラーを出して(当時は)終了してしまいました。脆弱性診断の入門用教材としてよく使われる箱庭BadStoreですが、HTMLが崩れている箇所はWebブラウザが辻褄が合うように解釈していることが判明しました。
どのようにHTMLが崩れていたのかは以下の記事で解説されています。
こちらの検証は9月に行ったもので診断ができませんでしたが、現在は該当部分のJSONを手書きすれば良いので、診断は可能です。
診断対象となるWebアプリケーションは私たちのチームで実装したSunflowerと、OWASP Broken Web Applicationsから提供されているものを利用しました。
7.2.1 Sunflower
診断練習用のWebアプリケーションは世にたくさんありますが、Himawariが検出したい8個の脆弱性がすべて存在するかつ簡単にPoCを行える脆弱なWebアプリケーション環境が無かったため、私たちのチームでSunflowerと名づけたPoC用の脆弱なWebアプリケーションを構築しました。
Sunflowerでは、以下の8種類の脆弱性を作りこんでいます。
- Cross-Site Scripting(Reflected・Stored)
- SQL Injection
- Cross-Site Request Forgery
- OS Command Injection
- Directory Traversal
- Open Redirect
- HTTP Header Injection
- Directory Listing
SunflowerはHimawariで実装されている脆弱性検出アルゴリズムの全ての脆弱性を網羅できるようになっています。
Sunflower構築後、手動でPoCを行って脆弱性が存在することを確認したうえで、Himawariで実装されている脆弱性検出アルゴリズムのPoCを行いました。
7.2.2. WAVSEP
WAVSEPは、Webアプリケーションに対する診断ツールの品質や精度の評価を支援するために設計された脆弱なWebアプリケーションです。いくつかの論文ではWAVSEPを利用して診断ツールの評価を実施していました。
WAVSEPでは、以下の6種類の脆弱性に加えて、各脆弱性のFalse Positive用のテストケースが用意されています。
Himawariが対応しているXSS, SQL Injection, Open Redirectの3つの脆弱性の評価を行いました。 (Local File InclusionはDirectory Traversalとは違うものだと認識してたので検査を実施しませんでした。)
WAVSEPでは脆弱性ごとにページが用意されていますが、意図的にそのページへリンクやフォームを用意していないため、WAVSEPのトップのURLを診断ツールに入力して診断してもどのページも発見できないまま終了してしまします。
ページ単位での診断を行うため、診断時間の比較は行わないこととします。
7.2.3 DVWAとGruyere
SunflowerやWAVSEPでは、アンカー要素でしかハイパーリンクを用意していないため、Crawl機能の性能を十分に確認できない問題があります。Crawl機能の性能はScan機能の精度に直結してくると考えているので、SunflowerやWAVSEP以外の脆弱なWebアプリケーションを用意する必要がありました。
そこで採用したのは、DVWA(Damn Vulnerable Web Application)とGruyereです。
DVWAの公式ドキュメントを参照すると、DVWAには以下の脆弱性を作りこんでいると記載があります。
- Brute Force
- Command Execution
- CSRF
- File Inclusion
- SQL Injection
- Insecure File Upload
- Cross Site Scripting(XSS)
- Easter eggs
Gruyereの公式ドキュメントを参照すると、Gruyereには以下の脆弱性を作りこんでいると記載があります。
- Cross-Site Scripting (XSS)
- Client-State Manipulation
- Cross-Site Request Forgery (XSRF)
- Cross Site Script Inclusion (XSSI)
- Path Traversal
- Denial of Service
- Code Execution
- Configuration Vulnerabilities
- AJAX vulnerabilities
- Other Vulnerabilities
また、DVWAとGruyereにはオリジン外へのリンクが沢山存在しています。
3.2. 診断のスコープ で述べた通りのオリジン外へのCrawl, Scanは実施しないようにできているかを確認する目的で実験を行いました。
8. 結果と考察
8.1. Sunflower
Sunflowerに備えられている脆弱性はCSRF脆弱性のFPを除いて、すべて検出することができています。 CSRF脆弱性のFP分を覗けば、Accuracyは1です。
8.2 WAVSEP
WAVSEPの診断結果をsectoolmarketのフォーマットで算出すると以下の表のようになりました。
WIVIT | SQLi | RXSS | LFI | RFI | Redirect | Backup | |
---|---|---|---|---|---|---|---|
Accuracy | × | 0.988 | 0.228 | × | × | 0.5 | × |
False Positives | × | 0.3 | 0 | × | × | 0 | × |
脆弱性ごとに精度を算出すると、以下の表のようになりました。
Accuracy | Precision | Recall | |
---|---|---|---|
Reflected XSS | 0.288 | 0.525 | 0.28 |
FP-Reflected XSS | 1 | 1 | - |
SQL Injection | 0.982 | 1 | 0.982 |
FP-SQL Injection | 0.7 | 0.7 | - |
Open Redirect | 0.5 | 1 | 0.5 |
FP-Open Redirect | 1 | 1 | - |
sectoolmarketの最終更新日が2016年なので比較対象とするのは好ましくありませんが、当時の診断ツールと比べるとOSS診断ツールとある程度(Reflected XSS以外は)肩を並べられる精度が出ています。
HimawariがFPやFNを出してしまったケースに関しては全て考察を行いました。
SQL Injectionで唯一FNを出してしまったケースでは、HimawariのPayloadを載せたPayload生成部分に問題がありました。Himawariでは、Crawl時に挿入したデータにPayloadを付け加える形でリクエストを生成しています。今回のテストケースでは、Payload以前に文字列が含まれていれば攻撃が刺さらないようになっていたためFNが発生しました。
FNを出してしまいましたが、Sitemapの編集によって検出は可能です。パラメータのValueを空文字にすれば空文字列にPayloadを付け加える形でリクエストを生成するので検出が可能になりますが、それを診断対象に向けたチューニングと言ってしまって良いものなのかは怪しいところです。
また、今回FNを出してしまったケース(SQL Injection - Test Cases: Case04-InjectionInUpdate-String-CommandInjection-WithDifferent200Responses.jsp)は差分処理でのアプローチをして脆弱性を判断するものなので、特にチューニングすることなく応答時間比較のアプローチで他のすべてを検出できているのは上出来だと考えられます。
SQL InjectionでFPを出してしまったケースでは、全てError Based Injectionの検出手法でした。False Positive用のテストケースは、SQLのError文をもとに脆弱性が存在するかを判断しているアルゴリズムでは偽陽性が出てしまうようなテストケースになっていたためFPが発生しました。
Reflected XSSでFNを出してしまったケースは、もともとアラートのあるページやVBScriptを使ったテストケースため検出することができませんでした。後述しますが、HimawariはJavaScriptへの対応を行っていないため、JavaScriptを扱ったテストケースはすべてFNになってしまいます。
JavaScriptベースのリダイレクトには対応していないため、Open Redirectの脆弱性検出のAccuracyは50%となっています。HTMLに存在するRedirectは追えているため、JavaScriptベースでないOpen Redirectは100%の精度で検出できています。
8.3. DVWAとGruyere
DVWAには2.3. 診断のスコープ で述べた通りのオリジン外へのCrawl、Scanが実施しないようにできているかを確認する目的で実験を行いました。
DVWAは34分9秒、Gruyereは8分22秒で診断を終えました。DVWAに存在する脆弱性の全体像が不明なため、自分達で検証ではTPとFPの検証のみとしました。
以下の図11に示しているのが、DVWAをCrawlをして得られたスコープ外のURLの一覧です。
また、DVWAにはパスワード変更ページが存在します。Scanの際にパスワード変更を行ってしまうとログインが不可能になったまま診断を終えてしまいます。3.4. で説明したHimawariの機能であるSitemapの編集によりパスワード変更ページを回避してScanを終えることができました。
8.4 自動診断ツールのメリット
Webアプリケーションの開発者がWebセキュリティに疎い場合は、診断を行おうとしてもまず何から始めればよいのかわからないと考えています。HimawariのようなBlack Box型の診断ツールを利用することで、簡単にかつ効率的な診断ができると自負しています。
しかし、8.3.であったWAVSEPのあるテストケースのように、診断対象の仕様を把握していないと検出が難しい場合が存在することは、脆弱性診断ツールを利用する人は頭に入れておくべきです。
9. Himawariの限界
Himawariは素早く自動的にWebアプリケーションへ診断を行うことが可能ですが、Himawariにはいくつかの限界があります。
Himawariは脆弱性を検出しなかった場合に脆弱性が存在しないこと証明することはできません。FP・FNが発生していることから、現在のHimawariの能力と限界の線引きをはっきりとさせておくことは今後の発展のためにも重要だと考えています。
9.1. JavaScriptへの対応
HimawariはJavaScriptを一切考慮していません。
そのため、location.href=’./hoge’
のようなリダイレクトには対応できず、診断対象サイトの仕様次第ではCrawlが全く出来ない可能性があります。
9.2. CSRF脆弱性検出アルゴリズム
アンチCSRFトークンの実装がされているWebアプリケーションに対するCSRF脆弱性検出は実装できていません。 4.2.3. で説明したとおり、CSRFの検出方法はレスポンスのステータスコードに依存しているため、トークンで対策されているにも関わらずCSRFが検出される可能性があります。
9.2. Open Redirect脆弱性検出アルゴリズム
以下の2点がそろっている場合は、Open Redirectの脆弱性とはなり得ません。
- もともと外部に遷移する仕様である。
- Webアプリケーションのユーザにとって外部ドメインに遷移することが容易にわかる。
ユーザにとって意図しないリダイレクトがOpen Redirectの脆弱性であるとすると、診断ツールが「意図しない」を汲み取ってOpen Redirectの脆弱性ではないと指摘することはかなり難しいと考えられます。
また、9.1. JavaScriptへの対応で述べた通り、HimawariのアルゴリズムはJavaScriptを考慮していないため、JavaScriptによるオープンリダイレクトの検出アルゴリズムは実装できていません。
9.3. DOM Based XSS検出アルゴリズム
9.1. JavaScriptへの対応で述べた通り、HimawariのアルゴリズムはJavaScriptを考慮していないため、DOM Based XSSと呼ばれる脆弱性の検出アルゴリズムは実装できていません。
9.4 診断するWebアプリケーションの実装に依存してしまう部分
HimawariはBlack Box型の診断ツールです。BlackBox型とは、リクエストとレスポンスから脆弱性が存在するかどうかを判断する方法です。
White Box型の診断ツールと違い、実際のソースコードから全体の構造やロジックを確認することはできないため、診断対象の明確な仕様書がなければ隅々までテストを行うことは難しい場合が存在します。
Black Box型の診断ツールはWebアプリケーションに関わっていない第三者でも、情報セキュリティに詳しくない人にでも非常に簡単に診断を行うことができますが、全ての脆弱性を検出することはとても難しいということをユーザは頭に入れて診断ツールを利用すべきです。
9.5. 差分処理
Himawariの脆弱性診断アプローチは、4.1.3. で述べたように応答時間比較と文字列の部分一致の2種類です。世の中に存在する他の脆弱性診断ツールでは、テキストの差分処理を検出アプローチとして採用しているものもありますが、Himawariはテキストの差分処理のアプローチを採用していません。
テキストの差分処理は評価基準が適切でないと、FP・FNが大量に発生してしまうことが予想させたため、検出アプローチとして採用しませんでした。差分処理を諦めたため、8.2. WAVSEP で述べたとおり、検出が難しい場面が発生してしまっています。
10. おわりに
最後までご覧いただきありがとうございます。 ここまでの話を踏まえたうえで、最終審査会で発表したスライドをご覧いただくとより伝わるかなと思います。
私たちの愛着のあるHimawariを今後もコツコツと開発を続けていきたいです。
最後までご覧いただきありがとうございました。
この記事はIPFactory Advent Calendar 2021 25日目の記事です。
昨日24日はfutabatoによる「Machine Learning for Web Vulnerability Detection: The Case of Cross-Site Request Forgery」でした。
この記事をもってIPFactory Advent Calendar 2021を完走することができました。
2022年もどうぞよろしくお願いいたします。よいお年をお迎えください。