La práctica de hoy hará uso de una aplicación web vulnerable llamada Juice Shop
diseñada y creada por OWASP
con varios contribuyentes a lo largo de los años. Se fue creando con una serie de errores y fallas de seguridad para demostrar la alta tasa de probabilidad que un programador no implemente bien su diseño. A continuación haremos varios ejercicios con explicación.
¿Cállate y déjame explicar, sí? La aplicación es una simple SPA (Single Page Application)
que usa una arquitectura MEAN (MongoDB Express Angular Node.js)
para poder proveer una aplicación de ventas. Sin embargo, no implementa MongoDB
sino MarsDB
pero usa como bd principal una SQLite
.
Si quieres correrla de forma local, ocuparás Docker
para obtener la imagen y correrla de forma local sin instalar de forma separada las dependencias. De lo contrario puedes usar Heroku
para una instancia en la nube.
Pueden ver el proyecto en Github
con más instrucciones en esto Juice Shop
Obtenemos la imagen más reciente
$ docker pull bkimminich/juice-shop
Corremos la imagen
$ docker run -d -p 3000:3000 bkimminich/juice-shop
Después de un minuto y medio, nos dirijimos a http://localhost:3000/
para visualizar la aplicación web.
La desinfección de entrada describe la limpieza y restregado de la entrada del usuario para evitar que salte la cerca y aproveche los agujeros de seguridad. Pero la desinfección completa de los insumos es difícil. Si bien algunos sitios vulnerables simplemente no se desinfectan en absoluto, otros lo hacen de manera incompleta, lo que brinda a sus propietarios una falsa sensación de seguridad.
Hay tres métodos en que el atacante puede llegar desde el cliente al servidor web, los cuales son:
- Peticiones GET
- Peticiones POST
- Cookies
Dentro de nuestras peticiones al servicio web alojado en nuestro servidor, tenemos que incluir información que ocuparemos para desplegar en la UI del cliente. Se adjuntan (a veces) dentro de la URL como parámetros y el contenido es dinámico. Por ejemplo:
http://servicioweb.com/busqueda.php?id=12&nombre=usuario
Estos son parámetros incluidos en la información del encabezado enviada desde el navegador al servidor web. Los datos POST no aparecen en la URL, pero los atacantes pueden manipularlos mediante complementos del navegador como Tamper Data For Firefox
, Burp Suite
o OWASP ZAP
.
A menudo se pasan por alto al desinfectar la entrada, las cookies creadas por un sitio web pueden contener datos explotables. Las cookies se almacenan como archivos de texto sin formato en la máquina del usuario final y un pirata informático puede modificarlas fácilmente para manipular los datos de entrada enviados al servidor.
Lo que haremos a continuación, es insertar una simple etiqueta h1
y ver si al cambiarlo a una etiqueta h5
se altera el tamaño en tiempo real.
Ahora, cambiaremos al siguiente tamaño y ver si el texto insertado por el usuario puede manipular el UI.
Como vemos, efectivamente sí existe un cambio o alteración en el tamaño del texto. Por lo que significa que hacemos una petición al servidor y no verifica si el texto que mandamos/mostramos al usuario tiene algún tipo de sintaxis que NO
debería leer/ejecutar.
Como vemos, sí se realizó un POST
al web server y aquí podemos ver el payload
.
Vamos a ver si podemos manipular el DOM con un poco de XSS
. Vamos a intentar con <iframe src="javascript:alert('xss')">
pero también funciona con <img src="asdf" onerror="alert('xss')"/>
Ahora que sabemos que este grupo de programadores (probablemente un grupo noob de developers del Tec Mante). Nos iremos al inicio de sesión y ya que ni pudieron con la validación de entrada de texto, al menos habrán usado consultas parametrizadas.
Usaremos un poquito de SQLi
, pero primero debemos comprobar que funcionará. Podemos hacer esto intentando insertar '
en la área del correo, con cualquier contraseña.
Como vemos, debieron haber hecho concatenación de texto con variables en sus consultas provocando así una falla en sus consultas SQL.
Pues cualquier solicitud que no pueda ser manejada correctamente por el servidor eventualmente se pasará a un componente de manejo de errores global que envía una página de error al cliente que incluye un seguimiento de la pila y otra información confidencial. La API se comporta de manera similar, devolviendo un objeto de error JSON con datos confidenciales, como cadenas de consulta SQL.
Podemos ver esto a continuación
Con esto, ahora sabemos que la consulta SQL que usan para la sesión de usuario es
SELECT * FROM Users WHERE email = ''' AND password = '3691308f2a4c2f6983f2880d32e29c84' AND deletedAt IS NULL
También sabemos que la contraseña la encriptan con el hash MD5, que es anticuado y no debería usarse más (JAMÁS
).
Vamos a intentar iniciar sesión con los siguientes datos. Usaremos el siguiente comando en el campo de correo:
' or 1=1--
Esto provocará que la base de datos termine la consulta anterior y agregue el OR 1=1
además de comentar lo que sobra en la consulta. Dejándonos con el siguiente comando SQL final
SELECT * FROM Users WHERE email ='' OR 1=1;
Esto permitirá autenticarnos con la primera cuenta que salga en la tabla Users
. Vamos a ver qué cuenta nos deja usar
Jamás tengas tu cuenta admin como el primer registro.
Ahora, trataremos de registrar un nuevo usuario. Podemos obtener la URL del API para esto en el form de registro, sin embargo podemos alterar el role
o nivel de acceso a admin
mediante una petición POST.
Abrimos nuestra consola para usar cURL
en Linux y Postman
en Windows/Linux.
curl -X POST -H "Content-Type: application/json" -d '{"email":"dirac@juice-sh.op","password":"imtheboss","role":"admin"}' http://localhost:3000/api/Users
Podremos ver que sí nos hemos generado esta cuenta
Nice