Logo Search packages:      
Sourcecode: paketto version File versions  Download package

scanrand.c

#include "paketto.h"
#include "pk_crypt.h"
#include "scanutil.h"
/*#include "d_services.h"*/

/* 
 * best effort has been made to audit
 * this code, but as they say...
 * never underestimate the power
 * of the turkey.
 */

void scanrand_usage();

int main(int argc, char **argv)
{
   int opt;
   extern char *optarg;
   extern int   opterr; 

   pcap_t *pcap;        /* PCAP descriptor */
   u_char *packet;            /* Our newly captured packet */
   char *p;
   char pfprogram[255];
   char dev[255];
   long source_ip  = 0;
   uint16_t source_port = 0;
   struct pcap_pkthdr pkthdr; /* PCAP packet information structure */
   struct bpf_program fp;     /* Structure to hold the compiled prog */
   char error[PCAP_ERRBUF_SIZE];          /* Structure for libpcap errors. */
   
   struct frame x, ic;
    
   int immediate = 1;
   int i,j,k,l,pid;
   float timeout = 10;
   int verify=1;
   int force_seed = 0;
   int force_sip  = 0;
   int resolve = 0;
   int send_packets = 1;
   int list_packets  = 1;
   int show_rejected =0;
   int show_accepted =1;

   int verbose = 0;

   int distco = 0;
   
   long li,lj;
   struct in_addr temp_ip, trace_ip;
   
   char buf[MX_B], buf2[MX_B], destbuf[1024], rangebuf[1024], portbuf[1024];
   char dest[MX_B];
   char *ttlrange = NULL;
   char *bandwidth = NULL;
   int check_icmp_seq = 0;
   
   u_char *seed = malloc(20);
   
   u_char *tcpscan = malloc(MX_B);
   struct libnet_link_int *temp = NULL;

   struct frame *scanx = malloc(sizeof(struct frame));

   struct timeval start, now, then, diff;

   FILE *targets, *logs;

   prng_state prng;
   pk_initrng(&prng);

   bzero(buf, sizeof(buf));
   bzero(buf2, sizeof(buf2));
      
        if(geteuid() != 0)
        {
                perror("PK requires root to access the network directly.");
                exit(EXIT_FAILURE);
        }

   p = NULL; 
   p = pcap_lookupdev(error);
   if(!p){
      fprintf(stderr, "Couldn't lookup default ethernet device with pcap_lookupdev: %s\n", error);    
      exit(EXIT_FAILURE);
   }
   snprintf(dev, sizeof(dev), "%s", p);
   
   while ((opt = getopt(argc, argv, "d:f:i:l:NSLeEs:p:t:b:cvT:D")) != EOF) {
      switch (opt) {
        case 'd':
           snprintf(dev, sizeof(dev), "%s", optarg);
           break;
      case 'f':
         targets = fopen(optarg, "r");
         break;
        case 'i':
           source_ip = ntohl(libnet_name_resolve(optarg, 0));
           force_sip++;
           break;
      case 'l':
         ttlrange = malloc(1024);
         snprintf(ttlrange, 1024, "%s", optarg);
         break;
      case 'N':
         resolve++;
         break;
      case 'S':
         list_packets = 0;
         break;
      case 'L':
         send_packets = 0;
         break;
        case 'e':
           show_rejected=1;
           break;
        case 'E':
           show_rejected=1;
           show_accepted=0;
           break;
        case 's':
         pk_sha1(seed, optarg, strlen(optarg));
         force_seed++;
           break;
        case 'p':
           source_port = atoi(optarg);
           break;
            case 't':
               timeout = atof(optarg);
               break;
        case 'b':
           bandwidth = malloc(1024);
           snprintf(bandwidth, 1024, "%s", optarg);
           break;
      case 'c':
         check_icmp_seq = 1;
         break;
      case 'v':
         verbose++;
         break;
      case 'D':
         distco++;
         break;
      default:
               scanrand_usage();
         }
   }           

   if(argv[optind] != NULL)
   {
      snprintf(buf, sizeof(buf), "%s", argv[optind]);
   }


   if(send_packets)
   {
      if(!parse_dest(dest, sizeof(dest), buf, ttlrange || targets)){
            fprintf(stderr, "Destination required.\n");
            scanrand_usage();
      }
   }

   if(!force_seed){
      yarrow_read(seed, 20, &prng);
   }
   
   if(!source_port){
      if(!force_seed){
             yarrow_read((char *)&source_port, 2, &prng);
      } else {
             pk_sha1(buf, seed, 20);      /* if you understand how paranoid this is, */
         memcpy(&source_port, buf, 2);/* you get a cookie.  This process is so a */
                                      /* single seed is sufficient to sync ports.*/
      }
   }

   if(!force_sip) source_ip=libnet_get_ipaddr(temp, dev, NULL);
   
   if(!bandwidth){
      bandwidth = malloc(1024);
      snprintf(bandwidth, 1024, "0");
      }


   if(verbose)fprintf(stderr, "Stat|=====IP_Address==|Port=|Hops|==Time==|=============Details============|\n");
   gettimeofday(&start, NULL);
   if(send_packets && list_packets) pid=fork();
   if(!pid && send_packets)
   {

      /* we're the sender */
      //sleep(1);  //give em a chance to start the listener
      usleep(100);
      //foo

      build_generic_syn(scanx); //scanx is the prototype packet
      scanx->ip->ip_src.s_addr = htonl(source_ip);
      scanx->tcp->th_sport = htons(source_port);
      if(distco)
      {
         scanx->tcp->th_flags = TH_ACK;
       scanx->ip->ip_ttl    = 216; /* XXX redundant with scanutil.  There's some
                             * interesting stuntage possible combining -D and
                             * -l; I'm intentionally making it possible to use. */
      }
      if(send_packets) raw_sock_syn_scan(dest, sizeof(dest), dev, scanx, \
                                    ttlrange, seed, bandwidth, verbose, resolve, 0);
      if(send_packets && targets)
      {
         while(fgets(dest, sizeof(dest), targets))
         {
            if(parse_dest(buf, sizeof(buf), dest, (ttlrange || targets))){    
               raw_sock_syn_scan(buf, sizeof(buf), dev, scanx, \
                              ttlrange, seed, bandwidth, verbose, resolve, 0);
               }
       }
         fclose(targets);
      }           
      free(scanx->data);
      exit(0);
   }

   /* we're the receiver */
   if(!list_packets) exit(0);

   /* Eventually, source port will be used to compute latency.  So we can't listen only
      for certain source ports...the crypto will have to authenticate all. */

   snprintf(pfprogram, sizeof(pfprogram), "tcp or icmp");
   pcap = NULL;
   pcap = pcap_open_live(dev, 65535, 1, 1, error);
   if(!pcap){
       fprintf(stderr, "Couldn't open device: %s", error);
       exit(1);
      }
       
   ioctl(pcap_fileno(pcap), BIOCIMMEDIATE, &immediate);  // prolly breaks nonblock
   
   if (pcap_compile(pcap, &fp, pfprogram, 1, 0x0) == -1) {
      pcap_perror(pcap, "pcap_compile");
      exit(EXIT_FAILURE);
   }
      
   if (pcap_setfilter(pcap, &fp) == -1) {
      pcap_perror(pcap, "pcap_setfilter");
      exit(EXIT_FAILURE);
   }
   gettimeofday(&now, NULL);
   gettimeofday(&then, NULL);

   while(!timeout || now.tv_sec <= (then.tv_sec + timeout))
   {
     packet = (u_char *) pcap_next(pcap, &pkthdr);  
     gettimeofday(&now, NULL); /* packet header sigfigs seem strange */
     if(packet &&
        parse_layers(packet, pkthdr.caplen, &x, 2, pcap_datalink(pcap), 0)){

         /* Accept ICMP packets. */
         if(x.ip->ip_p == IPPROTO_ICMP){     
            i=parse_layers((char *)&x.icmp->icmp_data,
                 pkthdr.caplen-LIBNET_ETH_H-(int)x.ip->ip_hl*4-8, /* XXX slight chance of bug */
                 &ic, 3, DLT_EN10MB , 1);
              if(i && ic.ip->ip_p == IPPROTO_TCP &&
                 x.icmp->icmp_type == ICMP_TIMXCEED){
               /* Some firewalls collapse on large numbers of connections from
                * the same local port to the same remote host.  So I varied the
                * local port according to the TTL, figuring I could extract the hops
                * travelled from the port number that returned.  But firewalls w/
                * local port randomizers don't translate the TCP chunk in the ICMP
                * error!  So we'll throw the actual info into IPID, on the assumption
                * that IPID *has* to be translated back for ICMP errors to work.
                * Ah, fun with layers...*/
               if((ic.tcp->th_sport <= htons(source_port) ||
                  ic.tcp->th_sport >= htons(source_port) - 255 &&
                  (!check_icmp_seq || ic.tcp->th_seq == bake_syncookie((char *)&ic.ip, seed))))
               {                    
                  timeval_subtract(&diff, &pkthdr.ts, &start);
                  gettimeofday(&then, NULL); /* just for the loop maintenance */
                      if(verbose){
                           fprintf(stderr, "Got %i on %s:\n", pkthdr.caplen, dev);
                           fprintf(stderr, " "); print_ip((char *)x.ip);
                     fprintf(stderr, "ICMP: "); print_ip((char *)ic.ip);
                     fprintf(stderr, "ICMP: "); print_tcp((char *)ic.tcp, 1);
                     }
                    bzero(buf, sizeof(buf));
                  bzero(buf2, sizeof(buf2));
                    /* whoa this works?! WTF */
                  snprintf(buf + 0, 16, inet_ntoa(x.ip->ip_src));
                  snprintf(buf +16, 16, inet_ntoa(ic.ip->ip_src));
                  snprintf(buf +32, 16, inet_ntoa(ic.ip->ip_dst));      
                  fprintf(stdout, "%3.3u = ", 255 - (source_port - ntohs(ic.tcp->th_sport)));
                     //fprintf(stdout, "%3.3u = ", ntohs(ic.ip->ip_id));
                     fprintf(stdout, "%16.16s|%-5i [%2.2hu]", buf,
                             ntohs(ic.tcp->th_dport), estimate_hopcount(x.ip->ip_ttl));
                     fprintf(stdout, "%4lu.%3.3lus", diff.tv_sec, diff.tv_usec/1000);
                     if(resolve==1)
                        fprintf(stdout, "(%35.35s)\n", libnet_host_lookup(x.ip->ip_src.s_addr, 1));
                     else if(resolve==2)
                        fprintf(stdout, "(%35.35s)\n", libnet_host_lookup(ic.ip->ip_dst.s_addr, 1)); 
                     else fprintf(stdout, "(%16.16s -> %-16.16s)\n", buf+16, buf+32);
               }
            }
            else if(x.icmp->icmp_type == ICMP_UNREACH)
               {
               if(ic.ip->ip_p == IPPROTO_TCP && /* no TCP flags in ICMP's TCP chunklet */
                  (!check_icmp_seq || ic.tcp->th_seq == bake_syncookie((u_char *)ic.ip, seed)))
                    {
                  timeval_subtract(&diff, &pkthdr.ts, &start);
                  gettimeofday(&then, NULL); /* just for the loop maintenance */
                  snprintf(buf2, sizeof(buf2), "un%2.2i", x.icmp->icmp_code);
                  snprintf(buf + 0, 16, inet_ntoa(x.ip->ip_src));
                  snprintf(buf +16, 16, inet_ntoa(ic.ip->ip_src));
                  snprintf(buf +32, 16, inet_ntoa(ic.ip->ip_dst));      
                  fprintf(stdout, "%s: %16.16s:%-5i [%2.2hu]",
                       buf2, buf+32, ntohs(ic.tcp->th_dport),
                       estimate_hopcount(x.ip->ip_ttl)); 
                  fprintf(stdout, "%4lu.%3.3lus", diff.tv_sec, diff.tv_usec/1000);                                                                      
                  if(resolve==1)
                     fprintf(stdout, "(%35.35s)\n", libnet_host_lookup(x.ip->ip_src.s_addr, 1));
                  else if(resolve==2)
                     fprintf(stdout, "(%35.35s)\n", libnet_host_lookup(ic.ip->ip_dst.s_addr, 1));
                  else       fprintf(stdout, "(%16.16s -> %-16.16s)\n", buf+16, buf);              
                     }
               }
              
           }
           /* Accept SYN|ACKs and RST|ACKs */
         else if(
             x.ip->ip_p == IPPROTO_TCP && 
            (x.tcp->th_flags == (TH_SYN | TH_ACK) ||
             x.tcp->th_flags == (TH_RST | TH_ACK) ||
             x.tcp->th_flags == (TH_RST         ))&& /* XXX small attack here */
             munch_syncookie((u_char *)x.ip, seed))
            {
                if(verbose>=2){
                     fprintf(stderr, "Got %i on %s:\n", pkthdr.caplen, dev);
                     fprintf(stderr, " "); print_ip((char *)x.ip);
               fprintf(stderr, " "); print_tcp((char *)x.tcp, 0);
               }
            gettimeofday(&then, NULL); /* just for the loop maintenance */
            bzero(buf, sizeof(buf));
            bzero(buf2, sizeof(buf2));
            timeval_subtract(&diff, &now, &start);
            if(x.tcp->th_flags == (TH_SYN | TH_ACK) && show_accepted) snprintf(buf2, sizeof(buf2), "  UP"); /* merry christmas */
            if(x.tcp->th_flags == (TH_RST | TH_ACK) && show_rejected) snprintf(buf2, sizeof(buf2), "DOWN"); /* happy holidays */
            if(x.tcp->th_flags == (TH_RST         )                 ) snprintf(buf2, sizeof(buf2), "DSCO"); /* santa got his ass handed to him */
            if((int)buf2[0]) /* :-P */
               {
               fprintf(stdout, "%s: %16.16s:%-5i [%2.2hu]", buf2, inet_ntoa(x.ip->ip_src), ntohs(x.tcp->th_sport), estimate_hopcount(x.ip->ip_ttl));
               fprintf(stdout, "%4lu.%3.3lus", diff.tv_sec, diff.tv_usec/1000);
               if(resolve)fprintf(stdout, "(%35.35s)\n", libnet_host_lookup(x.ip->ip_src.s_addr, 1));
               else       fprintf(stdout, "\n"); /*fprintf(stdout, "(%29.29s)\n", buf); */
               }
            }
         }
        }
        if(send_packets && list_packets){
        kill(pid, SIGKILL);
        waitpid(pid, error, 0);
      }
   }

void scanrand_usage()
{
   fprintf(stderr, "scanrand %s: Stateless TCP Scanner w/ Inverse SYN Cookies(HMAC-SHA1/32 in SEQ)\n", VERSION);
   fprintf(stderr, "Component of:  Paketto Keiretsu %s;    Dan Kaminsky  (dan@doxpara.com)\n", VERSION);
   fprintf(stderr,  "     Example:  scanrand -b10M 10.0.1.1-254:80,20-25,139\n");
   fprintf(stderr, "  Def. Ports:  Use  [quick/squick/known/all] instead of explicitly naming ports\n"); 
   fprintf(stderr, "     Options:  -S/-L:    Only send requests      / Only listen for responses\n");
   fprintf(stderr, "               -e/-E:    Show negative responses / Only show negative responses\n");
   fprintf(stderr, "               -t  [timeout]: Wait n full seconds for the last response   (10s)\n");   
   fprintf(stderr, "               -b[bandwidth]: Limit bandwidth consumption to n b/k/m/g bytes(0)\n");
   fprintf(stderr, "                              (0 supresses timeouts or maximizes bw utilization)\n");   
   fprintf(stderr, "               -N/-NN       : Enable name resolution (Prefer Source/Dest)\n");   
   fprintf(stderr, "               -v           : Mark packets being sent, as well as received\n");
   fprintf(stderr, "               -vv          : Output full packet traces to stderr\n");      
   fprintf(stderr, "  Addressing:  -d   [device]: Send requests from this L2 hardware device\n");
   fprintf(stderr, "               -i   [source]: Send requests from this L3 IP address\n");
   fprintf(stderr, "               -p   [  port]: Send requests from this L4 TCP Port\n");
   fprintf(stderr, "               -s   [  seed]: Use prespecified seed for scan verification\n");
   fprintf(stderr, "               -f   [  file]: Read list of targets from file\n");   
   fprintf(stderr, " Experiments:  -l  [ttl-ttl]: Statelessly TCP Traceroute\n");
   fprintf(stderr, "               -D           : Distco (Distance Discover) via forced RSTs\n");
   fprintf(stderr, "               -c           : Try checking Inverse SYN Cookie on Traceroute\n");
   fprintf(stderr, "       Notes:                 Use Control-C to exit before scanrand times out.\n");  
   fprintf(stderr, "                              Be sure to use a longer timeout for slow scans!\n");  
   fprintf(stderr, "                              [n]: estimated network distance from target host.\n");  
   fprintf(stderr, "                              Be careful about available bandwidth -- use -b!\n");
   exit(1);
}

Generated by  Doxygen 1.6.0   Back to index