PortSwigger Academy – NoSQL Injection

¡Hola a todos! Aquí estamos de nuevo y esta vez seguimos preparando la certificación Burp Suite Certified Professional (BSCP), que proporciona una base muy buena de cara a auditorías web y gestión de la presión, sobre todo en el examen para el cual te proporcionan 4 horas y hay que explotar hasta 6 vulnerabilidades. Además, se trata de un examen muy barato (<100€) lo que la hace sumamente atractiva.

Antes de nada, recordad que PortSwigger nos permite probar 30 días su versión profesional de Burp Suite. Os recomendamos que activéis esta versión para poder probar todas las funcionalidades de la herramienta.

En esta entrada explicaremos y solucionaremos todos los laboratorios relativos a NoSQL Injection. Hay muchos walkthroughs sobre cómo resolver estos laboratorios, pero exponerlos aquí nos sirve para afianzar conceptos y enseñaros además algunos trucos de uso de Burp Suite Professional, así como comentar veces que hemos visto las vulnerabilidades estudiadas en los laboratorios en la vida real. Sin más dilación, ¡comenzamos!

En este caso, hemos de decir que en la vida real es raro encontrarse con este tipo de vulnerabilidades. Lo más normal es utilizar bases de datos SQL, si bien últimamente el uso de NoSQL está aumentando. Por ello, los laboratorios resultan útiles ya que puede ser que te encuentres con aplicaciones de este tipo con más asiduidad con el tiempo.

Lab1 (Apprentice) – Detecting NoSQL injection

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, perform a NoSQL injection attack that causes the application to display unreleased products.». En este laboratorio debemos identificar y explotar una vulnerabilidad de NoSQL Injection para obtener productos no liberados.

Para resolverlo, aplicaremos la misma lógica que en el caso de las inyecciones SQL y que en todas las inyecciones en general. Tratemos de pensar cómo estará construida la consulta en el backend. Asimismo, debemos saber que en el caso de bases de datos NoSQL, cada una de ellas puede tener un lenguaje concreto de consulta, pero en este caso nos centramos en MongoDB que es la más utilizada. Tras mapear la aplicación, vemos que para listar productos se genera una petición como la siguiente.

Confirmamos que la aplicación es vulnerable con el siguiente payload genérico y, además, vemos que utiliza MongoDB.

'%22%60%7b%0d%0a%3b%24Foo%7d%0d%0a%24Foo%20%5cxYZ%00

Como decimos, imaginamos la consulta como algo así:

this.category = '<category>'

Por tanto, vamos a incluir un payload específico (negrita y marcado) que haga que la condición siempre sea cierta:

this.category = 'foo'||1||''

Lanzamos la petición y, como veremos, el laboratorio se resuelve, ya que la condición siempre es cierta:

Lab2 (Apprentice) – Exploiting NoSQL operator injection to bypass authentication

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, log into the application as the administrator user.». En este laboratorio debemos identificar y explotar una vulnerabilidad de NoSQL Injection para lograr escalar privilegios como «administrator».

Comenzamos evaluando la aplicación y vemos que únicamente tiene como superficie de exposición válida para la elevación de privilegios el inicio de sesión. Usamos el usuario «wiener:peter» y evaluamos cuál es la petición que se realiza.

Como vemos, tenemos un cuerpo JSON. Intentaremos inyectar payloads básicos de inyección de operadores con el objetivo de hacer bypass de la autenticación. Para ello, usamos el siguiente payload para el campo «username»:

{"$ne":"invalid"}

Y vemos una cosa curiosa, aunque no tenemos un usuario válido, la aplicación nos loggea como «wiener». Esto es porque la contraseña «peter» pertenece a ese usuario, pero nos estamos saltando la comprobación del mismo. Invertimos ahora el payload y lo ponemos en el campo «password». Asimimo, inyectamos el campo usuario con una expresión regular, dado que a priori no conocemos el nombre del usuario administrador:

{"username":{"$regex":"admin.*"},"password":{"$ne":"invalid"}}

Como vemos, obtenemos acceso y el nombre del usuario administrador. Ahora, simplemente pasando la cookie o realizando este mismo proceso en una petición de login interceptada, habremos resuelto el laboratorio. Como truco, también puedes dar botón derecho en la respuesta HTTP y click en «Open in browser» para darlo por resuelto.

Lab3 (Practicioner) – Exploiting NoSQL injection to extract data

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, extract the password for the administrator user, then log in to their account.». En este laboratorio debemos identificar y explotar una vulnerabilidad de NoSQL Injection para obtener las credenciales de administrador.

Accedemos en primer lugar con el usuario «wiener:peter» y observamos una API que nos permite listar otros usuarios. Capturamos dicha petición, pues será vulnerable:

Ahora, de nuevo, debemos deducir que se está utilizando una base datos NoSQL (probable debido al uso de JSON). Podemos enviar payloads genéricos, pero simplemente nos tirará un mensaje de error. Probemos a inyectar datos suponiendo que la base de datos es MongoDB. Dado que nos muestra datos de un usuario, la consulta tendrá una parte tal que así:

{"$where":"this.username=='<parámetro>'"}

Por tanto, para extraer datos, lo haremos con condiciones booleanas:

{«$where»:»this.username==’administrator’ && this.password[0] == ‘a’ || ‘a’==’b‘»}

Fíjate en el payload, en negrita y marcado. Aquí lo tienes por sí mismo:

administrator’ && this.password[0] == ‘a’ || ‘a’==’b

La consulta anterior tendrá éxito si y solo si la primera letra de la contraseña es una ‘a’. Por tanto, podemos automatizar con Burp Intruder este asunto, obteniendo todas las letras de la contraseña, suponiendo que el campo «this.password» exista (que existe, en este caso). Si no existiese, podríamos intentar incluso hacer fuerza bruta al nombre de dicho campo.

Como vemos al lanzar Burp Intruder en modo Cluster Bomb con el primer payload numérico y el segundo alfanumérico, obtenemos la contraseña del usuario administrador. Esto es porque dichas respuestas son las únicas cuya longitud difiere del resto, ya que de normal la aplicación devolverá el error «Could not find user» para todas las peticiones salvo aquellas para las que la letra de la contraseña en la posición que probamos sea la correcta, donde devolverá los datos del administrador. Por tanto, simplemente ordenando las letras y tomándolas como contraseña podemos iniciar sesión y resolver el laboratorio.

Lab4 (Practicioner) – Exploiting NoSQL operator injection to extract unknown fields

Lo primero de todo, lanzamos el laboratorio y configuramos en la pestaña «Scope» para que solamente se capturen peticiones a dicha web, ya que es la que tenemos bajo alcance. Esto es muy recomendable siempre en auditorías reales, pues se eliminará todo el ruido del navegador y nos centraremos solo en lo realmente importante: el alcance de la auditoría.

En segundo lugar, tomemos como referencia el objetivo que nos proponen: «To solve the lab, log in as carlos. En este laboratorio debemos identificar y explotar una vulnerabilidad de NoSQL Injection para obtener las credenciales de «carlos».

En este laboratorio, evaluaremos de nuevo el inicio de sesión. Fíjate cómo al incluir un payload de inyección de operadores básico en la contraseña para el usuario «carlos», recibimos una respuesta diferente que al utilizar una contraseña normal:

Es decir, tenemos de nuevo el bypass de la autenticación. Sin embargo, la cuenta está bloqueada y por ello no podemos aprovecharlo. ¿Qué podemos hacer? Pues intentar extraer información aprovechando los operandos NoSQL. Para ello, utilizaremos un payload como el siguiente:

{"username":"carlos","password":{"$ne":"invalid"
},
"$where":"Object.keys(this)[0].match('^.{0}a.*')"}

Fíjate en la cláusula WHERE, pues nos permite extraer el nombre del primer campo del objeto que estamos obteniendo de la base de datos. Automatizamos con Burp Intruder y obtenemos el nombre de dicho campo (filtramos las respuestas que no contengan «Invalid username or password» puesto que son las que la condición WHERE no se cumple y ordenamos las restantes).

Como vemos, el primer campo se llama «id». Iteramos ahora en el segundo campo (valor [1] de las Object.keys) y obtenemos su nombre. Acuérdate de filtrar las peticiones que tengan «Invalid username or password» puesto que son las «malas».

El campo 2 es «username». Vamos a por los campos siguientes:

Bien, ahora sabemos que el campo se llama «newPwdTkn». El siguiente paso del proceso es extraerlo para el usuario «carlos». Con el mismo enfoque, usaremos el siguiente payload:

{"username":"carlos","password":{"$ne":"invalid"
},
"$where":"this.newPwdTkn.match('^.{0}a.*')"}

De nuevo, tendremos que configurar Burp Intruder para iterar por todos los caracteres del token.

Antes de lanzar Burp Intruder, lanzamos un reseteo de contraseña para «carlos» en la web y, posteriormente, lanzamos el ataque, filtramos y ordenamos de nuevo la salida:

Ahora que tenemos el token «71a4a36908657468», lanzaremos una petición GET al endpoint «forgot-password» incluyendo el parámetro «newPwdTkn» y el valor obtenido y vemos que nos permite cambiar la contraseña. Este punto debemos deducirlo, pues no tenemos otro usuario con el que probar.

Finalmente, cambiamos la contraseña y… ¡¡Tachán, podremos acceder como «carlos» resolviendo el laboratorio!!

~km0xu95