VPSサーバーでWebサイト公開 備忘録 ~Linux、MySQLからAJAXまで

Dos攻撃など大量アクセスのログを検知するBashスクリプトを作成

Apacheのアクセスログのサイズが異常に大きくなっている場合があります。アクセスログをチェックして、ある特定の送信元から大量のアクセスがあった場合にメール通知するBashスクリプトの作成例です。

※目次をクリックすると目次の下部にコンテンツが表示されます。

短期間の大量アクセスのアクセスログの一例
私が運用しているVPSサーバーで実際に記録されていた一例です。
 
176.56.xxx.xxx – – [12/May/2015:05:01:16 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
176.56.xxx.xxx – – [12/May/2015:05:01:18 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
176.56.xxx.xxx – – [12/May/2015:05:01:17 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
176.56.xxx.xxx – – [12/May/2015:05:01:19 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
176.56.xxx.xxx – – [12/May/2015:05:01:19 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
176.56.xxx.xxx – – [12/May/2015:05:01:20 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
176.56.xxx.xxx – – [12/May/2015:05:01:21 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
176.56.xxx.xxx – – [12/May/2015:05:01:21 +0900] “POST /wp-login.php HTTP/1.0” 200 3589
 
46.19.xxx.xxx – – [02/Jun/2015:00:55:03 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
46.19.xxx.xxx – – [02/Jun/2015:00:55:03 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
46.19.xxx.xxx – – [02/Jun/2015:00:55:03 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
46.19.xxx.xxx – – [02/Jun/2015:00:55:03 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
46.19.xxx.xxx – – [02/Jun/2015:00:55:03 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
46.19.xxx.xxx – – [02/Jun/2015:00:55:03 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
46.19.xxx.xxx – – [02/Jun/2015:00:55:03 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
46.19.xxx.xxx – – [02/Jun/2015:00:55:04 +0900] “POST /xmlrpc.php HTTP/1.1” 403 275
Linuxのgrep、awk、sortなどを使って大量アクセスの送信元を抽出
1)送信元アドレスをキーにして集計
 
①時間を指定して抽出
 
アクセスログの日付フォーマットが”02/Jun/2015″の形式なので、昨日の日付を同フォーマットで出力する場合は下記のようにdateコマンドのオプションを指定します。
date +”%d/%b/%Y” –date “1 day ago”
 
②アクセスログから送信元アドレスのみを抽出
 
上記ログ出力例より送信元アドレスは1番目のフィールドなので、awkコマンドで以下のように指定して抽出できます。
awk ‘{print $1}’
 
③IPアドレス毎にソートして集計、カウント数が大きい順に20行出力
 
sort | uniq -c | sort -nr | head -20
実行例)
# more アクセスログのpath | grep `date +"%d/%b/%Y" --date "1 day ago"` | awk '{print $1}' | sort | uniq -c | sort -nr | head -20
 296990 46.19.139.xxx
    301 136.243.5.xxx
    189 36.52.118.xxx
    169 188.165.214.xxx
    147 75.134.131.xxx
     52 173.242.113.xxx
     45 58.138.159.xxx
     44 136.243.5.xxx
   :

 
2)送信元アドレスと宛先URLのパスのペアをキーにして集計
 
送信元アドレスのみの場合だと検索エンジンのロボットからのアクセスも含まれてしまいます。送信元アドレスと宛先URLのパスのペアをキーにして集計する場合は下記のようにします。
 
①時間を指定して抽出
 
上記1)の①と同様。
 
②アクセスログから送信元アドレスと宛先URLのパスのみを抽出
 
上記ログ出力例より送信元アドレスは1番目、宛先URLのパスは7番目のフィールドなので、下記コマンドで抽出できます。
awk ‘{print $1 $7}’
 
③IPアドレス毎にソートして集計、カウント数が大きい順に20行出力
 
上記1)の③と同様。
実行例)

# more アクセスログのpath | grep `date +"%d/%b/%Y" --date "1 day ago"` | awk '{print $1 $7}' | sort | uniq -c | sort -nr | head -20
 296990 46.19.139.xxx/xmlrpc.php
     23 36.52.118.xxx/favicon.ico
      8 36.52.118.xxx/wp-includes/js/wp-emoji-release.min.js?ver=4.2.2
      8 36.52.118.xxx/wp-admin/admin-ajax.php
      6 36.52.118.xxx/wp-login.php?loggedout=true
      5 36.52.118.xxx/wp-includes/js/jquery/jquery.js?ver=1.11.2
      5 36.52.118.xxx/wp-includes/css/dashicons.min.css?ver=4.2.2
      5 36.52.118.xxx/wp-includes/css/buttons.min.css?ver=4.2.2
      5 36.52.118.xxx/wp-admin/css/login.min.css?ver=4.2.2
      5 114.164.246.xxx/wp-content/plugins/akismet/_inc/form.js?ver=3.0.4
    :
アクセスログ内の大量アクセスのログを検知してメール通知するBashスクリプト
1)スクリプトの仕様
 
①下記3つのアクセスログを対象
access_log www1.example.com-access_log www2.example.com-access_log
 
②アクセスログから不審なログを抽出する方法は上記(2)の2)の方法
 
③上記②抽出したログのカウント数が100以上の場合はメール通知の対象として一時ファイルに記録
 
④上記③でメール通知の対象のログが記録されていた場合はメール通知
#!/bin/bash

ftmp_disk="/home/user/bkup/tmp_access"
fout_disk="/home/user/bkup/out_access"
fmail_disk="/home/user/bkup/mail_access"
: > $fout_disk

cd /var/log/httpd
logs=(access_log www1.example.com-access_log www2.example.com-access_log)
for (( i=0 ; i> $fout_disk
  more ${logs[i]} | grep `date +"%d/%b/%Y" --date "1 day ago"` | awk '{print $1 $7}' | sort | uniq -c | sort -nr | head -20 > $ftmp_disk
  while read line; do
    if [[ $line =~ ^([0-9]+)[[:space:]].* ]]; then
      if [ ${BASH_REMATCH[1]} -gt 100 ]; then
        echo $line >> $fout_disk
      fi
    fi
  done  $fmail_disk
  echo "To: user@myhome.com" >> $fmail_disk
  echo "Subject: Apache access-log Warning Dos" >> $fmail_disk
  echo "" >> $fmail_disk
  cat $fout_disk >> $fmail_disk
  /usr/sbin/sendmail -t 

※正規表現を使ったパターンマッチ、ファイル内のデータ読取りなどの方法については下記記事参照。
bashでパターンマッチを使って条件評価
ファイルの中身を一行ずつ読んで文字列を置換するbashスクリプト
 
2)上記1)のスクリプトをcronに登録
 
cronの設定についてはいろいろ方法があります。一例を示します。
 
例)毎日3時30分にcronで実行させる例
# vi /etc/crontab
 
30 3 * * * root /home/user/bkup/access.sh

モバイルバージョンを終了