SSI Injection
概要
先日Writeupの記事を書いたのですが、SSI Injectionという攻撃手法が出てきたのですが、筆者はそもそもSSIを知りませんでした。なので今回は実際にSSI Injectionの検証結果をブログに残したいと思いました。
SSIとは?
そもそもSSIとは何かということから今回の検証は始まりました。 SSIとはServer side Includesの略でHTMLに動きをつけるために使われるようです。 最近ではあまり使われることがないらしく今更感もあるのですが、過去にもSSI Injectionの事例があるようなので知識として入れておきたいと思い検証しました。
SSIの導入
今回SSIの導入はこちらの記事を参考にしました。
環境
Virtual Box 5.2.22
OS:Ubuntu18.04
Apache:2.4.29
導入
SSIを動かすためにはモジュールを読み込まなければいけないらしいのでapache2.confに以下の内容を付け足しました。
LoadModule include_module modules/mod_include.so LoadModule cgid_module modules/mod_cgid.so
/etc/apache2にはもともとmoduleというディレクトリは存在しないのでmod_include.soをコピーしてくる必要がありました。 mod_include.soファイルの検索を行い
sudo find / -name mod_include.so
/usr/lib/apache2/modules/mod_include.so
このような検索結果が返ってきたので/usr/lib/apache2/modules/をそのまま/etc/apache2/modulesにコピーしました。
sudo cp -r /usr/lib/apache2/modules/mod_include.so /etc/apache2/modules/
今回は/var/www/html下でSSIを使うのでapache2.confの設定ファイルに書き足しました。
<Directory /var/www/html> Options Includes AllowOverride None Require all granted AddType text/html .php .html AddOutputFilter INCLUDES .php .html </Directory>
Directoryの後には設定を適用するディレクトリのパスを指定します。
Optionはincludesを指定することによってSSIの使用を許可します。
AllowOverRideは.htaccessで使用できるディレクトリを指定する為のディレクティブです。今回は設定する必要がないのでNoneにしています。
Requireはアクセス制御の設定です。今回は全てのアクセスを許可します。
AddTypeディレクティブは与えられた拡張子を指定されたコンテントマップにマップしてくれます。今回は.phpと.htmlをで動くように指定しました。
AddOutputFilterは同じく.phpと.htmlを指定します。
ここでフィルタについて少し調べたのですが、この機能はApache2.0以降の機能であり、クライアントとサーバー間で送受信されるデータへの処理プロセスのことを言うようです。クライアントからサーバーに送られるデータを入力フィルタ、サーバーからクライアントへのデータは出力フィルタによって処理することによりApacheに入出力されるデータを加工する為の機能を提供しているようです。
また、Apache1.3まではSSIをハンドラとして実装していたらしいのですが、2.0からはフィルタとして提供されているようです。
よってApache1.3でSSIを有効にするにはAddHandlerディレクティブに設定しなければいけなかったようです。しかし、Apache2.0からはSSIをフィルタとして提供されるようになったのでAddOutputFilterディレクティブを使用します。
設定ファイルの編集が終わったので次に実際にSSIが動作するかテストをしてみました。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>SSI Test</title> </head> <body> <!--#echo var="DATE_LOCAL" --> </body> </html>
/var/www/htmlに移動してtest.htmlを作成しました。 SSIの現在の時刻を表示コードを記述してブラウザからアクセスしてみると
問題なく動作していました。
次にphpファイルでテストをしてみました。
<!--#echo var="DATE_LOCAL" -->
test.phpというファイルを作成して先ほどと同じように時刻を表示させようとすると
問題なく動きました。
検証
ユーザーから入力値を受け取るform.htmlと入力値をそのまま表示するview.phpを作成しました。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>form.html</title> </head> <body> <form action="view.php" method="post"> <input type="text" name="text" size="40">入力フォーム <input type="submit" value="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>view.php</title> </head> <body> <?php $value = $_POST["value"]; echo "入力値は".$value."です。"; ?> </body> </html>
入力値に先ほどの時間を表示するコードを入力すると
SSIのコードが問題なく動いてしましました。
また、SSIはOSコマンドの実行が可能な為、lsコマンドを実行してみると
<!--#exec cmd="ls" -->
ディレクトリの中身が見れてしまいました。
他にも
<!--#exec cmd="echo '<?php phpinfo();?>' > info.php" -->
ファイルの出力も行える為、webshellなどのバックドアの設置も可能でした。
対策
SSI Injectionの対策はXSSの対策と同様で特殊文字のエスケープによって対策することが可能になるそうです view.phpの$valueの値を直接代入するのではなくhtmlspecialchars関数に渡してから代入するようにすると
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>view.php</title> </head> <body> <?php $value = htmlspecialchars($_POST["value"]); echo "入力値は".$value."です。"; ?> </body> </html>
SSIが動作せず、文字列としてペイロードが表示されました。
おわりに
今回はSSI Injectionを検証してみました。 SSIはApacheの設定次第で動くので過去に動くように設定していて現在は使用していないものの設定をそのままにしている可能性も考えられますね。もしかしたら発火する可能性もあるかもしれませんね。