⬆️Client-Side Validation
Última actualización
Última actualización
Muchas aplicaciones web solo dependen del código JavaScript del frontend para validar el formato de archivo seleccionado antes de cargarlo y no lo cargarían si el archivo no está en el formato requerido (por ejemplo, si no es una imagen).
Sin embargo, como la validación del formato de archivo se realiza en el lado del cliente, podemos evitarla fácilmente interactuando directamente con el servidor, lo que nos permite omitir por completo las validaciones del frontend. También podemos modificar el código del frontend a través de las herramientas de desarrollo de nuestro navegador para desactivar cualquier validación existente.
El ejercicio al final de esta sección muestra una funcionalidad básica de subir una Imagen de perfil
, que se ve frecuentemente en aplicaciones web que utilizan funciones de perfil de usuario, como las aplicaciones web de redes sociales:
Sin embargo, esta vez, cuando aparece el cuadro de selección de archivos, no podemos ver nuestros scripts PHP
(o puede que estén en gris), ya que el cuadro de diálogo parece estar limitado únicamente a formatos de imagen:
De todas formas , aún podemos seleccionar la opción All Files
para seleccionar nuestro script PHP
, pero cuando lo hacemos, recibimos un mensaje de error que dice ( Only images are allowed!
), y el botón Upload
se deshabilita:
Esto indica algún tipo de validación del tipo de archivo, por lo que no podemos simplemente cargar un webshell a través del formulario de carga como hicimos en la sección anterior. Afortunadamente, toda la validación parece estar sucediendo en el front-end, ya que la página nunca se actualiza ni envía ninguna solicitud HTTP después de seleccionar nuestro archivo. Por lo tanto, deberíamos poder tener un control total sobre estas validaciones del lado del cliente.
Todo código que se ejecuta en el lado del cliente está bajo nuestro control. Si bien el servidor web es responsable de enviar el código front-end, la representación y ejecución del código front-end se realizan dentro de nuestro navegador. Si la aplicación web no aplica ninguna de estas validaciones en el back-end, deberíamos poder cargar cualquier tipo de archivo.
Como se mencionó anteriormente, para evitar estas protecciones, podemos:
Modificar la solicitud de carga al servidor back-end
Manipular el código front-end para deshabilitar estas validaciones de tipo.
Comencemos examinando una solicitud normal a través de Burp
. Cuando seleccionamos una imagen, vemos que se refleja como nuestra imagen de perfil y, cuando hacemos clic en Upload
, nuestra imagen de perfil se actualiza y persiste a través de actualizaciones. Esto indica que nuestra imagen se cargó al servidor, que ahora nos la muestra:
Si capturamos la solicitud de carga con Burp
, vemos la siguiente solicitud enviada por la aplicación web:
La aplicación web parece estar enviando una solicitud de carga HTTP estándar a /upload.php
. De esta manera, ahora podemos modificar esta solicitud para satisfacer nuestras necesidades sin tener las restricciones de validación de tipo del front-end. Si el servidor back-end no valida el tipo de archivo cargado, entonces, en teoría, deberíamos poder enviar cualquier tipo de archivo/contenido, y este se cargaría al servidor.
Las dos partes importantes de la solicitud son filename="HTB.png"
y el contenido del archivo al final de la solicitud. Si modificamos el filename
a shell.php
y modificamos el contenido de la webshell que usamos en la sección anterior, estaríamos cargando un webshell PHP
en lugar de una imagen.
Entonces, capturemos otra solicitud de carga de imagen y luego modifiquémosla en consecuencia:
Nota: También podemos modificar el Content-Type
del archivo cargado, aunque esto no debería jugar un papel importante en esta etapa, por lo que lo mantendremos sin modificar.
Como podemos ver, nuestra solicitud de carga se realizó correctamente y obtuvimos la respuesta File successfully uploaded
. Por lo tanto, ahora podemos visitar el archivo cargado e interactuar con él para obtener la ejecución remota del código.
Otro método para evitar las validaciones del lado del cliente es manipular el código del front-end. Como estas funciones se procesan completamente dentro de nuestro navegador web, tenemos control total sobre ellas. Por lo tanto, podemos modificar estos scripts o deshabilitarlos por completo. Luego, podemos usar la función de carga para cargar cualquier tipo de archivo sin necesidad de utilizar la función de captura y modificación de nuestras solicitudes con BurpSuite
.
Para comenzar, podemos hacer clic en [ CTRL+SHIFT+C
] para alternar el navegador Page Inspector
y luego hacer clic en la imagen de perfil, que es donde activamos el selector de archivos para el formulario de carga:
Esto resaltará la siguiente entrada de archivo HTML:
Aquí, vemos que la entrada de archivo especifica ( .jpg,.jpeg,.png
) como los tipos de archivo permitidos dentro del cuadro de diálogo de selección de archivos. Sin embargo, podemos modificar esto fácilmente y seleccionar All Files
como lo hicimos antes, por lo que no es necesario cambiar esta parte de la página.
La parte más interesante es onchange="checkFile(this)"
, que parece ejecutar un código JavaScript cada vez que seleccionamos un archivo, lo que parece realizar la validación del tipo de archivo. Para obtener los detalles de esta función, podemos ir a Console
con [ CTRL+SHIFT+K
] y luego podemos escribir el nombre de la función ( checkFile
) para obtener sus detalles:
Lo fundamental que nos llevamos de esta función es que comprueba si la extensión del archivo es una imagen, y si no lo es imprime el mensaje de error que vimos antes ( Only images are allowed!
) y desactiva el botón Upload
. Podemos añadir PHP
como una de las extensiones permitidas o modificar la función para quitar la comprobación de la extensión.
Afortunadamente, no necesitamos escribir ni modificar código JavaScript. Podemos eliminar esta función del código HTML, ya que su uso principal parece ser la validación del tipo de archivo y eliminarla no debería afectar a nada.
Para ello, podemos volver a nuestro inspector, hacer clic nuevamente en la imagen de perfil, hacer doble click en el nombre de la función ( checkFile
) en la línea 18
, y eliminarlo:
Consejo: También puedes hacer lo mismo para eliminar accept=".jpg,.jpeg,.png"
, lo que debería facilitar la selección del shell PHP
en el cuadro de diálogo de selección de archivos, aunque esto no es obligatorio, como se mencionó anteriormente.
Con la función checkFile
eliminada de la entrada del archivo, deberíamos poder seleccionar nuestro webshell PHP
a través del cuadro de diálogo de selección de archivo y cargarlo normalmente sin validaciones, similar a lo que hicimos en la sección anterior.
Nota: La modificación que realizamos en el código fuente es temporal y no se mantendrá en las actualizaciones de la página, ya que solo la estamos modificando en el lado del cliente. Sin embargo, nuestra única necesidad es omitir la validación del lado del cliente, por lo que debería ser suficiente para este propósito.
Una vez que cargamos nuestro webshell usando cualquiera de los métodos anteriores y luego actualizamos la página, podemos usar el Page Inspector
una vez más con [ CTRL+SHIFT+C
], hacer click en la imagen de perfil y deberíamos ver la URL de nuestro webshell cargado:
Si podemos hacer clic en el enlace de arriba, llegaremos a nuestro shell web cargado, con el que podemos interactuar para ejecutar comandos en el servidor back-end:
Nota: Los pasos que se muestran se aplican a Firefox, ya que otros navegadores pueden tener métodos ligeramente diferentes para aplicar cambios locales a la fuente, como el uso overrides
en Chrome.
Intente omitir las validaciones de tipo de archivo del lado del cliente en el ejercicio anterior, luego cargue un webshell para leer /flag.txt
Intentamos cargar una webshell PHP pero no nos deja, tiene una validación para solamente permitir imágenes:
Encontramos una función validate()
interesante, que es la que hace la validación de las imágenes:
Vamos a eliminar esta función del HTML, dejando solo el upload()
, ya que es una función posiblemente necesaria para subir este archivo:
Le damos a upload para subir la webshell en PHP, y si miramos ahora el código fuente nos encontramos con la ruta de la imagen:
Si accedemos entramos directamente a la webshell:
Bingo! Obtenemos la flag 🏆