Archivi tag: ddos

CentOS 6: kernel tuning volto al system hardening

Qualunque amministratore di sistema sa bene che 2 regole di firewalling in croce ed una password sufficientemente complessa non sono in grado di garantire un livello di sicurezza accettabile. Occorre, infatti, avere ben presente quali sono i pericoli a cui si dovrà far fronte mettendo un dato sistema in produzione, rischi che possono essere mitigati (a volte anche molto efficacemente) utilizzando qualche applicativo creato ad hoc (come, ad esempio, SELinux) e monitorando il sistema 24/7, sia a livello di risorse che a livello di operazioni sospette su determinati file o directory (in quest’ultimo caso parliamo di auditing).

Detto ciò, è altrettanto importante sapere che il kernel linux prevede alcuni meccanismi in grado di aumentare notevolmente la sicurezza del sistema operativo stesso, mettendolo al riparo da attacchi di tipo overflow, ip spoofing, ecc.

kernel

Tali meccanismi possono essere abilitati in modo permanente editando file /etc/sysctl.conf (in tal caso per rendere i settaggi operativi sarà necessario utilizzare il comando sysctl -p oppure effettuare un reboot), o, in alternativa, operando mediante /proc (rendendo subito effettive le modifiche ma non permanenti).

Per quanto mi riguarda, di solito opero in questo modo:

1) modifico i parametri di interesse mediante /proc (uno per uno, in modo da essere sicuro che , dopo ogni step, il sistema continua a funzionare come dovrebbe);

2) modifico il file sysctl.conf popolandolo con le direttive necessarie.

Ecco le modifiche da apportare al kernel on-the-fly:

#Misure anti overflow

echo 1 > /proc/sys/kernel/exec-shield
echo 2 > /proc/sys/kernel/randomize_va_space

#Misure anti ip spoofing e source route

echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
echo 1 > /proc/sys/net/ipv4/conf/default/log_martians
echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
echo 0 > /proc/sys/net/ipv4/conf/default/accept_source_route

#Misure anti ICMP redirect

echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects
echo 0 > /proc/sys/net/ipv4/conf/default/accept_redirects
echo 0 > /proc/sys/net/ipv4/conf/all/secure_redirects
echo 0 > /proc/sys/net/ipv4/conf/default/secure_redirects

#Misure anti DOS/DDOS basati su TCP (SYN FLOOD)

echo 1 > /proc/sys/net/ipv4/tcp_syncookies
echo 2 > /proc/sys/net/ipv4/tcp_synack_retries

#Misure anti smurf

echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

Nella fattispecie,  le misure anti overlflow hanno come obiettivo quello di impedire l’esecuzuone di shellcode su aree di memoria marcate come “non eseguibili” (exec-shield), facendo anche in modo che tutti i riferimenti a particolari funzioni presenti in memoria non siano accessibili facilmente da un utente malevolo, randomizzandone gli indirizzi di memoria (randomize_va_space)

Tra le misure anti ip spoofing e source route sono elencati 12 parametri, ovvero:

echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 1 > /proc/sys/net/ipv4/conf/default/rp_filter

che abilitano il return path filter, ovvero se l’IP sorgente di un dato pacchetto ricevuto su una specifica interfaccia non è raggiungibile mediante quest’ultima, il suddetto pacchetto verrà scartato;

echo 1 > /proc/sys/net/ipv4/conf/all/log_martians
echo 1 > /proc/sys/net/ipv4/conf/default/log_martians

che abilitano il logging dei pacchetti spoofati;

echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
echo 0 > /proc/sys/net/ipv4/conf/default/accept_source_route

il cui compito è quello di disabilitare il cosiddetto source route (ovvero “instradare” il pacchetto appena ricevuto lungo il “cammino” di rete ben preciso – comprensivo di hop – specificato al suo interno);

echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects 
echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects

che disabilitano l’invio dei pacchetti ICMP redirect;

echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects 
echo 0 > /proc/sys/net/ipv4/conf/default/accept_redirects

che disabilitano la ricezione degli ICMP redirect;

echo 0 > /proc/sys/net/ipv4/conf/all/secure_redirects 
echo 0 > /proc/sys/net/ipv4/conf/default/secure_redirects

affinchè anche gli ICMP redirect provenienti dal default gateway (e quindi teoricamente “sicuri”) vengano scartati.

Per quanto riguarda, invece, le misure anti attacchi DOS/DDOS basati sul procotollo TCP, ho abilitato i cosiddetti syncookies e limitato l’invio dei SYN/ACK a 2 soli tentativi (in modo da mitigare i SYN FLOOD):

echo 1 > /proc/sys/net/ipv4/tcp_syncookies
echo 2 > /proc/sys/net/ipv4/tcp_synack_retries

Infine, nelle misure anti smurf ho semplicemente disabilitato la ricezione dei broadcast ICMP:

echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

Per quanto riguarda, invece, il file /etc/sysctl.conf, le direttive da inserire sono le seguenti:

#Enable Exec-Shield
kernel.exec-shield = 1

# Enable ASLR
kernel.randomize_va_space = 1

# Controls source route verification
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 2

# Do not accept source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Do not accept or send ICMP redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0

# Log spoofed packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

#Ignore ICMP broadcasts
net.ipv4.icmp_echo_ignore_broadcasts = 1

Fine del kernel tuning. Alla prossima.

Traffico TCP sulla porta 0

Qualche giorno fa Nagios mi ha segnalato un allarme di sicurezza che mi ha lasciato alquato basito:

When a syslog message is generated by the device a SEC info IPACCESSLOGP list 102 denied tcp 77.223.136.170(0) - 95.245.162.62(0), 1 packet 9:5:46:40.62

In soldoni, l’ACL attiva sull’interfaccia dialer (WAN) del mio router ha “scartato” un segmento TCP proveniente dall’IP 77.223.136.170 (porta 0) e diretto al mio (vecchio) IP pubblico (ovvero 95.245.162.62, porta 0).

Ora, è sufficiente avere un minimo di dimestichezza con lo stack TCP/IP per capire che l’anomalia sta proprio nella porta sorgente ed in quella di destinazione. Infatti, la porta 0 è riservata ed il suo impiego può avvenire per i motivi (leciti) più disparati.

Ad esempio, nel caso in cui il pacchetto IP (formato da header + payload) superi la MTU del link che deve attraversare, esso subirà un processo specifico, denominato “frammentazione”.

In particolare, essendo l’header TCP parte del payload IP (per via dell’incapsulamento – vedi immagine sottostante), ciascun frammento potrebbe contenere la suddetta intestazione per intero o solo parzialmente. Nel primo caso, l’header TCP originario si troverebbe soltanto nel primo frammento, mentre tutti gli altri conterrebbero la sola intestazione IP (dotata di ID specifico del frammento, offset per la ricostruzione del traffico in fase di ricezione – dimensione e bit MFMore Fragment – pari a 0 o 1 a seconda che si tratti dell’ultimo frammento o meno).

encaps

Più in generale, la porta TCP/UDP pari a 0 potrebbe stare a significare, molto semplicemente, assenza di layer 4 (basti pensare al protocollo ICMP).

Per quanto riguarda, invece, l’uso malevolo della porta 0, possiamo distinguere 3 macro-tipologie di casi:

1) Attacchi di tipo fingerprint. Essi si basano sul presupposto che spesso e volentieri le ACL non possono essere definite in modo tale da droppare esplicitamente il traffico in ingresso sulla porta 0 (TCP o UDP), ergo puntare ad essa è un modo abbastanza efficace (ma non infallibile) per ottenere info sulla tipologia di router oggetto di interesse (OS fingerprint – leggete questo per ulteriori dettagli);

2) Attacchi volti ad “aggirare” le ACL. Ad esempio, forzando la frammentazione del pacchetto IP ed agendo sul campo offset,  si potrebbe riuscire, in teoria, a sovrascrivere parte dell’intestazione TCP originaria (che punta ad una porta di destinazione “lecitamente” raggiungibile dall’esterno, come potrebbe essere la 25 per il protocollo SMTP) con una porta non accessibile dall’esterno (ad esempio la 23 per il protocollo Telnet). Per ulteriori dettagli su tale tipologia di attacco (denominato tiny overlapping fragment attack) leggete questo.

3) Attacchi di tipo DoS/DDoS. Forzando la frammentazione dei pacchetti IP sottostanti al layer 4 (TCP/UDP) si potrebbe riuscire a “sovraccaricare” il router di destinazione, soprattutto per via dell’overhead dovuto all’attività di “ricostruzione” del traffico. Inoltre, puntando ad una porta non lecita, ad esempio la 0, lo si costringerebbe ad inviare dei messaggi ICMP Port Unreachable (se abilitati sull’interfaccia), sovraccaricandolo ulteriormente.

Della casistica appena illustrata credo che l’allarme ricada, molto banalmente, negli attacchi di tipo fingerprint. Ovviamente ho alzato il livello di attenzione per evitare “brutte” sorprese in futuro.

Vi terrò comunque aggiornati.

Aggiornamento 1

A quanto pare si è trattato proprio di un portscan/fingerprint. Infatti, dopo circa 5 giorni dallo scan sulla porta TCP 0, ho registrato il seguente traffico:

Jan 25 15:29:15 192.168.2.1 1738: 001735: Jan 25 15:29:14.483 UTC: %SEC-6-IPACCESSLOGP: list 101 permitted tcp 77.223.136.170(443) -> 79.31.118.x(43616), 1 packet
Jan 25 15:29:17 192.168.2.1 1739: 001736: Jan 25 15:29:15.988 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 77.223.136.170(256) -> 79.31.118.x(43617), 1 packet
Jan 25 15:29:18 192.168.2.1 1740: 001737: Jan 25 15:29:17.200 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 77.223.136.170(111) -> 79.31.118.x(43617), 1 packet
Jan 25 15:29:19 192.168.2.1 1741: 001738: Jan 25 15:29:18.204 UTC: %SEC-6-IPACCESSLOGP: list 101 permitted tcp 77.223.136.170(1106) -> 79.31.118.x(43616), 1 packet
Jan 25 15:29:20 192.168.2.1 1742: 001739: Jan 25 15:29:19.204 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 77.223.136.170(700) -> 79.31.118.x(43617), 1 packet
Jan 25 15:29:20 192.168.2.1 1743: 001740: Jan 25 15:29:20.208 UTC: %SEC-6-IPACCESSLOGP: list 101 permitted tcp 77.223.136.170(3493) -> 79.31.118.x(43616), 1 packet
Jan 25 15:29:22 192.168.2.1 1744: 001741: Jan 25 15:29:21.213 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 77.223.136.170(726) -> 79.31.118.x(43617), 1 packet
Jan 25 15:29:24 192.168.2.1 1746: 001743: Jan 25 15:29:23.365 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 77.223.136.170(777) -> 79.31.118.x(43618), 1 packet
Jan 25 15:29:26 192.168.2.1 1747: 001744: Jan 25 15:29:25.046 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 77.223.136.170(111) -> 79.31.118.x(43618), 1 packet

Aggiornamento 2

In data 26 Gennaio ho ricevuto un altro pacchetto da/verso la suddetta porta:

When a syslog message is generated by the device a SEC info IPACCESSLOGP list 101 denied tcp 23.236.147.202(0) - 79.31.118.x(0), 1 packet 0:14:52:02.45

Vediamo se tra qualche giorno il nuovo IP sorgente utilizzerà lo stesso ordine di port probing del suo predecessore.

Aggiornamento 3

Come volevasi dimostrare, a distanza di qualche ora è arrivato il port probing vero e proprio:

Jan 27 18:36:33 192.168.2.1 19380: 019433: Jan 27 18:36:32.479 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 23.236.147.202(139) -> 79.31.118.x(46096), 1 packet
Jan 27 18:36:35 192.168.2.1 19381: 019434: Jan 27 18:36:34.475 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 23.236.147.202(1002) -> 79.31.118.x(46097), 1 packet
Jan 27 18:36:36 192.168.2.1 19382: 019435: Jan 27 18:36:35.500 UTC: %SEC-6-IPACCESSLOGP: list 101 permitted tcp 23.236.147.202(2701) -> 79.31.118.x(46095), 1 packet
Jan 27 18:36:36 192.168.2.1 19383: 019436: Jan 27 18:36:36.500 UTC: %SEC-6-IPACCESSLOGP: list 101 permitted tcp 23.236.147.202(11967) -> 79.31.118.x(46095), 1 packet
Jan 27 18:36:38 192.168.2.1 19384: 019437: Jan 27 18:36:37.552 UTC: %SEC-6-IPACCESSLOGP: list 101 permitted tcp 23.236.147.202(1494) -> 79.31.118.x(46095), 1 packet
Jan 27 18:36:39 192.168.2.1 19385: 019438: Jan 27 18:36:38.556 UTC: %SEC-6-IPACCESSLOGP: list 101 permitted tcp 23.236.147.202(8021) -> 79.31.118.x(46095), 1 packet
Jan 27 18:36:43 192.168.2.1 19387: 019440: Jan 27 18:36:42.353 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 23.236.147.202(139) -> 79.31.118.x(46097), 1 packet
Jan 27 18:36:48 192.168.2.1 19388: 019441: Jan 27 18:36:47.154 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 23.236.147.202(139) -> 79.31.118.x(46095), 1 packet

Anche in questo caso le porte oggetto dell’attacco sono quelle > 1023. Ho quindi fatto qualche modifica all’ACL configurata sulla dia0 del mio router, sostituendo la regola:

access-list 101 permit tcp any gt 1023 any log

con:

access-list 101 permit tcp any gt 1023 any established log

in modo tale da consentire il traffico proveniente dalle porte > 1023 solo se si riferiscono a delle connessioni già esistenti.

Aggiornamento 4

Sono riuscito a ricreare parzialmente la suddetta tipologia di traffico, utilizzando un apposito tool denominato hping, il quale è in grado di forgiare dei pacchetti RAW/TCP/UDP/ICMP da impiegare durante le operazioni di OS fingerprint e non solo.

Ad esempio, mediante il comando:

[root@linuxbox ~]# hping3 -S -V <mio indirizzo IP>

sono riuscito a generare una sfilza di pacchetti TCP recanti i classici 40 byte di header, payload 0 e flag SYN settata a 1, la cui destinazione proprio è la famigerata porta 0.

Di seguito riporto il tracciato tcpdump da locale (grazie al quale si può notare che la porta sorgente è una porta alta, ovvero maggiore di 1023, e che la porta di destinazione è sempre la 0):

09:41:14.967184 IP 192.168.1.1.1232 > 79.31.118.x.0: Flags [S], seq 2094000106, win 512, length 0
09:41:15.967305 IP 192.168.1.1.1233 > 79.31.118.x.0: Flags [S], seq 517260399, win 512, length 0
09:41:16.967425 IP 192.168.1.1.1234 > 79.31.118.x.0: Flags [S], seq 399923675, win 512, length 0
09:41:17.967477 IP 192.168.1.1.1235 > 79.31.118.x.0: Flags [S], seq 725026004, win 512, length 0
09:41:18.967573 IP 192.168.1.1.rmtcfg > 79.31.118.x.0: Flags [S], seq 1830159741, win 512, length 0
09:41:19.967638 IP 192.168.1.1.1237 > 79.31.118.x.0: Flags [S], seq 342672970, win 512, length 0

Mentre il log generato dal mio router è il seguente:

Apr  3 09:39:35 192.168.2.1 108805: 108943: Apr  3 08:39:34.979 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 95.254.89.x(1232) -> 79.31.118.x(0), 1 packet
Apr  3 09:39:37 192.168.2.1 108807: 108945: Apr  3 08:39:36.979 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 95.254.89.x(1233) -> 79.31.118.x(0), 1 packet
Apr  3 09:39:39 192.168.2.1 108808: 108946: Apr  3 08:39:38.980 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 95.254.89.x(1234) -> 79.31.118.x(0), 1 packet
Apr  3 09:39:41 192.168.2.1 108809: 108947: Apr  3 08:39:40.980 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 95.254.89.x(1235) -> 79.31.118.x(0), 1 packet
Apr  3 09:39:43 192.168.2.1 108810: 108948: Apr  3 08:39:42.981 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 95.254.89.x(1236) -> 79.31.118.x(0), 1 packet
Apr  3 09:39:45 192.168.2.1 108811: 108949: Apr  3 08:39:44.977 UTC: %SEC-6-IPACCESSLOGP: list 101 denied tcp 95.254.89.x(1237) -> 79.31.118.x(0), 1 packet

Invece, forzando a 0 la porta sorgente del suddetto traffico (e mantenendola tale per tutta la durata del test – opzione -k) attraverso il comando:

[root@linuxbox ~]# hping3 -S -VV -s 0 -k <mio indirizzo IP>

sono riuscito ad intercettarlo localmente come dimostrato dal seguente tracciato:

10:32:21.495218 IP 192.168.1.1.0 > 79.31.118.x.0: Flags [S], seq 1600061111, win 512, length 0
10:32:22.495334 IP 192.168.1.1.0 > 79.31.118.x.0: Flags [S], seq 965785080, win 512, length 0
10:32:23.495411 IP 192.168.1.1.0 > 79.31.118.x.0: Flags [S], seq 677172521, win 512, length 0
10:32:24.495492 IP 192.168.1.1.0 > 79.31.118.x.0: Flags [S], seq 473418678, win 512, length 0

ma è stato successivamente scartato dal router sorgente, ergo non è mai giunto a destinazione.

Nei prossimi giorni proverò a ripetere il test utilizzando il router di un vendor differente.

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.

Firewall Cisco ASA ed attacchi DDoS/DoS

Ultimamente mi è capitato di dover far fronte a tutta una serie di attacchi DDoS, per lo più basati sul protocollo HTTP (connessioni half-open/embryonic, in cui manca il l’ACK finale poichè l’indirizzo IP sorgente del SYN è falso o soggetto a spoofing), mitigati senza troppe difficoltà da un cluster di Firewall Cisco ASA.

ddosLa configurazione che ho utilizzato per mitigare tale tipologia di attacchi è simile alla seguente:

ASA(config)# class-map mpf-policy
ASA(config-cmap)# match access-list outside_access_in
ASA(config-cmap)# exit
ASA(config)# policy-map mpf-policy-map
ASA(config-pmap)# class mpf-policy
ASA(config-pmap-c)# set connection conn-max 11500
ASA(config-pmap-c)# set connection embryonic-conn-max 3000
ASA(config-pmap-c)# set connection per-client-embryonic-max 200
ASA(config-pmap-c)# set connection per-client-max 95
ASA(config-pmap-c)# exit
ASA(config-pmap)# exit
ASA(config)# service-policy mpf-policy-map interface outside
ASA(config)# exit

Tutto è filato liscio per un po’ di tempo, fino a quando l’attaccante non ha deciso di cambiare strategia, passando da un attacco DDoS ad uno DoS (dunque con un solo IP sorgente) e dal protocollo TCP a quello UDP (molto più adatto a questa tipologia di attacco poichè connection-less).

La VPS utilizzata come sorgente di traffico, dotata di ampia banda (si trovava in una farm tedesca) è stata in grado, in un lasso di tempo brevissimo, di far collassare i firewall. Una volta identificato il suo IP ho creato un’ACL del tipo:

ASA(config)#deny ip host <IP attaccante> any

che però si è rivelata essere un’arma a doppio taglio visto che il firewall si è visto costretto a “maneggiare” e “bloccare” una mole di traffico tale per cui la sua CPU ha raggiunto livelli di carico assurdi (la dashboard di ASDM indicava un picco di oltre il 300% a fronte di un rate di pacchetti droppati superiore ai 100k  – vedi immagine sottostante).

dropped_ratedropped_rate

Fondamentalmente ciò è dovuto al fatto che ciascun modello di ASA può gestire solo una determinata mole di traffico (sessioni concorrenti, nuove connessioni/secondo, pacchetti/secondo, ecc – per ulteriori dettagli vedi qui), limite imposto soprattutto dalle caratteristiche hardware di cui è dotato (CPU, RAM, ecc.). Inoltre, per ciascun pacchetto scartato, è necessario un certo overhead, ragion per cui la suddetta ACL ha prodotto effetti collaterali che hanno portato ad un peggioramento della situazione.

Dopo qualche minuto di smarrimento, ho deciso di modificare la mia strategia (sulla falsariga di quella dell’attaccante), consentendo sul firewall tutto il traffico in ingresso dall’IP della VPS incriminata, demandando ai server la sua gestione. Nella fattispecie, ho configurato dei blackhole (aka null route) a livello 3, mediante il seguente comando:

route add -net <IP attaccante> gw 127.0.0.1 lo

Ho scelto questa strategia per 2 motivi:

1) I server sono dotati di maggiori risorse hardware rispetto ai firewall, quindi più “propensi” a gestire una tale mole di traffico in ingresso;

2) Lavorare a livello 3 anzichè a livello 4 implica un minor overhead.

Alla fine tale strategia si è rivelata vincente e l’attaccante ha deposto le armi.

E’ tutto, alla prossima.

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.

Contromisure agli attacchi DoS e DDoS

In questo post abbiamo visto cosa si intende per attacchi DoS e DDoS. Ora vedremo come si possono prevenire (dove possibile), riconoscere ed eventualmente bloccare (o mitigare).

In generale, possiamo affermare che esistono tre linee di difesa contro gli attacchi DoS e DDoS:

1) Prevenzione e cognizione: questa fase si sviluppa prima dell’attacco vero e proprio e comprende tutti quei meccanismi che consentono all’host vittima di resistere ai tentativi di negazione del servizio, continuando a garantire l’accesso da parte degli utenti legittimi.

2) Rilevazione degli attacchi e filtraggio: tale fase prevede un’accurata anlisi dei log, in modo da identificare le varie sorgenti dell’attacco, i servizi presi di mira (ad esempio il protocollo HTTP), e la tipologia di traffico (TCP oppure UDP);

3) Risalire alla sorgente dell’attacco: tale operazione è sicuramente la più complessa, in quanto il vero attaccante non si espone quasi mai direttamente, ma usa tutta una serie di tecniche di bouncing (basate su proxy anonimi) che gli consentono di mantenere un certo anonimato. A questo va ad aggiungersi l’utilizzo delle macchine zombie come front-end, rendendo ancora più difficile l’individuazione del vero colpevole.

Dopo questa breve introduzione prettamente teorica andiamo ad analizzare, uno per uno, i vari punti citati precedentemente, in modo tale da fornire degli esempi pratici che possono certamente tornare utili ai vari utenti/amministratori di sistema che si ritrovano a dover fronteggiare gli attacchi in questione. Occorre comunque fare una premessa: le varie tecniche descritte in questo post riguardano la configurazione di alcuni firewall hardware (PIX/ASA Cisco) e di alcuni firewall software, quali IPTABLES.

Ma veniamo a noi. Per prevenire gli effetti nefasti di un attacco DoS o DDoS basato sulla tecnica SYN-flood (e quindi sulle connessioni half-open) occorre operare sul numero di connessioni che il firewall può accettare. A tal proposito, nell’ambito dei firewall PIX/ASA possono essere utilizzati i seguenti comandi:

Per prima cosa definisco una class-map, in modo da rispettare l’approccio modulare tanto caldeggiato da Cisco:

hostname(config)# class-map <nome>

Inoltre, faccio in modo che in questa class-map venga controllato il traffico tcp diretto alla porta 80 (HTTP):

hostname(config)# match port tcp eq 80

Successivamente definisco una policy-map, alla quale assocerò la class-map creata in precedenza:

hostname(config)# policy-map <nome>
hostname(config-pmap)# class <nome>

A questo punto non mi resta che definire alcuni parametri, quali il numero massimo di connessioni attive, il numero massimo di nuove connessioni (embryonic, leggasi half-open) che il firewall può accettare, il numero massimo di connessioni embryonic per ogni host sorgente, il numero massimo di connessioni attive per ogni host sorgente ed infine l’eventuale uso di un numero di sequenza random:

hostname(config-pmap-c)# set connection {[conn-max number] [embryonic-conn-max number] [per-client-embryonic-max number] [per-client-max number][random-sequence-number {enable | disable}}

Procedo dunque con il settaggio dei timeout relativi ai vari tipi di connessione (già instaurate, half-open, half-closed e quelle basate sul protocollo tcp):

hostname(config-pmap-c)# set connection {[embryonic hh[:mm[:ss--] [half-closed hh[:mm[:ss--] [tcp hh[:mm[:ss--]}

Non ci resta che associare la policy-map appena creata a tutte le interfacce (global) oppure ad un’interfaccia specifica:

hostname(config)# service-policy policymap_name {global | interface <nome>}

A titolo di esempio, ecco una possibile configurazione del nostro PIX/ASA:

 firewall(config)# class-map tcp_syn
 firewall(config-cmap)# match port tcp eq 80
 firewall(config-cmap)# exit
 firewall(config)# policy-map tcpmap
 firewall(config-pmap)# class tcp_syn
 firewall(config-pmap-c)# set connection conn-max 100
 firewall(config-pmap-c)# set connection embryonic-conn-max 200
 firewall(config-pmap-c)# set connection per-client-embryonic-max 10
 firewall(config-pmap-c)# set connection per-client-max 5
 firewall(config-pmap-c)# set connection random-sequence-number enable
 firewall(config-pmap-c)# set connection timeout embryonic 0:0:45
 firewall(config-pmap-c)# set connection timeout half-closed 0:25:0
 firewall(config-pmap-c)# set connection timeout tcp 2:0:0
 firewall(config-pmap-c)# exit
 firewall(config-pmap)# exit
 firewall(config)# service-policy tcpmap interface outside

Vediamo ora una configurazione piuttosto semplice, ma comunque funzionale, relativa ad IPTABLES. Come già detto per i PIX/ASA, la configurazione che andremo a vedere ha come scopo principale quello di mitigare gli attacchi SYN-flood:

iptables -A INPUT -p tcp --syn -m limit --limit 5/s --limit-burst 10 -j DROP

con questa regola associata alla catena INPUT scarteremo tutti i segmenti tcp contenenti come flag syn nel caso in cui il firewall ne riceva più di 5 al secondo (oppure nel caso in cui ne riceva più di 10 consecutivamente).

Possiamo inoltre limitare ed eventualmente loggare i tentativi di port-scan, sui quali si basano alcuni attacchi DDoS già descritti nel post precedente.

Per fare ciò utilizziamo la rule:

iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m limit --limit 1/s -j DROP

In particolare, con questa regola stiamo droppando tutti i segmenti con flag SYN, ACK, FIN ed RST ricevuti dal firewall, nel caso in cui la loro frequenza sia superiore ad 1 al secondo. Da notare che tali flag vengono costantemente usate da nmap per “aggirare” i filtri imposti dal firewall (l’opzione -sS vi dice qualcosa?).

Infine, possiamo loggare il traffico matchato dalla catena INPUT mediante la seguente regola:

iptables -A INPUT -j LOG --log-prefix "Traffico in ingresso: "

Tali log verranno salvati in /var/log/syslog e saranno identificati dal prefisso “Traffico in ingresso: “ definito in precedenza. Infine, per quanto riguarda il logging degli hit relativi alle regole IPTABLES occorre fare una precisazione: nel caso in cui il firewall debba gestire un quantitativo di traffico in ingresso non indifferente (mediante la catena INPUT), loggare tutto quanto indiscriminatamente è una pratica piuttosto sconveniente, in quanto i file di log potrebbero assumere delle dimensioni eccessive e quindi riempire in poco tempo lo spazio su disco.

Proprio per evitare ciò, occorrerebbe definire delle catene dedicate, una che si occupi esclusivamente del controllo relativo agli attacchi syn-flood e l’altra dei port-scan. Ad esempio:

#SYN-flood

iptables -N SYN_FLOODS
iptables -A SYN_FLOOD -p tcp --syn -m limit --limit 5/s --limit-burst 10 -j RETURN
iptables -A SYN_FLOOD ! -p tcp  -j RETURN
iptables -A SYN_FLOOD -p tcp ! --syn  -j RETURN
iptables -A SYN_FLOOD -j LOG --log-prefix "SYN_FLOOD: "
iptables -A SYN_FLOOD -j DROP
iptables -A INPUT -p tcp --syn -j SYN_FLOOD

#Port-scan

iptables -N PORT-SCAN
iptables -A PORT-SCAN -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m limit --limit 1/s -j RETURN
iptables -A PORT-SCAN -j LOG --log-prefix "PORT_SCAN: "
iptables -A PORT-SCAN -j DROP
iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -j PORT-SCAN

Passiamo ora alla fase 2, ovvero alla rilevazione degli attacchi e filtraggio. Per prima cosa occorre individuare la tipologia di traffico su cui si basa l’attacco (ovvero se si tratta di segmenti TCP oppure di segmenti UDP). In secondo luogo è necessario identificare la porta (e quindi il servizio) a cui il DDoS sta puntando. Entrambe le operazioni possono essere effettuate grazie ad un’analisi delle connessioni in ingresso e dei log.

Per ciò che concerne i firewall PIX/ASA possiamo visualizzare le connessioni inbound mediante il comando:

sh conn

specificando, se è il caso, una particolare porta in modo da scremare l’output:

sh conn port 80

Nel caso in cui le connessioni instaurate con l’esterno siano prossime al numero massimo supportato dal firewall, possiamo digitare il comando:

clear conn port 80

e cancellarle in un colpo solo.

Per quanto riguarda i log, invece, essi possono essere visualizzati mendiante il comando:

sh log

Ora, occorre precisare che l’analisi dei log è di estrema importanza, in quanto ci consente di individuare abbastanza velocemente gli IP che hanno superato il numero massimo di connessioni consentite dalla policy-map impostata in precedenza. Quasi sicuramente tali IP saranno quelli associati alle macchine che stanno scagliando l’attacco.

Non ci resta quindi che creare un ACL (Access Control List) apposita da associare all’interfaccia outside. Personalmente ritengo che in questi casi conviene usare sempre e comunque le ACL nominali, in quanto consentono la cancellazione delle singole rule, senza dover ricreare ex-novo l’intera ACL.

Possiamo creare l’ACL nominale che chiameremo no_ddos mediante il comando:

firewall(config)# access-list no_ddos
firewall(config)# access-list no_ddos line 1 deny ip host <IP Sorgente dell'attacco> any
firewall(config)# access-list no_ddos line 2 deny ip host <altro IP Sorgente dell'attacco> any

e così via. In questo modo stiamo negando agli IP sorgenti dell’attacco qualunque possibilità di connessione al nostro firewall. Poichè le ACL hanno come policy di default il deny any any implicito, occorre consentire esplicitamente tutto il traffico legittimo. Se ad esempio abbiamo a che fare con un server Web che non prevede la pubblicazione di nessun altro servizio, possiamo definire la rule:

firewall(config)# access-list no_ddos line 3 premit tcp any any eq 80

Ovviamente, tale regola ha senso solo se sul server Web non vi sono contenuti multimediali. Nel caso in cui i contenuti multimediali siano presenti, oltre a permettere il traffico TCP occorrerà consentire anche quello UDP. Possiamo consentire il traffico basato su entrambi i protocolli mediante una sola regola, ovvero:

firewall(config)# access-list no_ddos line 3 premit ip any any eq 80

Per verificare che effettivamente gli IP filtrati dalla nostra ACL siano quelli che generano il maggior quantitativo di traffico basta usare il comando:

sh access-list no_ddos | include <IP>

L’output ci mostrerà il cosiddetto hitcount (abbreviato in hitcnt), ovvero quante volte il traffico in ingresso ha matchato la specifica rule dell’ACL. Valori elevati associati all’hitcount ci daranno la conferma che gli IP filtrati sono effettivamente quelli che stanno generando l’attacco.

A questo punto occorre fare alcune considerazioni. Come abbiamo già detto gli attacchi DDoS possono fare uso di macchine zombie, ovvero di macchine infettate da un applicativo malevolo che consente all’attaccante di ottenerne il controllo, in modo del tutto trasparente all’utente legittimo. Ci sono altri casi, però, in cui non si fa uso di macchine zombie, bensì di shell regolarmente acquistate. Tali shell hanno IP pubblico statico, ciò significa che ogni qual volta si connetteranno ad Internet, l’ISP assegnerà loro sempre lo stesso indirizzo IP. Questo rappresenta per noi, come è facile intuire, il caso migliore, in quanto si ha la certezza che bannando uno specifico indirizzo IP, una delle macchine della dosnet sarà permanentemente bloccata dal firewall.

Nel caso in cui la dosnet sia formata da macchine zombie le cose si fanno un pò più complesse. Poichè parliamo di normalissimi pc connessi ad Internet, è quasi certo che usino degli indirizzi IP dinamici. Questo significa che inserire il loro indirizzo IP all’interno dell’ACL rappresenta una soluzione temporanea, in quanto ad ogni riconnessione lo stesso pc infetto utilizzerà un nuovo indirizzo IP pubblico. Cosa fare dunque? Per prima cosa dobbiamo porci alcune domande:

1) I tentativi di attacco provengono da IP italiani o stranieri?

2) I contenuti pubblicati sul nostro server Web si riferiscono ad un utenza nazionale o internazionale?

Per rispondere alla prima domanda basta fare un copia incolla degli IP incriminati su una shell *nix ed utilizzare il comando host, oppure, più semplicemente, copiarlo in uno dei tanti siti sparsi per la rete che consentono, a partire dall’indirizzo IP, di risalire all’hostname.

Ora, mettiamo che gli attacchi vengano effettivamente sferrati da IP stranieri (come succede nel 99% dei casi). Cosa fare? E qui possiamo andare direttamente al punto 2): se l’utenza del sito è nazionale si potrebbe bannare esplicitamente l’intera classe IP incriminata, oppure (soluzione più drastica) consentire il traffico proveniente dai netblock italiani e droppare tutto il resto. A tal proposito ho trovato una lista (non so quanto aggiornata) dei vari AS italiani con relativi netblock (potrete trovarla qui).

Per quanto riguarda le ACL occorre fare delle precisazioni. C’è da dire che, nonostante le ACL nominali vengano applicate il più vicino possibile alla sorgente del traffico, quindi all’interfaccia outbound del firewall, esse richiedono un minimo di carico computazionale, in quanto devono analizzare il pacchetto in ingresso, identificare l’indirizzo IP sorgente (presente nell’header) ed eventualmente scartarlo o instradarlo verso l’interfaccia inbound. Se il traffico diretto al nostro firewall raggiunge proporzioni non indifferenti e le caratteristiche hardware di quest’ultimo sono abbastanza pietose (leggasi CPU poco performante e pochi MB di RAM), corriamo seriamente il rischio che il firewall stesso si schianti in men che non si dica.

Per ciò che concerne invece IPTABLES, il ban esplicito degli indirizzi IP può essere applicato direttamente sulla chain INPUT, utilizzando la seguente regola:

iptables -A INPUT -s <ip sorgente dell'attacco> -j DROP

Possiamo inoltre consentire il traffico HTTP diretto sulla porta 80 mediante la rule:

iptables -A INPUT -p tcp --dport 80 -j ACCEPT

e negare tutto il resto mediante la policy di default associata alla catena in questione:

iptables -P INPUT DROP

Anche in questo caso è essenziale l’analisi dei log (sia del firewall che del server Web) e l’analisi delle connessioni in ingresso (facilmente realizzabile mediante il comando netstat ed eventualmente grep).

Veniamo ora alla fase più complessa, ovvero a quella in cui si tenta di risalire al vero autore dell’attacco. Risalire alla sorgente dell’attacco prevede una mole di lavoro non indifferente, che spesso non da alcun risultato utile. Vi sono comunque, a mio avviso, diversi modi di operare:

1) Si potrebbe cercare di ottenere (durante l’attacco vero e proprio) l’accesso ad una delle macchine zombie. In questo modo, facendo un semplice netstat si riuscirebbe ad individuare tutti gli utenti connessi al pc e ad identificare altre macchine zombie oppure possibili proxy anonimi utilizzati dal vero attaccante. Con un pò di fortuna, se il proxy non è poi tanto anonimo come dice di essere e registra le connessioni in ingresso, da una semplice analisi dei log si potrebbe ottenere l’indirizzo IP del vero autore dell’attacco.

2) Si potrebbe notare l’accesso sistematico al portale Web da parte di un determinato indirizzo IP, in alcuni “momenti chiave”, ad esempio poco prima dell’attacco, durante l’attacco e poco dopo l’attacco. Per conteggiare gli accessi dell’IP sospetto si potrebbe impostare una regola in cima all’ACL no_ddos, ad esempio:

firewall(config)# access-list no_ddos line 1 permit ip host <IP sospetto> any

Discorso simile vale per IPTABLES:

iptables -A INPUT -s <ip sospetto> -j LOG --log-prefix "IP_SOSPETTO: "

e successivamente spulciare il file di log con l’ausilio di grep.

Spero di essere stato chiaro e utile, anche se sono ben conscio del fatto che non esiste un modus operandi standard per contrastare questi attacchi, in quanto le variabili in gioco sono davvero troppe.

Ci aggiorniamo, a presto.

Attacchi DoS e DDoS

Gli attacchi DoS (Denial of Service) e DDoS (Distribuited Denial of Service) rappresentano uno dei fenomeni più preoccupanti degli ultimi anni. Infatti, non è raro incappare in siti e portali di vario genere i cui tempi di risposta risultano mostruosamente alti, causando diversi problemi alla navigazione degli utenti legittimi e, in alcuni casi, l’irraggiungibilità del sito stesso.

Le motivazioni che stanno dietro a questa tipologia di attacco sono le più disparate:

1) motivazioni di tipo economico. Un’azienda potrebbe decidere di “investire” del denaro per cercare di arrecare danno al business di una società rivale, che magari opera nello stesso settore, soprattutto se la maggior parte dei proventi di quest’ultima derivano da un portale di e-commerce;

2) motivazioni di tipo logistico/strategico. Si potrebbe, ad esempio, costringere la comunità di un forum a “migrare” su un altro portale, promettendo in cambio la stabilità dei servizi offerti ed il ripristino della raggiungibilità del sito 24/7;

3) motivazioni di tipo politico/religioso. E’ sempre più frequente assistere ad attacchi di negazione del servizio diretti verso portali in cui viene manifestato un determinato orientamento politico/religioso.

Occorre precisare, inoltre, che con l’aumento della capacità di calcolo degli elaboratori e con l’incremento dell’ampiezza banda offerta dai vari ISP, gli attacchi DoS, ovvero quelli provenienti da un singolo host, stanno diventando obsoleti e del tutto inefficaci. Viceversa , gli attacchi di negazione del servizio distribuiti (DDoS) continuano a rappresentare una serie minaccia  nell’ambito dell’IT security, poichè riescono a saturare in pochissimo tempo le risorse dell’host vittima, causandone l’irraggiungibilità.

Classificazione degli attacchi e tecniche

Esistono diversi metodi per classificare gli attacchi DDoS ed uno di questi si basa proprio sul tipo di risorsa che l’attacco stesso tenta di consumare. Tale risorsa può essere rappresentata dalla CPU, dalla RAM o dalla memoria di massa su cui è installato il sistema operativo, oppure dalla capacità di tx/rx dell’host vittima. In quest’ultimo caso, una tecnica ampiamente utilizzata si basa proprio sulla struttura del protocollo TCP/IP e prende il nome di SYN-flood. Per capire bene come un attacco SYN flood viene perpetrato occorre fare un esempio:

Supponiamo che l’utente legittimo A voglia collegarsi al portale Web B.

1) Per prima cosa l’host A invia un pacchetto TCP/IP di tipo SYN, ovvero richiede la sincronizzazzione con il portale stesso, la quale si basa essenzialmente sullo scambio di un numero di sequenza iniziale (ISN – Initial Sequence Number). Il numero di sequenza iniziale è fondamentale, in quanto tutti gli altri pacchetti scambiati tra i due host in questione verranno identificati mediante un numero di sequenza incrementale, successivo all’ISN. Ma a cosa serve effettivamente il numero di sequenza? Serve semplicemente a ricostruire correttamente le informazioni ricevute, nel caso in cui esse non siano giunte a destinazione nel giusto ordine (ecco perchè il protocollo TCP è definito “affidabile”);

2) una volta che il portale Web, ovvero B, riceve il pacchetto SYN, risponde all’host A inviando un pacchetto SYN/ACK (leggasi riscontro di sincronizzazione);

3) infine, dopo aver ricevuto il SYN/ACK, l’host A invia al portale Web B un ulteriore pacchetto di riscontro, detto ACK, completando così la procedura di connessione (ecco perchè il protocollo TCP si dice “basato su connessione”).

L’insieme degli step 1), 2) e 3) rappresenta il cosiddetto three-way handshake, necessario affinchè una connessione TCP venga instaurata.

Supponiamo ora che un eventuale attaccante, ovvero C, voglia scagliare un DDoS verso il portale B. Esso per prima cosa forgerà dei pacchetti TCP/IP di tipo SYN, falsificando l’indirizzo IP mittente, magari inserendone uno inesistente. Il server Web risponderà ai pacchetti SYN inviando dei SYN/ACK verso l’IP inesistente, lasciando la connessione in buffer fino alla ricezione dell’ACK.

Ovviamente, tale ACK non verrà mai ricevuto, proprio perchè l’indirizzo IP a cui è stato inviato il SYN/ACK è inesistente (parliamo allora di connessioni mezze-aperte, dette anche half-open). Quindi, se il numero di pacchetti SYN inviati all’host vittima è abbastanza elevato e se i tempi di timeout delle connessioni TCP half-open sono troppo alti (per un errata configurazione del server), il portale Web si ritroverà con il buffer completamente saturo, e non sarà più in grado di accettare connessioni basate sul protocollo TCP, anche se legittime.

Recentemente, sono state sviluppate altre tecniche che puntano a saturare la capacità di tx/rx degli host vittima. Tra queste vi sono le connessioni half-closed e gli attacchi scan.

Nel primo caso, l’attaccante, ovvero C, crea delle connessioni legittime e di breve durata con il portale Web B. Successivamente, cerca di abbattere tali connessioni inviando dei pacchetti FIN all’host vittima. Quest’ultimo invierà all’attaccante un pacchetto FIN/ACK e successivamente rimarrà in attesa dell’ACK finale che causerà la disconnessione vera e propria. Se però, come nel caso delle connessioni half-open, l’ultimo ACK tarda ad arrivare ed il numero di pacchetti FIN è piuttosto elevato, il buffer tenderà ad esurirsi abbastanza velocemente causando disservizio.

Nel caso degli attacchi scan, invece, la negazione del servizio viene realizzata semplicemente usando i cosiddetti port-scan. Nella fattispecie, i port-scan vengono adoperati durante la fase preliminare di un attacco, detta footprinting o ricognizione, grazie alla quale è possibile identificare i tipi di servizi presenti sull’host vittima. Ogni servizio è in ascolto su una determinata porta ed in base a quest’ultima è possibile farsi un’idea di quali siano effettivamente i servizi pubblicati sul server che si sta scansionando. Ora, qui è necessario fare alcune precisazioni:

1) Esistono le cosiddette well-known port, che vanno dalla 1 alla 1023. Esse sono riservate a determinati servizi, come POP3 (110), SMTP (25), Telnet (23), FTP (20-21), SSH (22) e così via. Non è raro, però, che gli amministratori di sistema utilizzino delle porte non standard per la pubblicazione dei servizi (ad esempio mettendo in ascolto il server SSH su una porta > 1023 anzichè sulla 22). In questo modo si evita che script di scansione automatizzati individuino servizi in ascolto su porte standard e tentino automaticamente il login, perpetrando un attacco bruteforce basato su dizionario.

2) Alla luce di quanto appena detto, non è raro che i port-scan producano come risultato dei falsi positivi.

Ma vediamo adesso come funzionano i cosiddetti scan-attack. Quando viene effettuata una ricognizione mediante degli appositi tool (ad esempio nmap), vengono “simulate” delle connessioni sulle 1023 well-known port dell’host vittima, riuscendo in questo modo ad identificare su quali esso risulta effettivamente in ascolto. Ovviamente tale procedura genera del traffico e se i tentativi di scansione si ripetono ad intervalli di tempo brevissimi e se provengono da un numero abbastanza elevato di host (magari dotati di un’ampiezza di banda non indifferente), essi causeranno inevitabilmente un riempimento del buffer della vittima e quindi una probabile negazione del servizio. Inoltre, per aumentare ulteriormente la frequenza degli scan e quindi la mole complessiva degli stessi, può essere utilizzanto il protocollo UDP (mediente la flag -sU di nmap), il quale, a differenza del protocollo TCP, non prevede l’instaurazione di una connessione vera e propria, con tempi di tx/rx estremamente ridotti e quindi con maggiore probabilità di saturare il buffer.

Un altro criterio usato per la classificazione degli attacchi DDoS tiene conto della capacità dell’attaccante di “reclutare” nuove macchine dalle quali veicolare l’attacco vero e proprio. In particolare, parliamo di attacco DDoS diretto quando è proprio l’attaccante ad installare su alcune macchine vittima un software sviluppato ad hoc (solitamente un worm) che gli consentirà di ottenerne il controllo da remoto. Tali macchine diverranno quindi “zombie” ed andranno a far parte di un insieme di elaboratori infetti, chiamato botnet (o dosnet).

Sovente gli attacchi DDoS coinvolgono due livelli di macchine zombie: gli zombie master e gli zombie slave, dove i primi coordinano l’operato dei secondi. L’uso di due livelli di zombie rende più difficile l’identificazione della vera sorgente dell’attacco e fornisce una rete di host attaccanti più flessibile.

dos_figure_4.gif

Un attacco DDoS tramite riflettori (DRDoS) aggiunge un ulteriore livello di macchine, che andranno ad aggiungersi agli zombie master e slave.

drdos.gif

 

In questo caso, però, gli elaboratori che fungono da riflettori non sono delle macchine infette. Semplicemente, gli zombie slave, veicolati dagli zombie master, generano delle richieste contenenti come IP sorgente quello del portale Web vittima (B). Tali richieste verranno indirizzate verso i riflettori che risponderanno direttamente alla macchina bersaglio. Un attacco di questo tipo è sicuramente il più subdolo ed allo stesso tempo il più dannoso: subdolo perchè l’uso di macchine non infette come front-end dell’attacco rende ancora più difficile l’individuazione del vero attaccante, dannoso poichè a seconda del numero di macchine riflettori coinvolte, la mole di traffico diretta verso l’host vittima potrebbe essere di una portata tale da causare una negazione del servizio pressocchè immediata.

Costruzione di una rete di attacco

Durante la prima fase di un attacco DDoS, l’aggressore infetterà molte macchine tramite software zombie, in modo tale da ottenerne il controllo ed utilizzarle successivamente come teste di ponte durante l’attacco vero e proprio. Affinchè tale operazione vada a buon fine è necessario che vengano rispettate le seguenti condizioni:

1) il software che viene usato per infettare le macchine deve essere in grado di girare su un elevato numero di elaboratori, di nascondere la sua esistenza, di comunicare con l’attaccante oppure di essere dotato di un qualche tipo di meccanismo a innesco temporale, oltre, ovviamente, ad essere capace di veicolare l’attacco verso il bersaglio;

2) il software deve basarsi su una vulnerabilità molto diffusa ma che allo stesso tempo è stata trascurata da molti utenti/amministratori di sistema;

Inoltre, gli host vulnerabili vengono individuati mediante un’operazione di scansione, la quale può avere le seguenti caratteristiche:

1) potrebbe essere casuale, ovvero l’attaccante esamina degli indirizzi IP random, usando di volta in volta un seme differente;

2) potrebbe essere basata su una hit-list, ovvero su una lista di macchine potenzialmente vulnerabili;

3) potrebbe essere topologica, ovvero l’attaccante utilizza le informazioni contenute su una macchina già infetta per trovare altri host vulnerabili.

Nei prossimi giorni andremo ad esaminare in dettaglio quali sono le tecniche per mitigare, se non contrastare, attacchi di questo genere.

A presto.