Avanti Indietro Indice

19. TCP/IP

Il modello più diffuso per la trasmissione dei dati attraverso le reti è oggi il TCP/IP.

Il nome deriva dai suoi due protocollo principali: TCP (Transmission Control Protocol) e IP (Internet Protocol).

I dati che viaggiano nella rete sono organizzati in pacchetti, ciascuno contiene un'intestazione IP in cui sono presenti alcune informazioni molto importanti (indirizzo sorgente, indirizzo destinazione, lunghezza totale, ...) che permettono loro di giungere a destinazione. Inoltre se i pacchetti sono di tipo TCP allora conterranno anche un'intestazione TCP che raccoglie un insieme di informazioni (porta sorgente, porta destinazione, Type Of Service, flags, ...) utili per verificare la correttezza dei pacchetti, per riordinarli nell'ordine corretto, per stabilire a quale servizio sono destinati (ftp, telnet, mail, www, ...).

Il protocollo TCP è orientato alla connessione affidabile, si occupa di riassemblare, frammentare, riordinare, ritrasmettere, controllare i pacchetti. Esiste anche una "versione" più semplice nota come UDP (User Datagram Protocol) non basata su connessione e quindi inaffidabile ma estremamente veloce, in alcuni casi è preferita al TCP ad esempio per richieste al DNS (Domain Name System) o per tftp (Trivial ftp). Il protocollo IP ha come compito invece quello di instradare e consegnare i pacchetti a destinazione.

I pacchetti possono essere graficamente rappresentati in questo modo:


    +------------+------------+------------- - -
    |intestazione|intestazione|     DATI
    |    IP      |    TCP     |     ....
    +------------+------------+------------- - -
       20 bytes     20 bytes

                  [ Pacchetto ]

Sempre nei pacchetti IP sono inoltre incapsulati anche i pacchetti UDP e i pacchetti ICMP, questi ultimi usati per lo più per segnalare errori o problemi riscontrati nella rete o nella consegna dei pacchetti.

Per una completa descrizione dei campi delle varie intestazioni consultare l'appendice.

Il filtraggio dei pacchetti si basa proprio su queste informazioni per stabilire se un pacchetto deve essere accettato o meno. In particolare è importante conoscere come si stabilisce una connessione, come sono scambiati i dati, e quali sono i punti deboli.

La maggior parte dei servizi (ftp, telnet, mail) oltre all'indispensabile protocollo IP utilizzano anche il protocollo TCP che è affidabile, completo e basato su connessione.

19.1 Connessione "Three-way handshake"

La connessione si basa sul "Three-way handshake" ossia tre fasi in cui due computer stabiliscono e negoziano la connessione.

La prima fase prevede che il client richieda una connessione (SYN) alla macchina server, ossia invii un pacchetto completo di intestazione IP e TCP con il flag SYN impostato:


   +---+                                  +-------+
   |PC1|------------ SYN  --------------->|SERVER |
   +---+                                  +-------+

La seconda fase prevede che il server, se disponibile, invii un pacchetto di risposta affermativo (SYN/ACK):


   +---+                                  +-------+
   |PC1|<-------   SYN/ACK  ------------- |SERVER |
   +---+                                  +-------+

La terza fase prevede che il client invii a sua volta un pacchetto di conferma (ACK):


   +---+                                 +-------+
   |PC1| ----------  ACK   ----------->  |SERVER |
   +---+                                 +-------+

Concluse con successo queste fasi il client può cominciare a inviare i pacchetti con i dati.

NOTA: questo schema è semplificato e non ha preso in esame le porte e il 'sequence number'.

19.2 Porte

Per poter stabilire una connessione con un computer è necessario indicare a quale servizio (telnet, ftp, www, finger, rlogin, ...) si è interessati. Nel file /etc/services è possibile trovare un elenco dei servizi standard che si possono richiedere completi di numero, protocollo e in alcuni casi breve descrizione. Esempio:

...
echo             7/tcp
telnet          23/tcp
ftp             21/tcp
www             80/tcp          http            # WorldWideWeb HTTP
www             80/udp                          # HyperText Transfer Protocol
domain          53/tcp          nameserver      # name-domain server
domain          53/udp          nameserver
...

NOTA: in alcuni casi si possono trovare nomi differenti a seconda della distribuzione Linux (es. pop3 e pop-3) i numeri sono comunque gli stessi.

Le porte sono suddivise in porte note o privilegiate (well-known port) e porte non privilegiate. Le porte note appartengono all'intervallo da 1 a 1023, ad ognuna è associato un servizio e protocollo, secondo quanto stabilito dallo IANA (RFC 1700). Se un computer vuole offrire un servizio ftp a qualsiasi utente allora si dovrà mettere in "ascolto" sulla porta 21 in attesa che qualcuno invii una richiesta di connessione, quindi provvedere a stabilire la connessione (caso TCP) e a scambiare i dati.

Le porte che appartengono all'intervallo 1024-65535 sono invece utilizzato in genere dal client come vedremo.

L'intestazione TCP comprende due campi importanti: porta sorgente e porta destinazione. Quando si vuole stabilire una connessione per accedere ad una macchina presente nella rete utilizzando ad esempio il telnet è necessario che questi due campi siano impostati in modo appropriato, le fasi nel caso del telnet sono le seguenti:

Il client invia pacchetto inizio connessione specificando anche il servizio alla quale è interessato (es. telnet), indica inoltre verso quale porta devono essere indirizzati i pacchetti in risposta (ne seleziona una libera tra quelle dell'intervallo 1024-65535 partendo da 1024) e il protocollo:


   +---+                              +-------+
   |PC1|-----------  SYN  ----------->|SERVER |            PD = Porta Destinazione
   +---+            PD=23             +-------+            PS = Porta Sorgente
                   PS=1024                                 PT = Protocollo (tcp/udp/icmp)
                   PT=tcp

In questo caso è inviata una richiesta di connessione alla porta 23 (telnet) del server specificando che le risposte dovranno essere indirizzate alla porta 1024 del client, protocollo tcp.

Se il server offre quel servizio ed è in "ascolto" sulla porta 23 (telnet), se decide di accettare la connessione, invierà un pacchetto di conferma (ACK) dove specificherà che deve essere destinato alla porta 1024 del client, proveniente dalla sua porta 23:


   +---+                              +-------+
   |PC1| <-------  SYN/ACK ---------- |SERVER |            PD = Porta Destinazione
   +---+          PD=1024             +-------+            PS = Porta Sorgente
                   PS=23                                   PT = Protocollo (tcp/udp/icmp)
                  PT=tcp

Nota che ora la porta destinazione è 1024 e non più 23, la situazione si è insomma invertita.

Poi si prosegue più o meno nella stesso modo anche nella fase di invio/ricezione dei dati.

E' necessario precisare che in qualche caso alcuni servizi, ad esempio www, possono essere presenti su porte differenti. E' infatti possibile che ad esempio www sia disponibile invece che sulla porta 80 sulla 8080, sono comunque casi noti.

Altri servizi come RealPlayer, X Window, Quake, utilizzano porte prestabilite ma appartenenti all'intervallo 1024-65535, e non una delle note (1-1023). Ciò è dovuto al fatto che sono servizi resi disponibili recentemente.

In alcuni casi un servizio (es. dns/domain) è disponibile sia con protocollo tcp sia udp. Nel caso di dns ad esempio è utilizzato in genere il protocollo udp (veloce e privo di connessione 3-way handshake), ma in alcuni casi si rende necessario anche l'utilizzo del protocollo tcp più completo e affidabile. Ciò è importante per chi deve realizzare un firewall.

La porta sorgente è utile anche per distinguere tra due diverse connessioni alla stessa porta destinazione. Ad esempio quando si accede all'indirizzo www.linux.org e si aprono due pagine dello stesso sito con netscape come fa il client a riconoscere quali dati riguardano una e quali l'altra ? In base alla porta sorgente che sarà ovviamente diversa.

      
       +=============================+
       | Netscape                    |
       +-----------------------------+
       | www.linux.org/index.html    |<-----SP=80 (www) DP=1024 ... --- +------------+
       |^^^+============================+                               | SERVER WWW |
       |   | Netscape                   |                               |            |
       |   +----------------------------+                               |            |
       |   |www.linux.org/page1.html    |<--SP=80 (www) DP=1025 ... --- | linux.org  |
       |   |^^^^^^^^^^^^^^^^^^^^^^^^^^^^|                               |            |
       |   |                            |                               +------------+
       .   .                            .

19.3 Esempio

Esempio di una connessione ad un www server per reperire delle pagine web:

Supponiamo di voler instaurare una connessione con il sito internet www.linux.com e di aver la seguente situazione:


  
    +----+                              +----------+
    |PC1 |                              |SERVER WWW|                
    |    |                              |linux.com | 
    +----+                              +----------+
151.186.5.4                            198.186.203.55
     
       

Inseriamo l'indirizzo www.linux.com nel nostro browser e iniziamo una connessione. L'applicazione Netscape richiede quindi al kernel una connessione TCP al server www.linux.com. A questo punto è selezionata una porta sorgente tra quelle disponibili nell'intervallo 1024-65535 a partire però dalla 1024 se è disponibile. Il nome www.linux.com viene risolto attraverso il dns (Domain Name System), ossia un computer, il cui indirizzo deve essere presente nel file /etc/resolv.conf, che ha il compito di restituire l'indirizzo IP numerico corrispondente: 198.186.203.55.

Quindi tenta di instaurare una connessione al WEB server inviando un pacchetto con indirizzo sorgente l'indirizzo 151.186.5.4 (PC1), indirizzo destinazione 198.186.203.55 (www.linux.com), porta sorgente 1024, porta destinazione ovviamente 80 (porta nota www), flag SYN impostato. E' inoltre scelto arbitrariamente da Linux un 'sequence number' (numero di sequenza) es. 1000000.


    +----+                              +----------+
    |PC1 | ------------o------------->  |SERVER WWW|
    |    |            / \               |linux.org |
    +----+          /     \             +----------+
151.186.5.4       /         \          198.186.203.55
  ______________/             \______________________
 /                                                   \
 +----------------------------------------------------+
 | IP           IS=151.186.5.4 ID=198.186.203.55      |    IS=indirizzo sorgente
 |              ...                                   |    ID=indirizzo destinazione
 +----------------------------------------------------+
 | TCP          PS=1024        PD=80 (www)            |    PS=porta sorgente
 |              FLAG=SYN       SEQ_NR=1000000         |    PD=porta destinazione
 |              ...                                   |   
 +----------------------------------------------------+

Il server WEB www.linux.com riceve il pacchetto, accetta la connessione e risponde inviando un pacchetto di conferma con flag ACK impostato. Questo pacchetto inoltre conterrà il sequence number inviato con in più sommato 1 (SYN) (posto nel campo 'acknowledgement number') e il sequence number scelto dal server es. 2000000.


    +----+                              +----------+
    |PC1 | <-----------o-------------   |SERVER WWW|
    |    |            / \               |linux.org |
    +----+          /     \             +----------+
151.186.5.4       /         \          198.186.203.55
  ______________/             \______________________
 /                                                   \
 +----------------------------------------------------+
 | IP           IS=151.190.20.12 ID=198.186.203.55    |    IS=indirizzo sorgente   
 |              ...                                   |    ID=indirizzo destinazione
 +----------------------------------------------------+
 | TCP          PS=80 (www)    PD=1024                |    PS=porta sorgente
 |              FLAG=SYN+ACK   SEQ_NR=2000000         |    PD=porta destinazione
 |              ...            ACK_NR=1000001         |
 +----------------------------------------------------+

La macchina PC1 riceve il pacchetto controlla che il campo 'acknowledgement number' sia corretto e conclude la fase di connessione inviando un ultimo pacchetto TCP di conferma ossia con il flag ACK impostato. Il sequence number sarà 1000000 + 1 inoltre sarà inviato anche il sequence number del server con sommato 1 (SYN) ossia 2000001 nel campo 'acknowledgement number'.


    +----+                              +----------+
    |PC1 | ------------o------------->  |SERVER WWW|
    |    |            / \               |linux.org |
    +----+          /     \             +----------+
151.186.5.4       /         \          198.186.203.55
  ______________/             \______________________
 /                                                   \
 +----------------------------------------------------+
 | IP           IS=151.186.5.4 ID= 198.186.203.55     |    IS=indirizzo sorgente        
 |              ...                                   |    ID=indirizzo destinazione
 +----------------------------------------------------+
 | TCP          PS=1024        PD=80 (www)            |    PS=porta sorgente
 |              FLAG=ACK       SEQ_NR=1000001         |    PD=porta destinazione
 |              ...            ACK_NR=2000001         |
 +----------------------------------------------------+

A questo punto PC1 da Netscape può effettuare una richiesta HTTP, inoltrata come sempre con un pacchetto TCP sequence number 1000001 e ack number 2000001, flag ACK impostato.

Il server riceve e risponde con un pacchetto TCP con sequence number 2000001, acknowledgement number pari a 1000001 + (dimensione pacchetto TCP inviato da PC1), e i dati (pagina web) richiesti.

Quest'ultime due fasi poi si ripetono per ogni invio/ricezione di richieste/dati.

Terminata la visita al sito, PC1 chiude la connessione inviando un pacchetto TCP con il flag FIN impostato.

NOTA: l'utilizzo dei campi 'sequence number' e 'acknowledgement number' è fondamentale in quanto consente ai computer di controllare e verificare l'ordine e la correttezza dei pacchetti scambiati.

19.4 Problemi

Il meccanismo che permette di stabilire una connessione e scambiare dati non è perfetto, in alcuni casi anche a causa di errori presenti nelle varie implementazioni dello stack TCP/IP, è possibile aggirare e intromettersi nella comunicazione.

Sono note diverse tecniche che possono creare problemi riguardanti l'area della sicurezza, tra queste le più note sono: IP spoofing, smurfing, Blind spoofing, ...

IP spoofing

Quando si richiede una connessione ad una macchina, come si è visto, si inviano una serie di pacchetti dove nelle intestazioni sono presenti varie informazioni tra cui indirizzo sorgente, indirizzo destinazione, porta destinazione, ... In particolare l'indirizzo sorgente specifica l'indirizzo IP di chi invia i pacchetti, l'IP spoofing si basa proprio su questo campo, che può essere modificato, forgiato da un attacker per effettuare un attacco. E' possibile cioè che qualcuno possa creare e inviare dei pacchetti in modo tale che sembrino provenire da un qualunque indirizzo IP. Ciò consente di agire senza essere facilmente rintracciabilili.

Questo tipo di attacco è particolarmente pericoloso per quei servizi che sono impostati in modo da non richiedono login e password, e che quindi fanno affidamento per identificare l'utente solo sull'indirizzo IP.

Per proteggersi da questo tipo di attacchi è possibile impostare il parametro "rp_filter" presente nella directory /proc/sys/net/ipv4/conf/default in modo che tutti i pacchetti che arrivano dalla rete esterna aventi come indirizzo sorgente un'indirizzo della propria rete locale siano scartati. Per impostare questo parametro in modo che protegga tutte le interfacce presenti nella macchina (es. firewall) utilizzare:


if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ]
 then
   for f in /proc/sys/net/ipv4/conf/*/rp_filter
    do
      echo 1 > $f
    done
fi

Questa è la soluzione migliore, un'alternativa può essere quella di utilizzare iptables:

# Scartiamo tutti i pacchetti in entrata dall'interfaccia esterna (qui eth0) con indirizzo 
# uguale a quello della nostra rete
iptables -A FORWARD -i eth0 -s 207.102.5.0/24 -j DROP

Con questo comando tutti i pacchetti che arrivano all'interfaccia esterna eth0 aventi per indirizzo sorgente un indirizzo della nostra rete locale (207.102.5.0/24) sono scartati (DROP).

E' anche consigliato impedire che dalla nostra rete locale possano uscire dei pacchetti con indirizzo sorgente diverso da quello atteso, che dovrebbe essere ovviamente del tipo 207.102.5.x. Questo per impedire che qualcuno cerchi di inviare pacchetti di tipo "spoofing" dalla nostra rete locale.


       +---+
       |PC1|---+ eth1   eth0
       +---+   |  |      |
       +---+   |  \+---+/ 
       |MAC|---+---|   |---- INTERNET
       +---+   |   +---+
               .
  [RETE LOCALE]  [firewall]
  207.102.5.0/24

# iptables -A FORWARD -i eth1 ! -s 207.102.5.0/24 -j REJECT

I pacchetti giunti dalla rete locale (-i eth1) con indirizzo sorgente diverso da 207.102.5.0/24 (! -s 207.102.5.0/24) sono rifiutati (-j REJECT).

Dovrebbero essere eseguiti comandi simili per ogni interfaccia del firewall ed anche per la catena INPUT.

Proteggersi dall'IP spoofing è molto importante in quanto molti attacchi ne fanno ancora uso.

Blind spoofing

Questa tecnica si basa sull'IP spoofing e ha come scopo stabilire una connessione con un server utilizzando un indirizzo sorgente fasullo.

  +---+                 +---+
  |   |  <----o----     |   |
  +---+       ^         +---+
 [SERVER]     |        [ATTACKER]
              |
  +---+       '-------- pacchetto con indirizzo sorgente fasullo 213.120.4.3   
  |   |
  +---+
[213.120.4.3]

A prima vista potrebbe sembrare molto semplice ma in realtà non lo è. Quando si invia un pacchetto con indirizzo sorgente fasullo ad un server quest'ultimo invierà le risposte non all'attacker ma alla macchina con l'indirizzo IP uguale a quello fasullo indicato nel pacchetto.

  +---+                 +---+
  |   |                 |   |
  +---+                 +---+
 [SERVER]             [ATTACKER]
    |
    o <-- pacchetto di risposta diretto a 213.120.4.3 e non all'attacker
    |
    v
  +---+      
  |PC2|
  +---+
[213.120.4.3]

Il problema è che la macchina 213.120.4.3 riceve il pacchetto, rileva che non ha effettuato alcuna richiesta per quella connessione (infatti è stata fatta dall'attacker) e quindi invierà di conseguenza un pacchetto di RST per annullarla.

Questo chiuderebbe la connessione impedendo all'attacker di stabilire e concludere la connessione. L'attacker deve quindi impedire che ciò avvenga e ciò è possibile se riesce a bloccare PC2. A questo scopo si può utilizzare un DoS (Denial of Service) che non deve far altro che "disabilitare" forzatamente e per un certo tempo PC2 in modo che non sia in grado di inviare i pacchetti RST.

Risolto questo problema è necessario infine predire il sequence number iniziale inviato dal server, per concludere la "Three-way handshake" infatti è necessario che l'attacker invii un pacchetto di conferma (ACK) contenente l'acknowledgement number (basato sul sequence number inviato dal server) corretto. Fino a qualche tempo fa ciò era possibile e in alcuni casi era banale quindi l'attacker poteva concludere la connessione con successo, ora lo stack TCP/IP di vari sistemi operativi generano numeri di sequenza casuali difficilmente predicibili.

Abilitando la protezione contro l'IP spoofing e grazie alla capacità di Linux di generare sequence number casuali non facilmente predicibili, questo tipo di attacco è evitabile.

Port scanning

Tra gli strumenti utilizzati per ottenere informazioni utili per scoprire eventuali punti deboli di un computer connesso in rete ci sono i cosiddetti port scanner.

Attraverso questi programmi è possibile ottenere di una macchina un elenco delle porte aperte, ossia dei servizi (ftp, www, ...) che offre volutamente, potrebbe essere un server WWW, oppure no (macchina malconfigurata). Le porte aperte rappresentano un potenziale canale di comunicazione, utilizzabile per scambiare dati e per portare un eventuale attacco.

Le tecniche adottate sono diverse e permettono di ottenere un certo grado di anonimato, in genere non si desidera che la "macchina vittima" possa rilevare e registrare i port scanning.

Tra le tecniche più note troviamo:

Vanilla TCP connect()

Questa è la tecnica più semplice e consiste nella chiamata alla routine di sistema connect(). Se la porta desiderata (es. www) è aperta allora avrà successo altrimenti la porta risulterà irraggiungibile. I vantaggi di questa tecnica sono la velocità e il fatto che per eseguirla non è necessario possedere particolari privilegi (es. root). Lo svantaggio è che può essere facilmente rilevata e registrata dal server vittima.

TCP SYN (half-open) scanning

In questo caso non è necessario completare la "Three hand-shake", ossia si invia un pacchetto di richiesta connessione (SYN) alla porta della macchina vittima, e si attende una risposta che potrebbe essere RST (porta/servizio non disponibile) o SYN-ACK (porta/servizio disponibile), in quest'ultimo caso si provvederà allora ad inviare un pacchetto RST per chiudere immediatamente la connessione. Utile in quanto in alcuni casi i server non rilevano e registrano queste prove.

TCP FIN (stealth) scanning

Questa tecnica è stato implementata in quanto i tentativi basati sui pacchetti SYN è molto nota e quindi in molti casi i server sono in grado di rilevarla utilizzando anche specifici programmi. La soluzione in questo caso consiste nell'invio di un pacchetto FIN, in genere utilizzato per chiudere una connessione stabilita. La macchina che riceve questo pacchetto si è osservato che in genere, se la porta/servizio non è disponibile, invia un pacchetto in risposta di tipo RST, in caso contrario nulla è inviato. In base a queste informazioni è così possibile stabilire se un determinato servizio è o meno disponibile e senza dover utilizzare un pacchetto SYN. NOTA: macchine con sistema operativo Microsoft non operano in questo modo (standard), in caso di pacchetti FIN rispondono in ogni caso con un pacchetto RST.

UDP ICMP port unreachable scanning

In questo caso non si invia un pacchetto TCP ma bensì UDP (User Datagram Protocol). Questi pacchetti sono molto semplici ma non sono affidabili. In molti casi si è notato che inviando questi pacchetti verso una porta UDP si è ottenuto in risposta un pacchetto ICMP_PORT_UNREACH, ciò permette di conoscere quali porte UDP non sono sicuramente disponibili, mentre sulle altre è possibile fare solo alcune considerazioni. UDP è un protocollo inaffidabile che non si basa sul concetto di connessione quindi i pacchetti che si inviano o che si dovrebbero ricevere potrebbero andare persi, e quindi le informazioni ricavate potrebbero non corrispondere al vero. Altro problema è la scarsa velocità offerta. Utile però per verificare quale delle porte alte (1024-65535) UDP sono aperte.


Avanti Indietro Indice