COMMAND talkd SYSTEMS AFFECTED FreeBSD 1.0, 1.1, 2.1.0, 2.1.5, 2.1.6, 2.1.6.1 PROBLEM talk is a communication program which copies text from one users terminal to that of another, possibly remote, user. talkd is the daemon that notifies a user that someone else wishes to initiate a conversation. As part of the talk connection, talkd does a DNS lookup for the hostname of the host where the connection is being initiating from. Due to insufficient bounds checking on the buffer where the hostname is stored, it is possible to overwrite the internal stack space of talkd. By carefully manipulating the hostname information, it is possible to force talkd to execute arbitrary commands. As talkd runs with root privileges, this may allow intruders to remotely execute arbitrary commands with these privileges. This attack requires an intruder to be able to make a network connection to a vulnerable talkd program and provide corrupt DNS information to that host. Intruders may be able to remotely execute arbitrary commands with root privileges. Access to a valid user account on the local system is not required. Credit for this goes to AUSCERT. SOLUTION Recent versions of FreeBSD 2.2 -current may not be affected with this vulnerability due to improved security in new versions of BIND, which sanity-check the results of reverse name lookups performed by the DNS system. Workaround would be to disable the ntalkd program found in /etc/inetd.conf by commenting the appropriate line out and reconfiguring inetd. # grep -i ntalk /etc/inetd.conf ntalk dgram udp wait root /usr/libexec/ntalkd ntalkd After editing /etc/inetd.conf, reconfigure inetd by sending it a HUP signal. # kill -HUP `cat /var/run/inetd.pid` Patches that follows were based off of published work provided by BSDI, Inc. After applying these patches, recompile and re-install the affected utilities. For FreeBSD -current (2.2 prerelease and 3.0 prerelease) systems: Index: announce.c =================================================================== RCS file: /cvs/freebsd/src/libexec/talkd/announce.c,v retrieving revision 1.6 diff -u -r1.6 announce.c --- announce.c 1997/01/14 06:20:58 1.6 +++ announce.c 1997/01/18 08:27:04 @@ -34,7 +34,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)announce.c 8.2 (Berkeley) 1/7/94"; +static char sccsid[] = "@(#)announce.c 8.3 (Berkeley) 4/28/95"; #endif /* not lint */ #include @@ -43,13 +43,17 @@ #include #include #include + #include + #include -#include -#include +#include #include +#include #include -#include +#include +#include +#include extern char hostname[]; @@ -78,7 +82,7 @@ #define max(a,b) ( (a) > (b) ? (a) : (b) ) #define N_LINES 5 -#define N_CHARS 120 +#define N_CHARS 256 /* * Build a block of characters containing the message. @@ -100,33 +104,37 @@ char line_buf[N_LINES][N_CHARS]; int sizes[N_LINES]; char big_buf[N_LINES*N_CHARS]; - char *bptr, *lptr, *ttymsg(); + char *bptr, *lptr, *vis_user; int i, j, max_size; i = 0; max_size = 0; gettimeofday(&clock, &zone); localclock = localtime( &clock.tv_sec ); - (void)sprintf(line_buf[i], " "); + (void)snprintf(line_buf[i], N_CHARS, " "); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], "Message from Talk_Daemon@%s at %d:%02d ...", - hostname, localclock->tm_hour , localclock->tm_min ); + (void)snprintf(line_buf[i], N_CHARS, + "Message from Talk_Daemon@%s at %d:%02d ...", + hostname, localclock->tm_hour , localclock->tm_min ); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], "talk: connection requested by %s@%s", - request->l_name, remote_machine); + + vis_user = malloc(strlen(request->l_name) * 4 + 1); + strvis(vis_user, request->l_name, VIS_CSTYLE); + (void)snprintf(line_buf[i], N_CHARS, + "talk: connection requested by %s@%s", vis_user, remote_machine); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], "talk: respond with: talk %s@%s", - request->l_name, remote_machine); + (void)snprintf(line_buf[i], N_CHARS, "talk: respond with: talk %s@%s", + vis_user, remote_machine); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], " "); + (void)snprintf(line_buf[i], N_CHARS, " "); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; Index: talkd.c =================================================================== RCS file: /cvs/freebsd/src/libexec/talkd/talkd.c,v retrieving revision 1.5 diff -u -r1.5 talkd.c --- talkd.c 1997/01/14 06:21:01 1.5 +++ talkd.c 1997/01/18 08:26:44 @@ -71,7 +71,7 @@ void timeout(); long lastmsgtime; -char hostname[MAXHOSTNAMELEN]; +char hostname[MAXHOSTNAMELEN + 1]; #define TIMEOUT 30 #define MAXIDLE 120 For FreeBSD 2.1 based systems: --- announce.c 1995/05/30 05:46:38 1.3 +++ announce.c 1997/01/18 08:33:55 1.3.4.1 @@ -32,7 +32,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)announce.c 8.2 (Berkeley) 1/7/94"; +static char sccsid[] = "@(#)announce.c 8.3 (Berkeley) 4/28/95"; #endif /* not lint */ #include @@ -41,15 +41,18 @@ #include #include #include + #include -#include + #include -#include -#include +#include #include +#include #include -#include - +#include +#include +#include + extern char hostname[]; /* @@ -77,7 +80,7 @@ #define max(a,b) ( (a) > (b) ? (a) : (b) ) #define N_LINES 5 -#define N_CHARS 120 +#define N_CHARS 256 /* * Build a block of characters containing the message. @@ -99,33 +102,37 @@ char line_buf[N_LINES][N_CHARS]; int sizes[N_LINES]; char big_buf[N_LINES*N_CHARS]; - char *bptr, *lptr, *ttymsg(); + char *bptr, *lptr, *vis_user; int i, j, max_size; i = 0; max_size = 0; gettimeofday(&clock, &zone); localclock = localtime( &clock.tv_sec ); - (void)sprintf(line_buf[i], " "); + (void)snprintf(line_buf[i], N_CHARS, " "); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], "Message from Talk_Daemon@%s at %d:%02d ...", - hostname, localclock->tm_hour , localclock->tm_min ); + (void)snprintf(line_buf[i], N_CHARS, + "Message from Talk_Daemon@%s at %d:%02d ...", + hostname, localclock->tm_hour , localclock->tm_min ); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], "talk: connection requested by %s@%s", - request->l_name, remote_machine); + + vis_user = malloc(strlen(request->l_name) * 4 + 1); + strvis(vis_user, request->l_name, VIS_CSTYLE); + (void)snprintf(line_buf[i], N_CHARS, + "talk: connection requested by %s@%s", vis_user, remote_machine); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], "talk: respond with: talk %s@%s", - request->l_name, remote_machine); + (void)snprintf(line_buf[i], N_CHARS, "talk: respond with: talk %s@%s", + vis_user, remote_machine); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; - (void)sprintf(line_buf[i], " "); + (void)snprintf(line_buf[i], N_CHARS, " "); sizes[i] = strlen(line_buf[i]); max_size = max(max_size, sizes[i]); i++; Index: talkd.c =================================================================== RCS file: /home/ncvs/src/libexec/talkd/talkd.c,v retrieving revision 1.3 retrieving revision 1.3.4.1 diff -u -r1.3 -r1.3.4.1 --- talkd.c 1995/05/30 05:46:44 1.3 +++ talkd.c 1997/01/18 08:33:56 1.3.4.1 @@ -69,7 +69,7 @@ void timeout(); long lastmsgtime; -char hostname[MAXHOSTNAMELEN]; +char hostname[MAXHOSTNAMELEN + 1]; #define TIMEOUT 30 #define MAXIDLE 120