Skip to content

Race Condition

Introduction

This article covers cases of possible Race Condition on WordPress. A race condition occurs when the same component is requested in parallel, leading to multiple processes accessing and modifying shared resources simultaneously, which can result in duplicate operations, unauthorized actions, or unexpected behavior due to the lack of proper synchronization mechanisms.

Example Cases

Below is an example of vulnerable code:

add_action("wp_ajax_send_money", "send_money");
function send_money() {
global $wpdb;
$amount = urldecode( $_GET['amount'] ?? '' );
$receiver = urldecode( $_GET['receiver_id'] ?? '' );
$sender = get_current_user_id();
// Check balance
$balance = $wpdb->get_var($wpdb->prepare(
"SELECT balance FROM bank_accounts WHERE user_id = %d", $sender
));
if ($balance < $amount) {
return "Not enough balance.";
}
// Deduct amount
$wpdb->query($wpdb->prepare(
"UPDATE bank_accounts SET balance = balance - %d WHERE user_id = %d",
$amount, $sender
));
// Send amount
$wpdb->query($wpdb->prepare(
"UPDATE bank_accounts SET balance = balance + %d WHERE user_id = %d",
$amount, $receiver
));
return "Money sent successful!";
}
  1. Attacker has a balance of $12
  2. The attacker sends two requests at the exact same time to send $10 from the account
  3. Both requests pass through the if ($balance < $amount) check at the same time and return false leading to both requests proceeding forward
  4. The database operation is done and the transaction is successful for two $10 to another account.

To exploit this, any authenticated user needs to perform two or more parallel POST requests to the /wp-admin/admin-ajax.php endpoint specifying the needed parameters.form two or more parallel POST request to the /wp-admin/admin-ajax.php endpoint specifying the needed parameters.

Terminal window
curl "<WORDPRESS_BASE_URL>/wp-admin/admin-ajax.php?action=send_money&amount=10&receiver_id=1" & \
curl "<WORDPRESS_BASE_URL>/wp-admin/admin-ajax.php?action=send_money&amount=10&receiver_id=1" & \
curl "<WORDPRESS_BASE_URL>/wp-admin/admin-ajax.php?action=send_money&amount=10&receiver_id=1" & \
curl "<WORDPRESS_BASE_URL>/wp-admin/admin-ajax.php?action=send_money&amount=10&receiver_id=1" &
wait

Contributors

dhakalananda