Attacks on OAuth 2.0: redirect URI manipulation, token interception and authorization code interception in practice

Depov

Activist
ULTIMATE
SUPREME
PREMIUM
MEMBER
Joined
Feb 18, 2025
Messages
126
Reaction score
116
Deposit
0$
On theSaaS-platform with SSO through Keyclok, I found that theauthorization server is accepting redirect_uri with path traversal:https://app.client.com/callback/../../../evil.com - validationchecked only the beginning of the line. Substituting its URL, sent acashed link, the authorization code came to Burp Collaborator 12seconds after the clique. Full ATO, zero alerates in WAF. Suchmisconfig in OAuth 2.0 are found in every second web application withSSO-integration, and redirect URI is still the most undervaluedvector when testing authentication.


The location ofthe attacks on OAuth 2.0 in the chain of punching


Thevulnerabilities of OAuth 2.0 and OpenID Connect according to theMITRE AT&CK classification fall into several tactics at once.Steal Application Access Token (T1528), Credential Access) -intercepting tokens for access on behalf of the victim. ExploitPublic-Facting Application (T1190, Initial Access) - operation ofmisconfigs authorization server as entry points. Browser SessionHijacking (T1185, Collection) - interception of the session throughthe manipulation of OAuth flow in the browser. By OWASP it A07:2021 -Identification and Authentication Failures and API2:2023 - BrokenAuthentication


In practice, OAuthtesting begins in the recon phase. Indicators: "Come in"button "Introduce through Google/GitHub/Microsoft",requests for /authorize with parameters client_id, redirect_uri,response_type. If the app uses SSO - OAuth/OIDC is almost certainlyinvolved.


Adjustments to theenvironment and recon


Before testing,prepare the tools:


• Burp SuitePro with the AuthMatrix expansion - Community Edition will cover thebasic interception, but Pro is needed for Intruder and redirect_uriautomation


• Postman orcurlfor step-by-step playback OAuth flow


• Python 3.xwith library requestsfor automation: state/PKCE-p pair generation,mass check redirect_uri


Recon starts withendpoint discovery. Request /.well-known/openid-configuration on theauthorization server - there are listed authorization_endpoint,token_endpoint, response_types_supported,code_challenge_methods_supported. If the last field is missing - PKCE(Proof Key for Code Exchange) is not mandatory, and the attacksurface immediately expands. Fixing redirect_uri from customerregistration (if available through dynamic registration client ordocumentation) is a baseline point for redirect URI manipulation.


Redirect URIManipulation: bypassing validation in practice
1780080416590.png

The process ofnormalization is the transformation of a relative path into anabsolute with the help of built-in functions of the language.


ACM’s “OAuth2.0 Redirect URI Validation Falls Short, Literally” found that pathconfusion and parameter pollution are work vectors even againstservers that declare strict matching.






Open redirectchain. Find open redirect somewhere in the application - let's say,https://app.example.com/goto?url=https://evil.com. If redirect_uri isregistered as https://app.example.com/* (wildcard) or is checked byprefix or server has a weak statitization - the attacker substitutesopen redirectpoint end as a redirect_uri. The authorisation serverconsiders URI valid, but the code goes through the grid of redirectsto the left server. According to Salt Labs, it was this vector thatwas exploited in the vulnerabilities of Booking.com - redirectmanipulation URI through insufficient validation allowed the user'sOAuth session.






Subdomaintakeover. If redirect_uri contains wildcard *.example.com, and CNAMEfor staging.example.com indicates a deactivated cloud resource - theattacker captures the subdomain and receives a valid redirectpoint.Descope researchers described a similar vector with Google OAuthdomain takeover, where expired domain allowed you to log in to thevictim’s account.






In this scenario,phishing attacks become just a critically high level, as users see anofficial SSL certificate and a familiar domain.


Moreover, if an MXrecord is configured for the subdomain, a hacker can send and receiveletters on behalf of the company.


Check in BurpSuite


In Burp Proxyintercept the request to authorization_endpoint. Parameterredirect_uri - our goal. Send to Repemore and test mutations:


Code:


GET/authorize?response_type=code


&client_id=legit_client_id


&redirect_uri=https://app.example.com/callback/../../../evil.com


&scope=openid+profile+email


&state=random_value HTTP/1.1


Host:auth.example.com


What to check?


• Removal ofpath ( /callback→ → /)


• Additionsubpath (/callback/../../admin)


•URL-encoded characters ( %2e%2e%2fInstead of ../)


• Parametersin URI (/callback?next=https://evil.com)


•Substitution of another domain in path.


• Everymutation is in Repeater.


Reply 302 withyour URI in the title Location means: Validation is bypassed.






For automation:Burp Intruder with a payload list of 20-30 mutations redirect_uri,throttle 1 request/sec (so as not to trigger the rate limiting onIdP).


EncompassingAuthorization Code


Authorization code- one-time, lives seconds. But if you intercept it before theexchange on token by a legitimate client, the attacker gets access onbehalf of the victim. In addition to redirect URI manipulation, thereare less obvious leakage channels.


Leakage throughReferer Header


A mechanism thatRussian-language sources almost do not disassemble at the level ofHTTP requests. After receiving an authorization code, the browser isredirected to redirect_uri from code to query string:https://app.example.com/callback?code=AUTH_CODE&state=xxx. Ifexternal resources are downloaded on the callback page - analyticsscript, CDN font, tracking pixel - browser will send a full URLincluding ?code=AUTH_CODE in the headline Referer when requested tothe third party.






According to theIETF Security BCP (section 4.2 of Credential Leakage via RefererHeaders), this is a documented threat with a specific protectionmeasure: Referrer-Policy: no-referrer on the callback page.






How to check?


1. We gothrough the full OAuth flow through Burp.


2. In HTTPHistory, filter third-party requests for domains sent from thecallback page. If in the title Refereris present ?code=- the vector'sconfirmed.


Developersregularly forget about it: put PKCE, introduce BFF, but leave GoogleAnalytics JS on a callback page. I saw it on three independentprojects – and each time I wondered how carefully builtarchitecture collapsed because of one script.


Interruption ofOAuth Flow via XSS


A moresophisticated technique described in detail in the Habr-stage aboutthe authorization code injection. The attacker, having the XSS in thesame origin as redirect_uri, opens the hidden iframe withauthorization request. If the victim has an active session on IdP -the authorization of the silent (without interaction). Code is backin iframe, and JavaScript attacker reads it (same-origin policyallows access to content).






Key point:HttpOnly Cookies on session ID are not protected. The attacker doesnot steal the existing session - it initiates a new OAuth flow andreceives a fresh code. As described in OAuth 2.0 for Browser-BasedApplications: “an attacker receives its own accounts”, withoutcompromising existing ones.






When it works:


• XSSanywhere in the origin application (not necessarily on the callbackpage)


•response_modenot form_post(form_post sends code to the POST body,inaccessible to client JS)


• The victimhas an active session at IdP


When NOT working:


• IdPrequires repeated consent at each request (prompt=consent)


• Usedform_postResponse mode


• CSP bansiframe with IDP domain


Applicability:external web application pentest with OAuth/OIDC. Preliminary XSS inorigin is required - a separate vector that needs to be found beforethe operation of the OAuth flow.


OAuth Token Theft:Imlicit Flow and 307 Redirect


Immlicit flow(response_type=token)returns access token directly to the core URL:https://app.example.com/callback#access_token=eyJ.... IETF SecurityBCP explicitly recommends that implicit flow. But on the pentests, itis still found in the legacy of the SPA, mobile WebView andapplications collected by outdated tutorials since 2017.






If you see inauthorization request response_type=token - is a vulnerability in thecontext of modern recommendations. A URI fragment is not sent to theserver (does not fall into the logs), but is available throughJavaScript. For the blue team, this is a blind zone: the token isleaked, and in server logs are silence. The XSS bundle gives directATO without the need to exchange code for token.






Separately, it isworth recalling the incident with GitHub, Heroku and Travis CI,described by Descope researchers: the attackers stole OAuth tokensfrom the integrations of Heroku and Travis CI, used them to accessprivate GitHub repositories and then discovered AWS-credentials,which gave access to npm infrastructure. OAuth token theft is not anunlikely problem, but a path to the lateral movement through trustchain between services.






307 RedirectExploit. A lesser known vector (IETF BCP, section 4.12). If theauthorization server returns HTTP 307 instead of 302 afterauthentication, the browser forwards the POST query body (includingthe user’s credentials) to the client’s redirect_uri. Applicableto self-hosted IdP (Keyclok, customization) - check HTTP status codein Burp after sending the login form to IdP. The difference between302 and 307 is one figure, and the consequences are fundamentallydifferent.

PKCE Bypass and CSRF through No State

1780080259446.png
PKCE DowngradeAttack


PKCE (RFC 7636)binds code_verifier c code_challenge - without a verifier, theintercepted code is useless. But if the authorization server does notoblige PKCE - the attacker sends authorization request withoutcode_challenge. The server accepts the request, the code is issuedwithout reference to the verifier. This is the PKCE downgrade,described in the Xakep and IETF BCP checklist section 4.8.






Verification: sentauthorization request without parameters code_challenge andcode_challenge_method. If the server returns 302 from code -downgrade is possible. From /.well-known/openid-configuration Fieldcode_challenge_methods_supported: if not - PKCE is most likelyoptional.






There is a nuancethat is often overlooked. PKCE for Confidential Customers (ServingApplications with client_secret) - not a panacea. As detailed in theHabr-article: with XSS in the origin of the client, the attackercontrols both the challenge and the verifier, because he himselfinitiates the flow. PKCE protects against third-party codeinterception, but not from creating a new flow from the context ofXSS.


CSRF in OAuththrough no state


Parameter state -one-time token tied to the user session. Without him, the attackersubstitutes his authorization code in the callback-URL of the victim,and the application links the victim’s account to the attacker’saccount on IdP. Classic CSRF attack on OAuth, described in IETF BCPsection 4.7.






Verification:Remove state from authorization request or substitute for anarbitrary value. If the application accepts callback withoutvalidation state - CSRF is confirmed. In OpenID Connect, a similarrole is played by nonce, but check both parameters.


Vector Selection:Decision of the tree for the pentester
1780080154396.png

Procedure fortesting: recon (/.well-known/openid-configuration) - redirect URIfuzzing - PKCE enforcement - Referer leakage - valid stateation -XSS-dependent vectors.


What the WAF seesin attacks on OAuth 2.0


OPSEC when testingOAuth is a separate story. Where your actions leave traces:






IdP-logs. Eachauthorization request is logged. Keycloak writes all authorizationevents, Azure AD records consent grants. Massively redirect_uricreates an anomaly. Recommendation: throttle in Intruder 1 req/sec,no more than 30 mutations per session.






WAF. ModSecureityand cloud WAF (Cloudflare, AWS WAF) catch URL-encoded path traversal(%2e%2e%2f) in query parameters. Net URL mutations (substitutionpath, adding parameters) usually do not trigger the rules - WAF seesa valid HTTP request to a legitimate domain.






The annex. Mostapplications do not log the value redirect_uri from the responsemessage - this is what makes the redirect URI manipulation a quietvector. Implicit flow even quietly: a fragment of the URI(#access_token=...) does not reach the server at all, in the logs isempty.






Blind area of blueteam. The main problem is the correlation between the service eventon IdP and token usage on server resource. Without the SIEM-ruleconnecting these events, token theft through redirect manipulationremains invisible.






For more than twoyears of testing OAuth integrations in grocery companies, I observethe same pattern: teams are implementing OAuth according to theprovider’s documentation (Auth0, Keycloak, Azure AD), but do notcheck the behavior in non-standard input. The documentation describesthe happy path. The task of the pentester is to check path unhappy:what will happen if redirect_uri contains ../, if code_challenge Notavailable if response_mode replaced by a fragment instead ofform_post.






The mostunderrated vector of all described is Referer leakage. The developersimplement PKCE, build a BFF architecture, put HttpOnly on cookies -and at the same time leave a analytics script on the callback page,through which the code authorization leaks in the Referer header. NoWAF reacted because Referer is a regular HTTP mechanism, not ananomaly.






PKCE is presentedas a solution to all OAuth security problems. In reality, PKCE closesexactly one scenario: intercepting someone else’s service code. Itdoes not protect against XSS in the origin of the client, where theattacker initiates his own flow and controls both the challenge andverifier. BFF is also not a silver bullet: session ID, issued by theserver part after the code exchange, intercepts the same JavaScriptfrom iframe - HttpOnly cookie is not a hindrance because the attackerreads Set-Cookie from the headline of the answer to your ownfentch-request.
 
Top Bottom