TUCoPS :: Web :: PHP :: web5672.htm

PHP header() CRLF Injection
9th Sep 2002 [SBWID-5672]

		PHP header() CRLF Injection


		PHP 4.1.2, 4.2.2, 4.2.3 possibly others


		Matthew Murphy [mattmurphy@kc.rr.com] found :

		PHP's header() function is used to modify  HTTP  header  information  by
		specifying a header line, such as this:

		<?php header("Location: http://www.yahoo.com/"); ?>


		It is commonplace to see things such as this:

		--- REDIR.PHP ---

		<?php header("Location: $_GET['$url']"); ?>

		--- REDIR.PHP ---







		Will cause a series of lines to be produced:

		HTTP/1.1 302 Found

		Server: Xitami

		Date: Sat, 07 Sep 2002 21:50:17 GMT

		Content-length: 96

		Content-type: text/html

		X-powered-by: PHP/4.2.3

		{Location: http://www.yahoo.com/



		<SCRIPT>alert(document.cookie)</SCRIPT><!--}        <-- See our code in between the brackets

		Content-type: text/html


		The HTML produced is "broken" -- that  is,  it  doesn't  comply  to  RFC
		standards, because it doesn't have a "-->" tag. I did  this  to  supress
		the stupid "Content-type" header that PHP was dumping in the response.

		By using this, attackers can perform  cross-site  scripting  attacks  or
		initiate  downloads,  in  rare  cases  (via  HTTP   headers,   such   as
		content-dispostion, etc.)


		 Update (10 september 2002)



		Ulf Harnhammar adds [ulfh@update.uu.se] [http://www.metaur.nu] :

		PHP  has  several  functions  that  take  filenames  as  one  of   their
		arguments: fopen(), file() and some others. If  allow_url_fopen  is  set
		to On in php.ini, those functions also accept URLs  instead  of  regular
		files, and they connect to the  server  in  question  with  the  correct
		protocol. This  functionality  is  vulnerable  to  some  CRLF  Injection

		1) We start with the simple attacks. Let's say that this PHP snippet  is
		saved as snippet.php:



		echo '<pre>';




		echo '</pre>';




		If an attacker surfs to:




		(should be on one line)


		this HTTP query will be sent to www.site1.st:

		GET /api?sunnan=visby&vind=gotland HTTP/1.0

		Host: www.site2.st

		User-Agent: Ulf/0.0

		Referer: http://www.gnuheter.org/

		Cookie: user=ulf



		Host: www.site1.st

		User-Agent: PHP/4.1.2


		As you can see, the real headers from PHP are sent as well, but the  web
		server ignores them, as we send two CRLFs before them to  indicate  that
		the headers are over.

		Using this technique, we can add arbitrary  user  agents,  referers  and
		cookies. We can also break  out  of  restrictions  and  access  site2.st
		instead of the site site1.st that snippet.php tries to restrict  us  to,
		if site1.st and site2.st are virtual hosts on the same machine.

		2) If the PHP script is even worse, like this one called dotcom.php:



		$fp = fopen($url, 'r');





		we can connect to arbitrary ports and send (almost) arbitrary  commands,
		thus turning the dotcom.php script into a proxy and an open mail relay.

		If we surf to:





		(should be on one line)


		the PHP interpreter will connect to mail.site1.st on port 25,  and  send
		the following commands:

		GET / HTTP/1.0

		HELO my.own.machine

		MAIL FROM:<me@my.own.machine>

		RCPT TO:<info@site1.st>


		i will never say the word PROCRASTINATE again





		Host: mail.site1.st:25

		User-Agent: PHP/4.1.2


		Both PHP and the MTA will complain, but the mail is still sent.


		For more information about this group of problems, read  Ulf  Harnhammar
		"CRLF Injection" paper, which is available at





		 Workarounds :



		One solution is to make sure that all variables that are  used  in  this
		type of URL are clean, by including this command in your PHP scripts:

		$var = preg_replace('/\s+/', '', $var);


		Another solution: if your scripts don't need to access URLs like  files,
		you can switch off that functionality by setting allow_url_fopen to  Off
		in php.ini.

		 Update (13 spetember 2002)



		Stefan Esser [http://www.php.net], patched  PHP  for  that  purpose  and
		comments :


		Your fopen() thing does only occur if the  programmer  does  TWO  stupid
		things: A) pass  user  input  directly  to  a  function  without  proper
		validation, B) pass an url to a function that is not an url. Any  string
		that contains control chars cannot be a valid url.  Before  you  pass  a
		string that should be an url to any function you  MUST  urlencode()  it.
		No need for your reg expression at all.


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