Me encontre con una web la cual nesesitaba descargar un fichero que me resultaba de interes, donde la direccion de descarga era similar a esto:
http://www.sitio.com/descarga/download.php?file=archivo.extension, por lo que me propuse verificar si dicho downloader tenia alguna validación, para provocar un
Directory Transversal.
Lo que realize fue la peticion de este modo
http://www.sitio.com/descarga/download.php?file=download.php, para descargarme el archivo download.php
y heureca :)
Al abrir el archivo download.php podemos empezar a verificar las fallas de la validaciones:
$filename = $_GET['file'];
// addition by Jorg Weske
$file_extension = strtolower(substr(strrchr($filename,"."),1));
if ( ! file_exists( $filename ) )
{
echo "not file";
exit;
};
switch( $file_extension )
{
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
// change, added quotes to allow spaces in filenames, by Rajkumar Singh
header("Content-Disposition: attachment; filename=\"".basename($filename)."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filename));
readfile("$filename");
?>
en la primera linea, podemos ver que toma el nombre del archivo por la variable
$_GET['file'] y lo guarda en $filename, luego en la linea 4 lo que hace esta funcion es tomar todo el nombre del archivo y solo obtener su extension por ejemplo, si el archivo a descargar es
archivo.pdf la variable $file_extension va a contener
pdf, aca fue lo que me parecio algo muy bueno cuando estaba leyendo el codigo, pero solo lo usa para colocar el tipo de
MIME(linea 12), lo cual esta muy bien pero tambien ubiera filtrado con ellos una black-list para que no se pueda descargar entensiones peligrosas.
En la linea 31 mostramos el nombre del archivo que le aparecera al usuario cuadno descarga y en la linea 33 el Content-Lenght es el tamaño del archivo, ah y la linea 29 es el MIME del que hablamos anteriormente. :)
Como la descarga se realizo con un php podemos llegar a pensar que podemos descargar cualquier php de la web, entonces buscaremos descargar el index que es donde puede haber datos interesantes de conexion de base de datos :)
http://www.sitio.com/descarga/download.php?file=../index.php Al abrir el archivo index.php vemos esta informacion un poco mas interesante que la anterior
Nos descargamos el archivo class_DB.php, y dentro de ese archivo vemos una linea mucho mas interesante
include("conectar.php");
Y como piensan que sigue esto? ........... Si correcto, nos descargamos el archivo conectar.php
Bien ahora queda buscar el phpmyadmin, colocando www.sitio.com/phpmyadmin de la forma facil, y si no encontramos ahi podemos largar algun bruteador. O tambien que es la que mas me gusta por el cliente de mysql, primero comprobamos si el puerto esta abierto hacia el publico con Nmap :)
y ahora nos conectamos
Creo que queda entendida la peligrosidad de lo que se expone a no validar estas entradas asi como todas las entradas que se le da al usuario, siempre hay que verificarlas. Desde una simple bajada de archivo pudimos ingresar a sus datos, romper la confidencialidad de ellos, podriamos romper su integridad y hasta la disponibilidad de su sitio Web.
Para completar, al mismo script, le coloque seguridad, para que no se pueda descargar alguna extension peligrosa como php, asp, inc, etc. y para que no se pueda escalar directorios.
$index="http://".$_SERVER['SERVER_NAME']."/index.php";
$filename = basename($_GET['file']);
$ruta="descargas/".$filename;
// addition by Jorg Weske
$file_extension = strtolower(substr(strrchr($filename,"."),1));
#------------Bloque Seguridad ------------------
if(preg_match('/(php|asp|ini|inc|bak)/',$file_extension)){
header("Location:".$index);
}
elseif( $filename == "" )
{
header("Location:".$index);
}
elseif( ! file_exists( $ruta ) )
{
header("Location:".$index);
};
#-----------Fin Bloque Seguridad--------------
switch($file_extension )
{
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".$filename."\";" );#nombre del archivo en la descarga
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($ruta));
readfile("$ruta");
?>
La segunda linea usamos la funciona
basename, que logra que si el usuario coloca por ejemplo /carpeta/carpeta2/archivo.pdf, nos devilvera
archivo.pdf, eliminado toda la ruta anterior y con la ayuda de la linea 3 ponemos una carpeta llamada
descargas, la cual en ella contendra todos los archivos para descargas (valga la redundancia), y donde el usuario nunca podra escaparse de ella.
Asi por ejemplo si el usuario intenta descargar de esta forma
www.sitio.com.ar/download.php?file=/etc/passwd la variable
$filename quedara con el valor
passwd, y concatenando con la carpeta
descargas la variable
$ruta contendra
descargas/passwdEn el bloque de seguridad, la primer linea verifica con una expresion regular que si existe esas extensiones, te direcciones al index (se puede colocar tantas como guste en esa lista).
Eso es todo
Saludos