Archivi tag: tcp

PMTUD e TCP MSS

Topologia di massima

Due filiali interconnesse mediante un tunnel GRE/IPSEC instaurato sfruttando le rispettive linee ADSL. In particolare, sul sito A sono presenti diversi client che hanno necessità di “dialogare” con un server Web posto nel sito B.

Problema

I client accedono al server Web remoto con estrema lentezza e molte delle richieste effettuate vanno in timeout. Nella fattispecie, trattasi di un problema legato alla MTU (Maximum Transmission Unit) configurata sulle interfacce dei router delle 2 filiali, che provoca la suddetta sintomatologia.

Un po’ di teoria

Ma cos’è l’MTU? Essa, molto semplicemente, definisce la dimensione massima (in byte) di un pacchetto (o di un frame) che può attraversare una determinata interfaccia di rete. Ad esempio, nel caso del protocollo IP (layer 3) parliamo generalmente di 1500 byte, mentre nel caso del protocollo Ethernet (layer 2) la MTU è pari a 1526 byte (1500 byte “ereditati” dal protocollo IP + 22 byte di instestazione Ethernet e 4 byte di CRC). Quest’ultima è sicuramente la più rognosa, in quanto molto spesso gli switch sono unmanaged e quindi non è possibile accorgersi immediatamente dei cosiddetti frame giant, che vegnono quindi scartati “silenziosamente” provocando una comunicazione “a singhiozzo” (vedi questo post per ulteriori dettagli).

Per quanto riguarda invece la MTU IP, si avranno sicuramente dei problemi nel caso in cui:

1) i valori configurati sulle interfacce del router A e del router B differiscono tra di loro (in gergo parliamo di MTU mismatch);

2) lungo il cammino tra router A e il router B esiste un segmento la cui MTU è inferiore rispetto a quella configurata sui 2 router.

Nel primo caso possiamo correre ai ripari molto velocemente, configurando un valore di MTU identico sulle interfacce dei router delle 2 filiali. Ad esempio, possiamo definire la MTU di una data interfaccia utilizzando il comando:

Router(config-if)# ip mtu <valore in byte>

Nel secondo caso, invece, occorre fare un po’ di diagnostica ed eventualmente utilizzare delle configurazioni ad hoc.

In entrambi i casi i pacchetti che superano la MTU più bassa verranno “frammentati” e ricostruiti in fase di ricezione. Ovviamente tale operazione, oltre a causare un overhead sui router coinvolti, provocherà dei seri problemi a livello 4 (TCP) e superiori, inficiando in modo notevole l’accesso al servizio da parte degli utenti.

PMTUD

Per evitare quindi che si verifichi un’eccessiva frammentazione è stato messo a punto un meccanismo tale per cui un router riuscirà ad accorgersi automaticamente della presenza di un valore di MTU inferiore rispetto a quello configurato sulla propria interfaccia, riducendo di conseguenza la dimensione dei pacchetti che intende inoltrare. Tale meccanismo prende il nome di Path MTU Discovery, abbreviato in PMTUD. Più in dettaglio, essa si basa sull’invio/ricezione di messaggi ICMP unreachable type 3 code 4 ( vedi qui per ulteriori dettagli): se la MTU dei pacchetti ricevuti da un router supera la dimensione massima definita sulla propria interfaccia in ricezione, esso procederà con l’inoltro del suddetto messaggio verso il router mittente. In tal modo, quest’ultimo si accorgerà di quanto sta avvenendo e ridurrà di conseguenza la MTU in modo da riuscire ad “attraversare” il router interessato.

PMTUDOra, occorre precisare che non è tutto oro ciò che luccica, nel senso che molto spesso i pacchetti ICMP unreachable vengono disabilitati sia in TX che in RX (in questo caso si parla di PMTUD blackhole). Ad esempio, nel caso dei dispositivi di casa Cisco, essi sono disabilitati di default:

Router#sh ip int dia0 | i ICMP
  ICMP redirects are never sent
  ICMP unreachables are never sent
  ICMP mask replies are never sent

Il perchè di tale configurazione è presto detto: per loro stessa natura, i messaggi ICMP consentono di ottenere informazioni “sensibili” sulla rete target e possono anche essere utilizzati per generare attacchi di tipo DoS/DDoS. Infatti, se un utente malevolo facesse in modo di “sollecitare” la generazione dei messaggi ICMP unreachable da parte del router oggetto dell’attacco, riuscirebbe certamente a sovraccaricarlo, poichè la generazione del suddetto tipo di messagistica avviene a livello di CPU. Come workaround è comunque possibile settare un rate limit specifico, ad esempio:

Router(config)# ip icmp rate-limit unreachable df 500

dove 500 rappresenta il numero di millisecondi che deve intercorrere tra la generazione di un messaggio ICMP unreachable e quello successivo.

A titolo di cronaca, per abilitare i suddetti messaggi su una data interfaccia è sufficiente digitare il comando:

Router(config-if)# ip unreachable

Identificare il valore di MTU corretto: metodo trial and error

Occorre precisare che esiste un modo empirico per determinare la dimensione della MTU più piccola presente lungo il percorso tra il router A ed il router B. Esso si basa sull’utilizzo del comando ping dotato delle flag -f (che imposta a 1 il bit do not fragment nell’header IP) e -l (che imposta la dimensione del solo payload). Se ad esempio la MTU configurata sulla scheda di rete del nostro PC (con Windows 7 a bordo) fosse pari a 1500 byte, potremmo utilizzare il comando:

C:\Users\pippo> ping 192.168.1.1 -f -l 1472

dove 1472 è il massimo payload definibile senza che vi sia frammentazione, poichè ad esso verranno sommati i 20 byte di intestazione IP e gli 8 byte di instestazione ICMP (per un totale di 1500 byte). Utilizzando un payload di 1473 byte, la nostra scheda ci indicherà che abbiamo superato la MTU attraverso il seguente output:

C:\Users\pippo>ping 192.168.1.1 -l 1473 -f

Esecuzione di Ping 192.168.1.1 con 1473 byte di dati:
E' necessario frammentare il pacchetto ma DF è attivo.
E' necessario frammentare il pacchetto ma DF è attivo.
E' necessario frammentare il pacchetto ma DF è attivo.
E' necessario frammentare il pacchetto ma DF è attivo.

Tale metodo può essere utilizzato per identificare la MTU di interesse, abbassando di volta in volta la dimensione del payload fino a quando al posto del suddetto messaggio verranno visualizzati dei semplici ICMP echo reply.

Una piccola nota a margine: nel caso in cui si volesse utilizzare questa metodologia direttamente dalla CLI del router Cisco, è possibile utilizzare il seguente comando:

ping 192.168.1.1 source fa0/0 df-bit size 1500

dove 1500, in questo caso, rappresenta la dimensione totale del messaggio ICMP echo request (e non del solo payload come avveniva nel caso di Windows 7).

TCP MSS

L’acronimo MSS sta per Maximum Segment Size e rappresenta la dimensione massima (in byte) che può avere il payload (e solo il payload) di un segmento TCP. Il valore di default è 1460, ovvero 1500 byte di MTU meno i 20 byte di instestazione TCP ed i 20 byte di intestazione IP. Nel caso in cui la MTU più piccola relativa al percorso tra A a B fosse inferiore a quella di default, è possibile “forzare” il valore di MSS (in gergo parliamo di MSS clamping). Ad esempio, per i router Cisco potremo utilizzare il comando:

Router(config-if)# ip tcp adjust-mss <byte>

dove i byte da utilizzare sono dati dalla MTU più piccola meno 40 byte.

Un caso pratico (e molto diffuso tra gli end user) in cui l’MSS clamping torna davvero utile riguarda il protocollo PPPoE, che usa una MTU pari a 1492 byte (a differenza del PPPoA la cui MTU è quella classica, ovvero 1500 byte). In tal caso si può procedere con questa configurazione sull’interfaccia dia0:

Router(config-if)# ip mtu 1492
Router(config-if)# ip tcp adjust-mss 1452

Spero di aver fatto un minimo di chiarezza sul concetto di MTU e su quanto esso sia importante nell’ambito della comunicazione client/server basata sul protocollo TCP e superiori.

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.

Redirect del traffico in uscita mediante iptables

Iptables, ovvero l’interfaccia a linea di comando del celeberrimo firewall Netfilter, consente di fare dei veri e propri giochi di prestigio.

Ad esempio, potrebbe succedere che, per ragioni di sicurezza, un dato server Web non sia in ascolto sulla classica porta TCP 80, ma su una porta non standard (ad esempio la 9876). Supponiamo, inoltre, che a tale sito debbano accedere gli sviluppatori, che, di volta in volta dovranno forgiare opportune URL con l’estensione :9876.

netfilter.jpg

Per semplicifare loro la vita si può agire direttamente sul firewall/router, facendo un semplice redirect del traffico in uscita diretto alla porta 80 del server Web. Ecco la regola:

iptables -t nat -A OUTPUT -p tcp -d ipserverweb –dport 80 -j DNAT –to-destination ipserverweb:9876
Ovviamente potete lavorare anche di file hosts, aggiungendo dei record A statici che vi possano aiutare a creare le regole più facilmente, senza doversi obbligatoriamente ricordare gli indirizzi IP coinvolti a memoria.
In quest’ultimo caso la suddetta regola diverrebbe:
iptables -t nat -A OUTPUT -p tcp -d miodominio.com --dport 80 -j DNAT --to-destination miodominio.com:9876
Semplice, vero?
A presto.