File Upload Security

From: Date: Sat, 12 Apr 2008 00:24:05 +0000
Subject: File Upload Security
Groups: php.general 
Request: Send a blank email to php-general+get-272902@lists.php.net to get a copy of this message
One of my sites has been hacked and I'm trying to find the hole. The hack code creates dirs with "nobody" ownership, so it's obvious stuff is not via ftp [ownership would be foo] Site is virtual host, Linux/Apache I'm concerned about a file uploader my users use to upload photos. Can anyone see a hole in this scrip? Can my code upload an executable masquerading as an image file? $filetype = array("gif", "jpg", "jpeg", "png", "txt", css") function csvt_file_upload($filetype, $max_size) {
    $prohibits = array("exe", "php", "inc", "php3", "pl", "bat", "cgi"); //common executables.
    $absolute_max_size = 2000000;
    end($_FILES); //get the "name" used by the html <input.....
    $name = key($_FILES); //could use the register variables, but this is safer.
    if(isset($_FILES[$name]['name'])) $input_name = $_FILES[$name]['name'];
    $error = "no"; //reset for error checks
    if (!isset($filetype)) {
            echo "<p style=\"color:red\"> File type assignment missing </p> ";
            $error = "yes";
    };
    if (!isset($max_size)) {
            echo "<p style=\"color:red\"> Max file size assignment missing.</p>";
            $error = "yes";
    };
    $filename = $_FILES[$name]['name'];
    $tmp_name = $_FILES[$name]['tmp_name'];
    $size = $_FILES[$name]['size'];
    $absolute_path_file = getcwd(). DATA_DIR . $filename;
    if (($size >= $max_size) OR ($size > $absolute_max_size)) {
        echo "<p style=\"color:red\"> File size is too large.</p> ";
        $error = "yes";
    }
    $ext = substr(strrchr($filename, "."), 1); //get the extension, remove the "."
    if (in_array($ext, $prohibits)) {
        echo "<p style=\"color:red\">Illegal file type, executable.</p>\r\n";
        $error = "yes";
    }
    if (is_executable($filename)) {
        echo "<p style=\"color:red\">Illegal file type, executable file.</p>\r\n";
        $error = "yes";
    } //This is a double check in case $prohibits is incomplete.
    if (is_array($filetype) AND !in_array($ext, $filetype)) {
        echo "<p style=\"color:red\">Illegal file type.</p>\r\n";
        $error = "yes";
    }
if(!is_array($filetype) AND ($filetype != $ext)){
        echo "<p style=\"color:red\">Illegal file type.</p>\r\n";
        $error = "yes";
    }
    if ($error == "yes") {
        echo "<p style=\"color:red\">There was an error(s) with your file selection \"$input_name\" as the note(s) indicates. Please reselect, or remove your file selection and email for help. </p>\r\n";
    }
else {
        if(!move_uploaded_file($tmp_name, $absolute_path_file))
		die("<p style=\"color:red\">There was an error saving your file. Check permissions of " . DATA_DIR . " Must be 777 </p>\r\n");
chmod($absolute_path_file, 0644);
    }
    return;
}

« previous php.general (#272902) next »