Avanti Indietro Indice

20. FRAMMENTI

20.1 Descrizione

I pacchetti che viaggiano attraverso la rete hanno una dimensione, questa può variare da caso a caso. Nel caso Ethernet i pacchetti hanno una dimensione di 1500 byte, nel caso invece di pacchetti inviati verso internet attraverso l'interfaccia ppp0 (dialup) è in genere pari a 296 byte, ma è comunque possibile variarla modificando il parametro MTU (Maximum Transmission Unit).

Di questi 296 byte una parte è occupata dalle intestazioni (IP e TCP, o IP e ICMP ...) il resto dai dati.

In particolare un'intestazione TCP occupa 20 byte, e visto che deve essere incapsulato sempre in un pacchetto IP è necessario aggiungere anche l'intestazione IP (20 byte), quindi lo spazio a disposizione per i dati in ciascun pacchetto sarà pari a 296 (MTU) - 20 (intestazione IP) - 20 (intestazione TCP) = 256 byte.

Graficamente possiamo rappresentarli così:

        0      20      40                      295
        +-------+-------+------------------------+
        |  IP   |   TCP |   DATI                 |
        +-------+-------+------------------------+

Questo è valido per il primo pacchetto, infatti i pacchetti/frammenti successivi conterranno solo l'intestazione IP e i dati, l'intestazione TCP non sarà più necessaria:

        0      20                              295
        +-------+--------------------------------+
        |  IP   |            DATI                |
        +-------+--------------------------------+

Quindi se volessimo inviare 1500 byte di dati attraverso l'interfaccia ppp0, in realtà, come visto, non sarà spedito un solo pacchetto da 1500 byte, ma diversi pacchetti/frammenti:

La macchina che li riceverà provvederà poi a ordinarli, riassemblarli e a ricostruire i pacchetti originali.

20.2 Ping della morte, Teardrop, ...

I frammenti sono stati, particolarmente in passato, causa di notevoli problemi e crash delle macchine. Questi problemi sono derivati da una non corretta implementazione di molti stack TCP/IP.

Tra i più noti e citati ci sono il Ping della Morte (Ping of Death), Teardrop, Bonk, Zero Length Fragments.

Il Ping della morte si basa sul campo "Total Lenght" (lunghezza totale) del pacchetto IP. Un pacchetto IP non può essere lungo più di 65535 byte. Il ping della morte consiste nell'inviare un frammento con lunghezza di 1000 bytes e impostare il campo "Fragment Offset" del pacchetto stesso a 65400 byte, lo stack TCP/IP vulnerabile della macchina che lo riceve cercherà quindi di assemblare un pacchetto di lunghezza 65400+1000 byte = 66400 byte con risultati spiacevoli (crash).

Ora gran parte dei sistemi operativi sono immuni da questo tipo di attacco, ossia controllano la dimensione dei pacchetti riassemblati, anche linux ha sofferto di questo problema fino alla versione 2.0.24 del kernel.

Teardrop, Bonk, ... invece creano ad arte dei frammenti in modo tale che con il riassemblamento i frammenti si "sovrappongano" confondendo e mettendo in crisi la macchina destinataria.

I Zero length Fragments hanno creato problemi a Linux fino alla serie 2.2.4 del kernel. Questo attacco si basa sull'invio di un frammento di lunghezza zero, la macchina erroneamente lo accoda assieme agli altri frammenti da riassemblare, invece di scartarlo.

Per quanto riguarda il filtraggio dei pacchetti il problema riguarda la struttura dei frammenti successivi al primo, che come abbiamo visto non contengono l'intestazione TCP. Questo significa che non sarà possibile controllare i relativi campi.

Esistono comunque diverse soluzioni, ad esempio se la propria macchina firewall è l'unica che protegge la rete locale è possibile compilare il kernel con la voce "always defragment" selezionata, in questo modo tutti i frammenti diretti alle macchine della rete locale, prima di essere inoltrati, saranno riassemblati dal firewall. Questo inoltre permette di utilizzare iptables/ipchains senza doversi preoccupare dei frammenti.

In questo caso è necessario fare attenzione nel caso ci siano più firewall, se i frammenti dovessero arrivare parte a uno e parte all'altro il riassemblaggio fallirebbe miseramente.

Altrimenti sarà necessario accettare i frammenti e lasciare alle macchine destinatarie della rete locale il compito di riassemblarli (non consigliato). Con iptables è necessario specificare esplicitamente che i frammenti devono essere accettati con l'opzione '-f'.

Ad esempio è possibile accettare tutti i frammenti diretti alla rete locale, in questo modo:

iptables -A FORWARD -f -j ACCEPT

Oppure potremmo voler accettare solo i pacchetti www e i frammenti e rifiutare il resto:

iptables -A INPUT -p tcp ! --syn --sport www    -j ACCEPT
iptables -A INPUT -p tcp         --sport www -f -j ACCEPT
...
iptables -A INPUT -j REJECT

Nota: se si utilizza il tracciamento delle connessioni o il NAT, i frammenti prima di essere filtrati dal firewall saranno sempre riassemblati.


Avanti Indietro Indice