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

lc.c

#include <stdio.h>
#include <libnet.h>
#include <pcap.h>

#include "paketto.h"
#include "pk_crypt.h"

#define BFT

#define TRAILER_SHA1 1
#define TRAILER_ECC  2

struct pcap_state
{
      pcap_t         *pcap;   /* PCAP descriptor */
      u_char         *packet; /* Our newly captured packet */
      struct pcap_pkthdr pkthdr;    /* PCAP packet information structure */
      struct bpf_program fp;  /* Structure to hold the compiled prog */
      char            pfprogram[1024];
      char            dev[255];

      struct pcap_dumper_t *dump;
};

void lc_usage();
int pk_pcap_hexdump(FILE *stream, struct pcap_pkthdr *pkthdr, u_char *packet, int max, int reverse);
int pk_lc_addtrailer(char *buf, int bufsize, struct pcap_pkthdr *pkthdr, u_char *packet);
int pk_lc_l2send(struct link_state *ls, struct pcap_pkthdr *pkthdr, u_char *packet);
char *pk_fgets(char *buf, int length, FILE *stream);
int is_hex(char val);
char htoc(char b1, char b2);

struct pcap_state sniff, spoof;  // so we can close

int hexdump_from = 0;
int hexdump_to   = 0;
int reverse = 0;
int maxc = 76;
int verbose = 0;
int spoof_stderr;

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

      char        buf[65536];
      char        pbuf[2048] = ""; /* alas, no jumboframe support */
      char        type = 'h';
      unsigned char   c;
      struct pcap_pkthdr fake_pkthdr;     /* Needed for ASCII pcap spoof */

      char        error[PCAP_ERRBUF_SIZE];
      int             immediate, promisc = 1;
      int         i, j, k;
      int         pid;

      int         strip_hash = 0;
      
      int         spoof_packets = 0;
      int         sniff_packets = 0;
      char        sniff_file[4096] = "-";
      char        spoof_file[4096] = "-";


      char        spoof_key[20];
      char        sniff_key[20];
      int         trailer_sniff = 0;
      int         trailer_spoof = 0;
      struct link_state *ls = malloc(sizeof(struct link_state));

      prng_state prng;
      pk_initrng(&prng);
      
      if(geteuid() != 0)
        {
                perror("PK requires root to access the network directly.\n");
                exit(EXIT_FAILURE);
        }

      /* streams */
      setvbuf(stdin, NULL, _IONBF, 0);
      setvbuf(stdout, NULL, _IONBF, 0);

      /* network -> stdin pcap [in] */
      snprintf(sniff.pfprogram, sizeof(sniff.pfprogram), "");

      /* stdin pcap -> network [out] */
      snprintf(spoof.pfprogram, sizeof(spoof.pfprogram), "");

      while ((opt = getopt(argc, argv, "l:m:p:P:w:r:L:M:t:c:o:O:veS")) != EOF) {
            switch (opt) {
            case 'l':
                  sniff_packets = 1;
                  if(!strncmp(optarg, "00", 3)){
                        snprintf(sniff.dev, sizeof(sniff.dev), "%s", pcap_lookupdev(error));
                  } else {                      
                        snprintf(sniff.dev, sizeof(sniff.dev), "%s", optarg);
                  }
                  break;
            case 'm':
                  spoof_packets = 1;
                  if(!strncmp(optarg, "00", 3)){
                        snprintf(spoof.dev, sizeof(spoof.dev), "%s", pcap_lookupdev(error));
                  } else {                      
                        snprintf(spoof.dev, sizeof(spoof.dev), "%s", optarg);
                  }
                  break;
            case 'p':   /* Filter Incoming */
                  snprintf(sniff.pfprogram, sizeof(sniff.pfprogram), "%s", optarg);
                  break;
            case 'P':   /* Filter Outgoing */
                  snprintf(spoof.pfprogram, sizeof(spoof.pfprogram), "%s", optarg);
                  break;
            case 'w':
                  snprintf(sniff_file, sizeof(sniff_file), "%s", optarg);
                  break;
            case 'r':
                  snprintf(spoof_file, sizeof(spoof_file), "%s", optarg);
                  break;                  
            case 'v':
                  verbose++;
                  break;                  
            case 'e':
                  spoof_stderr++;
                  break;
            case 'M':
                  pk_sha1(spoof_key, optarg, strlen(optarg));
                  trailer_spoof = TRAILER_SHA1;
                  break;
            case 'L':
                  pk_sha1(sniff_key, optarg, strlen(optarg));
                  trailer_sniff = TRAILER_SHA1;
                  break;
            case 'S':
                  strip_hash++;
                  break;
            case 't':
                  type=*optarg;
                  if(type != 'p' && type != 'h'){
                        fprintf(stderr, "Invalid type:  Only _h_ex and _p_cap supported.\n");
                        lc_usage();
                  }
                  break;
            case 'o':
            case 'O':
                  i=sscanf(optarg, "%u-%u", &hexdump_from, &hexdump_to);
                  if(i!=2){
                        fprintf(stderr, "Invalid byterange: %s", optarg);
                        lc_usage();
                  }
                  if(opt=='O') reverse=1;
                  break;
            case 'c':
                  maxc = atoi(optarg);
                  break;
            default:
                  lc_usage();
                  break;
            }
      }                 

      if(!sniff_packets && !spoof_packets )lc_usage();      

      if(sniff_packets) {
            /* Read packets off the network */
            sniff.pcap = pcap_open_live(sniff.dev, 65535, promisc, 1, error);
            if (sniff.pcap == NULL) {
                  perror("pcap_open_live");
                  exit(EXIT_FAILURE);
            }
            if (ioctl(pcap_fileno(sniff.pcap), BIOCIMMEDIATE, &immediate)) {
                  /*perror("Couldn't set BPF to Immediate Mode.");*/
            }
            /* Compile and set the filter program */
            if (pcap_compile(sniff.pcap, &sniff.fp, sniff.pfprogram, 1, 0x0) == -1) {
                  pcap_perror(sniff.pcap, "pcap_compile");
                  exit(EXIT_FAILURE);
            }
            if (pcap_setfilter(sniff.pcap, &sniff.fp) == -1) {
                  pcap_perror(sniff.pcap, "pcap_setfilter");
                  exit(EXIT_FAILURE);
            }      

            /* prepare for printing text */
            switch(type){
                  case 'p':
                        sniff.dump = (void *)pcap_dump_open(sniff.pcap, sniff_file);
                        break;
                  case 'h':
                        if(sniff_file[0]=='-' &&
                           sniff_file[1]==0)    (void *)sniff.dump = stdout;
                        else sniff.dump = (void *)fopen(sniff_file, "w");
                        if(!sniff.dump){
                              fprintf(stderr, "Couldn't open file: %s\n", sniff.dump);
                              lc_usage();
                        }
                        break;
            }
            setvbuf((void *)sniff.dump, NULL, _IONBF, 0); /* XXX hi i'm too lazy to write a signal handler */

      }
      
      if(spoof_packets) {
            switch(type){
                  case 'p':
                        spoof.pcap = pcap_open_offline(spoof_file, error);
                        if (spoof.pcap == NULL) {
                              perror("pcap_open_offline");
                              exit(EXIT_FAILURE);
                        }
                  
                        /* Compile and set the filter program */
                        if (pcap_compile(spoof.pcap, &spoof.fp, spoof.pfprogram, 1, 0x0) == -1) {
                              pcap_perror(spoof.pcap, "pcap_compile");
                              exit(EXIT_FAILURE);
                        }
                        if (pcap_setfilter(spoof.pcap, &spoof.fp) == -1) {
                              pcap_perror(spoof.pcap, "pcap_setfilter");
                              exit(EXIT_FAILURE);
                        }           
                        break;
                  case 'h':
                        if(spoof_file[0]=='-' &&
                           spoof_file[1]==0)    (void *)spoof.pcap = stdin;
                        else spoof.pcap = (void *)fopen(spoof_file, "r");
                        if(!spoof.pcap){
                              fprintf(stderr, "Couldn't open file: %s\n", spoof.pcap);
                              lc_usage();
                        }
                        break;
                  }     
            ls->pcap = (void *)spoof.pcap;
            ls->trailer = trailer_spoof;
            if(ls->trailer) memcpy(&(ls->key), &spoof_key, sizeof(spoof_key));
            snprintf(ls->dev, sizeof(ls->dev), "%s", spoof.dev);
      }

      pid=0;
      pid=fork(); 
      while(1){
            /* this code sucks ... less than it did */
            i=1;
            if(!pid){
                  if(sniff_packets){
                     (void *)sniff.packet = pcap_next(sniff.pcap, &(sniff.pkthdr));
                     if(!sniff.packet) continue; /* network has "infinite packets, but there's blocking */
                     if(trailer_sniff){
                        pk_hmac(buf, sniff_key, sniff.packet, sniff.pkthdr.caplen-21);
                        //if(!memcmp(buf, &(sniff.packet[sniff.pkthdr.caplen-19]), 20))i++;
                        for(k=0; k<20; k++)
                        {
                              if((char)buf[0+k] != (char)sniff.packet[sniff.pkthdr.caplen-20+k]){
                                    i=0;
                                    k=20;
                              }
                        }
                        if(i && verbose)fprintf(stderr, "Found good!\n");
                        else if(verbose)fprintf(stderr, "Found bad!\n");
                        if(strip_hash) sniff.pkthdr.caplen-=20;
                     }
                     if(i && type=='p') pcap_dump((void *)sniff.dump, &(sniff.pkthdr), sniff.packet);
                     if(i && type=='h') pk_pcap_hexdump((void *)sniff.dump, &(sniff.pkthdr), sniff.packet, maxc, reverse);
                  }
            } else {
                  if(spoof_packets){
                     bzero(pbuf, sizeof(pbuf));
                     switch(type){
                        case 'p':
                           if(!pcap_dispatch(spoof.pcap, 0, (void *)pk_lc_l2send, (void *)ls))
                                 exit(0);
                           break;
                        case 'h':
                           /* we can't use fgets -- our lines are too big */
                           while(pk_fgets(buf, sizeof(buf), (FILE *)spoof.pcap)){
                              i=0;
                              j=0;
                              while(buf[i]==' '  && i<sizeof(buf))i++;
                              while(i<sizeof(buf) &&
                                    is_hex(buf[i]) &&
                                    is_hex(buf[i+1])){
                                    pbuf[j]=htoc(buf[i], buf[i+1]);
                                    i+=2;
                                    j++;
                                    while(buf[i]==' ' && i<sizeof(buf)){
                                          i++;
                                    }
                              }
                              if(j)
                              {     fake_pkthdr.caplen = j; 
                                    pk_lc_l2send((void *)ls, &fake_pkthdr, (void *)pbuf);
                              }
                           } 
                     }
                     kill(pid, SIGKILL);
                     wait(pid);
                     exit(0);
               }
            }                       
      }
      
}

char *pk_fgets(char *buf, int length, FILE *stream)
{
      int i, j;
      bzero(buf, length);
      if(feof(stream)) return(NULL);

      for(i=0; i<length; i++)
      {
            buf[i]=getc(stream);
            if(buf[i]=='\\'){
                  while(getc(stream)!='\n') if(feof(stream)) return(NULL);
                  buf[i]=getc(stream);
            }
            if(buf[i]=='\r'){
                  getc(stream);
                  buf[i]=getc(stream);
            }
            if(buf[i]=='\n') return(buf);
      }
      return(buf);
}

int is_hex(char val)
{
      if((val >= '0' && val <= '9') ||
         (val >= 'a' && val <= 'f')) {
            return(1);
      }
      return(0);
}

char htoc(char b1, char b2)
{
      char i,j,k;
      char buf[8];
      buf[0] = b1;
      buf[1] = b2;
      buf[2] = 0 ;
      if(i=strtoul(buf, NULL, 16)){
            return(i);
      } else  return(0);
      exit(0);
}

int pk_lc_addtrailer(char *buf, int bufsize, struct pcap_pkthdr *pkthdr, u_char *packet)
{
      if((pkthdr->caplen + bufsize) > 65535) return(0);
      memcpy(packet+(pkthdr->caplen)+1, buf, bufsize);
      pkthdr->caplen+=bufsize;
      return(1);
}

int pk_lc_l2send(struct link_state *ls, struct pcap_pkthdr *pkthdr, u_char *packet)
{
      int i;
      struct frame x;
      char error[4096]; /* XXX */
      struct libnet_link_int *link;
      char hash[20];

      if(ls->trailer){
            pk_hmac(hash, ls->key, packet, pkthdr->caplen);
            pk_lc_addtrailer(hash, 20, pkthdr, packet);
      }
      if(ls->link == NULL)
      {
            /* libnet */
            if ((ls->link = libnet_open_link_interface(ls->dev, error)) == NULL) {
                  fprintf(stderr, "Libnet failure opening link interface: %s", error);
                  exit(1);
            }
      }
      
      if(spoof_stderr) pk_pcap_hexdump(stderr, pkthdr, packet, maxc, reverse);
      i = libnet_write_link_layer(ls->link, ls->dev, packet, pkthdr->caplen);
      return(i);
}
int pk_pcap_hexdump(FILE *stream, struct pcap_pkthdr *pkthdr, u_char *packet, int max, int reverse)
{
      int i=0;
      int j=pkthdr->caplen-1;
      int k;
      /* evil evil globals */
      if(hexdump_from) i=hexdump_from-1;
      if(hexdump_to)   j=hexdump_to-1;
      if(hexdump_from > pkthdr->caplen) return(0);
      if(hexdump_to   > pkthdr->caplen) return(0);
      
      if(!hexdump_from)
      {
            for(/*i already set*/k=0;i<=j; i++)
            {
                  if(k>max){
                              fprintf(stream, "\\\n");
                          k=0;
                  }
                  fprintf(stream, "%2.2x ", packet[i]);
                  k+=3;

            }
      } else {
            fprintf(stream, "0x"); /* tells strtoul to go hex */
            if(reverse){
                  while(j>=i){
                        fprintf(stream, "%2.2hx", packet[j]);
                        j--;
                  }
            } else {
                  while(i<=j){
                        fprintf(stream, "%2.2hx", packet[i]);
                        i++;
                  }
            }
      }

      fprintf(stream, "\n");
      return(i);
}
                  
  

void lc_usage() 
{ 
   fprintf(stderr, "          lc:  Linkcat %s:  Low Latency stdio <-> Layer 2 Filtering Bridge\n", VERSION); 
   fprintf(stderr, "Component of:  Paketto Keiretsu %s;    Dan Kaminsky  (dan@doxpara.com)\n", VERSION);
   fprintf(stderr, "       Usage:  lc   [options]  [-l sniff->stdout] [-m stdin->spoof]\n\n"); 
   fprintf(stderr, "    Examples:  lc -l00 -p icmp   # sniff icmp packets, dump to stdout in hex\n");
   fprintf(stderr, "               lc -m00 -r dump   # spoof all hex packets found in file \"dump\"\n");
   fprintf(stderr, "     Options:  -l    [device]: Sniff packets from  this interface onto stdout\n");
   fprintf(stderr, "               -m    [device]: Spoof packets   to  this interface from stdin\n");
   fprintf(stderr, "               -p    [filter]: Filter interface before dumping to stdout\n");
   fprintf(stderr, "               -P    [filter]: Filter stdin before dumping to interface\n");
   fprintf(stderr, "               -w      [file]: Write sniff packets to file instead of stdout\n");
   fprintf(stderr, "               -r      [file]: Read spoofed packets from file instead of stdin\n");
   fprintf(stderr, "               -t       [h/p]: Operate on HEX text / Operate on Libpcap Dumps(h)\n");
   fprintf(stderr, "               -o       [m-n]: In Hex Mode, only emit the mth through nth bytes\n");
   fprintf(stderr, "               -O       [m-n]: Same as -b, but reverse the byte order\n");
   fprintf(stderr, "               -e            : Output spoofed bytes to stderr in hex form\n");
   fprintf(stderr, "               -c            : Limit line length to c characters (76)\n");
   fprintf(stderr, " Experiments:  -L       [key]: Verify HMAC-SHA1 hash from Ethernet Trailer\n"); 
   fprintf(stderr, "               -M       [key]: Insert HMAC-SHA1 hash into Ethernet Trailer\n");
   fprintf(stderr, "               -S            : Strip  hash upon successful verification\n");
   fprintf(stderr, "     WARNING:  Crypto is highly experimental and extremely vulnerable to Replay!\n");
   fprintf(stderr, "               This is just a basic demo of Ethernet Trailer Crypto.\n");    
   fprintf(stderr, "       Notes:  \"00\" as an interface will be replaced with any available.\n");
   exit(1);
}


Generated by  Doxygen 1.6.0   Back to index