Vulnerabilidad en archivos UPLOADER | #RoloMijan

Uploader PHP [Vulnerabilidad]

 


Muy buenas, en este caso vengo a explicar como se puede explotar una vulnerabilidad en un upload.php. Hay más información sobre esto en el foro, pero lo que he visto o es en video o no está explicado como a mi me gustaría que me lo explicaran.

Lo primero que tenemos que saber es que es un uploader en php.

Un uploader en php es un código que nos va a permitir subir un archivo a una página web.

En este caso nuestro código de prueba vulnerable va a ser el siguiente (El codigo no es propio, es este modificado).

  1. <html>
  2. <head>
  3. <style type="text/css">
  4. .upload{
  5. background:#e7e7e7;
  6. box-shadow:0px 0px 10px black;
  7. width:500px;
  8. height:200px;
  9. margin-right:auto;
  10. margin-left:auto;
  11. border-radius:20px;
  12.  
  13. }
  14. form{
  15.         margin: 126px auto 0;
  16.         width: 225px;
  17.     }
  18.     label{
  19.         display: block;
  20.     }
  21.     input[type="file"]{
  22.         display: block;
  23.         margin: 8px 0;
  24.     }
  25.     div.resultado{
  26.         margin: 25px auto 0;
  27.         width: 225px;
  28.     }
  29.     div.resultado img{
  30.         border: 2px solid #EEEEEE;
  31.         height: auto;
  32.         width: 225px;
  33.     }
  34. </style>
  35. </head>
  36. <body>
  37. <div class="upload">
  38. <form action="" method="post" enctype="multipart/form-data">
  39.     <br><br>Sube un archivo:
  40.     <input type="file" name="archivo" id="archivo" /> <br>
  41.     <input type="submit" name="boton" value="Subir" />
  42. </form>
  43. <div>
  44. <div class="resultado">
  45. <?php
  46. if(isset($_POST['boton'])){
  47.     // Hacemos una condicion en la que solo permitiremos que se suban imagenes y que sean menores a 20 KB
  48.     if ((true==true)  &&  ($_FILES["archivo"]["size"] < 200000000)) {
  49.      
  50.     //Si es que hubo un error en la subida, mostrarlo, de la variable $_FILES podemos extraer el valor de [error], que almacena un valor booleano (1 o 0).
  51.       if ($_FILES["archivo"]["error"] > 0) {
  52.         echo $_FILES["archivo"]["error"] . "<br />";
  53.       } else {
  54.           // Si no hubo ningun error, hacemos otra condicion para asegurarnos que el archivo no sea repetido
  55.           if (file_exists("archivos/" . $_FILES["archivo"]["name"])) {
  56.             echo $_FILES["archivo"]["name"] . " ya existe. ";
  57.           } else {
  58.            // Si no es un archivo repetido y no hubo ningun error, procedemos a subir a la carpeta /archivos, seguido de eso mostramos la imagen subida
  59.             move_uploaded_file($_FILES["archivo"]["tmp_name"],
  60.             "archivos/" . $_FILES["archivo"]["name"]);
  61.             echo "Archivo Subido <br />";
  62.             echo "<img src='archivos/".$_FILES["archivo"]["name"]."' />";
  63.           }
  64.       }
  65.     } else {
  66.         echo "Archivo no permitido";
  67.     }
  68. }
  69. ?>
  70. </div>
  71. </body>
  72. </html>

Este código nos deja subir archivos de cualquier extensión y aquí es donde nosotros nos vamos a aprovechar. En este caso yo voy a subir una shell c99.php, que es muy intuitiva de manejar.



Ya solo nos quedaría ir al directorio está el archivo malicios, en este caso: "/archivos/c99.php".

Dejo aquí una foto de la shell. El funcionamiento como digo es muy intuitivo.

 

 (Ya se que tengo que activar Windows xD)

Ahora voy a mostrar un filtro que NO DEBÉIS USAR y como hacer un bypass, es decir, saltarse el filtro.(Despues mostrare el filtro final).

  1. <html>
  2. <head>
  3. <style type="text/css">
  4. .upload{
  5. background:#e7e7e7;
  6. box-shadow:0px 0px 10px black;
  7. width:500px;
  8. height:200px;
  9. margin-right:auto;
  10. margin-left:auto;
  11. border-radius:20px;
  12.  
  13. }
  14. form{
  15.         margin: 126px auto 0;
  16.         width: 225px;
  17.     }
  18.     label{
  19.         display: block;
  20.     }
  21.     input[type="file"]{
  22.         display: block;
  23.         margin: 8px 0;
  24.     }
  25.     div.resultado{
  26.         margin: 25px auto 0;
  27.         width: 225px;
  28.     }
  29.     div.resultado img{
  30.         border: 2px solid #EEEEEE;
  31.         height: auto;
  32.         width: 225px;
  33.     }
  34. </style>
  35. </head>
  36. <body>
  37. <div class="upload">
  38. <form action="" method="post" enctype="multipart/form-data">
  39.     <br><br>Sube un archivo:
  40.     <input type="file" name="archivo" id="archivo" /> <br>
  41.     <input type="submit" name="boton" value="Subir" />
  42. </form>
  43. <div>
  44. <div class="resultado">
  45. <?php
  46. if(isset($_POST['boton'])){
  47.     // Hacemos una condicion en la que solo permitiremos que se suban imagenes y que sean menores a 20 KB
  48.     if ((($_FILES["archivo"]["type"] == "image/gif") ||
  49.     ($_FILES["archivo"]["type"] == "image/jpeg") ||
  50.     ($_FILES["archivo"]["type"] == "image/pjpeg")) &&
  51.     ($_FILES["archivo"]["size"] < 20000)) {
  52.      
  53.     //Si es que hubo un error en la subida, mostrarlo, de la variable $_FILES podemos extraer el valor de [error], que almacena un valor booleano (1 o 0).
  54.       if ($_FILES["archivo"]["error"] > 0) {
  55.         echo $_FILES["archivo"]["error"] . "<br />";
  56.       } else {
  57.           // Si no hubo ningun error, hacemos otra condicion para asegurarnos que el archivo no sea repetido
  58.           if (file_exists("archivos/" . $_FILES["archivo"]["name"])) {
  59.             echo $_FILES["archivo"]["name"] . " ya existe. ";
  60.           } else {
  61.            // Si no es un archivo repetido y no hubo ningun error, procedemos a subir a la carpeta /archivos, seguido de eso mostramos la imagen subida
  62.             move_uploaded_file($_FILES["archivo"]["tmp_name"],
  63.             "archivos/" . $_FILES["archivo"]["name"]);
  64.             echo "Archivo Subido <br />";
  65.             echo "<img src='archivos/".$_FILES["archivo"]["name"]."' />";
  66.           }
  67.       }
  68.     } else {
  69.         echo "Archivo no permitido";
  70.     }
  71. }
  72. ?>
  73. </div>
  74. </body>
  75. </html>

 Si os fijáis en estas lineas:

  1. if ((($_FILES["archivo"]["type"] == "image/gif") ||
  2.     ($_FILES["archivo"]["type"] == "image/jpeg") ||
  3.     ($_FILES["archivo"]["type"] == "image/pjpeg")) &&
  4.     ($_FILES["archivo"]["size"] < 20000))

 Lo que hace el php es comprobar el content type del archivo y no comprueba la terminación del archivo (si es php, html, etc). Para saltarte este filtro lo que hay que hacer es lo siguiente:

1º Hay que descargarse firefox, ya que vamos a usar una herramienta de firefox para esta prueba.

2º Hay que renombrar el archivo c99.php a c99.jpg, ya que es un tipo de los archivos que nos permite subir este uploader.

3º En la web le damos a examinar y ponemos nuestro archivo c99.jpg (NO LE DAMOS A SUBIR TODAVIA). Tiene que quedar asi.



4º Iniciamos Tamper Data. (Está en el menú de arriba en la barra de herramientas).



 5º Le damos a comenzar modificación.




6º Ya podemos darle a enviar el archivo, nos saldra una pantallita y le tenemos que dar a modificar.



7º Entonces nos saldrá otra pantalla y tenemos que modificar el código de la derecha.



En ese código hay que buscar algo de este estilo.

filename="c99.jpg"\r\nContent-Type: image/jpeg\r\n\r\n
 
Y cambiar "c99.jpg" por c99.php. Le das a enviar y listo. 
 
Esto saltará el filtro ya que aunque estas subiendo el archivo con la terminación 
.php el content type es de un jpg, y el código del upload comprueba el content 
type y no la terminación.

Por último una forma de arreglar esto sería añadir estas líneas.

El código ha sido editado porque como decía @seth seguía siendo vulnerable. 


  1. $blacklist = array(".php", ".phtml", ".php3", ".php4" , ".html", "htaccess");
  2.  
  3.     foreach ($blacklist as $item) {
  4.       if(preg_match("/$item\$/i", $_FILES['userfile']['name'])) {
  5.          echo "No se permiten archivos PHP";
  6.          exit;
  7.       }
  8.     }

 Con lo que el código final quedaría así.

  1. <html>
  2. <head>
  3. <style type="text/css">
  4. .upload{
  5. background:#e7e7e7;
  6. box-shadow:0px 0px 10px black;
  7. width:500px;
  8. height:200px;
  9. margin-right:auto;
  10. margin-left:auto;
  11. border-radius:20px;
  12.  
  13. }
  14. form{
  15.         margin: 126px auto 0;
  16.         width: 225px;
  17.     }
  18.     label{
  19.         display: block;
  20.     }
  21.     input[type="file"]{
  22.         display: block;
  23.         margin: 8px 0;
  24.     }
  25.     div.resultado{
  26.         margin: 25px auto 0;
  27.         width: 225px;
  28.     }
  29.     div.resultado img{
  30.         border: 2px solid #EEEEEE;
  31.         height: auto;
  32.         width: 225px;
  33.     }
  34. </style>
  35. </head>
  36. <body>
  37. <div class="upload">
  38. <form action="" method="post" enctype="multipart/form-data">
  39.     <br><br>Sube un archivo:
  40.     <input type="file" name="archivo" id="archivo" /> <br>
  41.     <input type="submit" name="boton" value="Subir" />
  42. </form>
  43. <div>
  44. <div class="resultado">
  45. <?php
  46.  
  47. $blacklist = array(".php", ".phtml", ".php3", ".php4" , ".html", "htaccess");
  48.  
  49.     foreach ($blacklist as $item) {
  50.       if(preg_match("/$item\$/i", $_FILES['userfile']['name'])) {
  51.          echo "No se permiten archivos PHP";
  52.          exit;
  53.      }
  54. }
  55. if(isset($_POST['boton'])){
  56.     // Hacemos una condicion en la que solo permitiremos que se suban imagenes y que sean menores a 20 KB
  57.     if ((($_FILES["archivo"]["type"] == "image/gif") ||  
  58.     ($_FILES["archivo"]["type"] == "image/jpeg") ||  
  59.     ($_FILES["archivo"]["type"] == "image/pjpeg")) &&  
  60.     ($_FILES["archivo"]["size"] < 200000000)) {
  61.      
  62.     //Si es que hubo un error en la subida, mostrarlo, de la variable $_FILES podemos extraer el valor de [error], que almacena un valor booleano (1 o 0).
  63.       if ($_FILES["archivo"]["error"] > 0) {
  64.         echo $_FILES["archivo"]["error"] . "<br />";
  65.       } else {
  66.           // Si no hubo ningun error, hacemos otra condicion para asegurarnos que el archivo no sea repetido
  67.           if (file_exists("archivos/" . $_FILES["archivo"]["name"])) {
  68.             echo $_FILES["archivo"]["name"] . " ya existe. ";
  69.           } else {
  70.            // Si no es un archivo repetido y no hubo ningun error, procedemos a subir a la carpeta /archivos, seguido de eso mostramos la imagen subida
  71.             move_uploaded_file($_FILES["archivo"]["tmp_name"],
  72.             "archivos/" . $_FILES["archivo"]["name"]);
  73.             echo "Archivo Subido <br />";
  74.             echo "<img src='archivos/".$_FILES["archivo"]["name"]."' />";
  75.           }
  76.       }
  77.     } else {
  78.         echo "Archivo no permitido";
  79.     }
  80. }
  81. ?>
  82. </div>
  83. </body>
  84. </html>

-------------------------
Post escrito por: @RoloMijan
Twitter: https://twitter.com/RoloMijan

Publicar un comentario

0 Comentarios

Slider Parnert

Subscribe Text

¿Quieres estar al día con noticias?