Manuali, links, fotografie e tanto altro
alla portata di un semplice click!
 
 Benvenuto Ospite
Manuali, immagini, fotografie e tanto altro a portata di un click

Cartoline virtuali

Cartolina n° 810



Sono presenti 1307 cartoline virtuali. Entra ora


Giochi online
Cheeta Race


1. ermesiti: 22,500
2. Daygo: 17,719
3. barone400: 8,400

Visualizza tutti i giochi.

News Reader















Guida ai Raw socket ed ai pacchetti TCP/IP, nemesy email Autore
.: Data Pubblicazione 02-Nov-2004 :: Letture:: 1261 :: Recensione :: Stampa solo questa pagina :: Stampa pagina con tutte le sottopagine:.
------------
Introduzione
------------
Ciao a tutti. Tanto per iniziare voglio spiegare i motivi per cui
ho voluto scrivere questo tutorial sui raw socket. I raw socket
permettono di gestire manualmente i pacchetti che inviamo su una
rete (anche in locale, sulla loopback device). In pratica, di solito,
quando ci connettiamo ad Internet il kernel impacchetta i dati che 
l'applicazione, diciamo un browser, vuole vengano inviati e aggiunge
delle informazioni relative alla nostra macchina. Ad esempio aggiunge
quale e' l'ip sorgente del pacchetto, a quale ip e' destinato il 
pacchetto,  a quale porta questo e' destinato ed altre informazioni
che vedremo in seguito. Con i raw socket (e qualche opzione particolare)
tutto questo lavoro sara' fatto da noi. E' uno sporco lavoro, ma qualcuno
deve pur farlo! 
Beh, spero che alla fine questa guida risulti utile a molti... almeno
a coloro che vogliono (cominciare a) capire come funzionano le reti
,internet in particolare, e vogliono divertirsi :)
Naturalmente tutte queste informazioni le ho acquisite cercando in rete
documenti a riguardo, non e' che una mattina mi sono svegliato e mi 
sono accorto di sapere qualcosa sui socket! Fate lo stesso.

Conoscenze di base

Se volete capire questa guida e i sorgenti contenuti dovete avere un 
minimo di conoscenza del C. Poi, se magari avete gia' usato i socket
tanto di guadagnato. Dovete avere pero' un minimo di dimestichezza con 
i socket e su come i byte sono ordinati al loro interno (host byte order
e network byte order).
Comunque, credo che la maggior parte di voi capira' subito il tutto, 
anche perche' non e' niente di particolare.



-------------
Cosa ci serve
-------------
Visto che andremo a vedere come si costruiscono pacchetti TCP/IP 
abbiamo bisogno di due strutture che ci permettano di mantenere 
tutte le informazioni necessarie. Queste due strutture sono:
struct iphdr e struct tcphdr. Le trovate negli header file ip.h e 
tcp.h (dovete includere  e ).
Andiamo a vedere cosa contengono queste due strutture. 

struct iphdr {
    unsigned int ihl:4;		// :4 indica che il membro e' composto 
				// di 4 bits
    unsigned int version:4;
    u_int8_t tos;
    u_int16_t tot_len;
    u_int16_t id;
    u_int16_t frag_off;
    u_int8_t ttl;
    u_int8_t protocol;
    u_int16_t check;
    u_int32_t saddr;
    u_int32_t daddr;
  };

ihl (IpHeaderLength) Lunghezza dell'header ip in parole da 32 bit. Se ha
		     valore 5 significa che e' lungo 5*4 byte. Il 
		     valore del campo ihl deve essere posto diverso da 5
		     solo nel caso in cui l'header contiene opzioni. 
		     Di solito questo e' fatto solo dai router.
version		     Versione del protocollo. Deve essere posto sempre 
		     uguale a 4 (non serve a niente metterlo a 6 perche'
		     la struttura dell'header IPv6 e' differente). 
tos (TypeOfService)  Controlla la priorita' del pacchetto. I primi 
		     tre bit sono interpretati dai router, gli altri
		     4 indicano la priorita' relativa al tipo di 
		     servizio richiesto: il primo di questi indica il 
		     Delay, il secondo Throughput, il terzo Reliability
		     il quarto Cost. 
tot_len		     Lunghezza dell'intero pacchetto. Questo valore deve
		     tener conto dell'header ip, di quello tcp (o icmp o
		     udp) e dei dati aggiuntivi accodati al pacchetto.
id		     Viene usato per riassemblare il pacchetto IP in caso
		     di frammentazione.
frag_off	     Viene usato per riassemblare il datagrammi frammentati
		     I primi tre bit sono le flag di frammentazione. Il
		     primo di questi bit e' sempre posto a zero. Il secondo
		     indica che non e' stato frammentato, il terzo invece 
		     il contrario. Per settare queste flag e' sufficiente
		     fare un OR con il valore esadecimale (per la don't
		     fragment flag   frag_off |= 0x4000, per la fragment
		     flag   frag_off |= 0x2000). Il valore di ip.frag_off
		     deve essere espresso in NetworkByteOrder, con la 
		     funzione htonl(unsigned long int).
ttl (TimeToLive)     Ad ogni passaggio attraverso un nodo questo valore 
		     e' decrementato di una unita'. Quindi piu' alto e'
		     piu' lontano potra' arrivare. Il valore massimo e'
		     255.
protocol	     Indica il protocollo contenuto nel pacchetto ip.
		     TCP = 0x06, UDP = 0x11, ICMP = 0x01
check		     Checksum. E' un valore calcolato all'invio. Ogni
		     volta che il contenuto all'interno dell'intero
		     pacchetto viene modificato deve essere ricalcolato.
saddr		     Indirizzo sorgente del pacchetto :) 
daddr		     Indirizzo destinatario del pacchetto.

Il protocollo IP di per se non garantisce che il pacchetto arrivi a 
destinazione. Il TCP e' il protocollo piu' utizzato e garantisce un 
meccanismo per stabilire una connessione affidabile e un'autenticazione.

struct tcphdr
  {
    u_int16_t source;
    u_int16_t dest;
    u_int32_t seq;
    u_int32_t ack_seq;
    u_int16_t res1:4;
    u_int16_t doff:4;
    u_int16_t fin:1;
    u_int16_t syn:1;
    u_int16_t rst:1;
    u_int16_t psh:1;
    u_int16_t ack:1;
    u_int16_t urg:1;
    u_int16_t res2:2;
    u_int16_t doff:4;
    u_int16_t res1:4;
    u_int16_t res2:2;
    u_int16_t urg:1;
    u_int16_t ack:1;
    u_int16_t psh:1;
    u_int16_t rst:1;
    u_int16_t syn:1;
    u_int16_t fin:1;
    u_int16_t window;
    u_int16_t check;
    u_int16_t urg_ptr;
};

source			Porta sorgente.
dest			Porta destinataria.
seq			Numero di sequenza
ack_seq			Acknowledgment number.
doff			Data offset
fin			Final. La connessione deve essere chiusa.
			La controparte deve rispondere con un altro
			pacchetto anch'esso con la flag fin settata.
syn			Synchronization. Questa flag indica che si 
			vuole inizare una nuova connessione.
rst			Reset. La connessione e' stata chiusa.
psh			Push. Il pacchetto non sara' trattenuto dallo 
			stack IP ma giungera' direttamente alla
			applicazione (usato per pacchetti contenenti 
			dati).
ack			Acknowledegment. Usato per avvertire la 
			controparte che il pacchetto precedente e' stato
			ricevuto correttamente.
urg			Urgent. il pacchetto sara' instradato piu' 
			velocemente dai router.
window			Quantita' di dati che si possono inviare prima 
			di ottenere una risposta con un ACK
check			Checksum. E' un valore calcolato all'invio. Ogni
		     	volta che il contenuto all'interno dell'intero
		     	pacchetto viene modificato deve essere 
			ricalcolato. Serve al ricevente per controllare
			l'integrita' del pacchetto.
urg_ptr			Urgent pointer. Se la flag urg non e' selezionata
			deve essere uguale a zero, altrimenti punta 
			alla fine dei dati che devono essere inviati
			con priorita'.

----------------
Un po' di codice
----------------
Beh... direte voi! Ora che ci facciamo con tutta sta robba. Semplice,
possiamo fare un programma che invii pacchetti spoofati o con qualsiasi
altra opzione vogliamo. Il codice che trovate sotto e' estratto da
Sacket, un tool GTK per creare pacchetti TCP/IP. Lo trovate qui: 
http://napolihak.da.ru


-------------------->-<---init_packet--->-<-----------------------------

char *init_packet (struct iphdr *ip, struct tcphdr *tcp) {

  char *sacket;
  int spoof;

/* Allochiamo un puntatore a vettore di char che contenga il tutto */
  sacket = calloc (1, sizeof (struct iphdr) + sizeof (struct tcphdr));
  ip     = (struct iphdr *) sacket;
  tcp    = (struct tcphdr *) (sacket + sizeof (struct tcphdr));


  ip->version = 4;
/* Ip header lenght */
  ip->ihl = 5;
/* TypeOfService */
  ip->tos = 0;

/* L'unsigned short integer frag_off e' utilizzato nel seguente modo:
 * (L'ordine dei bit e' dal piu' significativo a quello meno, cioe'
 *  da sinistra a destra in pratica :) )
 * 1° sempre uguale a 0
 * 2° don't fragment: il pacchetto non e' stato frammentato quando e' 
 *    		      stato inviato.
 * 3° more fragments following: il pacchetto e' stato frammentato.
 * 4°-16° l'offset del pacchetto ossia il numero d'ordine del frammento.
 *
 * Se volete che i pacchetti abbiano tutti la flag don't fragment settata
 * definite DNT_FRAGMENT (#define FRAGMENT).
 * Se volete che i pacchetti abbiano la flag more fragments following 
 * settata definite FRAGMENT (#define DNT_FRAGMENT).
 *
 */

#ifdef DNT_FRAGMENT
  /* settiamo la flag don't-fragment con 0x4000 */
  ip->frag_off |= 0x4000;
  /* frag_off deve essere espresso in network bite order */
  ip->frag_off = htons (ip->frag_off);
#endif

#ifdef FRAGMENT
  /* settiamo la flag don't-fragment con 0x2000 */
  ip->frag_off |= 0x2000;
  /* frag_off deve essere espresso in network bite order */
  ip->frag_off = htons (ip->frag_off);
#endif

#ifndef FRAGMENT
#ifndef DNT_FRAGMENT
  ip->frag_off |= 0x0000;
#endif
#endif

  ip->ttl |= 255;
/* Il pacchetto viene inviato a noi stessi.
 * La funzione inet_addr non consente di usare l'ip 
 * 255.255.255.255, visto che 255.255.255.255 convertito 
 * in unsigned long e' -1, lo stesso valore che la funzione 
 * restituisce per gli errori. Se sapete di dover utilizzare
 * l'ip 255.255.255.255 usate la funzione inet_aton
 */ 
  ip->daddr = inet_addr ("127.0.0.1");
  ip->protocol = IPPROTO_TCP;		// TCP  = 0x06
					// UDP  = 0x11
					// ICMP = 0x01

/* Porta di destinazione */
  tcp->dest = htons (8080);
  tcp->seq = inet_addr ("127.90.255.78");
  tcp->ack_seq = inet_addr ("200.10.90.79");
  tcp->urg = 0;
  tcp->ack = 1;
  tcp->psh = 1;
  tcp->rst = 0;
  tcp->syn = 0;
  tcp->fin = 0;
  tcp->window = 0;

  return sacket;
}

---------------------->-<---fine sorgente--->-<---------------------------

La funzione init_pack crea un pacchetto con un settaggio base. Alcune
cose, tipo tcp->ack e ip->daddr le ho inserite solo per far vedere
come si gestiscono i vari campi degli header. Molto semplice, vero?
init_pack restituisce un puntatore a char contenente il pacchetto 
inizializzato. Le strutture tcp e ip sono passate per puntatore visto
che dovranno essere riutilizzate in seguito.



--------------------->-<---sendsacket--->-<-----------------------------

int sendsacket (struct iphdr *ip, struct tcphdr *tcp, char *sacket) {

  struct sockaddr_in to;
  int pack_size = sizeof (struct iphdr) + sizeof (struct tcphdr);
  int fd, ja = 1;

/* Lunghezza totale del pacchetto espressa in network byte order */
  ip->tot_len = htons (pack_size);
  ip->id = getpid ();
  if (!spoof) 
     ip->saddr = htonl (INADDR_ANY);
  ip->check = in_chksum (( u_short *)&ip, sizeof (struct iphdr));

  tcp->source = getpid ();
  tcp->check = in_chksum ((u_short *)&ip, sizeof (struct tcphdr));


  to.sin_port = 0;
  to.sin_family = AF_INET;
  to.sin_addr.s_addr = ip->daddr;

  if ((fd = socket (PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
     return -2;
  }

/* Con la macro IP_HDRINCL avvertiamo il kernel che il pacchetto
 * contiene gia' l'header IP. Se non facessimo cosi il kernel 
 * aggiungerebbe di suo un altro header IP.
 */
  if (setsockopt (fd, IPPROTO_IP, IP_HDRINCL, &ja, sizeof (ja)) < 0)
     return -1;


  return (sendto (fd, sacket, pack_size, 0, (struct sockaddr*)&to, 
          sizeof (struct sockaddr)));
}

---------------------->-<---fine sorgente--->-<---------------------------

La funzione invia il pacchetto cosi come e' stato settato (da 
qualcun'altra funzione).
La funzione ritorna un intero. Se questo e' positivo l'invio 
ha avuto buon esito e il numero ritornato rappresenta il 
numero di bytes inviati. Se la funzione ritorna -2 c'e' 
stato un errore nella creazione del socket, probabilmente 
dovuto a problemi di privilegi (bisogna essere root). 
Tutti gli altri valori negativi indicano un errore generico.


u_short in_chksum (u_short *addr, int len) {

  int nleft = len , sum = 0;
  u_short *w = addr;
  u_short value = 0;

  while (nleft > 1) {
	sum += *w++;
	nleft -=2;
  }

  if (nleft == 1) {
	*(u_char *)(&value) = *(u_char *)w;
	sum += value;
  }

  sum = (sum >> 16) + (sum + 0xffff);
  sum += (sum >> 16);
  answer = ~sum;
  
  return (value);
}

Funzione per il calcolo del checksum.



---------------------
Considerazioni finali
---------------------
Dovete tenere presente che modificando l'ip sorgente del pacchetto 
non e' comunque possibile stabilire una connessione TCP. 
Lo chiarisco per quelli di voi che gia' stavano saltando dalla gioia
pensando di poter finalmente invia email anonime, o giocare
brutti scherzi :) Devo dire la verita', pure io ero tra voi :D 
Va bene, chiarito tutto spiego perche' non e' possibile. Non e' possibile
perche' il protocollo TCP impone un handshake iniziale. In questa
fase il client che richiede la connessione setta il campo seq del 
header tcp con un numero random, il campo ack_seq uguale a zero e la 
flag SYN uguale a 1. Quando il server riceve questo pacchetto risponde
con il campo ack_seq contenente un valore random e con le flag ACK e SYN 
settate, dopo di che il client risponde con la flag ACK settata. Il campo
ack_seq settato a zero impedisce di creare facilmente connessioni tcp 
spoofate. Dico facilmente perche' nei kernel 2.2.17 (mi pare fossero 
i .17) c'era un bug che permetteva di predire l'ack_seq che il kernel
avrebbe utilizzato. Ricordate che tutto questo vale solo per il TCP. 
L'UDP e l'ICMP non hanno queste caratteristiche quindi usando l'UDP 
magari potete creare un modo anonimo di comunicare con altri. Basterebbe
comunicarsi inizialmente gli indirizzi reali e poi comunicare tramite 
pacchetti UDP con sorgente spoofato.
Ah, dimenticavo di dirvi una cosa che ri-rendera' felicissimi quelli di 
voi che stanno in una LAN. Ricordate che non e' possibile spoofare una
connessione TCP completa a causa del ack_seq del server? Beh, se fosse
possibile sapere qual'e' questo numero allora il gioco sarebbe fatto.
Se siamo in Internet con una connessione dialup (con un modem, in 
pratica) non possiamo vedere qual'e' perche' a noi arriveranno 
solamente i pacchetti che hanno noi come destinazione. Ma se siamo 
in una LAN, eheh, tutto cambia! Se mettiamo la scheda ethernet in 
modalita' promiscua, possiamo vedere tutto il traffico che ci 
attraversa. In questo modo per vedere l'ack_seq number che il 
server usera' in risposta ad un nostro pacchetto spoofato bastera' 
usare come indirizzo spoofato quello di un computer i cui pacchetti 
passano attraverso la nostra scheda. Pero' la risposta al pacchetto 
inviato dal server dovra' essere il piu' veloce possibile per impedire
che il vero destinatario del pacchetto risponda con la flag RST 
chiudendoci cosi la connessione in faccia :(

Cos'altro dirvi? Esplorate, leggetevi i sorgenti del kernel o di 
qualsiasi altra cosa vi capiti tra le mani. Il "free software" e' bello
proprio per questo, per la possibilita' di accrescere le nostre 
conoscenze che da ad ognuno di noi. Bisogna solo cercare e imparare, 
cercare e imparare, cercare e imparare...
					N'eM Sy (nemesy.it@tiscalinet.it)
						 for napolihak.da.ru

Allego la mia chiave pubblica per chi di voi non solo mi volesse 
scrivere, ma addirittura con lo voglia fare con pgp.

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: PGP 6.5.8

mQEPAzvtfsUAAAEIAK/XtUG0jmS981V+uqgAd5xXnPQMi07mWXb++3TV5z+8mt4g
6SENRv97gLX0LbYbYOANB6+Clg0n/5ikNDxnCm6w+tHvKm9MMH5F1Tylr0HFz4Jo
LvvMLgtG3yc8QuzrtpuPZ6hdvnZ7z2HNb/kQqoHIh7xqmD+XmbLt9lVsY0I1AT6b
SeNzB5ets+wuBx10kRn2KOtu6mEPC1dXTBAVh+guF+nWF16mYZi6IHRr9kI2Z0jn
hF0H5zHUkg9hZwJz3ck7gHOkzOiJ7BU7H0K+vDK5lUc8P4N3WFYU8Jfd4g/T3TK5
8SJEwb11dsB89jfwbqd0ygO7w1SwCVa9+1y/88UAEQEAAbQgbmVtIGl0IDxuZW1l
c3kuaXRAdGlzY2FsaW5ldC5pdD6JARUDBRA77X7FCVa9+1y/88UBAWkgB/9+nIPm
tQMATzbm3sNOHXtax6nTh8HEA2+XpV1GXEuF/UTSslq6oTXEONHQ6I3BTILMKYqq
GTy/li6kRozq05P54fOYNcs3W8XcmxvsWilUQs9uiVdCuOW3kBI2goh0o9rnKx8w
N6sUlxLfRJwO90CN0Iy8TvzDlbjqqJHRqyFNR3x5LpsmaLUFC5XnEjeeIp+lgJO/
kD27FHT3dtdayGz0q2q18k1ggHaSisc+MlOFWuavP4tGdEcpFFC6kt8Z++7KV9ln
CAZwqKkaFSEXn5PyBgxbXaO9MOFoXmdE3Uknzx2lHalevZK+OTxKHUtWawe5TKDo
ES2qBzBPRsZc39BU
=i+/9
-----END PGP PUBLIC KEY BLOCK-----

			"Who controls the past controls the future.
			 Who controls the present controls the past.
			 Who controls the present, now?"
.: Ritorna ad argomento Programmazione :: Ritorna a Indice Argomenti :.
Network: Cartoline virtuali - Calendari - Modelle - Playmates - Sfondi - Forum - Old SecurityNews - Warez