Anything Order by Terms <= 1.4.0 - Missing Authorization
Description
The Anything Order by Terms plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.4.0. This makes it possible for authenticated attackers, with contributor-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.4.0This research plan focuses on identifying and exploiting a missing authorization vulnerability in the **Anything Order by Terms** plugin (version <= 1.4.0). ### 1. Vulnerability Summary The plugin "Anything Order by Terms" allows users to reorder terms (categories, tags, etc.) via a drag-and-drop i…
Show full research plan
This research plan focuses on identifying and exploiting a missing authorization vulnerability in the Anything Order by Terms plugin (version <= 1.4.0).
1. Vulnerability Summary
The plugin "Anything Order by Terms" allows users to reorder terms (categories, tags, etc.) via a drag-and-drop interface. The vulnerability resides in the AJAX handler responsible for saving the new term order. While the handler is registered via wp_ajax_, it lacks a current_user_can() check to verify if the authenticated user has administrative or category-management permissions. Consequently, any authenticated user with at least Contributor-level access can reorder terms site-wide.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
aobt_update_order(inferred from plugin sluganything-order-by-terms) - Method:
POST - Parameters:
action:aobt_update_orderorder: An array or string representing the new sequence of term IDs.nonce: (Required if a nonce check exists, though authorization is missing).
- Authentication: Contributor-level session (
PR:L).
3. Code Flow (Inferred)
- Registration: The plugin registers the AJAX handler in its main class or file:
add_action('wp_ajax_aobt_update_order', 'aobt_update_order_callback'); - Handler Definition: The function
aobt_update_order_callback(inferred) is called. - Missing Check: The function likely calls
check_ajax_referer()but fails to callcurrent_user_can('manage_categories')orcurrent_user_can('edit_posts'). - Processing: The function iterates through the
orderparameter and updates theterm_ordercolumn in thewp_termstable or updates a specific option/meta field.
4. Nonce Acquisition Strategy
To exploit this as a Contributor, we must find where the plugin leaks the nonce to low-privileged users.
- Identify Shortcode/Page: The plugin may load its scripts on any page where a term list is modified.
- Creation: Create a post as a contributor and check if the plugin enqueues scripts in the block editor or classic editor.
wp post create --post_type=post --post_status=publish --post_title="Nonce Leak Test" --post_author=[CONTRIBUTOR_ID]
- Extraction:
- Navigate to the newly created post or the WordPress Dashboard as the Contributor.
- The plugin likely uses
wp_localize_scriptto pass the nonce to the JS frontend. - Inferred JS Variable:
window.aobt_varsorwindow.aobt_params. - Inferred Nonce Key:
aobt_nonceornonce.
- Action:
- Use
browser_eval("window.aobt_vars?.nonce")or search the source code forwp_create_nonce.
- Use
5. Exploitation Strategy
Step 1: Preparation
Identify two categories (terms) and their current IDs. For example, Category A (ID 5) and Category B (ID 6).
Step 2: Request Execution
Using the http_request tool, send the following payload as the Contributor:
- URL:
http://[TARGET]/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: If the plugin expects a serialized string or comma-separated list, adjust theaction=aobt_update_order&nonce=[EXTRACTED_NONCE]&order[]=6&order[]=5orderparameter accordingly).
6. Test Data Setup
- Terms: Ensure at least two terms exist in a taxonomy (e.g., 'category').
wp term create category "Target Category A"wp term create category "Target Category B"
- User: Create a Contributor user.
wp user create attacker attacker@example.com --role=contributor --user_pass=password
- Initial State: Record the initial
term_orderfor these terms.wp db query "SELECT term_id, term_order FROM wp_terms WHERE name LIKE 'Target Category%'"
7. Expected Results
- Response: The server should return a
200 OKresponse, often with a body like1,success, or a JSON object{"success": true}. - Database Change: The
term_ordercolumn in thewp_termstable for the specified IDs should be updated to reflect the new order sent in the payload.
8. Verification Steps
- Check Term Order via CLI:
wp db query "SELECT term_id, term_order FROM wp_terms WHERE term_id IN (5, 6)" - Confirm Reversal: Verify that the order values have swapped or changed from their initial state recorded in step 6.
9. Alternative Approaches
- Generic Nonce: Check if the plugin uses a generic nonce like
wp_create_nonce( 'wp_rest' )or-1. If-1, any nonce generated for the user will work. - Parameter Format: If
order[]fails, tryorder=6,5ororder[0]=6&order[1]=5. - Taxonomy Specificity: Some plugins require a
taxonomyparameter (e.g.,&taxonomy=category). If the request fails, check the source for$_POST['taxonomy']. - No Nonce: If
check_ajax_refereris entirely absent, the exploit becomes a direct IDOR/Missing Authorization and can be executed with only theactionandorderparameters.
Summary
The Anything Order by Terms plugin for WordPress is vulnerable to unauthorized term reordering due to a missing capability check in its AJAX handler. This allows authenticated attackers with Contributor-level permissions or higher to manipulate the display order of categories, tags, and other taxonomies site-wide.
Vulnerable Code
// Inferred from research plan add_action('wp_ajax_aobt_update_order', 'aobt_update_order_callback'); function aobt_update_order_callback() { check_ajax_referer('aobt_nonce', 'nonce'); // Vulnerability: Missing current_user_can() check here $order = $_POST['order']; // ... logic to update term_order in wp_terms table ... wp_die(); }
Security Fix
@@ -100,6 +100,10 @@ function aobt_update_order_callback() { check_ajax_referer('aobt_nonce', 'nonce'); + if ( ! current_user_can( 'manage_categories' ) ) { + wp_die( -1 ); + } + $order = $_POST['order']; // ... rest of logic to update term order ...
Exploit Outline
To exploit this vulnerability, an attacker must be authenticated with at least Contributor-level access. First, the attacker extracts a valid nonce (likely named 'aobt_nonce') which the plugin typically exposes to the WordPress dashboard or editor scripts via wp_localize_script. Next, the attacker identifies the IDs of the terms (e.g., categories or tags) they wish to reorder. Finally, they send a POST request to /wp-admin/admin-ajax.php with the action parameter set to 'aobt_update_order', the valid nonce, and an 'order' array containing the term IDs in the attacker's preferred sequence. Because the plugin fails to call current_user_can(), the server processes the request and updates the term_order column in the database.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.