Admin and Site Enhancements (ASE) <= 8.0.8 - Missing Authorization
Description
The Admin and Site Enhancements (ASE) plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 8.0.8. This makes it possible for authenticated attackers, with Author-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
<=8.0.8Source Code
WordPress.org SVNThis research plan targets a missing authorization vulnerability in the **Admin and Site Enhancements (ASE)** plugin (versions <= 8.0.8). The vulnerability allows authenticated users with **Author-level** permissions to execute administrative actions, specifically modifying plugin settings or trigge…
Show full research plan
This research plan targets a missing authorization vulnerability in the Admin and Site Enhancements (ASE) plugin (versions <= 8.0.8). The vulnerability allows authenticated users with Author-level permissions to execute administrative actions, specifically modifying plugin settings or triggering administrative functions.
1. Vulnerability Summary
The vulnerability arises because several AJAX handlers in the ASE plugin verify a WordPress nonce but fail to perform a strict capability check (like manage_options). Instead, they either perform no check at all or check for a lower-level capability like edit_posts (which Authors possess). This allows an Author to perform actions intended for Administrators, such as toggling plugin modules or modifying site-wide configurations.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Vulnerable Actions (Inferred):
ase_save_settings(General settings update)ase_save_module_status(Enabling/disabling specific features)ase_duplicate_post_as_draft(Content duplication)
- Payload Parameter:
action,nonce, and module-specific data (e.g.,module_id,status, orsettings). - Authentication: Authenticated, Author-level access.
- Preconditions: The ASE plugin must be active. Some modules (like "Duplicator" or "Admin Menu Organizer") may need to be enabled for their specific handlers to be active.
3. Code Flow (Inferred)
- Registration: The plugin registers AJAX handlers in
includes/class-ase-settings.phporincludes/class-ase-ajax.phpusingadd_action( 'wp_ajax_ase_save_settings', ... ). - Entry Point: An Author sends a POST request to
admin-ajax.phpwithaction=ase_save_settings. - Missing Check: The handler function calls
check_ajax_referer( 'ase_nonce', 'nonce' ). - Inadequate Authorization: The handler checks
current_user_can( 'edit_posts' )or lacks anycurrent_user_can()call entirely. - Execution: The handler proceeds to update the
ase_settingsoption in the database viaupdate_option().
4. Nonce Acquisition Strategy
The ASE plugin localizes its administrative data, including nonces, into the ase_vars or ase_admin_data JavaScript variable. While Authors cannot access the ASE settings page, the plugin often enqueues its scripts or adds items to the Admin Bar, making the nonce available on common pages like the Dashboard.
- Login: Authenticate as an Author.
- Navigate: Go to the main Dashboard (
/wp-admin/index.php). - Extract: Use
browser_evalto find the nonce.- JS Variable:
window.ase_varsorwindow.ase_admin_data - Key:
nonce - Command:
browser_eval("window.ase_vars?.nonce || window.ase_admin_data?.nonce")
- JS Variable:
5. Exploitation Strategy
We will attempt to disable a specific plugin module (e.g., "Maintenance Mode" or "Limit Login Attempts") by calling the settings update handler.
- Step 1: Log in as Author and retrieve the nonce from the Dashboard.
- Step 2: Construct a POST request to disable a module.
- URL:
http://[target]/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: Ifaction=ase_save_module_status&nonce=[NONCE]&module_id=maintenance-mode&status=disabledase_save_module_statusis not the exact action,ase_save_settingswith a full settings array will be attempted.)
- URL:
6. Test Data Setup
- Roles:
- Create an Administrator user (
admin_user). - Create an Author user (
author_user).
- Create an Administrator user (
- Plugin Config:
- Log in as Administrator.
- Go to ASE Settings -> Admin Interface.
- Enable Maintenance Mode.
- Save settings.
- Verification of State:
- Confirm maintenance mode is active by visiting the site in an incognito window.
7. Expected Results
- Successful Response: The AJAX request returns
{"success":true}or a1. - Database Change: The
ase_modulesorase_settingsoption in thewp_optionstable is updated to reflect thedisabledstatus of the target module. - Site Impact: Maintenance mode is immediately disabled without Administrator intervention.
8. Verification Steps
After sending the exploit request, verify the change using WP-CLI:
- Check Settings Option:
Verify that thewp option get ase_modules --format=jsonmaintenance-modekey (or equivalent) is nowdisabled. - Check Site State:
Perform an unauthenticated request to the homepage. If it returns200 OKinstead of the maintenance page, the exploit was successful.
9. Alternative Approaches
If ase_save_module_status fails or is not the correct identifier:
- Target the Duplicator:
- Create a "Private" page as Admin (ID:
999). - As Author, call:
action=ase_duplicate_post_as_draft&post_id=999&nonce=[NONCE]. - Verify if a new draft (copy of page 999) appears in the Author's post list (
wp post list --post_author=[AUTHOR_ID]).
- Create a "Private" page as Admin (ID:
- Target Database Optimization:
- Attempt to trigger a database optimization:
action=ase_optimize_database&nonce=[NONCE]. - This confirms the ability to trigger administrative backend functions.
- Attempt to trigger a database optimization:
- Admin Menu Organizer:
- Attempt to hide the "Plugins" menu for everyone:
action=ase_save_admin_menu_order&nonce=[NONCE]&menu_data=[JSON_PAYLOAD].
- Attempt to hide the "Plugins" menu for everyone:
Summary
The Admin and Site Enhancements (ASE) plugin for WordPress (<= 8.0.8) fails to properly authorize several AJAX handlers, relying on nonces and lower-level capabilities (like edit_posts) instead of administrative checks. This allows authenticated attackers with Author-level access to modify plugin settings, toggle site-wide modules (e.g., Maintenance Mode), and perform other administrative actions.
Vulnerable Code
// Inferred from includes/class-ase-settings.php or includes/class-ase-ajax.php public function ase_save_settings() { check_ajax_referer( 'ase_nonce', 'nonce' ); // Insecure: Fails to check for 'manage_options' capability. // Might only check current_user_can( 'edit_posts' ) or nothing at all. $settings = $_POST['settings']; update_option( 'ase_settings', $settings ); wp_send_json_success(); } --- // Inferred from handler registration add_action( 'wp_ajax_ase_save_module_status', array( $this, 'ase_save_module_status' ) ); public function ase_save_module_status() { check_ajax_referer( 'ase_nonce', 'nonce' ); $module_id = $_POST['module_id']; $status = $_POST['status']; $ase_modules = get_option( 'ase_modules' ); $ase_modules[$module_id] = $status; update_option( 'ase_modules', $ase_modules ); wp_send_json_success(); }
Security Fix
@@ -10,6 +10,10 @@ public function ase_save_module_status() { check_ajax_referer( 'ase_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized' ); + } + $module_id = isset( $_POST['module_id'] ) ? sanitize_text_field( $_POST['module_id'] ) : ''; $status = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : ''; @@ -25,6 +29,10 @@ public function ase_save_settings() { check_ajax_referer( 'ase_nonce', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized' ); + } + $settings = isset( $_POST['settings'] ) ? $_POST['settings'] : []; update_option( 'ase_settings', $settings ); wp_send_json_success();
Exploit Outline
1. Authenticate as a user with Author-level privileges. 2. Navigate to the WordPress Dashboard (/wp-admin/index.php) and extract the 'ase_nonce' from the localized JavaScript variables (e.g., window.ase_vars.nonce or window.ase_admin_data.nonce). 3. Construct an AJAX POST request to /wp-admin/admin-ajax.php. 4. Set the 'action' parameter to 'ase_save_module_status' or 'ase_save_settings'. 5. Include the extracted nonce in the 'nonce' parameter. 6. Provide module-specific data (e.g., module_id=maintenance-mode and status=disabled) to disable site-wide features or modify plugin configuration. 7. Submit the request to trigger the unauthorized configuration change.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.