Merhaba

Son zamanlarda sıkca artan DDOS saldırıları can sıkmaya devam
ederken,kimi çeşitleri için korunma yolları mevcut kimileri içinse
gerçekten korunmak zor. Bunların içinden HTTP GET/POST flood ile sıkça
karşılaşıyorum. Bu atak çeşidi normal HTTP GET isteğini binlerce defa ve
farklı bot networklerden yaparak servis dışı bırakabiliyor sunucuları.
Geçenlerde yine yaşadığımız bu problem nedeniyle aklıma önceden bildiğim
ama örneğini görmediğim bir script yazmak geldi. Nasılsa HTTP GET isteği
yapılabilmesi için, TCP protokolü gereği gerçek ip adresinden gelmesi ve
80. porta bağlantı açması gerekiyor. Bu fikirden yola çıkarak şunu
yapabilen bir bash script yazmak aklıma geldi: Netstat çıktısı ile tcp
80. port üzerinden ( Portlar değiştirilebilir )  yapılan bağlantı sayısı
belli bir sayının üzerinde ise bu ip adresini belirli bir süre
yasaklayıp bunları bir listede tutan, daha sonra süresi doluncada bu
yasağı kaldıran bir script yazdım. Belirli bir seviyeye kadar getirdim.
Apache'nin benchmark tool'u "ab" ile atak simule ederek test ettim. Şuan
Centos üzerinde kusursuz çalışıyor. Tahminim diğer Linux
dağıtımlarındada kusursuz çalışır. Servis gibi çalışmasını sağladım,
kendini arka planda askıda tutuyor, yani scripti çalıştırdıktan sonra
bağlantınızı kesseniz bile çalışmaya devam ediyor ve 15 saniye gibi bir
aralıkla netstat çıktısına bakıp, örneğin 100 bağlantı (Bağlantı adeti
değiştirilebilir) üzerinde yapan ip adresini 1 dakika (Süre
değiştirilebilir) banlayıp, daha sonra süresi dolunca listede bu girdiyi
diyez ile işaretleyip bu yasağı kaldırıyor ama tekrar yaparsa bu listeye
kaçıncı defa girdiyse bu sayısını bir arttırıp daha sonra tekrar
yasaklıyor başındaki diyezi kaldırarak. Süresi dolunca yine aynı
işlemleri yapıyor. Yasaklamayı iptables ile 80. porta olan erişimini
DROP ederek yapıyor. Aynı ip adresi tekrar yakalanırsa engellenme süresi
bu listeye girdiği sayı kadar çarpılıp giderek artıyor. Yani banlanma
süresi sabit değil, suç işledikçe suçu oranında artıyor :)  Eğer scripti
kapatmak isterseniz kendisine "kapat" paremetresini vermeniz onu
durdurmaya yetiyor. Ayrıca "durum" parametresi ilede basitte olsa servis
çalışıyor mu, durmuş mu, yoksa öldürülmüş mü öğrenebiliyorsunuz.

Çok fonksiyonlu değil ama iş görebilecek bir script. Belki işine yarayan
olabilir diye ekte paylaşmak istedim. Deneyip yorum iletmek isteyen,
sorun yaşayan, sorusu olan, ilerletmek konusunda irtibata geçmek isteyen
olursa bir sakıncası yoktur benim için, elimden gelen yardımı yaparım.

İyi çalışmalar.

-- 
Barkink

#!/bin/bash
#Yazar: barkink
Amac="Netstat ciktisina bakarak, belli bir sayi uzerinde baglanti yapanlari 
belli bir sure engelleyip sonra serbest birakmak"
#Lisans: GPL.v2
#Version: 2.0
#Tarih: 19.01.2011
SUREC="/tmp/$(basename $0).lock"

id|cut -d" " -f1|grep -q root #Root olarak calisiyor mu kontrol
if [ $? -ne 0 ];then echo "Root ile calistirmalisin!";exit 1;fi

trap "rm -f $SUREC;exit 1" SIGINT SIGTERM SIGKILL #Kilit dosyayi kapatinca 
kaldir

## Bu degiskenler keyfe gore degistirilebilir ##
LISTE="/tmp/gecici.txt" #Banlanma surelerini takip ettigi gecici dosya
BAN=100  # Kac adet baglanti ve uzeri banlanacak
BANSURE=1 #dakika cinsinden
PORT=80
## Degiskenler bitti ##

###Programa verilen degiskenler burda toplaniyor ####
if [ $# -ge 1 ];then
                case $1 in
                basla)
                        ### Servis gibi calismasi icin arka plana atiyoruz 
burda####
                        if [[ -z "$ARKAPLAN" ]] ; then
                        ARKAPLAN=1 exec $0 $@ & exit
                        fi
                ;;
                durum)if [ -f $SUREC ];then ps aux|awk '{print $2}'|grep -q 
$(cat $SUREC) && echo "Servis calisiyor!" || echo "Kilit dosyasi var ama servis 
olmus!";else echo "Servis calismiyor!!";fi;exit 0;;
                kapat) shift;[ -f $SUREC ] && kill $(cat $SUREC) || echo "Arka 
planda calisan $0 programi bulunmuyor!";exit 0;; 
                -h|-H|yardim)
                #Help Satiri! Bu kismi doldurma konusunda yardim alabilirim.
                echo $AMAC
cat<<EOF
EOF
exit 0;;
                *)
                echo "Kullanim: $(basename $0) basla|kapat|durum|yardim";exit 
1;;
                esac
else
echo "Kullanim: $(basename $0) basla|kapat|durum|yardim";exit 1
fi


if [ -f $SUREC ];then
ps aux|awk '{print $2}'|grep -q $(echo $SUREC)
        if [ $? -eq 0 ];then 
        echo "Calisan baska bir servis var!";exit 1;
        else
        echo $$ > $SUREC
        fi
else
touch $SUREC && echo $$ > $SUREC
fi

## Iptables tablosunu temizle ##
iptables -F
iptables -X
iptables -F -t nat
##Banlanicak iplerin listesini tutacak dosya kontrol kismi##

if [ -f $LISTE ];then
rm -f $LISTE
fi

## Icerigi olustur###
echo "IP        GIRIS        CIKIS        HIT        ZAMAN        GIRIS-SAYISI" 
>> $LISTE

##Sonsuz dongu ac ve kontrole basla##
while [ 0 ];do 
NTSTCIKTI=$(netstat -nt|grep -i ":$PORT"|awk '{print $5}'|awk -F":" '{if ($3 != 
ffff)print $4;else print $1}'|sort -n |uniq -c|sort -nr|awk '{print $1":"$2}')
for i in $NTSTCIKTI;do
IP=$(echo $i|cut -d":" -f2)
BAG=$(echo $i|cut -d":" -f1)
TIME="$(date +%Y%m%d%H%M)"
HUMTIME="$(date +"%d/%m/%y-%H:%M")"
        if [ $BAG -ge $BAN ];then
                #echo "$IP adresi $BAG adet baglanti yapti, banlanacak."
                SATIR=$(grep -i  $IP $LISTE) #Satiri al
                        if [ ${#SATIR} -gt 1 ];then #eger satir bos degilse
                        #echo "$IP adresi listede var."
                        STATUS=$(echo $SATIR|grep -i '^#') #basinda diyez varsa 
getir,amacim bu satir basinda diyez varsa onu kaldirmak
                                if [ ${#STATUS} -gt 1 ];then # diyez varsa 
satir bos gelicek
                                        #echo "$IP adresi onceden 
listedeymis,basindaki diyez satir kaldirildi,sayisi artirildi"
                                        SAYISI=$(echo $SATIR|awk '{print $6}')
                                        CIKIS=$(echo $SATIR|awk '{print $3}')
                                        YCIKIS="$(date --date="+$(expr $BANSURE 
\* $(expr $SAYISI + 1)) minutes" +%Y%m%d%H%M)"
                                        sed -i -e 's/^\(#\)\('$IP'.*\)/\2/' -e 
's/\('$IP'.*\)\('$CIKIS'\)\(.*\)\('$SAYISI'\)/\1'$YCIKIS'\3'$(expr $SAYISI + 
1)'/' $LISTE
                                        iptables -A INPUT -s $IP -p tcp 
--destination-port 80 -j DROP
                                fi
                                
                        else
                        CIKIS="$(date --date="+$BANSURE minutes" +%Y%m%d%H%M)"
                        #echo "$IP listede yok. $CIKIS saatinde cikmak icin 
eklendi"
                        echo "$IP        $TIME        $CIKIS        $BAG        
$HUMTIME        1" >> $LISTE
                        iptables -A INPUT -s $IP -p tcp --destination-port 80 
-j DROP
                        fi
        fi
done
for j in $(sed -n '/^[^#]/p' $LISTE|awk '{if ($3 <= '$TIME') print $1;}');do
        #echo "$j suresi dolmus, listeden cikarilacak."
        sed -i 's/\('$j'.*\)/#\1/' $LISTE
        iptables -D INPUT -s $j -p tcp --destination-port 80 -j DROP
done
sleep 15
done
_______________________________________________
Linux-guvenlik mailing list
[email protected]
https://liste.linux.org.tr/mailman/listinfo/linux-guvenlik
Liste kurallari: http://liste.linux.org.tr/kurallar.php

Cevap