hacktricks/pentesting-web/oauth-to-account-takeover.md
carlospolop 63bd9641c0 f
2023-06-05 20:33:24 +02:00

26 KiB

OAuth para tomar el control de una cuenta

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Información básica

Existen varias versiones de OAuth, puedes leer https://oauth.net/2/ para tener 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 en tu cuenta, desde otra aplicación (el servidor de autorización).

Por ejemplo, supongamos que el sitio web https://yourtweetreader.com tiene una funcionalidad para mostrar todos los tweets que has enviado, incluyendo los 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. Una página de consentimiento aparecerá 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 podrá acceder a tus tweets en tu nombre.

Elementos importantes para entender en el contexto de OAuth 2.0:

  • propietario de recursos: El propietario de recursos es el usuario/entidad que otorga acceso a su recurso protegido, como los tweets de su 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 haya obtenido un token de acceso en nombre del propietario de recursos. 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 de recursos. 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 de recursos 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, 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 access_tokens
  • 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á solicitando del propietario de recursos
  • redirect_uri: El redirect_uri es la URL a la que se redirige al usuario después de que se complete la autorización. Esto generalmente debe coincidir con la URL de redireccionamiento que has registrado previamente con el servicio.
  • state: El parámetro state puede persistir datos entre la dirección del usuario al servidor de autorización y viceversa. Es importante que este sea un valor único ya que sirve como un mecanismo de protección 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 se va a devolver.
  • 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 junto con el client_id y el client_secret por la aplicación cliente para obtener un access_token.
  • access_token: El access_token es el token que la aplicación cliente utiliza para hacer solicitudes de API en nombre del propietario de recursos.
  • refresh_token: El refresh_token permite a una aplicación obtener un nuevo access_token sin solicitar al usuario

Ejemplo real

Poniendo todo esto junto, esto es lo que parece 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 de recursos, que autorices la aplicación de Twitter de https://yourtweetreader.com a 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 pedirá que acepte una página de consentimiento:

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

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

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

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 viene la parte interesante! Hay muchas cosas que pueden salir mal en una implementación de OAuth, aquí están las diferentes categorías de bugs que veo con frecuencia:

Configuración débil de redirect_uri

El redirect_uri es muy importante porque datos sensibles, como el code, se agregan 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 potencialmente puede tomar el control de la cuenta de una víctima usando el code ellos mismos y obteniendo acceso a los datos de la víctima.

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

Dependiendo de la lógica manejada por el servidor, hay una serie de técnicas para evitar un redirect_uri. En una situación en la que 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 el cliente de la parte que confía en la aplicación proporciona para que el usuario final pueda leer sobre cómo se utilizarán sus datos de perfil.
  • tos_uri - URL que el cliente de la parte que confía en la aplicación proporciona para que el usuario final pueda leer sobre los términos de servicio de la parte que confía en la aplicación.
  • initiate_login_uri - URI que utiliza el esquema https que un tercero puede utilizar para iniciar una sesión de inicio de sesión por el RP. También debe usarse para la 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 en particular, por lo que siempre vale la pena identificar qué parámetros son compatibles en tu servidor.

Si apuntas a 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 final 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, es 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. Carga útil posible 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 completamente o se utiliza de manera incorrecta. Si un parámetro de estado es inexistente o un valor estático que nunca cambia, es muy probable que el flujo de OAuth sea vulnerable a CSRF. A veces, incluso si hay un parámetro state, la aplicación puede no validar el parámetro y un ataque funcionará. La forma de explotar esto sería pasar por el proceso de autorización en su propia cuenta y detenerse justo después de autorizar. Luego encontrará una solicitud como:

https://yourtweetreader.com?code=asd91j3jd91j92j1j9d1

Después de recibir esta solicitud, puedes descartarla porque estos códigos suelen ser de un solo uso. Luego, puedes enviar esta URL a un usuario conectado y se agregará tu cuenta a la de ellos. Al principio, esto puede no parecer muy sensible ya que simplemente estás agregando tu cuenta a la cuenta de la 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 una Toma de control de cuenta 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 writeup de CTF y en la caja HTB llamada Oouch.

También he visto que el parámetro de estado se usa como un valor de redireccionamiento adicional varias veces. La aplicación usará 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 el encabezado de referencia.

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 cuenta. He visto configuraciones incorrectas 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 cuenta de PayPal del atacante

Pre Toma de control de cuenta

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 en la creación de la cuenta, intenta crear una cuenta con la dirección de correo electrónico de la víctima y una contraseña de 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, luego vincule su cuenta de Google a la cuenta creada por el atacante. Esto es una "pre toma de control de cuenta" 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 con la dirección de correo electrónico de la 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 una toma de control de cuenta.

Divulgación de secretos

Es muy importante reconocer cuáles de los muchos parámetros de OAuth son secretos y protegerlos. Por ejemplo, filtrar el client_id es perfectamente aceptable y 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 los access_tokens de los usuarios y la 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 luego tomará ese code y, utilizando el client_id y el 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 has consentido.

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 algo 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.

Fuerza bruta de secretos del cliente

Puedes intentar atacar por fuerza bruta el client_secret de un proveedor de servicios con el proveedor de identidad para intentar robar cuentas.
La solicitud para BF puede parecer similar 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]

Fuga de información del encabezado Referer + Estado

Una vez que el cliente tiene el código y el 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

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

Código de autorización eterno

El código de autorización debe vivir solo por un tiempo para limitar la ventana de tiempo en la que un atacante puede robarlo y usarlo.

Token de autorización/actualización no vinculado al cliente

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

Rutas felices, XSS, Iframes y mensajes de publicación 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/ puede ver que el token que AWS Cognito devuelve al usuario puede tener suficientes permisos para sobrescribir los datos del usuario. Por lo tanto, si puede cambiar el correo electrónico del usuario por un correo electrónico de usuario diferente, podría tomar el 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 detallada sobre cómo abusar de AWS Cognito, consulte:

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

Parámetros de SSRF

Uno de los URLs ocultos que puede pasar por alto es el punto final de registro de cliente dinámico. Para autenticar con éxito a los usuarios, los servidores OAuth necesitan conocer detalles sobre la aplicación cliente, como el "client_name", "client_secret", "redirect_uris", y así sucesivamente. Estos detalles pueden ser proporcionados 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 se asigna 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 los parámetros en esta solicitud: RFC7591 para OAuth y Openid Connect Registration 1.0.

Como se puede ver aquí, varios de estos valores se pasan a través de referencias URL y parecen ser posibles objetivos para Server Side Request Forgery. Al mismo tiempo, la mayoría de los servidores que hemos probado no resuelven estas URL 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 de 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 los ataques SSRF:

  • logo_uri - URL que hace referencia a un logotipo para la aplicación del cliente. Después de registrar un cliente, puedes intentar llamar al punto final de autorización de 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 de "logo_uri". Si el servidor recupera la imagen por sí mismo, el SSRF debería ser desencadenado por este paso. Alternativamente, el servidor puede incluir el logotipo a través de una etiqueta "<img>" del lado del cliente. Aunque esto no lleva a SSRF, puede llevar a XSS si la URL no está escapada.

  • jwks_uri - URL para el conjunto de claves JSON del cliente [JWK]. Este conjunto de claves es necesario en el servidor para validar las solicitudes firmadas realizadas en el punto final del token cuando se usan JWT para la autenticación del cliente [RFC7523]. Para probar la SSRF en este parámetro, registra una nueva aplicación de 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 recupera 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 a la "jwks_uri" suministrada porque necesita esta clave para comprobar la validez del parámetro "client_assertion" en tu solicitud. Esto probablemente solo será una vulnerabilidad de SSRF ciega, ya que el servidor espera una respuesta JSON adecuada.

  • sector_identifier_uri - Esta URL hace referencia a un archivo con una sola matriz JSON de valores de redirect_uri. Si es compatible, el servidor puede recuperar este valor tan pronto como envíes la solicitud de registro dinámico. Si esto no se recupera inmediatamente, 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 hacer una solicitud a tu malintencionado sector_identifier_uri.

  • request_uris - Una matriz 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 dinámico del cliente 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 confundir 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" se recupera 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 URL en lista blanca que se registraron previamente durante el proceso de registro del cliente. Es por eso que necesitamos suministrar "request_uris": "https://ybd1rc7ylpbqzygoahtjh6v0frlh96.burpcollaborator.net/request.jwt" de antemano.

Condiciones de carrera de los proveedores de OAuth

Si la plataforma que estás probando es un proveedor de OAuth, lee esto para probar posibles condiciones de carrera.

Referencias

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥