Magazine Informatica

Contromisure agli attacchi DoS e DDoS

Creato il 23 agosto 2010 da Nightfly

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 -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 -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 -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.


Potrebbero interessarti anche :

Ritornare alla prima pagina di Logo Paperblog

Possono interessarti anche questi articoli :