Archivi tag: netblock

CentOS 6 e contromisure agli attacchi DDoS: regole di firewalling basate sui netblock dei provider italiani

Scenario

Server Web Linux (basato su Apache) con CentOS 6 a bordo, dotato di 16 GB di RAM e 2 CPU con 4 core ciascuna. Totale assenza di firewall di frontend, ergo il filtraggio del traffico viene demandato direttamente al server in questione.

Problema

Da N giorni la suddetta macchina è vittima di attacchi di tipo DDoS, provenienti per lo più da IP stranieri (macchine zombie facenti parte di una botnet).

Soluzione

Creare delle regole netfilter ad hoc (mediante iptables), consentendo solo ed esclusivamente i netblock degli ISP italiani. Inoltre, per evitare che l’attaccante possa avvalersi di qualche proxy “aperto” made in Italy, sono stati bloccati ulteriori IP pubblici recuperati da un sito specifico. Infine, sono stati consentiti gli IP pubblici degli spider (aka crawler) utilizzati dai più importanti motori di ricerca (Google, Bing, Yahoo!), in modo tale da impedire che il sito Web hostato sul server venga penalizzato in termini di ranking.

Step 1: consentire gli IP italiani

Lo scrip bash (permit_ita.sh) che esegue tale operazione è il seguente:

#!/bin/bash

iptables -A INPUT -p tcp --dport 80 -j DROP
iptables -A INPUT -p tcp --dport 443 -j DROP

wget http://www.ipdeny.com/ipblocks/data/countries/it.zone -O ip_italiani.txt

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j ACCEPT
    iptables -I INPUT -s $line -p tcp --dport 443 -j ACCEPT
done < ip_italiani.txt

iptables-save

Il suo funzionamento è banale: per prima cosa vengono create 2 regole netfilter per droppare tutto il traffico HTTP/HTTPS diretto al sito Web. Successivamente viene scaricato (mediante wget) il contenuto del sito http://www.ip-deny.com/ipblocks/data/countries/it.zone, in cui è presente l’elenco dei netblock italiani. Infine, vegnono consentiti i netblock in questione.

Step 2: bloccare i proxy made in Italy

A questo punto possiamo procedere con il blocco dei proxy “open” italiani. Per fare ciò possiamo utilizzare il seguente scrip bash (block_proxy.sh):

#!/bin/bash

wget --user-agent="Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092416 Firefox/3.0.3"  http://spys.ru/free-proxy-list/IT/ -O lista_proxy.txt

grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" lista_proxy.txt | uniq > ip_proxy.txt

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j DROP
    iptables -I INPUT -s $line -p tcp --dport 443 -j DROP
done < ip_proxy.txt

iptables-save

Il sito target (ovvero quello che contiene la lista dei proxy da bloccare) è http://spys.ru/free-proxy-list/IT/, il quale effettua un filtraggio dei client che possono accedervi utilizzando lo User Agent come discriminante (quindi non è possibile scaricarne il contenuto se non si effettua uno spoofing di tale parametro tramite wget e l’opzione –user-agent).

Inoltre, poichè il contenuto del sito non è una “lista piatta” di IP pubblici, è stato necessario filtrare il tutto utilizzando un’espressione regolare in grado di individuare i 4 ottetti tipici dell’IPv4.

Step 3: consentire gli spider dei motori di ricerca

Come ultima fase, occorre consentire gli IP degli spider, utilizzando tale scrip (permit_spider.sh):

#!/bin/bash

while read line
do
    iptables -I INPUT -s $line -p tcp --dport 80 -j ACCEPT -m comment --comment "crawler"
done < ip_spider.txt

iptables-save

Il contenuto del file ip_spider.txt potete ricavarlo da qui (Google), qui (Yahoo!) e qui (Bing ed altri).

A configurazione completata, possiamo saggiare il carico sul server (intento a droppare il traffico proveniente dalla botnet) utilizzando htop.

Se la macchina regge e le risorse hardware locali non sono allo stremo potremo finalmente dire di aver vinto.

Alla prossima.

Script bash per i port scan su range di IP

Problema

Mancato aggiornamento dell’associazione IP/FQDN (record A DNS) mediante ddclient, che si traduce nell’impossibilità di conoscere il vero indirizzo IP pubblico del server (essendo dinamico).

Possibile soluzione

Conoscendo l’ISP e partendo dal fatto che almeno una porta non standard ( > 1023) è pubblicata all’esterno (ad esempio la TCP 4338) si può procedere con la scansione automatizzata dei netblock appartenenti al nostro Internet Service Provider. Nella fattispecie, l’ISP è Telecom Italia ed alcuni dei netblock ad esso associati sono i seguenti:

79.46.0.0/15
79.56.0.0/16
62.77.32.0/19
62.211.0.0/16
77.238.3.3/19
79.140.80.0/20
80.104.0.0/15
80.116.0.0/15
80.180.0.0/15
80.204.0.0/15
80.241.224.0/20
81.72.0.0/22
81.112.0.0/20
82.48.0.0/20
82.88.0.0/22
82.104.0.0/22
83.175.0.0/18
83.221.96.0/18
89.221.32.0/18
93.186.128.0/20
95.74.0.0/15
95.224.0.0/11
188.8.0.0/13
195.14.96.0/19
195.22.192.0/19
212.171.0.0/16
212.216.0.0/16
213.45.0.0/16
213.144.160.0/19
213.230.128.0/19
217.27.64.0/19
217.169.96.0/20
217.169.112.0/20
217.172.192.0/19
217.200.0.0/14
217.222.0.0/15

E’ possibile inserire la suddetta lista all’interno di un apposito file testuale, chiamandolo semplicemente netblock. Inoltre, i netblock sono oggetto di continui aggiornamenti, ergo prima di procedere sinceratevi che appartengano ancora all’ISP di riferimento (attraverso un semplice whois <netblock>).

Una volta fatto ciò, mediante l’uso di nmap, possiamo realizzare uno script bash che si occupi di scansionare i suddetti range di IP pubblici. Lo script è il seguente:

nightfly@nightbox:~$ cat autoscanner.sh
#!/bin/bash

sourcefile=/home/nightfly/netblock

resfile=/home/nightfly/results

targetfile=/home/nightfly/openports

while read line
do

        nmap -P0 $line -p 4338 >> $resfile

done < $sourcefile

cat $resfile | grep -B2 open >> $targetfile

exit 0;

La logica dello script è questa:

1) viene lanciato uno scan verso ogni singolo range specificato nel file netblock, prendendo in considerazione esclusivamente la porta di destinazione TCP 4338;

2) una volta terminata la scansione vengono cercate tutte le occorrenze del termine open, considerando anche le due righe precedenti ad esso, in modo da ottenere l’IP pubblico degli host su cui la porta in questione risulta in ascolto;

3) a questo punto, supponendo che dietro la porta TCP 4338 vi sia in ascolto un demone SSH, è possibile lanciare delle sessioni Secure SHell verso ciascun IP specificato nel file /home/nightfly/openports. Se a tali tentativi di connessione seguirà una richiesta di login, è molto probabile che il nostro server sia stato effettivamente identificato. Ovviamente, se il login non andrà a buon fine, la macchina che stiamo cercando è un’altra.

Buona scansione.

PS: il port scan, di per se, non è reato, ma potrebbe diventarlo se lo associerete a più tentativi di login non autorizzati. Inoltre, essendo i netblock in questione piuttosto ampi, la scansione richiederà molto tempo.

ddosinfo: script per la creazione automatica di ACL Cisco contro gli attacchi DDoS

In questo post vi ho mostrato un piccolo scrip per l’individuazione della nazionalità relativa agli IP sorgenti di un attacco DDoS. Avevo già preannunciato alcune modifiche, ovvero la generazione automatica delle ACL Cisco e l’aggiunta di un menù interattivo. Bhè, così è stato.

acl, cisco, acl standard, acl estese, acl nominali, bash, ddos, whois, IP, netblock

Per prima cosa installiamo il tool ipcalc, che ci servirà per calcolare le wildmask da impostare sulle ACL:

nightfly@nightbox:~$ sudo apt-get install ipcalc

Successivamente creiamo un file testuale vuoto su cui incolleremo il contenuto dello scrip e rendiamolo eseguibile:

nightfly@nightbox:~$ touch ddosinfo

nightfly@nightbox:~$ chmod +x ddosinfo

Non ci resta che copiarci dentro le seguenti direttive:

#!/bin/bash
touch ipinfo
touch target
touch parsed
touch acl
touch target_pari
touch target_dispari
touch target_parsed

while read line
do
        whois -F $line >> ipinfo
done < tlog

while read line
do
    locin=`echo $line | grep "*in"`
    loccy=`echo $line | grep "*cy"`
    if [[ -n "$locin" || -n "$loccy" --; then
        echo "$locin$loccy"  >> target
    fi
done < ipinfo

cat target | awk 'NR%2==1' >> target_dispari
cat target | awk 'NR%2==0' >> target_pari

paste target_dispari target_pari | grep -v "IT" >> target_parsed

while read line
do
        block=`echo $line | grep "*in" | sed s/*in://g`
    if [ -n "$block" ]; then
               wild1=`ipcalc $block | awk '{ print $1 }' | sed s/deaggregate//g`
        wild2=`ipcalc -b $wild1 | awk 'BEGIN { FS = "Wildcard: " } ; { print $2 }' | tr 'n' ' ' | sed 's/^[ t]*//;s/[ t]*$//;'`
        wild3=`ipcalc -b $wild1 | awk 'BEGIN { FS = "Address: " } ; { print $2 }' | sed 's/^[ t]*//;s/[ t]*$//'`
        echo "$wild3 $wild2" >> parsed
    fi
done < target_parsed

echo "Seleziona il tipo di ACL:"

echo "1 - standard"
echo "2 - estesa"
echo "3 - nominale"

read scelta;

if [ $scelta == 1 ]; then
    while true;
    do
    echo "Inserisci l'identificativo dell'acl (1-99):"
   
    read numero;
   
    if [[ $numero =~ ^([1-9]|[1-9][0-9])$ --;then
        while true;
        do
            echo "Scegli il protocollo (ip-tcp-udp):"
            read protocollo;
            if [[ $protocollo =~ ^(ip|tcp|udp)$ --;then
                while true;
                do
                    echo "Vuoi attivare il logging? (S/N):"
                        read logging;
                    if [ $logging == "S" ];then
                        while read line
                        do
                            network=`echo $line | awk 'BEGIN { FS = " " } ; { print $1 }'`
                            wildcard=`echo $line | awk 'BEGIN { FS = " " } ; { print $2 }'`
                            echo "access-list $numero deny $protocollo $network $wildcard any log" >> acl
                        done < parsed
                        break
                    else
                        if [ $logging == "N" ];then
                            while read line
                                        do
                                                network=`echo $line | awk 'BEGIN { FS = " " } ; { print $1 }'`
                                wildcard=`echo $line | awk 'BEGIN { FS = " " } ; { print $2 }'`
                                                echo "access-list $numero deny $protocollo $network $wildcard any" >> acl
                                        done < parsed
                        break
                        fi
                    fi
                done
            fi
            break
        done
    break
    fi
    done
fi

if [ $scelta == 2 ]; then
    while true;
    do

    echo "Inserisci l'identificativo dell'acl (100-199 oppure 2000-2699):"
    read numero;

    if [[ $numero =~ ^(1[0-9][0-9]|2[0-6][0-9][0-9])$ --;then
        while true;
        do
            echo "Scegli il protocollo (ip-tcp-udp):"
            read protocollo;
            if [[ $protocollo =~ ^(ip|tcp|udp)$ --;then
                while true;
                do
                    echo "Vuoi attivare il logging? (S/N):"
                        read logging;
                    if [ $logging == "S" ];then
                        while read line
                        do
                            network=`echo $line | awk 'BEGIN { FS = " " } ; { print $1 }'`
                            wildcard=`echo $line | awk 'BEGIN { FS = " " } ; { print $2 }'`
                            echo "access-list $numero deny $protocollo $network $wildcard any log" >> acl
                        done < parsed
                        break
                    else
                        if [ $logging == "N" ];then
                            while read line
                                        do
                                                network=`echo $line | awk 'BEGIN { FS = " " } ; { print $1 }'`
                                wildcard=`echo $line | awk 'BEGIN { FS = " " } ; { print $2 }'`
                                                echo "access-list $numero deny $protocollo $network $wildcard any" >> acl
                                        done < parsed
                        break
                        fi
                    fi
                done
            fi
            break
        done
    break
    fi
    done
fi

if [ $scelta == 3 ]; then

    while true;
    do
    echo "Inserisci il nome dell'acl:"
    read nome;
    if [[ $nome =~ [[:alpha:-- --;then
        while true;
        do
            echo "Scegli il protocollo (ip-tcp-udp):"
            read protocollo;
            if [[ $protocollo =~ ^(ip|tcp|udp)$ --;then
                while true;
                do
                    echo "Vuoi attivare il logging? (S/N):"
                        read logging;
                    if [ $logging == "S" ];then
                        while read line
                        do
                            network=`echo $line | awk 'BEGIN { FS = " " } ; { print $1 }'`
                            wildcard=`echo $line | awk 'BEGIN { FS = " " } ; { print $2 }'`
                            echo "access-list $numero deny $protocollo $network $wildcard any log" >> acl
                        done < parsed
                        break
                    else
                        if [ $logging == "N" ];then
                            while read line
                                        do
                                                network=`echo $line | awk 'BEGIN { FS = " " } ; { print $1 }'`
                                wildcard=`echo $line | awk 'BEGIN { FS = " " } ; { print $2 }'`
                                                echo "access-list $numero deny $protocollo $network $wildcard any" >> acl
                                        done < parsed
                        break
                        fi
                    fi
                done
            fi
            break
        done
    break
    fi
    done
fi

rm ipinfo
rm parsed
rm target_*

exit 0;

Tale scrip consente di scegliere tra 3 tipoligie di ACL (tutte per il protocollo IP), ovvero:

1) standard;

2) estese;

3) nominali.

Le ACL generate verranno salvate all’interno del file acl, mentre gli IP sorgenti da analizzare vanno posizionati nel file tlog. Non vi rimane dunque che copiare il contenuto del file acl ed incollarlo nel firewall/router, sotto il menù di configurazione (config#) e successivamente associare l’access control list appena creata all’interfaccia target.

Avrete certamente notato che il codice non è dei più semplici per via del parsing massiccio che si è reso necessario. Tuttavia non scoraggiatevi, se avete delle domande (ed individuate eventuali falle/miglioramenti) non esitate a contattarmi.

A presto.

DDoS: script bash per individuare la nazionalità degli IP sorgenti dell’attacco

Per arginare un attacco DDoS è necessario, prima di tutto, individuare quali sono gli IP pubblici da cui proviene. In secondo luogo, occorre capire se il sito vittima basa il proprio “business” esclusivamente su visite italiane. In questo caso, per realizzare delle opportune ACL in modo da filtrare il traffico in ingresso, si deve capire quali sono i netblock stranieri da interdire. Per fare ciò ho realizzato un piccolo scrip bash che legge gli IP da un file di testo (ricavati, ad esempio, analizzando i log del Firewall o del Web server) e ne individua il relativo netblock (e la nazionalità).

 

ddos,bash,script,linux,netblock,netmask,ip

Ecco lo scrip:

#!/bin/bash

touch ipinfo
touch target

while read line
do
        whois -F $line >> ipinfo
done < tlog

while read line
do
        locin=`echo $line | grep "*in"`
        loccy=`echo $line | grep "*cy"`
        if [[ -n "$locin" || -n "$loccy" --; then
                echo "$locin$loccy" >> target
        fi
done < ipinfo

rm ipinfo

exit 0;

Ovviamente è ancora ad una versione alpha (0.1). Appena avrò tempo provvederò ad aggiungere il calcolo automatico delle netmask e la creazione automatizzata della relative ACL Cisco (con un minimo di interattività).

Alla prossima.

NB: il file testuale tlog deve contenere un solo IP sorgente per riga.