OAuth from top to bottom. Examining protocol features and basic attacks targeting OAuth

Date: 23/06/2025

Most modern websites have an authentication form, and in its lower part you can often see buttons enabling you to sign in via various social networks. This login mechanism is based on the OAuth protocol, and today you’ll learn its structure and main vulnerabilities. At the end, you’ll solve two laboratory tasks to solidify the newly-gained knowledge.

I assume that you know what is authentication on a website. If you want to search for a job, place an order, or use government services online, you’ll be asked to prove that you are the account owner. In many cases, developers force you to log in even when it’s not really necessary: just to collect information about you.

To avoid entering your email every time, waiting for a message with a code or link to confirm your account, and inventing a sophisticated password, you can register once on one of the popular websites and log into other sites under this account.

This technology is called OAuth. It’s used in social networks and other major services when they offer you to sign in with your social network account.

Sign in page on AliExpress
Sign in page on AliExpress

This login technique has become so widespread nowadays that many people don’t even think about its mechanism, which is a big mistake: the devil is in the detail. There are so many subtle nuances in the OAuth protocol that I had to split the huge material about it into three parts.

In this and subsequent articles, I will analyze the OAuth and OpenID Connect technologies step by step, including differences between different protocol versions, and risks arising when these technologies are implemented incorrectly. At the end, you’ll solve two PortSwigger labs to find out how to exploit such vulnerabilities,.

Let’s start with the basics.

OAuth and its history

Aaron Parecki defines OAuth 2.0 as follows: an authentication method that allows users to grant websites or applications access to their personal data without sharing their passwords.

No need to enter additional information: you just press a button, give you consent, and voila! – the application immediately receives your data. On the modern web, OAuth is supported by almost all major websites, and many users prefer it rather then the classic mechanisms.

The protocol has been created a while ago. The OAuth concept was born in November 2007, during the development of Twitter OpenID (not to be confused with OpenID Connect), when the company was integrating it with Ma.gnolia, a bygone social bookmarking service where people could share saved links to various sites.

Ma.gnolia
Ma.gnolia

Twitter and Ma.gnolia have been integrated to enable Ma.gnolia to use Twitter’s dashboard widgets. According to Blaine Cook, then a lead developer at Twitter, no open-source mechanisms making it possible to delegate access to an API were available at that time.

There were a few similar solutions (most probably, you haven’t heard of them): AuthSub (Google), BBAuth (Yahoo), OpenAuth (AOL), Windows Live ID Web Authentication (Microsoft), and Facebook Auth (Meta). But all of them they were proprietary and, therefore, unsuitable; while older techniques (e.g. password sharing) were insecure and unsuitable for such scenarios. Ultimately, OAuth was proposed as a solution to this problem.

OAuth operating principle (an illustrative example)
OAuth operating principle (an illustrative example)

OAuth developers John Panzer and Eran Hammer-Lahav define the protocol as follows:

OAuth is like a valet key for all your web services. A valet key lets you give a valet the ability to park your car, but not the ability to get into the trunk or drive more than 2 miles or redline the RPMs on your high end German automobile. In the same way, an OAuth key lets you give a web agent the ability to check your web mail but NOT the ability to pretend to be you and send mail to everybody in your address book.

The final version (OAuth 1.0) was approved on December 4, 2007 (the announcement can be found in the web archive). In 2008, Google adopted the protocol, and its audience started growing exponentially. By 2010, Twitter forced all third-party applications to use its OAuth 1.0 implementation.

But a year earlier, in 2009, a session fixation attack was discovered; it allowed attackers to access other people’s resources. As a result of that audit, the enhanced OAuth 1.0a version was developed: it introduced the oauth_callback and oauth_verifier parameters to ensure protection against such attacks.

However, it didn’t solve other problems marring OAuth 1.0: insecurity and unhandiness. Developers complained that the first OAuth required too much cryptographic computation on the client side: requests had to be signed using HMAC. For many companies, such cryptography disrupted development deadlines and severely complicated testing.

In the three years since the inception of the first protocol version, developers invented a simpler, but more functionally advanced solution introducing multiple innovations and currently known as OAuth 2.0. This protocol appeared in 2010, and its latest version, RFC 6749, was released in October 2012.

Protocol structure

To make things easier to comprehend, let’s use a real example. OAuth supports several Flows that define how information is exchanged between the client, the resource server, and the authorization server (to be addressed a bit later). The most widely used Flow on desktop websites is Authorization Code Flow. Let’s start with it.

There is a well-known website called legacy.midjourney.com; it allows users to create images using a generative neural network.

To use its functionality and create images, you have to log into your account, and the authorization model on legacy.midjourney.com employs the OAuth technology.

OAuth consists of four components:

  • Resource Owner – a resource refers to various user data (e.g. email address, phone number, name, nickname, etc). The resource owner is the user who owns these data;
  • Application or Client – app that requires access to user’s resources. In this example, this is the Midjourney service who wants your username, avatar, and email address, which requires your consent;
  • Authorization server – server issuing OAuth access tokens to the client after successfully authenticating the resource owner and obtaining authorization. On Midjourney, Discord and Gmail act as authorization services; and 
  • Resource Server – website hosting the email, phone number, username, and other data that the client wants to receive. In this example, you log in via Discord (where you have already registered some time ago); accordingly, Discord acts as a resource server.

Schematically, Authorization Code Flow in OAuth looks as follows:

Authorization Code Flow
Authorization Code Flow

When I described the authorization server and resource server, you have probably noticed that, in this particular example, it’s Discord in both cases. It must be noted that in real life, same services often act as such servers (i.e. authorization server and resource server), but with different endpoints.

A diagram from the Microsoft documentation clearly illustrates this.

An alternative diagram from Microsoft
An alternative diagram from Microsoft

Don’t be scared by the scope of information: each point will be examined in order.

Authorization Request

The first stage is called Authorization Request.

  1. The user clicks the “Sign In” button on the website’s main page to log in; and 
  2. A pop-up appears asking the user to select a social network to log in with.

    Midjourney login page
    Midjourney login page
  3. You select Continue with Discord; the Midjourney app generates a link to Discord and redirects you to it. There you see a login form.

Discord login page
Discord login page

Importantly, the URL you’ve followed isn’t a raw link (e.g. /login). It contains multiple parameters generated by the app, and looks as shown below:

<https://discord.com/login>
?redirect_to=/oauth2/authorize
?response_type=code
&client_id=936929561302675456
&redirect_uri=https://www.midjourney.com/__/auth/handler
&state=AMbdmDkycu0e3INVMzD9TaBJsUz4DqLki0MEElniTdiomtU7ejHQwa-zsdFLI3lv11Dlz0syNqa-sQ_fO9vwS_buX5sfKH_JjP1GJfgq8P0yzkAwTKOFRgZgp1Trz61FhuNd99rep6mYA_0NZniAmHeU31AHLer3ENc9UYhlPv3F0d10TtqAo3jrHFTDnzmWBoryBJbuP1dHH7fmo-UKkqedWNxmSNnOqOIE2erMiwibVnP3bhpWZKH-ka0UB6FesAGOGyaNKZG1KY92X8Rai5ceovEDCRId9vW2q_GLwVTixPua1vD1ChLxPi7QgIiRQCk
&scope=identify email guilds.join guilds.members.read role_connections.write
&context_uri=https://www.midjourney.com

Let’s examine each of these parameters:

  • client_id – a random value generated by Discord or any other authorization server. This ID is issued to the website (in this case, it’s Midjourney). For each of the client services, the value is unique. It makes Discord understand what app is requesting personal data of its user (i.e. client_id is required for identification);
  • redirect_uri – the URI Discord should redirect the user to after successful authorization. In this example, Discord should return the user back to the Midjourney website. Several vulnerabilities originate from incorrect handling of this parameter (to be discussed later);
  • state – a unique value generated for each authorization session to protect against CSRF attacks. In one of the labs, you will learn how to deliver such attacks to steal other peoples’ accounts;
  • response_type – if OAuth is used as the authorization protocol, then the response_type parameter indicates which flow of this protocol should be used (there are several such flows, and they slightly differ from each other). In this example, the app inserts the code value there, but it can also be token or id token; and 
  • scope – data or endpoints the Midjourney client app wants the resource server to grant it access to.

In this example, the following attributes are used:

  • identify – allows the app to access the /users/@me Discord endpoint to get user information, but not email;
  • email – adds consent to provide user’s email. The above endpoint will now return it too; and 
  • guilds – enables the client to access the /users/@me/guilds endpoint that returns the username, user ID, banner, and other parameters.

In addition to identify, email, and guilds, a number of other attributes are available for the scope parameter (see the Discord documentation.

Consent Screen and Authorization Response

After you log in, you see a notification screen called the Consent Screen. It says that the Midjourney bot wants to access your data.

Consent Screen in Discord
Consent Screen in Discord

Sometimes, the authorization server makes some fields optional, and the user can select data to be transmitted. Yandex is a good example of this approach.

Consent Screen in Yandex
Consent Screen in Yandex

There are two buttons: you either refuse or agree to provide access to your data. If you agree, the site redirects you back to the URI received from the app in the redirect_uri parameter.

In the case of Midjourney, this link looks as follows:

https://midjourney.com/api/auth/callback/discord/
?code=<CENSORED>
&state=dLybVCqXiFHNLYcwiOLhrVKoQHMJwRKU9W7BxoDIGNo

where code is the authorization code just generated by the OAuth provider (this code is of key importance since it will be subsequently used as confirmation that the user has granted access to their data); while state is a parameter from the previous step that acts as a CSRF token.

When you click “Authorize”, grant is entered into the authorization server database: a given user has granted access to certain data to a certain service. The client receives a successful authentication ID associated with the data stored in the database. In this particular case, it’s code.

Access token request

So, the user agrees to provide their data, and Discord redirects the code back to Midjourney. Midjourney receives the authorization code and must exchange it for an OAuth token to be able to use it and request information about the user.

Such a flow might seem weird: why not give the token right away? The above-described procedure ensures that an attacker standing in the middle between the user and the server cannot hijack the OAuth token.

After receiving code from the user who has just arrived, the Midjourney app makes the following request to the authorization server somewhere on its backend (i.e. the user doesn’t see it):

POST /api/v10/oauth2/token HTTP/1.1
Host: discord.com
client_id=12345
&client_secret=SECRET
&redirect_uri=https://midjourney.com/callback
&grant_type=authorization_code
&code=<CENSORED>

Let’s examine all its parameters again (even though some of them repeat):

  • client_id is a unique value that Discord issued to Midjourney in advance so that it can uniquely identify itself, and Discord understands that it’s Midjourney who comes to it;
  • client_secret – as said above, an attacker could hijack user’s code and exchange it for an OAuth token on behalf of Midjourney (with its client_id), but the client_secret parameter ensures (to some extent) that the attacker won’t be able to do this. The app should keep client_secret secret and use it only when it sends requests to the resource server; while the server should check client_id against client_secret;
  • redirect_uri tells the resource server where it should return the token;
  • grant_type is the authorization type used; in this case, it’s the familiar authorization_code, which goes next; and 
  • code – code previously transmitted by the user and indicating user’s consent to data transfer.

In Python, such a request can be implemented as follows:

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
REDIRECT_URI = 'https://hackmag.com/'
def exchange_code(code):
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()

Access token grant

The authorization server validates the client_id and client_secret to make sure that it’s actually Midjourney who has come to it. And compares code with the one it has issued to the user. If all these data are correct, then it issues an access_token (aka OAuth token) and returns it with its response; using this OAuth token, the Midjourney app can get the user data.

{
"access_token": "6qrZcUqja7812RVdnEKjpzOL4CvHBFG",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "D43f5y0ahjqew82jZ4NViEr2YafMKhue",
"scope": "identify"
}

The OAuth token is unique; its lifetime is limited, and it’s user-specific. In addition to the token itself, the app returns some other attributes (e.g. token type, lifetime, and scope of data it’s issued for).

API Call and Resource Grant

Midjourney finally receives this token; in most cases, such tokens are stored in a database. Now it can access the Discord API with this token and get up-to-date user data.

Below is an example of a request for user information performed using an OAuth token. The user is specified in the Authorization header:

GET /api/v10/users/@me HTTP/1.1
Host: discord.com
Authorization: Bearer z0y9x8w7v6u5

At this point, the flow ends. Midjourney receives user’s email, name, and other data specified in scope.

{
"username":"carlos",
"[email":"carlos@carlos-montoya.net](mailto:email%22:%22carlos@carlos-montoya.net)",
}

Midjourney saves these data in its database and registers the user. Then the user is redirected to their personal account where the respective user name is displayed: it was received with the token from the Discord API.

Midjourney website after successful login
Midjourney website after successful login

The diagram below is provided to solidify the above information: it shows authentication to the same Midjourney website via Google.

Authorization Code Flow when you sign in with Google
Authorization Code Flow when you sign in with Google

Implicit Grant Flow

Depending on their purpose, developers can use different OAuth flows. The second such flow is called Implicit Grant Flow, and it’s simpler compared to the above-described one.

Implicit Grant Flow
Implicit Grant Flow

Remember the response_type parameter specified by the app? In the previous flow, code was substituted there; in this flow, it’s token. After the Authorization Code Grant stage, the app returns token instead of code, thus, bypassing the exchange of code for token.

Let’s briefly examine each step.

Step 1. The user clicks “Sign in with Midjourney”; the app generates a link and redirects the user to the authorization server.

The link is the same as before, but, as you can see, the response_type has changed:

<https://discord.com/login>
?redirect_to=/oauth2/authorize
?response_type=code
&client_id=936929561302675456
&redirect_uri=https://www.midjourney.com/__/auth/handler
&state=AMbdmDkycu0e3INVMzD9TaBJsUz4DqLki0MEElniTdiomtU7ejHQwa-zsdFLI3lv11Dlz0syNqa-sQ_fO9vwS_buX5sfKH_JjP1GJfgq8P0yzkAwTKOFRgZgp1Trz61FhuNd99rep6mYA_0NZniAmHeU31AHLer3ENc9UYhlPv3F0d10TtqAo3jrHFTDnzmWBoryBJbuP1dHH7fmo-UKkqedWNxmSNnOqOIE2erMiwibVnP3bhpWZKH-ka0UB6FesAGOGyaNKZG1KY92X8Rai5ceovEDCRId9vW2q_GLwVTixPua1vD1ChLxPi7QgIiRQCk
&scope=identify email guilds.join guilds.members.read role_connections.write
&context_uri=https://www.midjourney.com

The response_type value is token, which indicates that Implicit Grant is used.

Step 2. The user enters credentials and agrees to transmit personal information to the app; the consent page looks in the same way as before. To break the monotony, below is a Facebook consent page displayed when you log into AliExpress via Facebook.

Facebook consent page
Facebook consent page

Step 3. The authorization server generates a link with an embedded OAuth token and redirects the user back.

The link looks something like this:

#access_token=g0ZGZmNj4mOWIjNTk2Pw1Tk4ZTYyZGI3
&token_type=Bearer
&expires_in=600
&state=xcoVv98y2kd44vuqwye3kcq

Instead of code (that was in the previous flow), access_token is returned right away.

Step 4. The client part of the app extracts the token and starts using it in its requests to the resource server.

This is the reason why this scheme is called simplified: the token is directly returned to the user’s browser. Implicit Grant can be used in SPAs (Single Page Applications) and stored on the user’s side (or in mobile apps that don’t have a server part).

Currently, such a flow isn’t recommended for use, but you’ll see it in the labs.

OAuth and authentication

Before you start solving the labs, I have to make an important statement: OAuth wasn’t originally intended for authentication. It’s an authorization protocol whose purpose is to grant access to certain data of the resource owner to third-party apps, not to authenticate the resource owner.

Let’s get back to the example with the car. If you have rented a BMW using car sharing services and received its keys, this doesn’t mean that the car is now yours. The same is true for OAuth: if you bring a token to the service, it doesn’t know how you’ve got this token and grants you access only to certain resources.

But over time, people started misusing this protocol. Some websites use​​ OAuth for authentication, which contradicts its original concept and sometimes entails critical vulnerabilities resulting in account compromise.

The OAuth flow in such cases remains the same. But what’s important is how the app uses the received data. Let’s find a vulnerability in a lab with the following input data:

  • OAuth is used for authentication in Implicit Grant mode;
  • after receiving the access token, the user’s browser contacts the resource server and uses the received data to log in; and 
  • the web app trusts the user’s input and accepts the access token as a password.

Lab: Authentication bypass via OAuth implicit flow

In the Implicit Flow scenario, the token is returned directly to the user. You are going to see how a misconfiguration can result in account compromise on a website.

Start the lab, and you’ll see the blog main page. Since you are dealing with OAuth, you have to go to the “My account” page to examine the whole flow and analyze it.

Blog main page
Blog main page

Click on “My account”, and you’ll get to the Sign-in page.

Sign-in page
Sign-in page

You enter the login data provided in the lab description (‘wiener:peter’) and confirm that you authorize access to your profile and email.

Access authorization page
Access authorization page

Congrats! You successfully logged into your personal account!.. But the task was to log into someone else’s one…

My account
My account

Let’s take a closer look at the requests and figure out how the login process works.

The first request was sent to the “My account” page. Since you were not authenticated, you were redirected to the social network’s login page without the possibility to use standard authentication and authorization (since the website simply doesn’t have it).

Redirect to social network
Redirect to social network’s login page

The next request was an Authorization Request. The main application has created HTML code with a redirect implemented using the meta tag pointing to the authorization server.

<meta http-equiv=refresh content='3;url=https://oauth-0aeb00740370fc9c81e39155023700ad.oauth-server.net/auth?client_id=corfmvitwnpodbwncbim3&redirect_uri=https://0afc0017030dfc668162939300c10098.web-security-academy.net/oauth-callback&response_type=token&nonce=1924369299&scope=openid%20profile%20email'>

The same redirect can be seen on the Proxy History tab in response to the /social-login request.

Another redirect to the authorization server
Another redirect to the authorization server

The authorization server redirects you to the login page.

Authorization Request (a real-life example)
Authorization Request (a real-life example)

You enter your login and password, and another redirect occurs. This time, to the Consent Screen where you have to confirm your consent to grant access to your personal data.

Entering login and password on the social network website
Entering login and password on the social network website

Consent is confirmed with a simple POST request.

Request to confirm data transfer
Request to confirm data transfer

Finally, the OAuth server redirects you to the client app.

Redirect back to the client app
Redirect back to the client app

In the return link, you can see your access_token, its lifetime, and its type. Taking that this is a simplified flow, the token is returned to the user’s browser.

[https://0afc0017030dfc668162939300c10098.web-security-academy.net/oauth-callback
#access_token=0Ue2cGVe8U7e4xzKc_EFAxxipYPbDaRfP9YTXtdKxGV
&expires_in=3600
&token_type=Bearer
&scope=openid profile email](https://0afc0017030dfc668162939300c10098.web-security-academy.net/oauth-callback#access_token=0Ue2cGVe8U7e4xzKc_EFAxxipYPbDaRfP9YTXtdKxGV&expires_in=3600&token_type=Bearer&scope=openid%20profile%20email)

So, you return to the /oauth-callback page of the main app where its JavaScript tells you to make a request to the app using your email, username, and token.

Script that executes further logic
Script that executes further logic

This is an authentication request where:

  • data received from the resource server are used as email and username; and 
  • access_token received from the authorization server is used as the password.

In response, the server returns its cookie that you will use to navigate the website.

You successfully logged into the site, and the site returned a cookie
You successfully logged into the site, and the site returned a cookie

Under the hood, your browser makes the following requests: browser → server (token validation) → Resource Owner.

If the token is valid, the server believes that you’ve successfully authenticated with the email specified in the request. And this the main problem: the server trusts any data that you’ve specified as email and username and issues a cookie to the user passed in this parameter.

To solve this lab, you have to log in as carlos@carlos-montoya.net. All you have to do is replace your email with the address of the user on whose behalf you want to log in and send a request to get the cookie.

Let’s do this!

API request with other person
API request with other person’s email and login

If all operations were performed correctly, the server should issue a new cookie. This cookie belongs to the user carlos@carlos-montoya.net. The server accepts email and username from you and trusts them implicitly; this is where the vulnerability lies. When you send data, it simply validates the token, and if this token is valid, the server sends it to the personal account of the user specified in your request.

Opening response in browser
Opening response in browser

Open the page in your browser using the option “Request in browser → In original session” to make sure that you’ve successfully solved the first lab.

Lab successfully solved
Lab successfully solved

CSRF attacks on OAuth

CSRF exploitation
CSRF exploitation

OAuth is a very flexible protocol that offers plenty of possibilities for developers. This is the reason why vulnerabilities occur in it: developers are eager to complete their project as quickly as possible and use the first piece code found on the Internet; sometimes, such code contains gross errors.

In the next lab, you must first register in the classic way. After registration, you can attach a social media profile to your account in the settings and use it to log into the account registered in the first step.

This might seem unusual, but such an approach is still used (although less frequently than in the past). The sticking point is the state parameter that protects against CSRF attacks by preventing a hacker from performing actions on behalf of another user.

CSRF token operating principle
CSRF token operating principle

The CSRF token operating principle is very simple:

  1. The client app (e.g. Midjourney) generates a unique state string and inserts it into the link directing the user to the authorization server at the Authorization Request stage;

  2. After the user is authenticated, the authorization server redirects that user back to the specified redirect_uri with the same state parameter embedded in the URL; and

  3. After receiving the response, the client app compares the received state value with the previously generated and stored value. If the two values ​​match, this confirms that the request is authentic, and authentication can continue.

An attacker cannot use their own link with their own state and send it to some random user because it’s tied to the attacker’s cookie, which is generated in the same way as in the first step. As a result, a CSRF attack becomes impossible.

But the state parameter is optional, and many developers neglect it. In this lab, it’s missing, and you have to gain control over the website’s admin account by exploiting this vulnerability.

Lab: Forced OAuth profile linking

Open the main page of the familiar blog; this time, it features new posts.

Blog main page
Blog main page

Go to “My account”. Now you have two sets of credentials: the first set is a classic one used to log into the website; while the second set of credential is used to log in with social media. Since the social network isn’t yet linked to your account, login in the classic way.

Login page
Login page

Enter credentials of the user wiener to get access to “My account”. In addition to the familiar fields username and email that were present in the previous lab, you can see your API key and the option making it possible to attach a social profile to the current account (to access “My account” via a social network without the need to enter your login and password).

My account
My account

Let’s click “Attach a social profile” and examine the whole flow, just like you did before. After all, this procedure is an integral part of vulnerability scanning.

First, you are redirected to the social network’s Sign-in page.

Social network
Social network’s Sign-in page

Here you enter the password for the second account (i.e. peter.wiener) and confirm that you authorize access to your profile and email.

Access authorization page
Access authorization page

After that, you see a notification that your social media account has been successfully linked.

Social media account successfully linked
Social media account successfully linked

The flow doesn’t differ much from the previous lab, but now it’s used in a new scenario. Your task is to compromise the admin. To complete it, you have to exploit a vulnerability (that has to be discovered yet!) and use Exploit Server to deliver malicious payload to the admin.

Exploit Server wasn’t involved in the previous task, but this scenario requires user interaction; therefore, it’s presence is mandatory. You have to deploy your payload on Exploit Server and lure the admin there. All CSRF attacks involve requests sent on behalf of the user, which requires some markup.

Exploit Server
Exploit Server

Let’s examine HTTP History in Burp Suite again. You are interested in Authorization Response (i.e. redirect to the app that occurs when you agree to provide access to your data).

Request to link account to authorization code
Request to link account to authorization code

As you can see, the parameter that protects against CSRF attacks is absent there. There is only code that which acts as a user consent factor. So, what happens if the admin, who has already logged into the admin account on the website, follows this link?

An unpleasant surprise will occur:

  1. The admin follows the link that links (sorry for tautology) hacker’s social account to victim’s (i.e. admin’s) account; and 
  2. The hacker can now use hacker’s social network account to log into victim’s (i.e. admin’s) account.

To implement this attack, you have to write some HTML code that will perform such a redirect. If you have the Pro version of Burp Suite, it can automatically generate a form for a CSRF attack: right-click on the request → Engagement Tools → Generate CSRF PoC. But for better understanding, let’s do this manually: the required code is very simple.

The HTML code must perform the required redirect with your code. To make the user follow the URL specified in content, use the meta tag with the http-equiv attribute. 0 is the delay before the redirect (understandably, this operation must be performed as soon as the user gets to the page).

<meta http-equiv="refresh" content="0; url=https://<lab subdomain>.web-security-academy.net/oauth-linking?code=<code>" />

Copy the markup above and paste to it the URL containing the linking. To do so, right-click on the request and select Copy URL.

Copying URL from Burp
Copying URL from Burp

The final code looks as follows:

<meta http-equiv="refresh" content="0; url=https://0aa000b304cfe7de81ffa71800960086.web-security-academy.net/oauth-linking?code=UV_ah4kbQkY7GdedaCFP6pwFxcM_z9CW9Hv0ePlfSNM" />

Now go to Exploit Server and insert this code into the Body field. This will be the content of the page located at /exploit.

Exploit Server with payload
Exploit Server with payload

To check whether everything works correctly, click Store to save your project and then go to this page. If you are 100% sure that everything is correct, you can immediately contact the admin by clicking “Deliver exploit to victim.”

Next, go to “Access log” to view Nginx logs showing all visits to the page. I grayed out my own IPs so that you can see an IP address belonging to the admin. If the admin visited this page, then the bot has successfully done its job.

Nginx log showing the admin
Nginx log showing the admin

Now go back to the blog and sign-in with the social network.

Login page
Login page

If the attack was successful, you’ll now find yourself not in your account, but in the admin’s account.

Admin
Admin’s account

Go to the Admin panel and delete the user carlos (as required by the task).

Admin panel where you can delete users
Admin panel where you can delete users

Voila! You can see a notification that you’ve solved the lab

Lab successfully solved
Lab successfully solved

Conclusions

Congrats! You’ve successfully accomplished the following tasks: (1) got a basic understanding of the OAuth technology; (2) examined its history and learned how this authorization protocol has appeared; (3) analyzed its operating principle using Midjourney as an example; (4) conceived Authorization Code Flow and its simplified version (i.e. Implicit Grant Flow); and (5) solved two labs simulating basic attacks on the OAuth protocol.

In subsequent articles, I am going to present a few more technologies that are essential to the modern web. In addition, I will show how to combine various vulnerabilities into chains to deliver attacks against more sophisticated and protected websites.

Related posts:
2023.07.29 — Invisible device. Penetrating into a local network with an 'undetectable' hacker gadget

Unauthorized access to someone else's device can be gained not only through a USB port, but also via an Ethernet connection - after all, Ethernet sockets…

Full article →
2023.04.04 — Serpent pyramid. Run malware from the EDR blind spots!

In this article, I'll show how to modify a standalone Python interpreter so that you can load malicious dependencies directly into memory using the Pyramid…

Full article →
2022.04.04 — Elephants and their vulnerabilities. Most epic CVEs in PostgreSQL

Once a quarter, PostgreSQL publishes minor releases containing vulnerabilities. Sometimes, such bugs make it possible to make an unprivileged user a local king superuser. To fix them,…

Full article →
2023.07.20 — Evil modem. Establishing a foothold in the attacked system with a USB modem

If you have direct access to the target PC, you can create a permanent and continuous communication channel with it. All you need for this…

Full article →
2023.06.08 — Cold boot attack. Dumping RAM with a USB flash drive

Even if you take efforts to protect the safety of your data, don't attach sheets with passwords to the monitor, encrypt your hard drive, and always lock your…

Full article →
2022.06.01 — Routing nightmare. How to pentest OSPF and EIGRP dynamic routing protocols

The magic and charm of dynamic routing protocols can be deceptive: admins trust them implicitly and often forget to properly configure security systems embedded in these protocols. In this…

Full article →
2023.06.08 — Croc-in-the-middle. Using crocodile clips do dump traffic from twisted pair cable

Some people say that eavesdropping is bad. But for many security specialists, traffic sniffing is a profession, not a hobby. For some reason, it's believed…

Full article →
2023.02.21 — Herpaderping and Ghosting. Two new ways to hide processes from antiviruses

The primary objective of virus writers (as well as pentesters and Red Team members) is to hide their payloads from antiviruses and avoid their detection. Various…

Full article →
2023.07.07 — Evil Ethernet. BadUSB-ETH attack in detail

If you have a chance to plug a specially crafted device to a USB port of the target computer, you can completely intercept its traffic, collect cookies…

Full article →
2023.03.26 — Attacks on the DHCP protocol: DHCP starvation, DHCP spoofing, and protection against these techniques

Chances are high that you had dealt with DHCP when configuring a router. But are you aware of risks arising if this protocol is misconfigured on a…

Full article →