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 <sys/types.h>
    @@ -43,13 +43,17 @@
     #include <sys/time.h>
     #include <sys/wait.h>
     #include <sys/socket.h>
    +
     #include <protocols/talkd.h>
    +
     #include <errno.h>
    -#include <syslog.h>
    -#include <unistd.h>
    +#include <paths.h>
     #include <stdio.h>
    +#include <stdlib.h>
     #include <string.h>
    -#include <paths.h>
    +#include <syslog.h>
    +#include <unistd.h>
    +#include <vis.h>

     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 <sys/types.h>
    @@ -41,15 +41,18 @@
     #include <sys/time.h>
     #include <sys/wait.h>
     #include <sys/socket.h>
    +
     #include <protocols/talkd.h>
    -#include <sgtty.h>
    +
     #include <errno.h>
    -#include <syslog.h>
    -#include <unistd.h>
    +#include <paths.h>
     #include <stdio.h>
    +#include <stdlib.h>
     #include <string.h>
    -#include <paths.h>
    -
    +#include <syslog.h>
    +#include <unistd.h>
    +#include <vis.h>
    +
     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