PDA

View Full Version : [PHP] problema sicurezza - upload immagini


Alessio.16390
10-10-2014, 23:18
Buonasera,
debutto così: sto diventando pazzo!

Spiego,
anni fà, almeno 5, acquistai uno script che nel tempo ho mantenuto ed aggiornato io dato che non ha avuto più supporto dal venditore.

Trattasi di un portale per l'upload di immagini,
ora ho un problema serio da mesi, praticamente non so perchè, da quando sono passato ad un server con su PHP 5 il codice di invio immagini ha un bug, che non avveniva con PHP 4!

Praticamente non funziona il controllo del tipo di file, e quindi con tutti i rischi del caso, un malintenzionato può uploadare una shell php e prendere controllo della macchina, fare un defance, avere accesso al DB e quant'altro.
(ho trovato diversi file php uplodati..)
ho impostato la macchina per il ripristino dei file del sito automatico, quindi non è tanto la paura del deface, quanto il voler risolvere e dormire tranquillo.


Se qualcuno così gentile vuole darmi una mano a capire dove si trova l'errore, inserisco il codice.



<?php


function findExtension ($filename)
{
$filename = strtolower($filename) ;
$exts = split("[/\\.]", $filename) ;
$n = count($exts)-1;
$exts = $exts[$n];
return $exts;
}


function imagecreatefromunknown($path) {

$ext = findExtension($path);

switch ($ext) {
case "jpg":
$img = imagecreatefromjpeg($path);
break;
case "gif":
$img = imagecreatefromgif($path);
break;
case "png":
$img = imagecreatefrompng($path);
break;
}

return $img;
}



$max = 5;
$total = 0;


if (isset($_POST["tags1"])) {

$date = date("d-m-y");
$lastaccess = date("y-m-d");
$ip= $_SERVER['REMOTE_ADDR'];

//CHECK IF THE IP OF THE PERSON IS BLOCKED OR NOT
$result = mysql_query("SELECT id FROM `blockedip` WHERE ip = '$ip'");
$number = mysql_num_rows($result);
if ($number) die("Sorry ! Your ip is blocked from uploading any image. <br><br><a href='index.php'>Go back to homepage</a>");


for ($i=1; $i < ($max+1); $i++)
{
if (trim($_FILES["image" . $i]["name"]) != "") {

$total = $total + 1;
if ( (trim($_POST["tags" . $i]) != "") ) {

$tags = htmlspecialchars(trim($_POST["tags" . $i]));

$name = "image" . $i;

//CHECK IF VALID IMAGE TYPE
if (( ($_FILES[$name]["type"] == "image/gif")
|| ($_FILES[$name]["type"] == "image/jpeg")
|| ($_FILES[$name]["type"] == "image/pjpeg")
|| ($_FILES[$name]["type"] == "image/x-png")
|| ($_FILES[$name]["type"] == "image/bmp")
|| ($_FILES[$name]["type"] == "image/png")))
{

$size = intval(($_FILES[$name]["size"] / 1024) / 1024);

if ($session == true)
$limit = $maxsizemember;
else
$limit = $maxsizeguest;

if ($size > $limit)
die ("Sorry ! The size of the image exceeds the $limit Mb limit.");


if ($_FILES[$name]["error"] > 0) {
die("Error: " . $_FILES[$name]["error"]);
}
else {
$n = $_FILES[$name]["name"];
$rndName = md5($n . date("d-m-y") . time()) . "." . findExtension($n);
$uploadPath = "pictures/" . $rndName;
$tempPath = $_FILES[$name]["tmp_name"];
move_uploaded_file($tempPath, $uploadPath);
}

}
else
die("Sorry ! \"{$_FILES[$name]["name"]}\" is an invalid image.");


$imagePath = $uploadPath;


$img = imagecreatefromunknown($imagePath);

$mainWidth = imagesx($img);
$mainHeight = imagesy($img);

if (($mainWidth > 150) && ($mainWidth < 2000) && ($mainHeight < 1600))
{

$a = ($mainWidth >= $mainHeight) ? $mainWidth : $mainHeight;

$div = $a / 150;
$thumbWidth = intval($mainWidth / $div);
$thumbHeight = intval($mainHeight / $div);


$myThumb = imagecreatetruecolor($thumbWidth, $thumbHeight);
imagecopyresampled($myThumb, $img, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $mainWidth, $mainHeight);
$thumbPath = "thumbnails/" . basename($imagePath);
imagejpeg($myThumb, $thumbPath);



if (($type == "public") && ($watermark == "true")) {
$imgMark = imagecreatefromgif("watermark.gif");

$dX = $mainWidth - imagesx($imgMark);
$dY = $mainHeight - imagesy($imgMark);
imagecopymerge($img, $imgMark, $dX, $dY, 0, 0, imagesx($imgMark), imagesy($imgMark), 40);

$ext = findExtension($imagePath);

switch ($ext) {
case "jpg":
imagejpeg($img, $imagePath); break;
case "png":
imagepng($img, $imagePath); break;
}
}



$details = intval(filesize($imagePath) / 1024) . " kb (" . $mainWidth . " x " . $mainHeight . ")" ;
$id = md5($thumbPath . date("d-m-y") . time());



if ($session == false)
$q = "INSERT INTO `images`(id, image, thumb, tags, details, date, access, type, ip)
VALUES('$id', '$imagePath', '$thumbPath', '$tags', '$details', '$date', '$lastaccess', 'public', '$ip')";
else
{
if ($opt == "gallery")
$q = "INSERT INTO `images`(id, galleryid, image, thumb, tags, details, date, access, type, ip)
VALUES('$id', '$galleryid', '$imagePath', '$thumbPath', '$tags', '$details', '$date', '$lastaccess', 'gallery', '$ip')";
else
$q = "INSERT INTO `images`(id, userid, image, thumb, tags, details, date, access, type, ip)
VALUES('$id', '$loggedId', '$imagePath', '$thumbPath', '$tags', '$details', '$date', '$lastaccess', 'member-{$type}', '$ip')";
}

if(!($result_set = mysql_query($q))) die(mysql_error());

echo "<center><a href=\"show-image.php?id=$id\"><img src='thumb.php?id=$id'></a></center><br>";
echo "Image \"{$_FILES["image" . $i]["name"]}\" uploaded successfully. <br><br>";


echo "<LABEL id='title'>HTML:</LABEL><br><input type='text' size=92 onclick=\"this.select();\" value=\"<a href='{$website}/show-image.php?id=$id'> <img src='{$website}/{$thumbPath}' alt='Image Hosting' border='0'> </a>\">";
echo "<br><br>";


echo "<LABEL id='title'>BB Code:</LABEL><br><input type='text' size=92 onclick=\"this.select();\" value=\" {$website}/{$thumbPath} ({$website}/show-image.php?id={$id})\">";
echo "<br><br>";


echo "<LABEL id='title'>Direct Image Link (HTML):</LABEL><br><input type='text' size=92 onclick=\"this.select();\" value=\"<a href='{$website}'> <img src='{$website}/{$imagePath}'> </a>\">";
echo "<br><br>";


echo "<LABEL id='title'>Direct Image Link (BB Code):</LABEL><br><input type='text' size=92 onclick=\"this.select();\" value=\" {$website}/{$imagePath} ({$website})\">";
echo "<br><br>";

echo "<LABEL id='title'>URL:</LABEL><br><input type='text' size=92 onclick=\"this.select();\" value=\"{$website}/show-image.php?id=$id\">";

echo "<br><br><hr color='#233c9b'><br>";


}
else
echo "Sorry ! Image \"{$_FILES["image" . $i]["name"]}\" is either too small or too large.<br><hr color='#b1ddf6'>";

}
else
echo "You have not entered any tags for the image \"{$_FILES["image" . $i]["name"]}\" <br><hr color='#b1ddf6'>";
}
}

}

if ($total == 0)
echo "Sorry ! You must upload atleast one image.";


?>





Ringrazio di cuore.

Alessio.16390
10-10-2014, 23:29
Leggendo un attimo la documentazione di PHP
ho visto che la funzione da me usata ha questa bella caratteristica:


This value is completely under the control of the client and not checked on the PHP side.



Quindi magari lo script di per se funziona, infatti IO non riesco ad uplodare file PHP, ma visto che il controllo è lato client e non server-side,
un pincopallino può far passare un file php per file immagine lato client e quindi mi ritrovo il file sul server.
Complimenti a PHP :eek: :cry:

Alessio.16390
10-10-2014, 23:41
Si lo so,
sto facendo tutto da solo!

Ma secondo voi, può essere una soluzione utilizzare mod_access di apache ed un file .htaccess nella cartella dove risiedono i file uplodati?


Tipo

ForceType application/octet-stream
<FilesMatch "(?i)\.jpe?g$">
ForceType image/jpeg
</FilesMatch>
<FilesMatch "(?i)\.gif$">
ForceType image/gif
</FilesMatch>
<FilesMatch "(?i)\.png$">
ForceType image/png
</FilesMatch>

<Files *.php>
Order Deny,Allow
Deny from all
</Files>


Facendo una prova funziona,
non blocca l'uplod di file .php
ma,
non li possono eseguire.


:mc: ;)

Alessio.16390
22-10-2014, 17:08
Provo ad Uppare.
:fagiano: :help:

Alessio.16390
22-10-2014, 18:19
Domanda: questo snippet

function findExtension ($filename)
{
$filename = strtolower($filename) ;
$exts = split("[/\\.]", $filename) ;
$n = count($exts)-1;
$exts = $exts[$n];
return $exts;
}

L'hai fatto tu?


No,
Da GalaxyScript.com che non esiste più da anni.


anni fà, almeno 5, acquistai uno script che nel tempo ho mantenuto ed aggiornato io dato che non ha avuto più supporto dal venditore.


EDIT:
php.net consiglia di usare explode al posto di split,
ma il risultato è lo stesso.

Daniels118
23-10-2014, 08:05
La colpa non è del PHP, ma del programmatore che ha realizzato lo script.
Il campo 'type' dei files contiene infatti il MIME type inviato dal browser negli header HTTP, operazione più che lecita, che serve come suggerimento per il server, deve essere poi quest'ultimo a convalidare i dati.
Se ti interessa verificare che il file sia un'immagine, basta che lo passi a getimagesize e testi il return code.