Brute Force Attack対策+α(Firewalld)
20170517

パスワードやファイル名に対してのブルートフォースアタック、総当り攻撃、辞書攻撃及びhttpサーバへのディレクトリトラサーバル対策

SSH、FTP、MAIL、HTTP、およびDNSサーバのログを定期的に監視し、攻撃元IPをFirewalldの「Drop」ゾーンに登録していくスクリプトを自動実行させます。
攻撃を検知してから何らかの処置を取る事から、簡易的ではありますがIPSのような動作となります。
※攻撃元は動的なIPアドレスを利用されることが多いため、Firewalldの一時的なルールに追加するスクリプトとしております。
 そのため、システム再起動時には初期化されますが、登録期間が短ければ(未ログローテーション)再登録されます。

※iptablesをご利用の方は、Brute Force Attack対策(iptables)をご参照ください。
確認環境
 CentOS7.x
 CentOS6.x
 CentOS5.x
 Cron
 sshd
 vsftpd
 Postfix+Dovecot
 Apache
 BIND

頻繁にtmpファイルを作成する事から、「tmpfs(RAMディスク)」の設定も検討して下さい。
20160415 メールの強化と処理を大きく変更した。
◆処理の流れ(デフォルトの場合)
 1.SSH、FTP、MAIL、HTTP、およびDNSサーバのログをCronにて1分毎に監視する。

 2.累計10回の不正アクセスの痕跡を確認した場合はIPレベルでのアクセス拒否を実施する。
 →Firewalldの「Drop」ゾーンに登録
 →不正なアクセスのログが無ければ処理の終了
 →ホワイトリストファイルにIPアドレスを1行ずつ記述する事で監視除外IPの指定が可能
 →HTTP監視においては、存在しないディレクトリ及びファイルの参照を試みる行為を監視します。
 →また、HTTP監視においては誤検知を減らす工夫が必要となる為、除外ディレクトリの指定が可能

 3.不正アクセスの痕跡を確認し、対処した事場合は詳細をログに保存

 4.上記内容をroot宛にメールで送信

◆監視ログメッセージ
 SSH
  "Invalid user"
  "Failed password"

 FTP
  "FAIL LOGIN"

 MAIL
  "authentication failure"
  "auth failed"
  "Recipient address rejected: User unknown in local recipient table"
  "SSL_accept error"
#  "NOQUEUE: reject:"
  "policyd-spf"

 HTTP
  "File does not exist"
  "script" & "not found or unable to stat"
  "../"
  "//"

 DNS
  "denied"
◆まずはシェルスクリプトの作成
 [root@Server ~]# vi /root/brute_force_attack.sh

#!/bin/sh
export LANG=ja_JP.UTF-8

# Ver 20160415

# 攻撃判断回数(デフォルト10回以上)
NG="10"

# ログ監視の有効化設定 「no」で無効。(デフォルトは全て有効)
TELNET_CHECK="yes"
SSH_CHECK="yes"
FTP_CHECK="yes"
MAIL_CHECK="yes"
HTTP_CHECK="yes"
DNS_CHECK="yes"

# 監視ログファイル
SSH_LOG="/var/log/secure"
FTP_LOG="/var/log/vsftpd.log"
MAIL_LOG="/var/log/maillog"
HTTP_LOG="/var/log/httpd/error_log"
HTTP_LOG2="/var/log/httpd/access_log"
DNS_LOG="/var/log/named.log"

# HTTP監視除外ディレクトリ及びファイル設定(デフォルトでは「/home」ディレクトリ 以下に存在するファイル全て)
DIR="/home"

# 攻撃を検知した際にメールを送信するか否か。「no」で無効。(デフォルト有効)
MAILMESSAGES="yes"
# メール送信先アドレス。(デフォルトroot宛)
MAILADDRESS="root"

# 動作ログのファイル名
BR_LOG="/var/log/brute_force_attack.log"

# ホワイトリストファイルの指定
WHITE_LIST="/root/sh/allow_ip"

# 一時ファイル作成ディレクトリの指定
TMP_DIR="/tmp"

# 以降設定不要

# タイムスタンプ設定
LOG_DATE=`date '+%Y/%m/%d %k:%M:%S'`
# 一時ファイル設定
TMP="$TMP_DIR/brute_force_attack.tmp"
TMP2="$TMP_DIR/brute_force_attack2.tmp"

function_CORE()
{
if [ $1 = "TELNET" ] ; then
SYSTEM_NAME="$1"
grep "login:" $SSH_LOG | grep "FAILED LOGIN" | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" > $TMP
elif [ $1 = "SSH" ] ; then
SYSTEM_NAME="$1"
grep "sshd" $SSH_LOG | grep "Invalid user" | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" > $TMP
grep "sshd" $SSH_LOG | grep "Failed password" | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
elif [ $1 = "FTP" ] ; then
SYSTEM_NAME="$1"
grep "FAIL LOGIN" $FTP_LOG | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" > $TMP
elif [ $1 = "MAIL" ] ; then
SYSTEM_NAME="$1"
grep "authentication failure" $MAIL_LOG | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" > $TMP
grep "auth failed" $MAIL_LOG | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
grep "Recipient address rejected: User unknown in local recipient table" $MAIL_LOG | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
grep "SSL_accept error" $MAIL_LOG | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
# grep "NOQUEUE: reject:" $MAIL_LOG | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
# 下記、SPF導入済みのログ
grep "policyd-spf" $MAIL_LOG | grep "Fail" | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
elif [ $1 = "HTTP" ] ; then
SYSTEM_NAME="$1"
DIR_LIST=`ls $DIR`
grep "error" $HTTP_LOG | grep "File does not exist" | grep -v "$DIR_LIST" | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" > $TMP
grep "error" $HTTP_LOG | grep "script" | grep "not found or unable to stat" | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
grep "\.\./" $HTTP_LOG2 | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
grep "//" $HTTP_LOG2 | grep -v http:// | grep -v https:// | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
#個人的にadminを拒否
# grep "admin" $HTTP_LOG2 | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" >> $TMP
elif [ $1 = "DNS" ] ; then
SYSTEM_NAME="$1"
grep "denied" $DNS_LOG | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" > $TMP
else
:
fi

cp -p $TMP $TMP2

if [ -s $WHITE_LIST ]; then
WHITE=`cat $WHITE_LIST`
grep -v "$WHITE" $TMP2 > $TMP
cp -pr $TMP $TMP2
fi

BLACK=`firewall-cmd --list-all-zones | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+"`
grep -v "$BLACK" $TMP2 > $TMP

LIST=`cat $TMP`
for IP in $LIST
do
COUNT=`grep -w "$IP" $TMP | wc -l`
if [ $COUNT -ge $NG ] ; then

firewall-cmd --list-all-zones | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" > $TMP2
if grep -w "$IP" $TMP2 >/dev/null 2>&1; then
:
else

if grep -w $IP $BR_LOG >/dev/null 2>&1; then
echo "["$LOG_DATE"] ""[$SYSTEM_NAMEログ監視] IP をFirewallのDrop-Zoneへ再登録:"$COUNT "回 ["$IP"]" >> $BR_LOG
firewall-cmd --zone=drop --add-source=$IP
else
echo "["$LOG_DATE"] ""[$SYSTEM_NAMEログ 監視] IPをFirewallのDrop-Zoneへ登録:"$COUNT "回 ["$IP"]" >> $BR_LOG
firewall-cmd --zone=drop --add-source=$IP
if [ $MAILMESSAGES = "yes" ] ; then
echo -e "[$SYSTEM_NAME] ログ監視にて、"$COUNT"回の不正なアクセスログを確認。\n対象ホストのIPアドレスをFirewallのDrop-Zoneへの登録しました。\n\nIPアドレス [$IP]"| mail -s "$0" $MAILADDRESS
fi
fi
fi
fi
done

# 一時ファイル削除
rm -f $TMP $TMP2
}

# 実行
if [ $TELNET_CHECK = "yes" ] ; then
function_CORE TELNET
fi
if [ $SSH_CHECK = "yes" ] ; then
function_CORE SSH
fi
if [ $FTP_CHECK = "yes" ] ; then
function_CORE FTP
fi
if [ $MAIL_CHECK = "yes" ] ; then
function_CORE MAIL
fi
if [ $HTTP_CHECK = "yes" ] ; then
function_CORE HTTP
fi
if [ $DNS_CHECK = "yes" ] ; then
function_CORE DNS
fi
◆一応実行権限を付与
 [root@Server ~]# chmod +x /root/brute_force_attack.sh
◆cronにて自動実行するよう設定しましょう。
 [root@Server ~]# echo "*/1 * * * * root bash /root/brute_force_attack.sh >/dev/null 2>&1" >> /etc/crontab

この場合、1分毎に監視して対処します。
変更する場合はcrontabにて設定を確認して下さい。

終わり。