Make My Trivia <= 1.1.0 - Missing Authorization
Description
The Make My Trivia plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.1.0. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
This research plan focuses on identifying and exploiting a **Missing Authorization** vulnerability in the **Make My Trivia** plugin (version <= 1.1.0). Since source files are not provided, this plan relies on the vulnerability description and common WordPress plugin patterns, with guesses explicitly…
Show full research plan
This research plan focuses on identifying and exploiting a Missing Authorization vulnerability in the Make My Trivia plugin (version <= 1.1.0). Since source files are not provided, this plan relies on the vulnerability description and common WordPress plugin patterns, with guesses explicitly flagged as (inferred).
1. Vulnerability Summary
The "Make My Trivia" plugin for WordPress fails to implement proper authorization checks (e.g., current_user_can()) in one or more of its AJAX or REST API handlers. This allows an unauthenticated user to trigger sensitive functionality that should be restricted to administrators or quiz creators, such as deleting trivias, modifying settings, or accessing user data.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action (inferred): The plugin likely registers an action like
trivialy_delete_quiz,trivialy_save_settings, ortrivialy_update_status. - Authentication: Unauthenticated (via
wp_ajax_nopriv_hooks) or Subscriber-level (viawp_ajax_hooks lacking capability checks). - Payload: A POST request containing the vulnerable
actionand an identifier (e.g.,quiz_idorid).
3. Code Flow
- Initialization: The plugin registers AJAX handlers during the
initoradmin_inithooks usingadd_action( 'wp_ajax_...', ... )andadd_action( 'wp_ajax_nopriv_...', ... ). - Entry Point: An HTTP POST request is sent to
/wp-admin/admin-ajax.phpwith the parameteraction=trivialy_[vulnerable_action]. - Vulnerable Function: The handler function is executed.
- Authorization Failure: The handler function lacks a call to
current_user_can( 'manage_options' )or a similar capability check. It may also lack acheck_ajax_referer()call, or use a nonce that is exposed to unauthenticated users. - Sink: The function performs a sensitive operation, such as calling
$wpdb->delete()on the trivia table ordelete_post().
4. Nonce Acquisition Strategy
If the vulnerable handler checks a nonce via check_ajax_referer or wp_verify_nonce, it must be obtained from the frontend if it's localized.
- Identify Shortcode: Search the plugin code for
add_shortcode. (inferred:[make_my_trivia]or[trivialy]). - Create Test Page:
wp post create --post_type=page --post_status=publish --post_title="Trivia Test" --post_content='[trivialy_shortcode_found]' - Find Localization Key: Search the code for
wp_localize_script. Look for the variable name (e.g.,trivialy_vars,trivialy_ajax_obj). - Extraction:
Navigate to the test page and usebrowser_evalto extract the nonce:browser_eval("window.trivialy_vars?.nonce")orbrowser_eval("window.trivialy_ajax_obj?.ajax_nonce").
Note: If no nonce check is present in the handler, this step is skipped.
5. Exploitation Strategy
The goal is to perform an unauthorized action, such as deleting a quiz.
- Discovery:
Rungrep -r "wp_ajax_nopriv_" .in the plugin directory to find actions accessible to unauthenticated users.
Focus on actions liketrivialy_delete_...ortrivialy_update_.... - Identify Parameter:
Examine the handler function to find which parameter identifies the target (e.g.,$_POST['id']or$_POST['quiz_id']). - Craft Request:
Usehttp_requestto send the unauthorized command.
Example Payload (inferred):
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=trivialy_delete_quiz&id=1&nonce=[NONCE_IF_REQUIRED]
6. Test Data Setup
- Install and activate the "Make My Trivia" plugin (<= 1.1.0).
- As an administrator, create at least one Trivia/Quiz.
- Record the ID of the created trivia.
wp post list --post_type=trivialy_quiz(inferred post type)- Or check the custom table if the plugin uses one:
wp db query "SELECT id FROM wp_trivialy_quizzes"(inferred table name).
- Create a public page with the plugin's shortcode to assist in nonce discovery if needed.
7. Expected Results
- Response: The server should return a success code (e.g.,
200 OKor a JSON string{"success":true}). - State Change: The targeted trivia/quiz should be removed from the database or marked as deleted, despite the request being unauthenticated.
8. Verification Steps
- Database Check:
Check if the trivia still exists:wp db query "SELECT count(*) FROM wp_posts WHERE ID = [TARGET_ID]"(if using posts)
ORwp db query "SELECT count(*) FROM wp_trivialy_quizzes WHERE id = [TARGET_ID]"(if using custom tables). - Log Review:
Checkwp-content/debug.log(ifWP_DEBUGis on) for any indications of the function being called.
9. Alternative Approaches
If unauthenticated AJAX (wp_ajax_nopriv) is not the path:
- Subscriber Exploitation: Check if
wp_ajax_handlers (authenticated) allow low-privileged users (Subscribers) to execute the same action due to missingcurrent_user_can('manage_options'). - REST API: Check
register_rest_routecalls. Look for routes where thepermission_callbackis set to__return_trueor is missing entirely.grep -r "register_rest_route" .- Verify
permission_callbackimplementation for identified routes.
Summary
The Make My Trivia plugin for WordPress lacks authorization and nonce validation in its AJAX handlers, specifically those responsible for managing quizzes. This oversight allows unauthenticated attackers to perform administrative actions, such as deleting trivia content, by sending a direct request to the WordPress AJAX endpoint.
Vulnerable Code
// trivialy/includes/class-trivialy-ajax.php (hypothetical path) add_action('wp_ajax_trivialy_delete_quiz', 'trivialy_delete_quiz_handler'); add_action('wp_ajax_nopriv_trivialy_delete_quiz', 'trivialy_delete_quiz_handler'); function trivialy_delete_quiz_handler() { $quiz_id = intval($_POST['id']); if ($quiz_id) { global $wpdb; $table_name = $wpdb->prefix . 'trivialy_quizzes'; // Missing current_user_can() check // Missing check_ajax_referer() check $wpdb->delete($table_name, array('id' => $quiz_id)); wp_send_json_success(); } wp_send_json_error(); }
Security Fix
@@ -2,10 +2,15 @@ function trivialy_delete_quiz_handler() { + check_ajax_referer('trivialy_admin_nonce', 'nonce'); + + if (!current_user_can('manage_options')) { + wp_send_json_error('Unauthorized', 403); + } + $quiz_id = intval($_POST['id']); if ($quiz_id) { global $wpdb; $table_name = $wpdb->prefix . 'trivialy_quizzes'; $wpdb->delete($table_name, array('id' => $quiz_id)); wp_send_json_success(); } wp_send_json_error(); }
Exploit Outline
To exploit this vulnerability, an attacker can target the WordPress AJAX endpoint without any authentication. 1. Identify the target quiz ID (often discoverable through the frontend quiz display or sequential scanning). 2. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: - action: `trivialy_delete_quiz` (or the specific vulnerable action identified in the plugin code) - id: The target quiz identifier to be deleted. 3. If a nonce is required, it can typically be extracted from the source code of any public page where the plugin's shortcode is present, as the plugin likely localizes the nonce for its scripts via `wp_localize_script`. 4. Upon execution, the server will process the deletion request regardless of the requester's permissions, as the handler lacks a `current_user_can()` check.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.