iT邦幫忙

1

[分享] Linux postfix 阻檔大量發信機制做法

前言:
自建郵件主機 Linux + postfix + dovecot
除了垃圾郵件過濾末過於帳號被猜中而被半夜
大量寄信隔日被列入黑名單窘境

另因內部系統異常透過程式自動發eMail告急,確無
人處理造成郵件主機癱渙.

時至今日因工作上主管決定購買商業郵件伺服器,而
得以卸職機會.將所處理這方面經驗釋出給與需要人參考.

環境要求:
1).只適合本機帳號 (/etc/passwd)
2).不適用於海外工作者需大量寄信(建議用 vpn 克服)
3).利用 bash script 所攥寫.透過 crond 執行
會產生報表 report.txt
白名單設在 iptables.deny 及被 blocaking ip 也會寫入此檔
透過 /etc/rc.local 每次重開機重新執行 iptables.deny 內容

不足之處:
1).未來希望有高人補足 ad 使用者 或 mysql 帳號資料庫整合檢查

主程式: Check_eMail.sh

#!/bin/bash
#
# test --> sh -x ChekMail-num.sh
#
cat /dev/null > now_list.txt

cat /dev/null > temp.txt
cat /dev/null > log.txt
cat /dev/null > report.txt

echo " " >> report.txt
echo "-=---------------------------=-"   >> report.txt
echo "     The process !             "   >> report.txt
echo "-=---------------------------=-"   >> report.txt

LIMIT=10

if  [ "$(date +'%d')" -lt 10 ];  then
        nn=`date +'%b %d'`
        cat /var/log/maillog | grep "$(echo $nn | sed 's/0/ /g')" > maillog
else
        cat /var/log/maillog | grep "$(date +'%b %d')" > maillog
fi

user_name=$(awk -F':' '$3>=500{print $1}' /etc/passwd)

for loop in $user_name
do
  echo -n "$loop," >> now_list.txt
  cat ./maillog | grep sasl_username=$loop | wc -l >> now_list.txt
done

for loop in $user_name
do
  num=$(cat before_list.txt | grep "$loop" | cut -d ',' -f 2 | head -n 1)
  num1=$(cat now_list.txt | grep "$loop" | cut -d ',' -f 2 | head -n 1)
  num2=$((num1 - num))
  if [ "$num2" -ge "$LIMIT" ] ; then
       echo  "$loop,1" >> log.txt
  fi 
done


# +++ remove user list ...
sed -i '/aaa/d' log.txt
sed -i '/bbb/d' log.txt


# +++ function_name
check_bulk_mailling(){
   # 4. Check local ip send email number > 10000
   cat before_list.txt | sort -n -t ',' -k 2 -r | head -n 5 > log.txt

   sed -i '/aaa/d' log.txt
   sed -i '/bbb/d' log.txt

   user_name=$(awk -F',' '{print $1}' ./log.txt)
   f_LIMIT=3000

   echo " " >> report.txt
   echo "-=-----------------------------------=-"   >> report.txt
   echo "     Display bulk mailing Local IP!    "   >> report.txt
   echo "-=-----------------------------------=-"   >> report.txt

   for loop in $user_name
   do
       cat ./maillog | grep sasl_username=$loop | awk -F' ' '{print $7}' \
       | cut -d '[' -f 2 | cut -d ']' -f 1  > temp.txt

       sort temp.txt | uniq -c | sort -n -t ' ' -k 1 -r | head -n 5 > ip_list.txt

       f_num=$( cat ip_list.txt | awk -F' ' '{print $1}' )

       for loop1 in $f_num
       do
          hit_ip=$( cat ip_list.txt | grep $loop1 | awk -F' ' '{print $2}' )
          if [ `echo "$loop1" | awk '{print int($0)}'` -ge "$f_LIMIT" ] ; then
             f_num2=$( iptables -L -n | grep "$hit_ip" | wc -l )
             if [ $f_num2 = '0' ]; then
	             /sbin/iptables -I INPUT -i $networkcard -s $hit_ip -j DROP
                 echo "IP: $hit_ip ; Num: $loop1 ; Id: $loop  is drop"  >> report.txt
                 # exit 0
             else
                 echo "IP: $hit_ip ; Num: $loop1 ; Id: $loop  is drop"  >> report.txt
             fi
          fi     
       done
   done
}


if [ -z log.txt  ] ; then
   mv -f now_list.txt before_list.txt
   check_bulk_mailling
   exit 0
fi


# -=--------------------------------------------------=-
#
cat /dev/null > temp.txt
cat /dev/null > dropip.txt

BAD_LIST="./temp.txt"

user_name=$(awk -F',' '{print $1}' ./log.txt)

for loop in $user_name
 do
  cat ./maillog | grep sasl_username=$loop | awk -F' ' '{print $7}' \
  | cut -d '[' -f 2 | cut -d ']' -f 1  >> temp.txt
done


for i in $( cat $BAD_LIST | sort -u )
 do
    {
        # hit=$(cat $BAD_LIST | egrep -o "$i" | wc -l)
           if [ `echo $i | cut -d \. -f 1` != "10" ] ; then
              if   [ `echo $i | cut -d \. -f 1` == "172" ] && [ `echo $i | cut -d \. -f 2` == "17" ] && \
                   [ `echo $i | cut -d \. -f 3` == "2" ] ;  then
                      echo "Bypass ip: $i " >> report.txt  # ByPass 172.17.2.x 
              else
                  echo "$i" >> dropip.txt  
              fi
           fi
    }
done


# -=--------------------------------------------------=-
#
cat ./dropip.txt | sort -t '.' -k1n,1 -k2n,2 -k3n,3 -k4n,4 -o dropip.txt

denyfilepath="/etc/rc.d/iptables.deny"
target1=`cat ./dropip.txt`
networkcard="eth0"

declare -i k=0

if [ `cat \./dropip.txt | wc -l` -eq "0" ] ; then
   echo "No IP Address Drop"  >> report.txt 
   mv -f now_list.txt before_list.txt
   check_bulk_mailling
   exit 0
fi

for i in $target1; do

  if [ -f "$denyfilepath" ]; then
       target2=`cat $denyfilepath | grep $i`
  else
       echo "# 1??.1??.1.1??"  > $denyfilepath
       echo "# 2??.6?.1??.1??" >> $denyfilepath
  fi

  if [ "$target2" = "" ]; then
         if [ $k -eq 0 ]; then
            echo " " >> $denyfilepath
            echo "#-=--------------------------------------------------------------------------=- " >> $denyfilepath
            echo "#  ChekMail-num.sh  "`date` >> $denyfilepath
         fi
         echo -n "/sbin/iptables -A INPUT -i "'$EXTIF'" -s $i -j DROP" >> $denyfilepath
         lname=$(cat ./maillog | grep sasl_username | grep "$i" | cut -d "=" -f 4 | head -n 1)
         echo "   # --- use LoginName $lname " >> $denyfilepath
         declare -i k=$k+1

         /sbin/iptables -I INPUT -i $networkcard -s $i -j DROP
         # echo "IP: $i Add to $denyfilepath"

         echo "(new)IP: $i to use as drop"  >> report.txt
     else
         lname=$(cat report.txt | grep "$i" | wc -l )
         if [ $lname -eq '0' ];  then
              echo "IP: $i to use as drop"  >> report.txt
         fi
  fi
done


# 2.
# -=--------------------------------------------------=-
#
echo " " >> report.txt
echo "-=-----------------------------------=-"   >> report.txt
echo "     Display TOP 10 User !             "   >> report.txt
echo "-=-----------------------------------=-"   >> report.txt
cat ./log.txt  >> report.txt

echo " " >> report.txt
echo "-=----------------------------------------------------=-"   >> report.txt
echo "     Use ip , Login Name , Number of times              "   >> report.txt
echo "-=----------------------------------------------------=-"   >> report.txt

num=$( cat dropip.txt | wc -l  )

if [ $num -ge "0" ]; then
  for i in $(cat ./dropip.txt)
  do
      cat ./maillog | grep sasl_username | grep "$i" | cut -d "=" -f 4 | head -n 1 > lname.txt
      echo -n "$i," >> report.txt
      for j in $(cat lname.txt)
      do
          echo -n "$j," >> report.txt
          cat ./maillog | grep sasl_username="$j" | grep "$i" | wc -l >> report.txt
      done
  done
fi

mv -f now_list.txt before_list.txt


# 3.
today=`/bin/date +"%F"`
timestamp=`/bin/date +"%F %T"`

user_name=$(awk -F',' '{print $1}' ./log.txt)

for loop in $user_name
do
     hit=$(cat report.txt | egrep -o "$loop" | wc -l)
     hit=$((hit - 1))
     if [ "$hit" -ge "$LIMIT" ] ; then
         echo $today@home! | passwd --stdin $loop
         echo "$timestamp eMail account: $loop " >> Lock_eMail.txt
     fi     
done


# 4. Check local ip send email number > 10000
check_bulk_mailling

II. 報表 report.txt 內容

# more report.txt
-=---------------------------=-
     The process !
-=---------------------------=-
IP: 127.0.0.1 to use as drop
IP: 110.64.194.132 to use as drop

-=-----------------------------------=-
     Display TOP 10 User !
-=-----------------------------------=-
cpril,1
school,1

-=----------------------------------------------------=-
     Use ip , Login Name , Number of times
-=----------------------------------------------------=-
127.0.0.1,school,1
110.64.194.132,school,6

-=-----------------------------------=-
     Display bulk mailing Local IP!
-=-----------------------------------=-

iii. 白名單檔內容 iptables.deny

# more /etc/rc.d/iptables.deny
#   Valid IP List
# -=-----------------=-
#   110.64.194.132
#   120.228.202.173
#   121.147.1.146
#   57.123.45.135
#   127.0.0.1

#-=--------------------------------------------------------------------------=-
#  ChekMail-num.sh  Thu Oct 15 18:31:32 CST 2020
/sbin/iptables -A INPUT -i $EXTIF -s 61.60.203.139 -j DROP   # --- use LoginName ann

敬請諸位參考!

1

可以考慮採用 Policyd 來搭配,它還有 Web UI 可以使用。

kuang001 iT邦新手 4 級 ‧ 2021-04-14 07:16:58 檢舉

大大: 感恩提供資訊參考! 會詳加研究.

2
japhenchen
iT邦大師 1 級 ‧ 2021-04-14 09:37:19

用SASL + SSL來解決外網連接發信的問題
用 fail2ban 來解決駭客踹密碼的問題
至於公司內的合法大量發信的需求,只能用人事規範要求,無法也難以禁止,至於發信速率你可以在postfix內拉大處理時間

至於駭客盜用你們信箱帳密的事,我覺得機率微乎其微,人家也沒必要用你們的主機來狂發信,只要確定你們沒做SPF + DMARC + DKIM做防偽造信件的話,用其他沒反relay的smtp server,就能偽造發信人成你們的郵箱域名,然後你們就RBLed!所以你們一定要做好SPF + DMARC + DKIM,長篇大論,自行到GOOGLE搜尋,很多教學

這裡也有郵箱測試工具可用
https://mxtoolbox.com/

https://www.mail-tester.com/
(拿不到8分就有很大的問題了,gmail是滿分10分)

https://talosintelligence.com/
volume超過3就要開始內部檢討了

0
msnman
iT邦研究生 1 級 ‧ 2021-04-14 11:17:09

再建一台發信主機,主要用於收信的主機不對外開放relay

我要發表回答

立即登入回答