透過分析secure日誌自動抵禦非法登陸ip的指令碼

tonywi888發表於2007-11-16
因為程式設計基本功差,寫了很冗長的程式碼,不過作為初學shell script還是有點作用的,而且給大家提供個思路。歡迎高手幫忙簡化,當然請把語法說明白點……主要用了awk的列印功能,grep的查詢關鍵字所匹配的行,for do done迴圈,if elif else判斷,以及一些其他的小知識點,對於初學shell script的新手應該有點用處。
這個是我在rhel4版本上(說白了就是redhat as4版本)編的,要用的話,把中文部分去掉就行。另外附件裡面是完全不用添刪的版本,自己全考過去就能用了……如果你的secure檔案記錄非法登陸的關鍵字不同,比如不是Invalid user或者Failed password for root,請仔細分析到底是怎麼記錄的,然後對這個指令碼進行改動,主要是grep "Invalid user" $LOGFILE | awk '{print $NF}' > badlist1_tmp1和grep "Failed password for root" $LOGFILE | awk '{print $11}' > badlist2_tmp1這兩部分需要改動。

#!/bin/bash #宣告使用bash,最好加這一行,出了問題的時候用vi編輯能幫你分析語法錯誤
###########################
#get words #這一段為了獲取試圖非法登陸本機的ip地址
LOGFILE=/var/log/secure #定義logfile變數,如果你的日誌不是/var/log/secure,可以自己指定
#這兩行為了清除上次留下的記錄,因為用了>>,不刪會影響這次執行的效果
rm -rf badlist1_tmp2
rm -rf badlist2_tmp2

#用grep從logfile中獲取帶有"Invalid user"字樣的行;用awk程式將第$NF($NF是awk用來統計本行有多少個區域的變數)個域提取出來輸出給當前目錄下的檔案badlist1_tmp1
grep "Invalid user" $LOGFILE | awk '{print $NF}' > badlist1_tmp1
#與上面類似,關鍵字變為Failed password for root,列印匹配行中的第11個域的內容,不過這次提取後,得到的大概是::ffff:xxx.xxx.xxx.xxx這樣的效果,而且每次非法登陸都會記錄一次,需要進一步簡化
grep "Failed password for root" $LOGFILE | awk '{print $11}' > badlist2_tmp1

#定義變數tmp1,內容是檔案badlist1_tmp1的內容啦
tmp1=`cat ./badlist1_tmp1`
#定義了兩個新的變數
newtmp=
oldtmp=
#執行迴圈,作用是讓變數i每次讀出badlist1_tmp中的一條內容,也就是前面說的大概是::ffff:xxx.xxx.xxx.xxx這樣的內容,然後裁剪掉前8個字元(用cut命令),再一條一條的記錄在檔案badlist1_tmp2中,這樣迴圈結束後會生成一個全部記錄非法ip的檔案了。同時,這個迴圈還會把連續訪問的非法ip過濾掉(也就是不進行記錄,只記錄和上一條ip不同的ip),當然如果同時有兩個人在非法登陸,兩個ip是交替出現的話就無能為力了。
for i in $tmp1
do
#只對每條記錄的第8個字元以後的內容記錄
newtmp=`echo $i | cut -c8-`
#如果新被記錄的ip與上一條不同,則將這個ip記錄追加寫入到badlist1_tmp2檔案中
if [ "$newtmp" != "$oldtmp" ] ; then
echo $newtmp >> badlist1_tmp2
fi
#把本次迴圈得到的ip保留,開始進入下一次迴圈
oldtmp=$newtmp
done

#這段作用和上面一樣,不過是讀取另外一個檔案了
tmp1=`cat ./badlist2_tmp1`
for i in $tmp1
do
newtmp=`echo $i | cut -c8-`
if [ "$newtmp" != "$oldtmp" ] ; then
echo $newtmp >> badlist2_tmp2
fi
oldtmp=$newtmp
done

#將兩個新生成的只記錄了少量ip的檔案合併,並將它的內容賦給變數tmp1
cat ./badlist2_tmp2 >> ./badlist1_tmp2
tmp1=`cat ./badlist1_tmp2`
#定義變數number為整數型,tmplist為陣列,變數number初始值為0
declare -i number
declare -a tmplist
number=0
#逐步讀出tmp1中的每條記錄賦給陣列tmplist,相當於把剩下所有的ip都記錄下來,總共會有$number+1條記錄,這個number變數的值將在下一次迴圈程式中使用。
for i in $tmp1
do
tmplist[$number]=$i # echo ${tmplist[$number]}這條註釋掉的是我測試錯誤的時候用的
number=$number+1
done
#echo "There is $number IP record for all badlist files" 這也是我為了排錯加的。


#####################
#here for reduse complex line#下面為了去掉因為其他原因留下的重複的ip記錄
#刪除finalist檔案也是為了避免一些麻煩,因為後面用>>追加的,所以要保持一開始finallist為空
rm -rf finallist
#第一條記錄肯定是沒有重複啦,先輸入進finallist檔案
echo ${tmplist[0]} > finallist
#注意i的初始值為1,這樣從第二條記錄才開始進行比較輪詢的過程,i的最大值是$number的值,也就是前面一段程式中統計的有多少條記錄的統計-1(為什麼減1,因為第一條記錄不會重複的,所以就沒有計算進去)。
for (( i=1;i<=$number;i=i+1 ))
do
#這是個巢狀輪詢啦,現定義了一個整數型變數firstrec,初始值為0。
declare -i firstrec
firstrec=0
#j這個變數從0開始,就是為了讓第二條記錄tmplist[1]能夠與第一條記錄tmplist[0]進行比較,變數j的最大值要小於i,否則自己跟自己比較當然會一樣,而且這樣就等於每次都是與排在自己前面的記錄進行比較,只要與前面所有的記錄都不同就會被記錄在finallist裡面了!
for (( j=0;jdo
# echo "${tmplist[$i]}, ${tmplist[$j]} , $j " #測試錯誤用的,可以不要。
#當本條記錄確認與前面的記錄不同時,變數fristrec保持不變,如果發現相同就會自動+1
if [ "${tmplist[$i]}" != "${tmplist[$j]}" ] ; then
firstrec=$firstrec
else
# echo "This rec has been recorded!" #測試錯誤用的,可以不要。
firstrec=$firstrec+1
fi
done
# echo "The $i loop finish" #測試錯誤用的,可以不要。
#跳出巢狀的迴圈後看看是否firstrec為0,如果是0,那就意味著和前面所有的記錄都不同,當然要加進finallist檔案了,否則什麼都不作(:代表null,什麼都不作),如果firstrec的值小於0,顯然出錯了,趕緊跳出程式吧!
if [ $firstrec -eq 0 ]; then
echo ${tmplist[$i]} >> finallist
elif [ $firstrec -lt 0 ]; then
echo "Some thing error! '$firstrec' little than 0!"
exit 99
else
:
fi
# echo "${tmplist[$i]},'$i' is $i . " #測試錯誤用的,可以不要。
#開始讀入下一條記錄
done

#結束
#end[@more@]轉中國網管論壇

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8570952/viewspace-982587/,如需轉載,請註明出處,否則將追究法律責任。

相關文章