==============================================================================
-----------[ BFi numero 10, anno 4 - 30/09/2001 - file 12 di 18 ]-------------
==============================================================================
-[ HACKiNG ]------------------------------------------------------------------
---[ IPv6 PACKET F0RGiNG
-----[ Kundera - http://dskull.tzone.it
Consumo : 1 bottiglione di Pepsi da 1,5l - 1 pacchetto di Chesterfield
comprato ieri
Musica : Steve Ray Vaughan & Double Trouble "Live Alive" .
---[---------------------------------------------------------------------------
---[Ipv6 packet forging - by Kundera ]---
Ok ragazzi, siamo nel 2001, le risorse ipv4 stanno piano piano esaurendosi
(sara' vero?) e anche io mi sto un po' esaurendo a vedere sempre il solito
header ip :-). Con il buon vecchio ipv4 ne abbiamo fatte di tutti i colori, ma
fra un po' (non so quando) si cambia solfa! arriva l'ipv6! e' quindi bene
iniziare a saperne qualcosa... Vediamo un po' come e' fatto e sopratutto come
possiamo fabbricare in casa i nostri bei pacchettini da spedire nella rete.
Ipv6 e' sostanzialmente diverso dal suo predecessore e la caratteristica
fondamentale (a mio avviso) e' sicuramente la "modularita'" del protocollo che
dopo l'header di base, necessario per il routing, puo' avere altri headers (in
un determinato ordine uno dopo l'altro) che offrono le stesse funzionalita' di
ipv4 (infatti alcuni headers incorporano le stesse opzioni di ipv4) piu' altre
nuove interessanti opzioni, questi sono detti "Extension Headers".
Ma iniziamo dal principio e vediamo (prima di forgiarlo) come e' fatto
esattamente l'header base di ipv6 prendendo come riferimento l'RFC 1883 :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Prio. | Flow Label |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload Length | Next Header | Hop Limit |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Source Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Destination Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Version = La versione e' un campo a 4 bit e a meno che non vogliamo suscitare
strane reazioni nello stack ricevente direi che e' meglio settarlo a
6 :)
Prio. = Priority, altro campo a 4 bit che ha praticamente la stessa funzione
del campo TOS di ipv4. Il kernel o l'applicazione (mediante chiamata
setsockopt()) setta un valore in base al tipo di servizio che
contiene il pacchetto e di conseguenza la precedenza che deve avere
nelle operazioni di routing.
Ecco i valori concordati nell'RFC :
0 - uncharacterized traffic
1 - "filler" traffic (e.g., netnews)
2 - unattended data transfer (e.g., email)
3 - (reserved)
4 - attended bulk transfer (e.g., FTP, NFS)
5 - (reserved)
6 - interactive traffic (e.g., telnet, X)
7 - internet control traffic (e.g., routing protocols, SNMP)
C'e' pero' da fare una precisazione, l'RFC 1883 e' datata Dicembre 1995 e nel
1997 durante l'IPng Meeting di Monaco e' stato deciso di portare questo campo
a 1 byte, generando la nuova RFC ufficiale di ipv6, la numero 2460.
Flow Label = Questo campo a 24 bit e' molto interessante ed offre una funzione
nuova rispetto a ipv4 : il flusso della comunicazione.
Un "flusso" e' identificato unicamente come la coppia
"indirizzo sorgente" e valore del campo "flow label" compreso tra
1 e 0xFFFFFF scelto in modo random dalla macchina che genera il
pacchetto; valore che dovrebbe mantenere fino alla fine della
sessione per assicurarsi un certo "tempo di commutazione" nei
nodi ipv6 attraversati. Infatti i router intermedi che processano
il pacchetto possono tenersi (se abilitato) una cache dei flussi
per evitare di andare ogni volta a rianalizzare l'intero header
ipv6 + gli eventuali extension headers.
E' chiaro che se il nuovo pacchetto che arriva ha lo stesso flow
label del precedente dovra' essere trattato nello stesso modo
perche' avra' molto probabilmente lo stesso set e valori di
headers.
Questa cache deve essere pero' di norma aggiornata ogni 6
secondi.
Se un nodo sorgente non intende avvalersi del flusso settera'
questo campo a 0. Con la nuova RFC 2460 questo campo e' passato
di conseguenza a 20 bit, ma la sua funzionalita' resta invariata.
Il flow label sara' quindi compreso tra 1 0x0FFFFF .
Payload Length = Campo di 2 byte che indica la lunghezza in ottetti del
pacchetto escluso l'header ipv6 base. La lunghezza massima
del payload e' naturalmente 65535 byte ma con ipv6 sono
ammessi payload anche piu' lunghi (detti "Jumbo payloads"),
ma per questo ci vuole l'"Hop-by-Hop" extension header, in
questo caso il valore di payload length e' zero. E'
considerato come appartenente al payload tutto quello che
segue l'header base, inclusi gli extension headers.
Qui si puo' notare la differenza dallo stesso campo di ipv4
che includeva anche la lunghezza dell'header a causa delle
opzioni, l'header base ipv6 invece ha sempre la stessa
lunghezza.
Next Header = Questo campo a 1 byte e' praticamente come il campo protocol
type di ipv4 dato che utilizza gli stessi valori (vedi
/etc/protocols).
Identifica l'header immediatamente seguente l'header ipv6.
Hop Limit = Campo di 1 byte che ha la stessa funzione del campo TTL di ipv4.
Ogni volta che il pacchetto attraversa un nodo ipv6 il valora
viene decrementato di 1. Se il valore raggiunge zero viene
generato un messaggio di "hop limit exceeded in transit" di
Icmpv6.
Source & destination address = Il famoso campo a 128 bit che identifica
indirizzo sorgente e destinazione del
pacchetto.
La struttura di un indirizzo ipv6 e' abbastanza
complicata e questi indirizzi si possono
dividere in diverse tipologie, e' questo un
argomento che meriterebbe un articolo a
parte, ma la mancata trattazione nei paragrafi
successivi non toglie nulla allo scopo finale.
Noi considereremo l'indirizzo come una normale
sequenza di 16 byte.
Considerando la nuova RFC 2460 il pacchetto che andremo a costruire sara'
cosi' strutturato:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Traffic Class | Flow Label (20 bit) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload Length | Next Header | Hop Limit |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Source Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Destination Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Dopo aver fatto conoscienza con quello che dobbiamo costruire vediamo in
dettaglio in che modo si possono manipolare questi pacchetti su Linux. Quello
che ci serve e' un kernel dal 2.2 in su con il supporto ipv6 abilitato
(ricompilate se necessario) e tutti gli headers del kernel installati
(directory /usr/src/linux/include).
Io pero' 'ste cose le ho fatte con il 2.4.0, quindi se volete essere sicuri
fatelo con un kernel recente dalla 2.4.0 in su.
Ok, partiamo con il codice:
<-| /k6/k6pktb.c |->
/* Kundera ipv6 base-header packet-builder with raw sockets. */
/* tested on Linux 2.4.0 i386*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PACKLENGTH 1480
/* Definiamo i soliti include con in piu' i 2 base di ipv6 e andiamo a vedere
come e` definito l'header in ipv6.h:
*
* IPv6 fixed header
*
* BEWARE, it is incorrect. The first 4 bits of flow_lbl
* are glued to priority now, forming "class".
*
struct ipv6hdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 priority:4,
version:4;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8 version:4,
priority:4;
#else
#error "Please fix "
#endif
__u8 flow_lbl[3];
__u16 payload_len;
__u8 nexthdr;
__u8 hop_limit;
struct in6_addr saddr;
struct in6_addr daddr;
};
Vediamo che il campo "flow label" e` un array di 8 byte di nome flow_lbl
(quindi 24 bit) conforme con l'RFC vecchia. Anche con l'ultimo kernel 2.4.7
rimane definito in questo modo, ma non e` comunque un problema, dopo vedremo
che con qualche trucchetto costruiremo un pacchetto conforme alla nuova
RFC 2460 utilizzando questa "vecchia" struttura.
*/
int sok,error,i,ver=6,p_number=10;
__u32 flow=0x000000;
int hoplimit=200,nexth=59,class=0;
char *device;
struct ifreq interface;
struct sockaddr_in6 destipv6;
struct sockaddr_in6 sourceipv6;
/*
Definiamo le due strutture che conterranno l'indirizzo sorgente e quello
destinazione (sourceipv6,destipv6), ma che contengono altri campi che pero`
non servono con i raw sockets.
*/
char *source=NULL,c;
char *destination=NULL;
struct ipv6hdr *IPV6TURBO;
/*
Definiamo un puntatore alla struttura dell'header ipv6 che chiameremo
IPV6TURBO (sei cilindri turbo :) )
*/
char packet[PACKLENGTH],*data;
/*
Definiamo un buffer di 1480 byte (MTU del tunnel ipv4-ipv6) che prendera` poi
forma come pacchetto ipv6. Se cerchiamo di spedire un pacchetto piu` grosso
con il raw socket il kernel NON gestiraa` la frammentazione non inserendo
l'extension header per la frammentazione e ci dara` un errore alla sendto() .
Se l'MTU dell'interfaccia e` diversa si puo' cambiare il valore di PACKLENGTH.
*/
void usage (void)
{
printf("Kundera IPv6 packet-builder.\n");
printf("usage : -I -v -c -f "\
" -n -h -s "\
"