DEV Community

arturo melgarejo
arturo melgarejo

Posted on

CandyVault - WriteUp

Este es el primer WriteUp que escribo en la pagina de dev.to. La razon principal de empezar a crear estos writeups es porque considero que el documentar que es una buena forma de medir y guardar el progreso, asi como contribuir y ayudar en el aprendizaje de otros.

Introducción
Este reto pertenece a la categoría very-easy de los challenges Web de HackTheBox. Cuando tengo poco tiempo realizo este tipo de retos, ya que solo sueles tener que romper la lógica, o vulnerar una vez, no tienes que encadenar varios fallos de diseño o vulnerabilidades.
Este reto consiste en explotar una vulnerabilidad de NOSQL injection, mas especificamente, usa MONGODB.

Fase de reconocimiento y búsqueda de vulnerabilidades

Sin necesidad de replicar la instancia del proyecto en Docker, descargamos el archivo de proyecto y navegamos hasta ./challenge/application.

Al editar el archivo app.py, reconocemos que el servidor usa como framework Flask. Normalmente se suele usar Django para aplicaciones web con python, pero en este caso usan Flask que es mas para pequeñas webs, aplicaciones en desarrollo que requieren de un servidor web, y en general para pruebas sobre proyectos. Por esa razon se suele obviar cambiar el modo de Debug a Producción. No obstante nuestro servidor usa en run.py:

debug=False

Ademas, vemos que la aplicacion usa MongoDB. Para conectarse usa una clave que la coge a través de config.py, y el mismo hace una llamada a una variable de entorno que no podríamos leer. Por tanto (parece) que a menos que podamos leer las variables de entorno o un objeto que queramos, no podríamos acceder a la BD.

Sin mucho mas analizar el archivo, que es muy sencillo y no tiene mas módulos que app.py, nos damos cuenta que cuando nos autentiquemos nos devolverá la flag.

user = users_collection.find_one({"email": email, "password": password})

if user:
    return render_template("candy.html", flag=open("flag.txt").read())

Enter fullscreen mode Exit fullscreen mode

Fijémonos que a demas de decirnos que es lo que tenemos que hacer, ya nos da una gran pista sobre que rumbo tomar para explotar la aplicación:

if content_type == "application/x-www-form-urlencoded":
    email = request.form.get("email")
    password = request.form.get("password")

elif content_type == "application/json":
    data = request.get_json()
    email = data.get("email")
    password = data.get("password")
Enter fullscreen mode Exit fullscreen mode

hmm… Curioso ¿Porqué una aplicacion querria aceptar tanto json como POST normal? Obviamente porque quieren que lo veamos y vayamos directos al grano. Aqui ocurre una especie de error parecido al de deserialización con PHP para usar objetos y conseguir explotación remota. Solo que en nuestro caso, lo usaremos para hacer una injección a mongodb.
Sabemos que una petición “normal” en json seria

{
  "email": "ejemplo@medium.us",
  "password": "2024miperro"
}
Enter fullscreen mode Exit fullscreen mode

Y tambien sabemos que la aplicacion usa data.get(), lo cual nos permite poder crear un objeto diferente a una string, ya que en python las variables se les define el tipo/objeto en tiempo real

Además (Estamos cooking), con un poco de investigacion, vemos que la función find_one, toma operadores como $eq, $gt, $lt, y $ne.

Estos fitros se le pasan a la función find_one en forma de objetos de los campos, como

{"password": {"$lt": 5}}
/
variable["password"]["lt"] = 5
Enter fullscreen mode Exit fullscreen mode

Bueno pues podemos usar $ne=null para que nos devuelva cualquiera que no sea nulo. Con esto y un bizcocho en teoría habríamos vulnerado la aplicacion.

Ahora solo falta explotarla

Explotación
Para la fase de explotación, realizaremos lo siguiente:

Interceptaremos la petición post de un login normal en BURP.
Cambiaremos el valor de los campos user y password a los de (en formato json) a “password/login”:”$ne”:null, con su sintaxis adecuada.
Además, para que la aplicacion acepte el json, cambiaremos el header de … url-encoded … a application/json. Consecuentemente dejaremos una linea de espacio entre los header de http y el inicio de nuestro nuevo JSON.
Disfrutar de nuestra flag.

Top comments (0)