土日の勉強ノート

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

OWASP ZAPの自動スキャン結果の分析と対策:リスク中すべて

ハッキング・ラボのつくりかた 完全版 仮想環境におけるハッカー体験学習」と「体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践」(通称:徳丸本)を参考に、セキュリティの勉強を進めています。

前回は、以前 に行った OWASP ZAP の自動脆弱性スキャンの結果の「オープンリダイレクト」について、分析と対策までやりました。

今回は、リスク中の内容を見ていきます。

それでは、やっていきます。

参考文献

はじめに

「セキュリティ」の記事一覧です。良かったら参考にしてください。

セキュリティの記事一覧
・第1回:Ghidraで始めるリバースエンジニアリング(環境構築編)
・第2回:Ghidraで始めるリバースエンジニアリング(使い方編)
・第3回:VirtualBoxにParrotOS(OVA)をインストールする
・第4回:tcpdumpを理解して出力を正しく見れるようにする
・第5回:nginx(エンジンエックス)を理解する
・第6回:Python+Flask(WSGI+Werkzeug+Jinja2)を動かしてみる
・第7回:Python+FlaskのファイルをCython化してみる
・第8回:shadowファイルを理解してパスワードを解読してみる
・第9回:安全なWebアプリケーションの作り方(徳丸本)の環境構築
・第10回:Vue.jsの2.xと3.xをVue CLIを使って動かしてみる(ビルドも行う)
・第11回:Vue.jsのソースコードを確認する(ビルド後のソースも見てみる)
・第12回:徳丸本:OWASP ZAPの自動脆弱性スキャンをやってみる
・第13回:徳丸本:セッション管理を理解してセッションID漏洩で成りすましを試す
・第14回:OWASP ZAPの自動スキャン結果の分析と対策:パストラバーサル
・第15回:OWASP ZAPの自動スキャン結果の分析と対策:クロスサイトスクリプティング(XSS)
・第16回:OWASP ZAPの自動スキャン結果の分析と対策:SQLインジェクション
・第17回:OWASP ZAPの自動スキャン結果の分析と対策:オープンリダイレクト
・第18回:OWASP ZAPの自動スキャン結果の分析と対策:リスク中すべて ← 今回

徳丸本の環境構築については、以下の第9回でやりました。

daisuke20240310.hatenablog.com

また、徳丸本が用意してくれている、脆弱なアプリケーション Bad Todo の準備については、以下の第12回でやりました。今回も、この環境を使ってやっていきます。

daisuke20240310.hatenablog.com

リスク中の検出結果の確認

リスク中の内容を見ていきます。いくつか出ていますが、JQuery のバージョンが古い、とか、ブラウザのセキュリティ機能を強化するためのHTTPレスポンスヘッダに指定がない、など、直接的な影響のない脆弱性という感じです。

まず、ディレクトリブラウジングについて見ていきます。

ディレクトリ・リスティングの脆弱性の分析と再現

脆弱性スキャンの指摘結果には、ディレクトリブラウジングという名前の指摘になっていますが、徳丸本では、ディレクトリ・リスティングという名前で説明がされています。ここでは、徳丸本に合わせて、ディレクトリ・リスティングと呼ぶことにします。

これはよくある内容で、簡単に再現できたので、分析と再現をまとめてやっていきます。

以下のように、ディレクトリを指定すると、そのディレクトリの内容が見えてしまう脆弱性です。

ディレクトリ・リスティングの脆弱性の分析と再現
ディレクトリ・リスティングの脆弱性の分析と再現

これは、単純に、Webサーバ(Bad Todo アプリでは Apache)に対する設定がよくありません。ディレクトリを指定されたときに、ディレクトリの内容が見えないように設定しなければいけません。

ディレクトリ・リスティングの脆弱性の対策

Apache の設定を変えて、ディレクトリ・リスティングを禁止します。

Bad Todo アプリは、Apache で動いていて、以下の対応でディレクトリ・リスティングを禁止できると思います。

Apache の設定ファイルは、以下の /etc/apache2/apache2.conf が有効になってそうでした。

<Directory /var/www/>
        Options Indexes FollowSymLinks ExecCGI
        AllowOverride None
        Require all granted
        <FilesMatch "\.php$">
                SetHandler application/x-httpd-php-5.3.3
                Action application/x-httpd-php-5.3.3 /cgi-bin/php-5.3.3
        </FilesMatch>
        <FilesMatch \.cgi$>
                SetHandler cgi-script
        </FilesMatch>
</Directory>

ディレクトリ・リスティングを禁止するには、Options Indexes FollowSymLinks ExecCGIIndexes を削除すればいいようです。

実際に、Indexes を削除して、以下のように、Apache を再起動したところ、ディレクトリ・リスティングを禁止できていました。

$ sudo service apache2 restart

ディレクトリ・リスティングを禁止できた
ディレクトリ・リスティングを禁止できた

自動脆弱性スキャンの再実行

では、自動脆弱性スキャンを実行します。ディレクトリブラウジングの指摘は無くなっていました。対策は成功したようです。急にリスク中が減った気もしますが、まぁいいですかね。

自動脆弱性スキャンの再実行結果
自動脆弱性スキャンの再実行結果

リスク中の検出結果の確認(続き)

続いて、Vulnerable JS Library(JQuery のバージョンが古い)を見ていきます。

Vulnerable JS Libraryの脆弱性の分析

version 1.8.3 は脆弱だと指摘されています。徳丸本でも、この件について言及があり、wasbook には、version 3.2.1 も含まれています。

Vulnerable JS Libraryの脆弱性の確認
Vulnerable JS Libraryの脆弱性の確認

Vulnerable JS Libraryの脆弱性の対策

ソースコードを検索すると、JQuery の参照は、todolist.php だけのようです。

以下のように修正しました。

--- todo.org/todolist.php       2018-08-16 12:03:14.000000000 +0900
+++ todo.change/todolist.php    2024-08-17 18:25:39.000000000 +0900
@@ -19,7 +19,7 @@
 ?><html>
 <head>
 <link rel="stylesheet" type="text/css" href="css/common.css">
-<script src="../js/jquery-1.8.3.js"></script>
+<script src="../js/jquery-3.2.1.min.js"></script>
 <title>一覧</title>
 </head>
 <body>

その後、Firefox で Bad Todo の todolist.php をアクセスしていると、OWASP ZAP で、version 3.2.1 is vulnerable. と、まだ指摘が出てしまいました。version 3.3.1 でも同様でした。

仕方ないので、最新版を以下の公式サイトからダウンロードします。現時点の最新版は、v3.7.1 でした。

jquery.com

「Download JQuery」というボタンをクリックして、「Download JQuery 3.7.1」というボタンをクリックします。すると、「jquery-3.7.1.min.js」が表示されるので、右クリックして名前を付けて保存を押し、保存したファイルを wasbook にアップロードします。

ソースコードは、上記と同様に <script src="../js/jquery-3.7.1.min.js"></script> に変更します。

これで、OWASP ZAP で指摘が出なくなりました。

Missing Anti-clickjacking Headerの脆弱性の分析

Missing Anti-clickjacking Header という脆弱性を見ていきます。

指摘の説明では、Content-Security-Policy、X-Frame-Options のどちらも設定されていない、ということでした。

Missing Anti-clickjacking Headerの脆弱性
Missing Anti-clickjacking Headerの脆弱性

徳丸本では、クリックジャッキングという攻撃手法の説明の中で、X-Frame-Optionsヘッダについての説明があります。

簡単に言うと、クリックジャッキングとは、iframeタグを使って、罠内容を隠して、ボタンをクリックさせるという攻撃手法です。

Missing Anti-clickjacking Headerの脆弱性の対策

徳丸本では、X-Frame-Optionsヘッダを設定すれば、iframe、frame を禁止できるとあります。

サイトとして、これらのタグを使用していないのであれば、常に X-Frame-Optionsヘッダを出力するように、Webサーバ(Apache)に設定も可能ということです。

具体的には、以下の一文を追加するだけでした。

Header always set X-Frame-Options "SAMEORIGIN"

編集が出来たら、文法チェックを行い、Apache を再起動します。

$ sudo apache2ctl configtest
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
Syntax OK
$ sudo service apache2 restart

HTTPレスポンスを確認したところ、ちゃんと X-Frame-Options が追加されていました。

X-Frame-Optionsが出力されている
X-Frame-Optionsが出力されている

Hidden File Foundの脆弱性の分析

次は、Hidden File Foundの脆弱性を見ていきます。

これは、重要なファイルが検出されたということのようです。

phpinfo.php と server-status の2ファイルが指摘されています。

Hidden File Foundの脆弱性
Hidden File Foundの脆弱性

phpinfo.php は、wasbook が提供しているファイルなので問題ありません。

server-status の方は、以下のように、Apache で用意されている Webサーバの状態を確認できるもののようです。

Apacheのserver-status
Apacheのserver-status

Hidden File Foundの脆弱性の対策

phpinfo.php の方は意図的ということで対策はしないことにします。

server-status の方は、一応、対策を行います。

Apache の設定で、無効化すればいいようです。

/etc/apache2/mods-available/status.load は、以下のようになっています。

LoadModule status_module /usr/lib/apache2/modules/mod_status.so

これをコメントアウトします。

#LoadModule status_module /usr/lib/apache2/modules/mod_status.so

あとは、文法チェックをして、Apache を再起動します。

$ sudo apache2ctl configtest
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message
Syntax OK
$ sudo service apache2 restart

Content Security Policy (CSP) Header Not Setの脆弱性の分析

Content-Security-Policy レスポンスヘッダに設定されていない、という指摘のようです。

Content Security Policy (CSP) Header Not Setの脆弱性
Content Security Policy (CSP) Header Not Setの脆弱性

徳丸本では、Content-Security-Policy について説明がされていて、これを指定すると、XSS攻撃に対する防御策として期待ができる、と書かれていますが、一方で、JavaScript も禁止されるため、現状は、Content-Security-Policy の動向に注視する、と書かれていました。

これについては、対策は行わないことにします。

自動脆弱性スキャンの再実行

この時点で、自動脆弱性スキャンを再実行します。

自動脆弱性スキャンの再実行の結果
自動脆弱性スキャンの再実行の結果

まだ対策を行っていない、アンチCSRFトークンが使用されていない、以外は、想定通り、指摘がなくなっていました。

アンチCSRFトークンが使用されていないの脆弱性の分析

最後は、アンチCSRFトークンが使用されていないの脆弱性です。

アンチCSRFトークンが使用されていないの脆弱性
アンチCSRFトークンが使用されていないの脆弱性

CSRF とは、クロスサイト・リクエストフォージェリの略で、クロスサイトスクリプティングとよく似ている脆弱性です。

一方で、XSS に比べて、対策はとても難しい脆弱性のようです。例えば、罠サイトを経由させることが前提となりますが、パスワード変更を行う POSTリクエストに対して、CSRF攻撃をしかけた場合と、正規のサイトでパスワード変更を行う POSTリクエストは、Referer 以外に、区別ができないとのことです。

そこで、CSRFトークンとは、セッション変数に乱数(トークン)を設定しておき、パスワード変更を行うリクエストのフォームに、hiddenパラメータとして、同じ乱数を渡します。

パスワード変更を受けるページでは、セッション変数の乱数が設定されていることを確認し、その乱数と hiddenパラメータの乱数が一致することを確認します。

これにより、罠サイトからの POSTリクエストではないことが確認できます。これがアンチCSRFトークンです。

CSRF に対策を行うには、POSTリクエスト全てを対象にする場合、大がかりな対応が必要になります。一方で、外部リンクからのリクエストを全て禁止にするわけにいかないケースもあります。

よって、徳丸本では、重要なところだけ CSRF の対策を行うことを推奨していました。

指摘されている 7件について詳しく見ていきます。

No. リクエスト 用途 判断と理由
1 POST ログイン データベースを変更しないPOSTリクエストなので対策不要
2 GET TODOの検索 GETリクエストなので対策不要
3 POST TODOの削除/完了 データベースを変更するので対策必要
4 GET TODOの検索 No.2と同じ
5 POST TODOの削除/完了 No.3と同じ
6 GET TODOの検索 No.2と同じ
7 POST TODOの削除/完了 No.3と同じ

というわけで、対策が必要なのは1か所となりました。

アンチCSRFトークンが使用されていないの脆弱性の対策

徳丸本のソースコードの /45/45-002a.php/45/45-003a.php に、CSRF対策のトークンを埋め込んだ実装があるので、この内容を使わせていただきます。

修正するソースコードは、todolist.phpeditlist.php の2ファイルです。

ここで1点注意です。自動脆弱性スキャンを実行する前に、アンチCSRFトークンを、ツール→オプション... で設定したと思います。ここで「todotoken」という名前で設定しました。トークンの名前にはこの名前を使う必要があります。違う名前だと正しく診断できないようです。

まず、todolist.php です。今回の修正内容だけを貼ります。ログインしている場合にだけ、トークンの準備をしています。また、hiddenパラメータにトークンを設定しています。

--- todo.org/todolist.php       2018-08-16 12:03:14.000000000 +0900
+++ todo.change/todolist.php    2024-08-17 22:09:01.000000000 +0900
@@ -8,6 +8,15 @@
   if (empty($reqid))
     $reqid = -1;

+  if (is_loggedin()) {
+    if (empty($_SESSION['todotoken'])) { // トークンが空なら生成
+      $todotoken = bin2hex(openssl_random_pseudo_bytes(24));
+      $_SESSION['todotoken'] = $todotoken;
+    } else {  // トークンがもともとあればそれを使う
+      $todotoken = $_SESSION['todotoken'];
+    }
+  }
+
   try {
     $dbh = dblogin();
     $sql = "SELECT todos.id, users.userid, todo, c_date, due_date, done, org_filename, real_filename, public FROM todos INNER JOIN users ON users.id=todos.owner AND (todos.owner=? OR ?) AND (todos.owner = ? OR todos.public > 0 OR ? > 0)";
@@ -74,6 +83,7 @@
         }
       ?>
       </table><br>
+      <input type="hidden" name="todotoken" value="<?php echo htmlspecialchars($todotoken, ENT_COMPAT, 'UTF-8'); ?>">
       <button type="submit" name="process" value="dellist">削除</button>
       <button type="submit" name="process" value="donelist">完了</button>
       <button type="submit" name="process" value="exportlist">エクスポート</button>

次に、editlist.php の修正点です。hiddenパラメータのトークンとセッション変数のトークンを取得します。error_log() はデバッグ用で両方のトークンをログ出力しています。hiddenパラメータのトークンが設定されていることと、両方のトークンが一致していることを条件に処理を継続します。条件が満たされない場合はエラー終了します。

--- todo.org/editlist.php       2018-08-19 10:26:23.000000000 +0900
+++ todo.change/editlist.php    2024-08-17 22:09:26.000000000 +0900
@@ -3,6 +3,13 @@
 require_loggedin();
 $id = $user->get_id();

+$p_token = filter_input(INPUT_POST, 'todotoken');
+$s_token = @$_SESSION['todotoken'];
+error_log("p_token=" . $p_token . ", s_token=" . $s_token);
+if (empty($p_token) || $p_token !== $s_token) {
+  die('正規の画面からご使用ください'); // 適当なエラーメッセージを表示する
+}
+
 $ids = @$_POST['id'];
 if (empty($ids)) {
   die('項目をチェックして下さい');

ログ出力は以下のような感じです。

p_token=1bc99a12b0d2d66f2a004f04c9795ab2eb4100c43c8f030f, s_token=1bc99a12b0d2d66f2a004f04c9795ab2eb4100c43c8f030f

2つのトークンが一致していることが分かります。

自動脆弱性スキャンの再実行

最後に、自動脆弱性スキャンを再実行します。

個数が合わないですが、5件は、ログイン、TODO の検索のみでした。対策は成功したようです。

自動脆弱性スキャンの再実行の結果
自動脆弱性スキャンの再実行の結果

だいぶ長かったですが、リスク中の対策は以上です。

おわりに

今回は、自動脆弱性スキャンのリスク中の脆弱性について、再現と対策を行いました。

次回はどうしましょうか。。

今回は、Chromium のロゴを使わせていただきました。ありがとうございます。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。