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
INTELMEX
INTELMEX

This is a short biography of the post author. Maecenas nec odio et ante tincidunt tempus donec vitae sapien ut libero venenatis faucibus nullam quis ante maecenas nec odio et ante tincidunt tempus donec.

No hay comentarios.:

Publicar un comentario