LoginSignup
0
0

More than 5 years have passed since last update.

ModSecurity for CentOS5.x

Last updated at Posted at 2013-08-30

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に追記する

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アプリ

sql_injection.php

<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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0