Главная
Архив новостей
Безопасность в Unix
Безопасность в Windows
Сборник FAQ'ов
Телефония, фрикинг
Кредитные карты
Криптография
Истории о хакерах
Программы, утилиты
_el@sp.sz.ru

RB2 Network

Приложение 4. Программа сканирования TCP портов.

/*
 * resolve.c
 *           by Uriel Maimon (lifesux@cox.org)
 */
#include 
#include 
#include 
#include 
#include 

int resolve( const char *name, struct sockaddr_in *addr, int port )
     {
        struct hostent *host;

        /* clear everything in case I forget something */
        bzero(addr,sizeof(struct sockaddr_in));

        if (( host = gethostbyname(name) ) == NULL )  {
#ifndef RESOLVE_QUIET
           fprintf(stderr,"unable to resolve host \"%s\" -- ",name);
           perror("");
#endif
           return -1;
        }

        addr->sin_family = host->h_addrtype;
        memcpy((caddr_t)&addr->sin_addr,host->h_addr,host->h_length);
        addr->sin_port = htons(port);

        return 0;
     }

int resolve_rns( char *name , unsigned long addr )
     {
        struct hostent *host;
        unsigned long address;

        address = addr;
        host = gethostbyaddr((char *)&address,4,AF_INET);

        if (!host)  {
#ifndef RESOLVE_QUIET
           fprintf(stderr,"unable to resolve host \"%s\" -- ",inet_ntoa(addr));
           perror("");
#endif
           return -1;
        }
        strcpy(name,host->h_name);
        return 0;
     }

unsigned long addr_to_ulong(struct sockaddr_in *addr)
     {
        return addr->sin_addr.s_addr;
     }
/*
 * EOF
 *//*
 * tcp_pkt.c
 *           by Uriel Maimon (lifesux@cox.org)
 */

/* remove inlines for smaller size but lower speed */
#include 
#include 
#include 
#include 
#include 

#define IPHDRSIZE sizeof(struct iphdr)
#define TCPHDRSIZE sizeof(struct tcphdr)
#define PSEUDOHDRSIZE sizeof(struct pseudohdr)

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

     /*
      * HEXDUMP()
      *
      * not too much to explain
      */
inline void HEXDUMP(unsigned len, unsigned char *data)
{
   unsigned i;
   for (i=0;isaddr = s_addr;
        pseudo->daddr = t_addr;
        pseudo->protocol = IPPROTO_TCP;
        pseudo->tcplength = htons(TCPHDRSIZE+datasize);

        /* The TCP pseudo-header was created. */

        tcp->th_sport   = htons(s_port);
        tcp->th_dport   = htons(t_port);
        tcp->th_off     = 5;          /* 20 bytes, (no options) */
        tcp->th_flags   = tcpflags;
        tcp->th_seq     = htonl(seq);
        tcp->th_ack     = htonl(ack);
        tcp->th_win     = htons(win); /* we don't need any bigger, I guess. */

        /* The necessary TCP header fields are set. */

        tcp->th_sum = in_cksum(pseudo,PSEUDOHDRSIZE+TCPHDRSIZE+datasize);

        memset(packet,0,IPHDRSIZE);
        /* The pseudo-header is wiped to clear the IP header fields */

        ip->saddr    = s_addr;
        ip->daddr    = t_addr;
        ip->version  = 4;
        ip->ihl      = 5;
        ip->ttl      = 255;
        ip->id       = random()%1996;
        ip->protocol = IPPROTO_TCP; /* should be 6 */
        ip->tot_len  = htons(IPHDRSIZE + TCPHDRSIZE + datasize);
        ip->check    = in_cksum((char *)packet,IPHDRSIZE);

        /* The IP header is intact. The packet is ready. */

#ifdef TCP_PKT_DEBUG
        printf("Packet ready. Dump: \n");
#ifdef TCP_PKT_DEBUG_DATA
        HEXDUMP(IPHDRSIZE+TCPHDRSIZE+datasize,packet);
#else
        HEXDUMP(IPHDRSIZE+TCPHDRSIZE,packet);
#endif
        printf("\n");
#endif

        return sendto(socket, packet, IPHDRSIZE+TCPHDRSIZE+datasize, 0, (struct sockaddr *)address, sizeof(struct sockaddr));
     }
/*
 * EOF
 */
/*
 *  Port Scanning without the SYN flag / Uriel Maimon
 *  (lifesux@cox.org)
 */

#define RESOLVE_QUIET

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "resolve.c"
#include "tcp_pkt.c"

#define STCP_VERSION "1.32"
#define STCP_PORT  1234                /* Our local port. */
#define STCP_SENDS 3
#define STCP_THRESHOLD 8
#define STCP_SLOWFACTOR 10

void banner(void)
     {
        printf("\nscantcp\n");
        printf("version %s\n",STCP_VERSION);
     }

void usage(const char *progname)
     {
        printf("\nusage: \n");
        printf("%s       [sf]\n\n",progname);
        printf("\t : 0: half-open scanning (type 0, SYN)\n");
        printf("\t           1: stealth scanning (type 1, FIN)\n");
        printf("\t           2: stealth scanning (type 2, ACK)\n");
        printf("\t : source address (this host)\n");
        printf("\t   : target to scan\n");
        printf("\t  : ports/and or ranges to scan - eg: 21-30,113,6000\n");
        printf("\t : microseconds to wait between TCP sends\n");
        printf("\t  : seconds to wait for TCP replies\n");
        printf("\t[sf]     : slow-factor in case sends are dectected to be too fast\n\n");
     }

unsigned char *dest_name;
unsigned char *spoof_name;
struct sockaddr_in destaddr;
unsigned long dest_addr;
unsigned long spoof_addr;
unsigned long usecdelay;
unsigned      waitdelay;

int slowfactor = STCP_SLOWFACTOR;

struct portrec                         /* the port-data structure */
{
   unsigned           n;
   int                state;
   unsigned char      ttl;
   unsigned short int window;
   unsigned long int  seq;
   char               sends;
} *ports;

char *portstr;
unsigned char scanflags;
int done;
int rawsock;                           /* socket descriptors */
int tcpsock;
int lastidx = 0;                       /* last sent index */
int maxports;                          /* total number of ports */

void timeout(int signum)               /* timeout handler           */
     {                                 /* this is actually the data */
        int someopen = 0;              /* analyzer function. werd.  */
        unsigned lastsent;
        int checklowttl = 0;

        struct portrec *p;

        printf("* SCANNING IS OVER\n\n");
        fflush(stdout);

        done = 1;

        for (lastsent = 0;lastsentstate == -1)
               if (p->ttl > 64)
               {
                  checklowttl = 1;
                  break;
               }
          }

/* the above loop checks whether there's need to report low-ttl packets */

        for (lastsent = 0;lastsentn);

             tcpip_send(rawsock,&destaddr,
                        spoof_addr,destaddr.sin_addr.s_addr,
                        STCP_PORT,ntohs(destaddr.sin_port),
                        TH_RST,
                        p->seq++, 0,
                        512,
                        NULL,
                        0);
          }                            /* just RST -everything- sent   */
                                       /* this inclued packets a reply */
                                       /* (even RST) was recieved for  */
        for (lastsent = 0;lastsentstate)
                    {
                     case -1: break;
                     case 1 : printf("# port %d is listening.\n",p->n);
                       someopen++;
                       break;
                     case 2 : printf("# port %d maybe listening (unknown response).\n",
                                     p->n);
                       someopen++;
                       break;
                     default: printf("# port %d needs to be rescanned.\n",p->n);
                    }
                  break;
                case TH_ACK:
                  switch (p->state)
                    {
                     case -1:
                       if (((p->ttl < 65) && checklowttl) || (p->window >0))
                         {
                            printf("# port %d maybe listening",p->n);
                            if (p->ttl < 65) printf(" (low ttl)");
                            if (p->window >0) printf(" (big window)");
                            printf(".\n");
                            someopen++;
                         }
                       break;
                     case 1:
                     case 2:
                       printf("# port %d has an unexpected response.\n",
                              p->n);
                       break;
                     default:
                       printf("# port %d needs to be rescanned.\n",p->n);
                    }
                  break;
                case TH_FIN:
                  switch (p->state)
                    {
                     case -1: break;
                     case 0 :
                       printf("# port %d maybe open.\n",p->n);
                       someopen++;
                       break;
                     default:
                       printf("# port %d has an unexpected response.\n",p->n);
                    }
               }
          }

        printf("-----------------------------------------------\n");
        printf("# total ports open or maybe open: %d\n\n",someopen);
        free(ports);

        exit(0);                       /* heh. */

     }

int resolve_one(const char *name, unsigned long *addr, const char *desc)
     {
        struct sockaddr_in tempaddr;
        if (resolve(name, &tempaddr,0) == -1) {
           printf("error: can't resolve the %s.\n",desc);
           return -1;
        }

        *addr = tempaddr.sin_addr.s_addr;
        return 0;
     }

void give_info(void)
     {
        printf("# response address           : %s (%s)\n",spoof_name,inet_ntoa(spoof_addr));
        printf("# target address             : %s (%s)\n",dest_name,inet_ntoa(dest_addr));
        printf("# ports                      : %s\n",portstr);
        printf("# (total number of ports)    : %d\n",maxports);
        printf("# delay between sends        : %lu microseconds\n",usecdelay);
        printf("# delay                      : %u seconds\n",waitdelay);
        printf("# flood dectection threshold : %d unanswered sends\n",STCP_THRESHOLD);
        printf("# slow factor                : %d\n",slowfactor);
        printf("# max sends per port         : %d\n\n",STCP_SENDS);
     }

int parse_args(int argc, char *argv[])
{
   if (strrchr(argv[0],'/') != NULL)
     argv[0] = strrchr(argv[0],'/') + 1;

   if (argc < 7)
   {
      printf("%s: not enough arguments\n",argv[0]);
      return -1;
   }

   switch (atoi(argv[1]))
   {
      case 0  : scanflags = TH_SYN; break;
      case 1  : scanflags = TH_FIN; break;
      case 2  : scanflags = TH_ACK; break;
      default : printf("%s: unknown scanning method\n",argv[0]);
                return -1;
   }
   spoof_name = argv[2];
   dest_name = argv[3];
   portstr = argv[4];
   usecdelay = atol(argv[5]);
   waitdelay = atoi(argv[6]);
   if (argc > 7) slowfactor = atoi(argv[7]);
   if ((usecdelay == 0) && (slowfactor > 0))
     {
        printf("%s: adjusting microsecond-delay to 1usec.\n");
        usecdelay++;
     }
   return 0;
}

int build_ports(char *str)       /* build the initial port-database */
{
   int i;
   int n;
   struct portrec *p;
   int sport;
   char *s;
   s        = str;
   maxports = 0;
   n        = 0;

   while (*s != '\0')
     {
        switch (*s)
          {
           case '0':
           case '1':
           case '2':
           case '3':
           case '4':
           case '5':
           case '6':
           case '7':
           case '8':
           case '9':
             n *= 10;
             n += (*s - '0');
             break;
           case '-':
             if (n == 0) return -1;
             sport = n;
             n = 0;
             break;
           case ',':
             if (n == 0) return -1;
             if (sport != 0)
               {
                  if (sport >= n) return -1;
                  maxports += n-sport;
                  sport = 0;
               } else
               maxports++;
             n = 0;
             break;
          }
        s++;
     }
   if (n == 0) return -1;
   if (sport != 0)
     {
        if (sport >= n) return -1;
        maxports += n-sport;
        sport = 0;
     }
   else
     maxports++;

   maxports+=2;

   if ((ports = (struct portrec *)malloc((maxports)*sizeof(struct portrec))) == NULL)
     {
        fprintf(stderr,"\nerror: not enough memory for port database\n\n");
        exit(1);
     }
   s        = str;
   maxports = 0;
   n        = 0;

   while (*s != '\0')
     {
        switch (*s)
          {
           case '0':
           case '1':
           case '2':
           case '3':
           case '4':
           case '5':
           case '6':
           case '7':
           case '8':
           case '9':
             n *= 10;
             n += (*s - '0');
             break;
           case '-':
             if (n == 0) return -1;
             sport = n;
             n = 0;
             break;
           case ',':
             if (n == 0) return -1;
             if (sport != 0)
               {
                  if (sport >= n) return -1;
                  while (sport <= n)
                    {
                       for (i=0;in == sport) break;

                       if (i < maxports-1 )
                         printf("notice: duplicate port - %d\n",sport);
                       else
                         {
                            (ports+maxports)->n = sport;
                            maxports++;
                         }
                       sport++;
                    }
                  sport = 0;
               } else
               {
                  for (i=0;in == n) break;

                  if (i < maxports-1 )
                    printf("notice: duplicate port - %d\n",n);
                  else
                    {
                       (ports+maxports)->n = n;
                       maxports++;
                    }
               }
             n = 0;
             break;
          }
        s++;
     }

   if (n == 0) return -1;
   if (sport != 0)
     {
        if (sport >= n) return -1;
        while (sport <= n)
          {
             for (i=0;in == sport) break;

             if (i < maxports-1 )
               printf("notice: duplicate port - %d\n",sport);
             else
               {
                  (ports+maxports)->n = sport;
                  maxports++;
               }
             sport++;
          }
        sport = 0;
     } else
     {
        for (i=0;in == n) break;

        if (i < maxports-1 )
          printf("notice: duplicate port - %d\n",n);
        else
          {
             (ports+maxports)->n = n;
             maxports++;
          }
     }

   printf("\n");

   for (i=0;istate = 0;
        p->sends = 0;
     }

   return 0;
}

struct portrec *portbynum(int num)
{
   int i = 0;
   while ( ((ports+i)->n != num) && (istate != 0) || (p->sends == STCP_SENDS))
          {
             doneports++;
             lastidx++;
             lastidx %= maxports;
          }
        else
          break;
     }

   if (save)
     lastidx = oldlastidx;
   else
     lastidx = (lastidx + 1) % maxports;

   if (doneports == maxports) return NULL;

   return p;
}

inline unsigned long usecdiff(struct timeval *a, struct timeval *b)
{
   unsigned long s;

   s = b->tv_sec - a->tv_sec;
   s *= 1000000;
   s += b->tv_usec - a->tv_usec;

   return s;                           /* return the stupid microsecond diff */
}

void main(int argc, char *argv[])
{
   int lastsent = 0;
    char buf[3000];
    struct iphdr  *ip   = (struct iphdr *)(buf);
   struct tcphdr *tcp  = (struct tcphdr *)(buf+sizeof(struct iphdr));
    struct sockaddr_in from;
   int fromlen;
    struct portrec *readport;
    fd_set rset, wset;
    struct timeval waitsend, now, del;
    unsigned long udiff;
    int sendthreshold = 0;

   banner();

   if (parse_args(argc,argv))
     {
        usage(argv[0]);
        return;
     }

   if (resolve_one(dest_name,
                    &dest_addr,
                    "destination host")) exit(1);

   destaddr.sin_addr.s_addr = dest_addr;
   destaddr.sin_family = AF_INET;

   if (resolve_one(spoof_name, &spoof_addr, "source host")) exit(1);

   if ( build_ports(portstr) == -1)
     {
        printf("\n%s: bad port string\n",argv[0]);
        usage(argv[0]);
        return;
     }

   give_info();

   if ((tcpsock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
     {
        printf("\nerror: couldn't get TCP raw socket\n\n");
        exit(1);
     }
   if ((rawsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
     {
        printf("\nerror: couldn't get raw socket\n\n");
        exit(1);
     }

   /* well, let's get to it. */

   done = 0;

   printf("* BEGINNING SCAN\n");
   fflush(stdout);

   gettimeofday(&waitsend,NULL);

   while (!done)
     {
        if (nextport(1) == NULL)
          {
             alarm(0);             /* no more sends, now we just  */
             signal(SIGALRM,timeout); /* to wait  seconds */
             alarm(waitdelay);        /* before resetting and giving */
          }                           /* results.                    */

        FD_ZERO(&rset);
        FD_SET(tcpsock,&rset);

        gettimeofday(&now,NULL);

        udiff = usecdiff(&waitsend,&now);

        /* here comes the multiple choice select().
         * well, there are 3 states:
         * 1. already sent all the packets.
         * 2. didn't send all the packets, but it's not time for another send
         * 3. didn't send all the packets and it is time for another send.
         */

        if (nextport(1) != NULL)
          if (udiff > usecdelay)
          {
             FD_ZERO(&wset);
             FD_SET(rawsock,&wset);
             select(FD_SETSIZE,&rset,&wset,NULL,NULL);
          } else
          {
             del.tv_sec = 0;
             del.tv_usec = usecdelay;
             select(FD_SETSIZE,&rset,NULL,NULL,&del);
          }
        else
          select(FD_SETSIZE,&rset,NULL,NULL,NULL);

        if (FD_ISSET(tcpsock,&rset))   /* process the reply */
          {
             fromlen = sizeof(from);

             recvfrom(tcpsock,&buf,3000,0,
                      (struct sockaddr *)&from,&fromlen);

             if (from.sin_addr.s_addr == destaddr.sin_addr.s_addr)
               if (ntohs(tcp->th_dport) == STCP_PORT)
               {
                  printf("* got reply");

                  readport = portbynum(ntohs(tcp->th_sport));

                  if (readport == NULL)
                    printf(" -- bad port");
                  else
                    {
                       sendthreshold = 0;
                       if (!readport->state)
                         {
                            readport->ttl    = ip->ttl;
                            readport->window = tcp->th_win;

                            if (tcp->th_flags & TH_RST)
                              {
                                 readport->state = -1;
                                 printf(" (RST)");
                                 if (readport->ttl    < 65) printf(" (short ttl)");
                                 if (readport->window > 0) printf(" (big window)");
                              }
                            else
                              if (tcp->th_flags & (TH_ACK | TH_SYN))
                              {
                                 readport->state = 1;
                                 printf(" (SYN+ACK)");
                                 tcpip_send(rawsock,&destaddr,
                                            spoof_addr,destaddr.sin_addr.s_addr,
                                            STCP_PORT,readport->n,
                                            TH_RST,
                                            readport->seq++, 0,
                                            512,
                                            NULL,
                                            0);
                              }
                            else
                              {
                                 readport->state = 2;
                                 printf(" (UNEXPECTED)");
                                 tcpip_send(rawsock,&destaddr,
                                            spoof_addr,destaddr.sin_addr.s_addr,
                                            STCP_PORT,readport->n,
                                            TH_RST,
                                            readport->seq++, 0,
                                            512,
                                            NULL,
                                            0);
                              }
                         }
                       else
                         printf(" (duplicate)");
                    }
                  printf("\n");
                  fflush(stdout);
               }
          }

        if (nextport(1) != NULL)
          if (FD_ISSET(rawsock,&wset)) /* process the sends */
          {
             readport = nextport(0);

             destaddr.sin_port = htons(readport->n);

             printf("* sending to port %d ",ntohs(destaddr.sin_port));

             readport->seq = lrand48();
             readport->sends++;

             tcpip_send(rawsock,&destaddr,
                        spoof_addr,destaddr.sin_addr.s_addr,
                        STCP_PORT,ntohs(destaddr.sin_port),
                        scanflags, readport->seq++, lrand48(),
                        512, NULL, 0);

             gettimeofday(&waitsend,NULL);

             FD_ZERO(&wset);
             printf("\n");

             if ((++sendthreshold > STCP_THRESHOLD) && (slowfactor))
               {
                  printf("\n\n -- THRESHOLD CROSSED - SLOWING UP SENDS\n\n");
                  usecdelay *= slowfactor;
                  sendthreshold = 0;
               }
          }
     }
}
/*
 * EOF
 */---
          
<== Back to main page