Hello,
i have here a php script written with the one module and themes upload and extract can.


<?php
/**
 * Unzip the source_file in the destination dir
 *
 * @param   string      The path to the ZIP-file.
 * @param   string      The path where the zipfile should be unpacked, if false the directory of the zip-file is used
 * @param   boolean     Indicates if the files will be unpacked in a directory with the name of the zip-file (true) or not (false) (only if the destination directory is set to false!)
 * @param   boolean     Overwrite existing files (true) or not (false)
 * 
 * @return  boolean     Succesful or not
 * 
 *  original script location http://de.php.net/manual/de/ref.zip.php
 *  thx to darki777 and nielsvandenberge
 */
$src_file = $_GET['file'];
$uploadpath = $_POST['uploadpath']; //path for upload
$posted_file = $_FILES['file']['type'];
$a = $_FILES['file']['size']; 
$file_type = "application/x-zip-compressed";
$filesize = "1048576"; // 1024byte=1kb, 1024byte*1024=1mb
$upload = $_FILES['file']['tmp_name'];

function unzip($src_file, $dest_dir=false, $create_zip_name_dir=true, $overwrite=true)
{
  if(function_exists("zip_open"))
  {   
      if(!is_resource(zip_open($src_file)))
      { 
          $src_file=dirname($_SERVER['SCRIPT_FILENAME'])."/".$src_file; 
      }
      
      if (is_resource($zip = zip_open($src_file)))
      {          
          $splitter = ($create_zip_name_dir === true) ? "." : "/";
          if ($dest_dir === false) $dest_dir = substr($src_file, 0, strrpos($src_file, $splitter))."/";
         
          // Create the directories to the destination dir if they don't already exist
          create_dirs($dest_dir);

          // For every file in the zip-packet
          while ($zip_entry = zip_read($zip))
          {
            // Now we're going to create the directories in the destination directories
           
            // If the file is not in the root dir
            $pos_last_slash = strrpos(zip_entry_name($zip_entry), "/");
            if ($pos_last_slash !== false)
            {
              // Create the directory where the zip-entry should be saved (with a "/" at the end)
              create_dirs($dest_dir.substr(zip_entry_name($zip_entry), 0, $pos_last_slash+1));
            }

            // Open the entry
            if (zip_entry_open($zip,$zip_entry,"r"))
            {
             
              // The name of the file to save on the disk
              $file_name = $dest_dir.zip_entry_name($zip_entry);
             
              // Check if the files should be overwritten or not
              if ($overwrite === true || $overwrite === false && !is_file($file_name))
              {
                // Get the content of the zip entry
                $fstream = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));           
                
                if(!is_dir($file_name))            
                file_put_contents($file_name, $fstream );
                // Set the rights
                if(file_exists($file_name))
                {
                    chmod($file_name, 0777);
                }
                else
                {
                    print "<p><span style=\"color:red;\">File is not found!</span></p>";
                }
              }
             
              // Close the entry
              zip_entry_close($zip_entry);
            }      
          }
          // Close the zip-file
          zip_close($zip);
      }
      else
      {
        print '<p>Sorry, Zip Archive is not found?!</p>';
        return false;
      }
     return true;
  }
  else
  {
      if(version_compare(phpversion(), "5.2.0", "<"))
      $infoVersion="(use PHP 5.2.0 or later)";
      
      print "<p>You need to install/enable the php_zip.dll extension $infoVersion</p>"; 
  }
}

function create_dirs($path)
{
  if (!is_dir($path))
  {
    $directory_path = "";
    $directories = explode("/",$path);
    array_pop($directories);
   
    foreach($directories as $directory)
    {
      $directory_path .= $directory."/";
      if (!is_dir($directory_path))
      {
        mkdir($directory_path);
        chmod($directory_path, 0777);
      }
    }
  }
}

/* function bytes($a) on http://www.php.net/manual/de/function.number-format.php#72969 */

function bytes($a) {
    $unim = array("B","KB","MB","GB","TB","PB");
    $c = 0;
    while ($a>=1024) {
        $c++;
        $a = $a/1024;
    }
    return number_format($a,($c ? 2 : 0),",",".")." ".$unim[$c];
}
if ($uploadpath){
if($upload)
   {
   if ($posted_file == $file_type){
if($_FILES['file']['size'] <  $filesize)
      {
      move_uploaded_file($_FILES['file']['tmp_name'], "$uploadpath/".$_FILES['file']['name']);
      print "<p>The file ".$_FILES['file']['name']." is uploaded. Click <a href='".$_SERVER['REQUEST_URI']."?file=".$uploadpath."/".$_FILES['file']['name']."'>here for unpack</a>. </p>";
      
      }

   else
      {
         print "<p>Filesize is ".bytes($a);$a = $filesize; print "! max. allowed ".bytes($a)."!</p>";
      }

    } else {print "<p>Only '".$file_type."' file types allowed.</p>"; }}
    else {print " Change file to upload!";} } if ($upload== "" &$src_file == ""){print " Change Theme or Module!";}
    
if ($src_file) {create_dirs($path); unzip($src_file, $dest_dir=false, $create_zip_name_dir=true, $overwrite=true); print "File is unpacked!";
} else { print'
<form action="" method="post" enctype="multipart/form-data"> <br />
<label><b>Theme:</b> <input type="radio" name="uploadpath" class="form-radio" value="themes" /></label><br />
<label><b>Module:</b> <input type="radio" name="uploadpath" class="form-radio" value="modules" /></label><br />
<label><b>File:</b> <input type="file" name="file" size="40" style="width:14em;"></label><input type="submit" value="Submit"> 
</form>';} ?>

One can build a block with this code or change this to module.

Comments

yelvington’s picture

http://drupal.org/project/upload_package provids for Web-based uploads of modules. However, the boldface is clear:

Note from the security team: this module requires your webserver to be able to write Drupal modules. This is inherently insecure. Usage on live sites is strongly discouraged.

A secure website typically runs the webserver as an unprivileged pseudouser, and file ownership/permissions belong to a real user. This prevents a webserver security breach from allowing a hacker to change the site's contents.

In order to support uploading of files using a Web browser, the security needs to be weakened. Drupal does this by requiring you to change the permissions and/or ownership of the files/ directory during installation.

For the files/ directory, Drupal implements an .htaccess file that turns off PHP (and all other special file handlers). See http://drupal.org/node/66763 for details.

In order to support the uploading of templates and modules, you have to break this security paradigm and grant the server the ability to write executable files. When the webserver has the right to upload executable files, you have opened a fairly dangerous security hole in your site that could potentially be exploited by a hacker. This hole would allow a hacker to not only deface the site but also steal private information from the database.

Evgenij’s picture

thanks for this info! That php-script was just one example. It can also be useful for someone.