hacktricks/pentesting-web/oauth-to-account-takeover.md

27 KiB

OAuth a Toma de control de cuenta

Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Información Básica

Existen varias versiones de OAuth, puedes leer https://oauth.net/2/ para obtener una comprensión básica.

En este artículo, nos centraremos en el flujo más común que encontrarás hoy en día, que es el tipo de concesión de código de autorización OAuth 2.0. En esencia, OAuth proporciona a los desarrolladores un mecanismo de autorización para permitir que una aplicación acceda a datos o realice ciertas acciones contra tu cuenta, desde otra aplicación (el servidor de autorización).

Por ejemplo, digamos que el sitio web https://yourtweetreader.com tiene funcionalidad para mostrar todos los tweets que has enviado, incluyendo tweets privados. Para hacer esto, se introduce OAuth 2.0. https://yourtweetreader.com te pedirá que autorices su aplicación de Twitter para acceder a todos tus Tweets. Aparecerá una página de consentimiento en https://twitter.com mostrando qué permisos se están solicitando, y quién es el desarrollador que lo solicita. Una vez que autorices la solicitud, https://yourtweetreader.com será capaz de acceder a tus Tweets en tu nombre.

Elementos que son importantes entender en un contexto de OAuth 2.0:

  • propietario del recurso: El propietario del recurso es el usuario/entidad que otorga acceso a su recurso protegido, como sus Tweets de la cuenta de Twitter. En este ejemplo, serías .
  • servidor de recursos: El servidor de recursos es el servidor que maneja las solicitudes autenticadas después de que la aplicación ha obtenido un token de acceso en nombre del propietario del recurso. En este ejemplo, sería https://twitter.com
  • aplicación cliente: La aplicación cliente es la aplicación que solicita autorización del propietario del recurso. En este ejemplo, sería https://yourtweetreader.com.
  • servidor de autorización: El servidor de autorización es el servidor que emite tokens de acceso a la aplicación cliente después de autenticar con éxito al propietario del recurso y obtener autorización. En el ejemplo anterior, sería https://twitter.com
  • client_id: El client_id es el identificador de la aplicación. Este es un identificador único público y no secreto.
  • client_secret: El client_secret es un secreto conocido solo por la aplicación y el servidor de autorización. Esto se utiliza para generar tokens de acceso
  • response_type: El response_type es un valor que detalla qué tipo de token se está solicitando, como code
  • scope: El scope es el nivel de acceso solicitado que la aplicación cliente está pidiendo al propietario del recurso
  • redirect_uri: El redirect_uri es la URL a la que se redirige al usuario después de que la autorización está completa. Esto generalmente debe coincidir con la URL de redirección que previamente has registrado con el servicio
  • state: El parámetro state puede persistir datos entre que el usuario es dirigido al servidor de autorización y de nuevo. Es importante que este sea un valor único ya que sirve como un mecanismo de protección contra CSRF si contiene un valor único o aleatorio por solicitud
  • grant_type: El parámetro grant_type explica cuál es el tipo de concesión, y qué token va a ser devuelto
  • code: Este code es el código de autorización recibido del servidor de autorización que estará en el parámetro de cadena de consulta “code” en esta solicitud. Este código se utiliza en conjunto con el client_id y client_secret por la aplicación cliente para obtener un token de acceso
  • access_token: El access_token es el token que la aplicación cliente utiliza para hacer solicitudes de API en nombre de un propietario del recurso
  • refresh_token: El refresh_token permite a una aplicación obtener un nuevo token de acceso sin solicitar al usuario

Ejemplo Real

Juntándolo todo, así es como se ve un flujo real de OAuth:

  1. Visitas https://yourtweetreader.com y haces clic en el botón "Integrar con Twitter".
  2. https://yourtweetreader.com envía una solicitud a https://twitter.com pidiéndote, el propietario del recurso, que autorices la aplicación de Twitter de https://yourtweetreader.com para acceder a tus Tweets. La solicitud se verá así:
https://twitter.com/auth
?response_type=code
&client_id=yourtweetreader_clientId
&redirect_uri=https%3A%2F%2Fyourtweetreader.com%2Fcallback
&scope=readTweets
&state=kasodk9d1jd992k9klaskdh123

3. Se le mostrará una página de consentimiento:

4. Una vez aceptado, Twitter enviará una solicitud de regreso a la redirect_uri con los parámetros code y state:

https://yourtweetreader.com?code=asd91j3jd91j92j1j9d1&state=kasodk9d1jd992k9klaskdh123

5. https://yourtweetreader.com tomará ese code, y utilizando el client_id y client_secret de su aplicación, hará una solicitud desde el servidor para recuperar un access_token en tu nombre, lo cual les permitirá acceder a los permisos a los que diste tu consentimiento:

POST /oauth/access_token
Host: twitter.com
...{"client_id": "yourtweetreader_clientId", "client_secret": "yourtweetreader_clientSecret", "code": "asd91j3jd91j92j1j9d1", "grant_type": "authorization_code"}

6. Finalmente, el flujo está completo y https://yourtweetreader.com hará una llamada API a Twitter con tu access_token para acceder a tus Tweets.

Hallazgos de Bug Bounty

¡Ahora, la parte interesante! Hay muchas cosas que pueden salir mal en una implementación de OAuth, aquí están las diferentes categorías de errores que veo con frecuencia:

Configuración débil de redirect_uri

El redirect_uri es muy importante porque datos sensibles, como el code, se añaden a esta URL después de la autorización. Si el redirect_uri puede ser redirigido a un servidor controlado por un atacante, esto significa que el atacante puede potencialmente tomar control de la cuenta de una víctima utilizando el code por sí mismos, y ganando acceso a los datos de la víctima.

La forma en que esto se va a explotar variará según el servidor de autorización. Algunos solo aceptarán el mismo camino de redirect_uri exacto que se especificó en la aplicación cliente, pero algunos aceptarán cualquier cosa en el mismo dominio o subdirectorio del redirect_uri.

Dependiendo de la lógica manejada por el servidor, hay una serie de técnicas para evadir un redirect_uri. En una situación donde un redirect_uri es https://yourtweetreader.com/callback, estas incluyen:

  • Redirecciones abiertas: https://yourtweetreader.com/callback?redirectUrl=https://evil.com
  • Traversal de ruta: https://yourtweetreader.com/callback/../redirect?url=https://evil.com
  • Regexes débiles de redirect_uri: https://yourtweetreader.com.evil.com
  • Inyección de HTML y robo de tokens a través del encabezado referer: https://yourtweetreader.com/callback/home/attackerimg.jpg

Otros parámetros que pueden ser vulnerables a Redirecciones Abiertas son:

  • client_uri - URL de la página de inicio de la aplicación cliente
  • policy_uri - URL que la aplicación cliente Parte Confiante proporciona para que el usuario final pueda leer sobre cómo se utilizarán sus datos de perfil.
  • tos_uri - URL que la aplicación cliente Parte Confiante proporciona para que el usuario final pueda leer sobre los términos de servicio de la Parte Confiante.
  • initiate_login_uri - URI utilizando el esquema https que un tercero puede usar para iniciar un inicio de sesión por el RP. También debe usarse para redirección del lado del cliente.

Todos estos parámetros son opcionales según las especificaciones de OAuth y OpenID y no siempre son compatibles en un servidor particular, por lo que siempre vale la pena identificar qué parámetros son compatibles en tu servidor.

Si tu objetivo es un servidor OpenID, el punto de descubrimiento en **.well-known/openid-configuration** a veces contiene parámetros como "registration_endpoint", "request_uri_parameter_supported", y "require_request_uri_registration". Estos pueden ayudarte a encontrar el punto de registro y otros valores de configuración del servidor.

XSS en la implementación de redirección

Como se menciona en este informe de bug bounty https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html podría ser posible que la URL de redirección se refleje en la respuesta del servidor después de que el usuario se autentique, siendo vulnerable a XSS. Posible payload para probar:

https://app.victim.com/login?redirectUrl=https://app.victim.com/dashboard</script><h1>test</h1>

CSRF - Manejo inadecuado del parámetro state

Muy a menudo, el parámetro state se omite por completo o se usa de manera incorrecta. Si un parámetro state es inexistente, o un valor estático que nunca cambia, el flujo OAuth probablemente será vulnerable a CSRF. A veces, incluso si hay un parámetro state, la aplicación podría no realizar ninguna validación del parámetro y un ataque funcionará. La forma de explotar esto sería pasar por el proceso de autorización en tu propia cuenta y pausar justo después de autorizar. Entonces te encontrarás con una solicitud como:

https://yourtweetreader.com?code=asd91j3jd91j92j1j9d1

Después de recibir esta solicitud, puedes descartar la solicitud ya que estos códigos suelen ser de un solo uso. Luego puedes enviar esta URL a un usuario con sesión iniciada, y se agregará tu cuenta a su cuenta. Al principio, esto podría no parecer muy sensible ya que simplemente estás agregando tu cuenta a la cuenta de una víctima. Sin embargo, muchas implementaciones de OAuth son para fines de inicio de sesión, por lo que si puedes agregar tu cuenta de Google que se utiliza para iniciar sesión, podrías potencialmente realizar un Account Takeover con un solo clic, ya que iniciar sesión con tu cuenta de Google te daría acceso a la cuenta de la víctima.

Puedes encontrar un ejemplo sobre esto en este CTF writeup y en el HTB box llamado Oouch.

También he visto que el parámetro state se utiliza como un valor de redirección adicional varias veces. La aplicación utilizará redirect_uri para la redirección inicial, pero luego el parámetro state como una segunda redirección que podría contener el code dentro de los parámetros de consulta, o en el encabezado referer.

Una cosa importante a tener en cuenta es que esto no solo se aplica a situaciones de inicio de sesión y toma de control de cuentas. He visto malas configuraciones en:

  • Integraciones de Slack que permiten a un atacante agregar su cuenta de Slack como destinatario de todas las notificaciones/mensajes
  • Integraciones de Stripe que permiten a un atacante sobrescribir la información de pago y aceptar pagos de los clientes de la víctima
  • Integraciones de PayPal que permiten a un atacante agregar su cuenta de PayPal a la cuenta de la víctima, lo que depositaría dinero en la PayPal del atacante

Pre Account Takeover

Uno de los problemas más comunes que veo es cuando las aplicaciones permiten "Iniciar sesión con X" pero también con nombre de usuario/contraseña. Hay 2 formas diferentes de atacar esto:

  1. Si la aplicación no requiere verificación de correo electrónico al crear una cuenta, intenta crear una cuenta con la dirección de correo electrónico de una víctima y una contraseña del atacante antes de que la víctima se haya registrado. Si la víctima luego intenta registrarse o iniciar sesión con un tercero, como Google, es posible que la aplicación haga una búsqueda, vea que el correo electrónico ya está registrado y luego vincule su cuenta de Google a la cuenta creada por el atacante. Esto es un "pre account takeover" donde un atacante tendrá acceso a la cuenta de la víctima si la creó antes de que la víctima se registrara.
  2. Si una aplicación OAuth no requiere verificación de correo electrónico, intenta registrarte con esa aplicación OAuth y luego cambia la dirección de correo electrónico por la dirección de correo electrónico de una víctima. El mismo problema que se mencionó anteriormente podría existir, pero estarías atacándolo desde la otra dirección y obteniendo acceso a la cuenta de la víctima para un account takeover.

Disclosure of Secrets

Es muy importante reconocer cuáles de los muchos parámetros de OAuth son secretos y protegerlos. Por ejemplo, filtrar el client_id está perfectamente bien y es necesario, pero filtrar el client_secret es peligroso. Si esto se filtra, el atacante puede potencialmente abusar de la confianza e identidad de la aplicación cliente de confianza para robar access_tokens de usuario e información/acceso privado para sus cuentas integradas. Volviendo a nuestro ejemplo anterior, un problema que he visto es realizar este paso desde el cliente, en lugar del servidor:

5. https://yourtweetreader.com entonces tomará ese code, y utilizando el client_id y client_secret de su aplicación, hará una solicitud desde el servidor para recuperar un access_token en tu nombre, lo que les permitirá acceder a los permisos a los que diste tu consentimiento.

Si esto se hace desde el cliente, el client_secret se filtrará y los usuarios podrán generar access_tokens en nombre de la aplicación. Con un poco de ingeniería social, también pueden agregar más alcances a la autorización de OAuth y todo parecerá legítimo ya que la solicitud vendrá de la aplicación cliente de confianza.

Client Secret Bruteforce

Puedes intentar bruteforce el client_secret de un proveedor de servicios con el proveedor de identidad para intentar robar cuentas.
La solicitud para BF puede parecerse a:

POST /token HTTP/1.1
content-type: application/x-www-form-urlencoded
host: 10.10.10.10:3000
content-length: 135
Connection: close

code=77515&redirect_uri=http%3A%2F%2F10.10.10.10%3A3000%2Fcallback&grant_type=authorization_code&client_id=public_client_id&client_secret=[bruteforce]

Encabezado Referer filtrando Código + Estado

Una vez que el cliente tiene el código y estado, si se refleja dentro del encabezado Referer cuando navega a una página diferente, entonces es vulnerable.

Token de Acceso Almacenado en el Historial del Navegador

Ve al historial del navegador y verifica si el token de acceso está guardado allí.

Código de Autorización Permanente

El código de autorización debería vivir solo por un tiempo para limitar la ventana de tiempo donde un atacante puede robarlo y usarlo.

Token de Autorización/Actualización no vinculado al cliente

Si puedes obtener el código de autorización y usarlo con un cliente diferente, entonces puedes tomar control de otras cuentas.

Caminos Felices, XSS, Iframes y Mensajes Post para filtrar valores de código y estado

AWS Cognito

En este informe de recompensa por errores: https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/ puedes ver que el token que AWS Cognito devuelve al usuario podría tener suficientes permisos para sobrescribir los datos del usuario. Por lo tanto, si puedes cambiar el correo electrónico del usuario por el de otro usuario, podrías ser capaz de tomar control de otras cuentas.

# Read info of the user
aws cognito-idp get-user --region us-east-1 --access-token eyJraWQiOiJPVj[...]

# Change email address
aws cognito-idp update-user-attributes --region us-east-1 --access-token eyJraWQ[...] --user-attributes Name=email,Value=imaginary@flickr.com
{
"CodeDeliveryDetailsList": [
{
"Destination": "i***@f***.com",
"DeliveryMedium": "EMAIL",
"AttributeName": "email"
}
]
}

Para obtener información más detallada sobre cómo abusar de AWS Cognito, consulta:

{% embed url="https://cloud.hacktricks.xyz/pentesting-cloud/aws-pentesting/aws-unauthenticated-enum-access/aws-cognito-unauthenticated-enum" %}

Abusando de tokens de otras aplicaciones

Como se menciona en este artículo, los flujos de OAuth que esperan recibir el token (y no un código) podrían ser vulnerables si no verifican que el token pertenece a la aplicación.

Esto se debe a que un atacante podría crear una aplicación compatible con OAuth e iniciar sesión con Facebook (por ejemplo) en su propia aplicación. Luego, una vez que una víctima inicia sesión con Facebook en la aplicación del atacante, el atacante podría obtener el token OAuth del usuario otorgado a su aplicación y usarlo para iniciar sesión en la aplicación OAuth de la víctima utilizando el token del usuario de la víctima.

{% hint style="danger" %} Por lo tanto, si el atacante logra que el usuario acceda a su propia aplicación OAuth, podrá tomar control de la cuenta de la víctima en aplicaciones que esperan un token y no verifican si el token fue otorgado a su ID de aplicación. {% endhint %}

Según este artículo, era posible hacer que una víctima abriera una página con un returnUrl apuntando al host del atacante. Esta información se almacenaría en una cookie (RU) y en un paso posterior el prompt preguntará al usuario si quiere dar acceso al host del atacante.

Para evitar este prompt, era posible abrir una pestaña para iniciar el flujo de Oauth que configuraría esta cookie RU usando el returnUrl, cerrar la pestaña antes de que se mostrara el prompt y abrir una nueva pestaña sin ese valor. Entonces, el prompt no informará sobre el host del atacante, pero la cookie estaría configurada para él, por lo que el token se enviaría al host del atacante en la redirección.

Parámetros de SSRFs

Una de las URLs ocultas que podrías pasar por alto es el punto final de registro de cliente dinámico. Para autenticar usuarios con éxito, los servidores OAuth necesitan conocer detalles sobre la aplicación cliente, como el "client_name", "client_secret", "redirect_uris", etc. Estos detalles se pueden proporcionar a través de la configuración local, pero los servidores de autorización OAuth también pueden tener un punto final de registro especial. Este punto final normalmente está mapeado a "/register" y acepta solicitudes POST con el siguiente formato:

POST /connect/register HTTP/1.1
Content-Type: application/json
Host: server.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJ ...

{
"application_type": "web",
"redirect_uris": ["https://client.example.org/callback"],
"client_name": "My Example",
"logo_uri": "https://client.example.org/logo.png",
"subject_type": "pairwise",
"sector_identifier_uri": "https://example.org/rdrct_uris.json",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client.example.org/public_keys.jwks",
"contacts": ["ve7jtb@example.org"],
"request_uris": ["https://client.example.org/rf.txt"]
}

Hay dos especificaciones que definen parámetros en esta solicitud: RFC7591 para OAuth y Openid Connect Registration 1.0.

Como puedes ver aquí, varios de estos valores se pasan a través de referencias URL y parecen objetivos potenciales para Server Side Request Forgery. Al mismo tiempo, la mayoría de los servidores que hemos probado no resuelven estas URLs inmediatamente cuando reciben una solicitud de registro. En su lugar, simplemente guardan estos parámetros y los usan más tarde durante el flujo de autorización OAuth. En otras palabras, esto es más como un SSRF de segundo orden, lo que hace que la detección de caja negra sea más difícil.

Los siguientes parámetros son particularmente interesantes para ataques SSRF:

  • logo_uri - URL que hace referencia a un logotipo para la aplicación cliente. Después de registrar un cliente, puedes intentar llamar al punto final de autorización OAuth ("/authorize") usando tu nuevo "client_id". Después del inicio de sesión, el servidor te pedirá que apruebes la solicitud y puede mostrar la imagen del "logo_uri". Si el servidor obtiene la imagen por sí mismo, el SSRF debería activarse en este paso. Alternativamente, el servidor puede simplemente incluir el logotipo a través de una etiqueta cliente-side "<img>". Aunque esto no conduce a SSRF, puede llevar a XSS si la URL no está escapada.
  • jwks_uri - URL para el documento del conjunto de claves web JSON del cliente [JWK]. Este conjunto de claves es necesario en el servidor para validar solicitudes firmadas hechas al punto final del token cuando se usan JWTs para la autenticación del cliente [RFC7523]. Para probar SSRF en este parámetro, registra una nueva aplicación cliente con un "jwks_uri" malicioso, realiza el proceso de autorización para obtener un código de autorización para cualquier usuario y luego solicita el punto final "/token" con el siguiente cuerpo:

POST /oauth/token HTTP/1.1
...
``
grant_type=authorization_code&code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=eyJhbGci...

Si es vulnerable, el servidor debería realizar una solicitud HTTP de servidor a servidor al "jwks_uri" suministrado porque necesita esta clave para verificar la validez del parámetro "client_assertion" en tu solicitud. Esto probablemente solo será una vulnerabilidad SSRF ciega, ya que el servidor espera una respuesta JSON adecuada.

  • sector_identifier_uri - Esta URL hace referencia a un archivo con un único array JSON de valores de redirect_uri. Si es compatible, el servidor puede obtener este valor tan pronto como envíes la solicitud de registro dinámico. Si esto no se obtiene de inmediato, intenta realizar la autorización para este cliente en el servidor. Como necesita conocer los redirect_uris para completar el flujo de autorización, esto obligará al servidor a realizar una solicitud a tu sector_identifier_uri malicioso.
  • request_uris - Un array de los request_uris permitidos para este cliente. El parámetro "request_uri" puede ser compatible con el punto final de autorización para proporcionar una URL que contenga un JWT con la información de la solicitud (ver https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.6.2).

Incluso si el registro de cliente dinámico no está habilitado, o requiere autenticación, podemos intentar realizar SSRF en el punto final de autorización simplemente usando "request_uri":\

GET /authorize?response_type=code%20id_token&client_id=sclient1&request_uri=https://ybd1rc7ylpbqzygoahtjh6v0frlh96.burpcollaborator.net/request.jwt

Nota: no confundas este parámetro con "redirect_uri". El "redirect_uri" se utiliza para la redirección después de la autorización, mientras que "request_uri" es obtenido por el servidor al inicio del proceso de autorización.

Al mismo tiempo, muchos servidores que hemos visto no permiten valores arbitrarios de "request_uri": solo permiten URLs en la lista blanca que se pre-registraron durante el proceso de registro del cliente. Por eso necesitamos suministrar "request_uris": "https://ybd1rc7ylpbqzygoahtjh6v0frlh96.burpcollaborator.net/request.jwt" de antemano.

Condiciones de Carrera en Proveedores de OAuth

Si la plataforma que estás probando es un proveedor de OAuth lee esto para probar posibles Condiciones de Carrera.

Referencias

Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks: