TUCoPS :: Web :: PHP :: php2.htm

PHP programs which provide file upload capability retrieve arbitrary files
Vulnerability

    php

Affected

    _Almost_ any PHP program which provides file upload capability

Description

    Following is based on a  Secure Reality Pty Security Advisory  #1.
    They found this particular issue a while ago but were planning  to
    disclose it at a  later date once we  had a chance to  investigate
    its imact on  most popular PHP  software.  However,  the issue was
    recently  half  found/disclosed  by  a  poster  on the php-general
    mailing list, who didn't appear to realise its impact.

    PHP is  a feature  heavy web  scripting language  that has  become
    widely popular.  One of its many features is easy handling of file
    uploads from remote browsers.  This functionality is very commonly
    used, particularly  in photo  gallery, auction  and webmail  style
    applications.

    The way that PHP handles file uploads makes it simple to trick PHP
    applications into working on  arbitrary files local to  the server
    rather than files uploaded by the user.  This will generally  lead
    to a remote  attacker being able  to read any  file on the  server
    that  can  be  read  by  the  user  the  web server is running as,
    typically 'nobody'.

    Impact:

        1. File disclosure
        2. (1) will often lead to disclosure of PHP code
        3. (2)   will   often    lead   to   disclosure  of   database
           authentication data
        4. (3) may lead to machine compromise

    When files are  uploaded to a  PHP script, PHP  receives the file,
    gives it a random name  and places it into a  configured temporary
    directory.   The PHP  script is  given information  about the file
    that was uploaded  in the form  of 4 global  variables.  Presuming
    the file  field in  the form  was called  'hello', the 4 variables
    would be:

        $hello = Name of temporary file (e.g '/tmp/ASHDjkjbs')
        $hello_name = Name of file when it was on the remote computer (e.g 'c:\hello.tmp)
        $hello_type = Mime type of file (e.g 'text/plain')
        $hello_size = Size of uploaded file (e.g 2000 bytes)

    The temporary  file is  automatically deleted  at the  end of  the
    execution of the  script so the  PHP script usually  needs to move
    it somewhere else.   For example, it  might copy the  file into  a
    blob in a MySQL database.

    The problem is actually in the way PHP behaves by default.  Unless
    deliberately configured otherwise  (via register_globals =  Off in
    php.ini) the  values specified  in form  fields upon  a submit are
    auctomatically declared  by their  form name  as global  variables
    inside the PHP script.

    If You had a form with an input field like

        <INPUT TYPE="hidden" NAME="test" VALUE="12">

    When the PHP script is called to handle the form input, the global
    variable $test is set.  This is a significant security risk.   The
    problem  is  simple,  cluttering  the  global  namespace with user
    defined input  so destablizes  the environment  that it  is almost
    impossible to write in it securely.

    Back to the issue at hand. Using the fact mentioned above, we  can
    create  the  four   variables  $hell,  $hello_name,   $hello_type,
    $hello_size ourselves using form input like the following

        <INPUT TYPE="hidden" NAME="hello" VALUE="/etc/passwd">
        <INPUT TYPE="hidden" NAME="hello_name" VALUE="c:\scary.txt">
        <INPUT TYPE="hidden" NAME="hello_type" VALUE="text/plain">
        <INPUT TYPE="hidden" NAME="hello_size" VALUE="2000">

    This  should  lead  the  PHP  script  working  on the passwd file,
    usually resulting in it being disclosed to the attacker.

    Here's  how  you  can  reproduce  this  on  your  own.  Create the
    following file as "test.php" on the http server running php:

        <!-- test.php ##################################################### -->
        <html>
        <body>
        <form action="<?php echo $PHP_SELF ?>" method="POST"
	        ENCTYPE="multipart/form-data">
            <input type="file" name="userfile">
            <input type="submit">
        </form>
        <pre>
        <?php
           echo("userfile       =$userfile      \n");
           echo("userfile_name = $userfile_name \n");
           echo("userfile_type = $userfile_type \n");
           echo("userfile_size = $userfile_size \n");
        ?>
        </pre>
        </body>
        </html>
        <! -- CUT HERE #################################################### -->

    Now, create a  file on your  LOCAL computer called  test.html with
    the following contents:

        <!-- test.html ##################################################### -->
        <html>
        <body>
        <form action="http://YOUR_SERVER_HERE/blah/blah/test.php"
	        ENCTYPE="multipart/form-data" method="POST">
            <input type="file" name="userfile">
            <input type="hidden" name="userfile" value="hackme">
            <input type="submit">
        </form>
        </body>
        </html>
        <! -- CUT HERE #################################################### -->

    Go  to  http://YOUR_SERVER_HERE/blah/blah/test.php  and  run   the
    script, upload any file.  Note the output.  Now open test.html  on
    your LOCAL  computer and  repeat the  same steps  you did when you
    were on the server.  Hit submit.  Note the change in output.

Solution

    PHP supports  RFC 1867  based file  uploads.   PHP saves  uploaded
    files in a  temporary directory on  the server, using  a temporary
    name.  This temporary name is  exposed to the PHP script as  $FOO,
    where "FOO" is  the name of  the file input  tag in the  submitted
    form.  Many  PHP scripts process  $FOO without taking  measures to
    ensure that  it is  in fact  a file  that resides  in a  temporary
    directory.   It's  possible  for  a  remote  attacker  to   supply
    arbitrary file names as values  for FOO, by submitting a  standard
    form input  tag by  that name,  and thus  cause the  PHP script to
    process arbitrary files.

    Never trust  any input  that may  be coming  from the remote user.
    Always test whether  the variable you  expect to contain  the path
    of an upload  file, actually contains  a file path  of a temporary
    file  in  the  system.    It  is  strongly  recommended  to   turn
    register_globals off if possible.  If register_globals is off, you
    can  safely  check  $HTTP_POST_VARS[]  for  information  about the
    upload files  (see below).   If register_globals  is kept  on, one
    must  realize  that  any  variable  in  the  global scope might be
    overwritten by remote user input.

    New versions of PHP  have been packaged (4.0.3RC1  and 3.0.17RC1),
    to  make  it  easier  to  secure  scripts from this vulnerability.
    They  include  a  new  function  that  make  it  easy to determine
    whether a certain filename is a temporary uploaded file or not:

        /* Test whether a file is an uploaded file or not */
        is_uploaded_file($path);

    PHP 4.0.3 also features a new convenience function:

        /* Move an uploaded file to a new location.  If the file is not
          * a valid upload file, no action will take place.
          */
        move_uploaded_file($path, $new_path);

    In   addition,   as   of   PHP    4.0.3,   it's   safe   to    use
    $HTTP_POST_FILES["FOO"]["tmp_name"] - which  cannot be written  to
    by any remote user input,  even when register_globals is on.   The
    new versions are currently in testing, and thus have the RC tag.

    PHP 4.0.3RC1:

        http://www.php.net/do_download.php?download_file=php-4.0.3RC1.tar.gz

    PHP 3.0.17RC1 (upgrading to PHP 4.0 is strongly recommended):

        http://www.php.net/distributions/php-3.0.17RC1.tar.gz

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