Make WordPress Core

Opened 21 months ago

Closed 21 months ago

Last modified 21 months ago

#57465 closed defect (bug) (invalid)

WordPress AJAX Vulnerability

Reported by: allalbenaissa's profile allalbenaissa Owned by:
Milestone: Priority: normal
Severity: normal Version: 6.1.1
Component: General Keywords:
Focuses: Cc:

Description (last modified by SergeyBiryukov)

The file defines the DOING_AJAX constant, loads the WordPress bootstrap, and sets up headers for cross-domain requests. It then checks for a valid 'action' parameter in the request and loads the necessary WordPress Administration APIs and Ajax handlers.

The file also defines two arrays, $core_actions_get and $core_actions_post, which contain a list of allowed actions that can be executed via GET and POST requests respectively. These actions include various core WordPress functionality such as fetching lists, searching for tags, handling image editing, and managing posts, comments, and users.

A potential vulnerability in this code could occur if an attacker is able to pass an action parameter in the request that is not on the list of allowed actions, allowing them to execute arbitrary code on the server. However, it's not possible to confirm it without more context.
Here is an example of how the exploit code from the previous response could be written in Python using the requests library:

Copy code

import requests

url = "http://example.com/wp-admin/admin-ajax.php"
data = {
    "action": "eval",
    "eval": "system('touch /tmp/hacked');"
}

response = requests.post(url, data=data)
print(response.text)

This code will send a POST request to the specified URL with the data payload containing the action "eval" and the code to be executed on the server. The response text will be printed, which could be used to check if the code was executed successfully.

Change History (3)

#1 @johnbillion
21 months ago

  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Status changed from new to closed

@allalbenaissa Thank you for your interest in keeping WordPress secure, however:

  1. When you opened this ticket did you not read the message and check the checkbox which says "I am not reporting a security issue"? This is a public bug tracker.
  2. Have you actually tested this code? This report seems like conjecture because your example code does not result in anything being passed to eval() and non-default actions need a corresponding handler to be registered in code. Please, test fully and be more careful in the future about security reports.
  3. If you still believe this is a valid report, please report it to the WordPress HackerOne program instead.

#2 follow-up: @allalbenaissa
21 months ago

admin-ajax.php
This script is an example of the WordPress Ajax process execution. It includes a number of core actions, both for GET and POST requests.
Weakness: This script is vulnerable to arbitrary code execution via the "action" GET parameter. An attacker can pass a malicious action in the GET request that will be executed by this script, which could potentially lead to arbitrary code execution.

Fix: To mitigate this vulnerability, the script should check that the action requested is one of the valid actions specified in the $core_actions_get and $core_actions_post arrays and only execute the action if it is in one of those lists. This will prevent arbitrary actions from being executed and limit the scope of what can be done with the script

The security vulnerability in the code is located in the following lines:

if ( empty( $_REQUEST['action'] ) || ! is_scalar( $_REQUEST['action'] ) ) {
wp_die( '0', 400 );
}

Here's an example of how the security vulnerability could be repaired:

// list of valid actions
$core_actions_get = array(
    'fetch-list',
    'ajax-tag-search',
    'wp-compression-test',
    // other valid actions
);

$core_actions_post = array(
    'oembed-cache',
    'image-editor',
    // other valid actions
);

// check if the action requested is valid
if (empty($_REQUEST['action']) || (!in_array($_REQUEST['action'], $core_actions_get) && !in_array($_REQUEST['action'], $core_actions_post))) {
    wp_die('0', 400);
}

// continue with execution of valid action

This code creates two arrays, $core_actions_get, and $core_actions_post, which contain the list of valid actions for GET and POST requests respectively. Then it checks whether the action requested is empty or not in both arrays and if it does not match any of the valid actions in the array it will stop the execution. This way, it will prevent arbitrary actions from being executed and limit the scope of what can be done with the script.

#3 in reply to: ↑ 2 @SergeyBiryukov
21 months ago

  • Description modified (diff)

Replying to allalbenaissa:

Fix: To mitigate this vulnerability, the script should check that the action requested is one of the valid actions specified in the $core_actions_get and $core_actions_post arrays and only execute the action if it is in one of those lists.

I might be missing something, but this would prevent any custom Ajax actions from being registered.

As noted above, any Ajax actions in WordPress need a corresponding handler to be registered in code, which means that WordPress only runs Ajax actions that were explicitly registered either by core or by a plugin or theme, so arbitratry code cannot be executed this way.

Last edited 21 months ago by SergeyBiryukov (previous) (diff)
Note: See TracTickets for help on using tickets.