Conditional race coverage for temporary intermediate states of objects

Conditional Competition at Portswigger Training Ground

Conditional competition for temporary intermediate states of objects

Lab: Partial construction race conditions

Necessary knowledge points before experiment

Some frameworks try to prevent accidental data corruption by using some form of request locking. For example, PHP’s native session handler module handles only one request per session at a time.

Many applications create objects in multiple steps, which can introduce temporary intermediate states that can be exploited.

For example, when registering a new user, an application might create the user in the database and set its API key using two separate SQL statements. This leaves a user with an existing door but whose API key is uninitialized.

Frameworks often allow you to pass in arrays and other non-string data structures using non-standard syntax. For example, in PHP:

  • param[]=foo is equivalent to param = ['foo']
  • param[]=foo & amp;param[]=bar is equivalent to param = ['foo', 'bar']
  • param[] is equivalent to param = []

If an account is registered, authentication is issued before the SQL statement is assigned a value.

Experimental requirements

This experiment includes a user registration mechanism. The race condition allows you to bypass email verification and register with an arbitrary email address that does not belong to you.

To resolve the lab issue, create an account exploiting this race condition, then log in and delete user carlos.

Infiltration begins

  • Visit the corresponding shooting range interface
https://portswigger.net/web-security/race-conditions/lab-race-conditions-partial-construction
  • start shooting range
1. Site Analysis

This is a SHOP type of website

You can view article information, purchase, log in, register and other function points. According to the prompts, we come to the registration function point.

You need a username, email and password to register. I found that you can only use the recommended email to register.

Tried to register account 1 and found that the registration was successful.

I registered the account of 1 again and found that I could not register.

I tried to register account 2 and found that the registration was successful using the same email address, indicating that the same email address can be registered and reused.

However, you cannot log in directly with your account and password, and you need to activate by email.

Got into trouble without knowing my email address

2. Find suspicious function points (view Burp history for analysis)

The normal process is
Front-end registration → The back-end sends an email and pre-registers the user’s account/password information in the database → User activation email → The back-end assigns permissions to the user → The user can access normally

Register to send packets

The account obtained through competition under these conditions also has no authority and is useless

While browsing, I found a suspicious js

const createRegistrationForm = () => {<!-- -->
    const form = document.getElementById('user-registration');

    const usernameLabel = document.createElement('label');
    usernameLabel.textContent = 'Username';
    const usernameInput = document.createElement('input');
    usernameInput.required = true;
    usernameInput.type = 'text';
    usernameInput.name = 'username';

    const emailLabel = document.createElement('label');
    emailLabel.textContent = 'Email';
    const emailInput = document.createElement('input');
    emailInput.required = true;
    emailInput.type = 'email';
    emailInput.name = 'email';

    const passwordLabel = document.createElement('label');
    passwordLabel.textContent = 'Password';
    const passwordInput = document.createElement('input');
    passwordInput.required = true;
    passwordInput.type = 'password';
    passwordInput.name = 'password';

    const button = document.createElement('button');
    button.className = 'button';
    button.type = 'submit';
    button.textContent = 'Register';

    form.appendChild(usernameLabel);
    form.appendChild(usernameInput);
    form.appendChild(emailLabel);
    form.appendChild(emailInput);
    form.appendChild(passwordLabel);
    form.appendChild(passwordInput);
    form.appendChild(button);
}

const confirmEmail = () => {<!-- -->
    const container = document.getElementsByClassName('confirmation')[0];

    const parts = window.location.href.split("?");
    const query = parts.length == 2 ? parts[1] : "";
    const action = query.includes('token') ? query : "";

    const form = document.createElement('form');
    form.method = 'POST';
    form.action = '/confirm?' + action;

    const button = document.createElement('button');
    button.className = 'button';
    button.type = 'submit';
    button.textContent = 'Confirm';

    form.appendChild(button);
    container.appendChild(form);
}

3. Js analysis | Benchmarking behavior

Get a rough idea of naming from json

  • Function createRegistrationForm creates a registration form by operating DOM
  • The function confirmEmail is used to create a confirmation email function.

In the confirmation email function, the POST request’s /confirm endpoint is accessed, and the spliced parameter is token

The created form will obtain token and confirm submission

4./confirm endpoint analysis | Benchmark behavior

token is forbidden if it is empty

token is 1, which proves that the token is verified to be 0, which is incorrect.

If it is a newly registered user, it is usually empty. You can find that it is banned. The try array is not banned.

5. Complete the experiment | Prove concept

When I register an account, if there are two SQL statements, can I give the account an empty token before the application assigns the token? This way you can bypass the email verification mechanism for user registration.

Construct an enumeration to create users, and at the same time, the conditional competition mechanism of concurrent token verification is empty and the user is successfully acquired.

User informationa4016:111111

Login account

Open the management panel and delete the user to complete the experiment.