Single-Sign On Gadgets: Escalate (Self-)XSS to Account Takeover

We discussed this vulnerability during Episode 185 on 06 February 2023

A bit of research on leaking access tokens from OAuth2/OIDC flows, in all cases you already need a cross-site scripting vulnerability to exist on the host recieving the callback, it does present an interesting case of escalating two often unimportant issues, a self-XSS and a Login CSRF, into an account takeover though.

The author presents three cases of “SSO Gadgets”. These are different techniques you may be able to use to capture a usable token. They all make a few assumptions: the attacker must have an XSS on the host already, the victim user must already have authorized the application, and the identity provider support the prompt=none URL parameter which tells it to immediately return with the code without needing any user interaction.

Implicit Flow Support - The implicit flow is a weak OAuth2 flow where the access token is returned in the URL and that token can be used immediately against the provider. In this case, an attacker can simply open a new window to the provider, wait for the redirect to happen and read the token from the URL.

Confidential Client, Using Code Flow with no PKCE - Normally with this flow, the user will be redirected back to the host with a token, but unlike the implicit flow the token is not immediately useful. Instead the server will send the token and a secret value back to the provider, who will then give them the access token. This way the access token is never exposed to clients. The trick to be able to hijack the code from these flows is to disrupt that exchange process and prevent the server from actually trying to exchange the token that is sent back.

The author mentioned two tricks that might be useful to do this, one is changing the repsonse_type making it so token will no longer be in the expected location. Setting it to fragment for example will make it invisible to the server-side to read, but can still be captured by an attacker with an XSS. Another trick would be to provide an invalid state. If the server validated the state before trying to consume the token, it may fail without consuming the token. In both cases, the attacker ends up with this “exchange token”. They can then start their own OAuth2/OIDC flow, and swap out their rela exchange token for the captured one. The server will then process that stolen token and log the attacker into the victim’s account. There are likely other ways the flow could be broken, but the two mentioned are probably the most common.

Single-Page Application with Code Flow and PKCE - This one is a bit “meh” to me, an XSS on a single-page application is already basically game over. All they do for this one is just simulate the normal flow since they have all the access from the XSS. CCompute the code_verifier and code_challenge values, open a new window with the appropiate OAuth code flow URL and the computed values, await the redirect and obtain the code.

They provide a “real-world” example, though they don’t provide any application details. It is an interesting chain though, and a nice escalation from normally pretty weak issues.

The first issue in the chain, is a Login CSRF, the ability to force another user to login as an attacker controlled account. They chain this with a self-XSS in their username. Often this is not seen as a terribly useful chain since the XSS just provided access to the attacker’s own account even if the victim is on it, though they combine it with one of their SSO Gadgets. As the victim would still have their session with the identity provider, they can use an SSO Gadget to steal their access token through the XSS while they are logged into the victim.

Lastly, they call out that Oauth applications registered with Google as “Web Applications” cannot disable the implicit flow, so that gadget is widely available.