pcre-devel libxml2-devel のインストール
yum install pcre-devel libxml2-devel
apacheのダウンロード
cd /usr/local/src
wget http://ftp.jaist.ac.jp/pub/apache//httpd/httpd-2.2.25.tar.gz
tar zxvf httpd-2.2.25.tar.gz
mod_unique_id インストール
cd /usr/local/src/httpd-2.2.25/modules/metadata
/usr/local/apache2/bin/apxs -cia mod_unique_id.c && echo OK
apr インストール
cd /usr/local/src/httpd-2.2.25/srclib/apr
./configure && make && make install && echo OK
apr-util インストール
cd /usr/local/src/httpd-2.2.25/srclib/apr-util
./configure --with-apr=/usr/local/apr/bin/apr-1-config && \
make && make install && echo OK
apache インストール
./configure \
--enable-so \
--enable-rewrite \
--enable-mods-shared="unique_id" \
--with-pcre \
--with-apr=/usr/local/apr/bin/apr-1-config \
--with-apr-util=/usr/local/apr/bin/apu-1-config \
--prefix=/usr/local/apache2 && \
make && make install && echo OK
apache 再構築の場合前回のコンパイルオプションの確認方法
/usr/local/src/httpd-2.2.xx/config.status --version
modsecurity インストール
2.7系最新を使うとlibxml2が2.6.29でないとだめだといわれる。
CentOS 5.x 標準のlibxml2のバージョンは2.6.26のため2.6系をダウンロードしてくる。
cd /usr/local/src/
wget http://sourceforge.net/projects/mod-security/files/modsecurity-apache/2.6.8/modsecurity-apache_2.6.8.tar.gz/download
tar zxvf modsecurity-apache_2.6.8.tar.gz
cd modsecurity-apache_2.6.8
./configure
--prefix=/usr/local/apache2 \
--with-apxs=/usr/local/apache2/bin/apxs \
--with-apr=/usr/local/apache2/bin/apr-1-config \
--with-apu=/usr/local/apache/bin/apu-1-config \
--with-pcre=/usr/bin/pcre-config \
--with-libxml=/usr/bin/xml2-config \
--enable-pcre-match-limit=90000 \
--enable-pcre-match-limit-recursion=90000 \
LDFLAGS=-L/usr/local/apache2/lib
apacheのエラーログに「Execution error - PCRE limits exceeded (-8)」とエラーを吐かれたので
http://forum.parallels.com/showthread.php?99430-ModSecurity-Rule-execution-error-PCRE-limits-exceeded
を参考にした。
CRS
最新版のCRSを使うと「Error parsing actions: Unknown action: ver」と怒られるのでv2.2.5を探してくる。
参考:http://sourceforge.net/mailarchive/message.php?msg_id=29864155
CRSの設置
cd /usr/local/src/
wget https://github.com/SpiderLabs/owasp-modsecurity-crs/tarball/v2.2.5
mkdir -p /usr/local/apache2/conf/modsecurity
tar zxvf SpiderLabs-owasp-modsecurity-crs-v2.2.5-0-g28e4ec8.tar.gz
cd SpiderLabs-owasp-modsecurity-crs-5c28b52
cp -av base_rules/* /usr/local/apache2/conf/modsecurity/
日本語をGET/POSTすると攻撃扱いになるのでリストから外す
diff -u modsecurity_crs_41_sql_injection_attacks.conf.org modsecurity_crs_41_sql_injection_attacks.conf
--- modsecurity_crs_41_sql_injection_attacks.conf.org 2012-09-19 22:24:02.000000000 +0900
+++ modsecurity_crs_41_sql_injection_attacks.conf 2013-09-01 02:08:29.000000000 +0900
@@ -152,7 +152,7 @@
#
# This rule attempts to identify when multiple (4 or more) non-word characters are repeated in sequence
#
-SecRule ARGS "\W{4,}" "phase:2,capture,t:none,t:urlDecodeUni,block,id:'960024',rev:'2.2.5',msg:'SQL Character Anomaly Detection Alert - Repetative Non-Word Characters',logdata:'%{tx.0}',setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},setvar:tx.sql_injection_score=+1,setvar:'tx.msg=%{rule.msg}',setvar:tx.%{rule.id}-WEB_ATTACK/RESTRICTED_SQL_CHARS-%{matched_var_name}=%{tx.0}"
+#SecRule ARGS "\W{4,}" "phase:2,capture,t:none,t:urlDecodeUni,block,id:'960024',rev:'2.2.5',msg:'SQL Character Anomaly Detection Alert - Repetative Non-Word Characters',logdata:'%{tx.0}',setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},setvar:tx.sql_injection_score=+1,setvar:'tx.msg=%{rule.msg}',setvar:tx.%{rule.id}-WEB_ATTACK/RESTRICTED_SQL_CHARS-%{matched_var_name}=%{tx.0}"
apacheの設定
vi /usr/local/apache2/conf/httpd.conf
httpd.confに追記する
#----------------------------------------------------------
# ModSecurity
#----------------------------------------------------------
LoadModule security2_module modules/mod_security2.so
LoadFile /usr/lib64/libxml2.so
<IfModule mod_security2.c>
#----------------------------------------------------------
# メイン
#----------------------------------------------------------
#--- 参考: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual
#--- 参考: http://open-groove.net/category/modsecurity/
#--- 動作モード
# (On:遮断, Off:無効, DetectionOnly:検知のみ)
SecRuleEngine On
#SecRuleEngine DetectionOnly
#--- デフォルトアクション
# (検出パターンに合致したときの動作を定義)
# phase
# 1.Request headers (REQUEST_HEADERS)
# 2.Request body (REQUEST_BODY)
# 3.Response headers (RESPONSE_HEADERS)
# 4.Response body (RESPONSE_BODY)
# 5.Logging (LOGGING)
SecDefaultAction "phase:2,deny,log,status:406"
#--- テンポラリファイル格納先
SecTmpDir /tmp/
#--- 永続的データの格納先
SecDataDir /tmp/
#--- リクエストボディのバッファリング指示
SecRequestBodyAccess On
#--- 最大リクエストボディサイズを指定
SecRequestBodyLimit 13107200
#--- アップロードファイルサイズを除いた最大リクエストボディサイズ
SecRequestBodyNoFilesLimit 131072
#--- 最大メモリバッファサイズ
SecRequestBodyInMemoryLimit 131072
#--- リミット時の動作
SecRequestBodyLimitAction Reject
#----------------------------------------------------------
# ルール
#----------------------------------------------------------
# SecRule VARIABLES OPERATOR [ACTIONS]
# VARIABLES : チェックを実行する変数を指定
# OPERATOR : フィルタリングルールを記述
# @rx : 正規表現によるパターンマッチング
# @pm : パラレルパターンマッチング
# @pmFromFile : 対象文学列をリスト化したファイルを対象にパターンマッチング
# @@beginsWith: 対象文学列の始まりにおいてパターンマッチング
# @contains : 対象文学列の全体からパターンマッチング
# @endWith : 対象文学列の終わりにおいてパターンマッチング
# @streq : 対象文学列が完全一致しているかどうかをチェック
# @within : 指定した範囲内でパターンマッチング
# ACTIONS : ルールにマッチした場合のアクションを指示
SecRule \
REQUEST_HEADERS:Content-Type \
"text/xml" \
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
Include /usr/local/apache2/conf/modsecurity/modsecurity_crs_41_sql_injection_attacks.conf
#----------------------------------------------------------
# ログ
#----------------------------------------------------------
#--- 監査ログの動作モード
# (On:すべて記録, Off:無効, RelevantOnly:SecAuditLogRelevantStatusに合致したステータスコードのみを記録)
SecAuditEngine On
#---監査ログの記録対象とするサーバ応答コード
# (SecAuditEngine が RelevantOnly)
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
#--- 監査ログの出力タイプ
# (Serial:1ファイルに記載, Concurrent:セッション毎に個別ファイルを生成)
SecAuditLogType Serial
#--- 監査ログの出力場所
SecAuditLog /var/log/modsecurity.log
#--- 監査ログの出力項目
# A:AuditLog ヘッダー
# B:リクエストヘッダー
# C:リクエストボディ
# D:Reserved
# E:レスポンスボディ
# F:レスポンスヘッダー
# G:Reserved
# H:追加情報。パターンにマッチしたアクセスだとここにタグが付与される。
# I:ファイルを除外した、コンパクトなリクエストボディ
# J:Reserved
# K:トランザクションにマッチした全てのルール
# Z:最後の境界線
SecAuditLogParts "ABIFHKZ"
#----------------------------------------------------------
# デバッグ
#----------------------------------------------------------
#--- デバッグログ
SecDebugLog /var/log/modsecurity_debug.log
#--- デバッグログレベル
# 0:no logging.
# 1:errors (intercepted requests) only.
# 2:warnings.
# 3:notices.
# 4:details of how transactions are handled.
# 5:as above, but including information about each piece of information handled.
# 9:log everything, including very detailed debugging information
SecDebugLogLevel 3
</IfModule>
apacheの再起動
/usr/local/apache2/bin/apachectl configtest
/etc/init.d/httpd restart
確認
wget -S --spider "http://localhost/?and%201=1;--"
確認用WEBアプリ
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<html>
<head><title>SQL Injection TEST</title></head>
<body>
<?php
#-----------------------------------------------------------
# SQLインジェクションテストクラス
#-----------------------------------------------------------
class SQL_INJECTION_TEST{
var $conn;
var $data;
var $sql;
#-----------------------------------------------------------
# SQLITEに接続
#-----------------------------------------------------------
function db_connect(){
$dsn = "sqlite::memory:";
$this->conn = new PDO($dsn);
}
#-----------------------------------------------------------
# CREATE TABLE
#-----------------------------------------------------------
function db_table_check(){
$sql = "CREATE TABLE IF NOT EXISTS
tablename
(id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE,
password TEXT UNIQUE)";
#--- テーブル作成
$stmt = $this->conn->prepare($sql);
$stmt->execute();
#--- 初期データー登録
$this->db_insert("root", "qwerty");
$this->db_insert("yamada", "wD?mZwrcr37n");
$this->db_insert("tanaka", "neeAnbH=4k7K");
$this->db_insert("sato", "F2s&jQ8eTtwQ");
$this->db_insert("yamaguti","y8=bZ7CVkCsd");
$this->db_insert("sugimoto","t7mRPZ&3fVsE");
$this->db_insert("oda", "7zU4@LYPyJmw");
}
#-----------------------------------------------------------
# INSERT
#-----------------------------------------------------------
function db_insert($name, $password){
$sql = "INSERT INTO tablename (name, password) VALUES ('{$name}', '{$password}')";
if ($name){
$stmt = $this->conn->prepare($sql);
$flag = $stmt->execute();
}else{
echo "INSERT FALSE";
}
}
#-----------------------------------------------------------
# SELECT
#-----------------------------------------------------------
function db_select($select_sql){
$stmt = $this->conn->prepare($select_sql);
$stmt->execute();
echo "<table border=\"1\" rules=\"all\">";
echo "<tr><th>ID</th><th>NAME</th><th>PASSWORD</th></tr>";
while ($row = $stmt->fetch()) {
echo "<tr>";
echo "<td>".$row["id"] . "</td>";
echo "<td>".$row["name"] . "</td>";
echo "<td>".$row["password"] . "</td>";
echo "</tr>";
};
echo "</table>";
}
#-----------------------------------------------------------
# マジッククオート Off
#-----------------------------------------------------------
function magic_quotes_off($str) {
if (get_magic_quotes_gpc()) {
return stripslashes($str);
}else{
return $str;
}
}
#-----------------------------------------------------------
# POST/GET データーからSQLを生成
#-----------------------------------------------------------
function set_data($post_data='', $get_data=''){
if ($post_data != ''){
$data = $post_data;
}
if ($get_data != ''){
$data = $get_data;
}
$this->data = $this->magic_quotes_off($data);
$this->sql = "SELECT id, name, password FROM tablename WHERE password = '{$this->data}'";
}
#-----------------------------------------------------------
# POST/GET データーを出力
#-----------------------------------------------------------
function get_data(){
return $this->data;
}
#-----------------------------------------------------------
# POST/GET データーからSQLを生成されたものを出力
#-----------------------------------------------------------
function get_sql(){
return $this->sql;
}
#-----------------------------------------------------------
# POST/GET データーからSQLを実行
#-----------------------------------------------------------
function get_injection(){
$this->db_select($this->sql);
#if ($this->data){
# $this->db_select($this->sql);
#}else{
# echo "POST/GET Data None <br />";
#}
}
}
?>
<hr>パスワード入力<br />
<br />
<form action="?" method="post">
PASSWORD:<input type="text" name="data" size="20" value="">
<input type="submit" value="ログイン(POST)">
</form>
<form action="?" method="get">
PASSWORD:<input type="text" name="data" size="20" value="">
<input type="submit" value="ログイン(GET)">
</form>
SQLインジェクションコード「' OR 'A' = 'A' --」
<hr>
<?php
$post_data = $_POST['data'];
$get_data = $_GET['data'];
$hoge = new SQL_INJECTION_TEST();
$hoge->db_connect();
$hoge->db_table_check();
$hoge->set_data($post_data, $get_data);
echo "~~結果~~<br />";
echo "発行したSQL : " . $hoge->get_sql() . "<br />";
$hoge->get_injection();
echo "<hr>~~登録全データー~~<br />";
echo "発行したSQL : SELECT id, name, password FROM tablename<br />";
$hoge->db_select("SELECT id, name, password FROM tablename");
参考
http://www.modsecurity.org/
http://dev.classmethod.jp/cloud/aws/ec2-amazon-linux-waf-modsecurity-install/
http://www.ipa.go.jp/files/000017312.pdf