WP Terms Popup – Terms and Conditions and Privacy Policy WordPress Popups <= 2.10.0 - Missing Authorization
Description
The WP Terms Popup – Terms and Conditions and Privacy Policy WordPress Popups plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.10.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
<=2.10.0What Changed in the Fix
Changes introduced in v2.11.0
Source Code
WordPress.org SVN. I will focus on `wptp_save_settings` as the primary target. * Setup: Install plugin, create a popup, set it sitewide. * Nonce extraction: Create a page, or just check the homepage if popups are enabled. * Exploit: Send `action=wptp_save_settings&termsopt_sitewide=0` (disabl…
Show full research plan
.
I will focus on `wptp_save_settings` as the primary target.
* Setup: Install plugin, create a popup, set it sitewide.
* Nonce extraction: Create a page, or just check the homepage if popups are enabled.
* Exploit: Send `action=wptp_save_settings&termsopt_sitewide=0` (disabling the popup).
* Verification: Check the option value via WP-CLI.
* The nonce is `wptp-ajaxhandler-nonce`.
* The JS variable is `wptp_ajax_object.ajax_nonce`.
* The action used in `ajaxhandler_css` and `ajaxhandler_popup` is `wptp-ajaxhandler-nonce`.
* If `wptp_save_settings` also uses this nonce, we are in business.
* If it doesn't use a nonce at all, even better.
Wait, what if the action name is `wptp_designer_save_css`?
The public file has `ajaxhandler_css`.
The public file also mentions "WP Terms Popup Designer" in the `readme`.
If the base plugin contains the AJAX handler for the Designer's CSS...
`ajaxhandler_css` in the public file is for *fetching* the CSS.
What if there's a counterpart for *saving*?
Let's assume the
Summary
The WP Terms Popup plugin for WordPress is vulnerable to unauthorized information disclosure and access due to missing capability checks and insufficient validation on its AJAX handlers. Unauthenticated attackers can exploit this to retrieve the content of arbitrary posts, including private or draft content, by providing a specific post ID to the public-facing AJAX endpoints.
Vulnerable Code
/** * Handle CSS AJAX. * * @since 2.0.0 */ public function ajaxhandler_css() { // check_ajax_referer('wptp-ajaxhandler-nonce', 'wptp_nonce'); if (!isset($_POST['wptp_nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['wptp_nonce']), 'wptp-ajaxhandler-nonce')) { exit(); } $wptp_content['css'] = $this->popup_css($_POST['termspageid']); die(json_encode($wptp_content)); } /** * Handle HTML AJAX. * * @since 2.0.0 */ public function ajaxhandler_popup() { // check_ajax_referer('wptp-ajaxhandler-nonce', 'wptp_nonce'); if (!isset($_POST['wptp_nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['wptp_nonce']), 'wptp-ajaxhandler-nonce')) { exit(); } $wptp_content['popup'] = $this->popup_html(sanitize_text_field($_POST['termspageid'])); die(json_encode($wptp_content)); }
Security Fix
@@ -9,7 +9,7 @@ * Plugin Name: WP Terms Popup * Plugin URI: https://termsplugin.com * Description: Ask users to agree to a popup before they are allowed to view your site. - * Version: 2.10.0 + * Version: 2.11.0 * Author: Link Software LLC * Author URI: https://linksoftwarellc.com * License: GPL-2.0+ @@ -26,7 +26,7 @@ /** * Currently plugin version. */ -define('WP_TERMS_POPUP_VERSION', '2.10.0'); +define('WP_TERMS_POPUP_VERSION', '2.11.0'); function activate_wp_terms_popup() { @@ -163,15 +163,25 @@ */ public function ajaxhandler_css() { - // check_ajax_referer('wptp-ajaxhandler-nonce', 'wptp_nonce'); - if (!isset($_POST['wptp_nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['wptp_nonce']), 'wptp-ajaxhandler-nonce')) { - exit(); + wp_die('', 'Forbidden', array('response' => 403)); } - $wptp_content['css'] = $this->popup_css($_POST['termspageid']); + if (!isset($_POST['termspageid']) || !is_numeric($_POST['termspageid'])) { + wp_die('', 'Bad Request', array('response' => 400)); + } + + $terms_page_id = intval($_POST['termspageid']); + + // Verify that the post exists, is of the correct type, and is published + $post = get_post($terms_page_id); + if (!$post || $post->post_type !== 'termpopup' || $post->post_status !== 'publish') { + wp_die('', 'Bad Request', array('response' => 400)); + } + + $wptp_content['css'] = $this->popup_css($terms_page_id); - die(json_encode($wptp_content)); + wp_die(json_encode($wptp_content)); } /** @@ -181,15 +191,25 @@ */ public function ajaxhandler_popup() { - // check_ajax_referer('wptp-ajaxhandler-nonce', 'wptp_nonce'); - if (!isset($_POST['wptp_nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['wptp_nonce']), 'wptp-ajaxhandler-nonce')) { - exit(); + wp_die('', 'Forbidden', array('response' => 403)); } - $wptp_content['popup'] = $this->popup_html(sanitize_text_field($_POST['termspageid'])); + if (!isset($_POST['termspageid']) || !is_numeric($_POST['termspageid'])) { + wp_die('', 'Bad Request', array('response' => 400)); + } + + $terms_page_id = intval($_POST['termspageid']); + + // Verify that the post exists, is of the correct type, and is published + $post = get_post($terms_page_id); + if (!$post || $post->post_type !== 'termpopup' || $post->post_status !== 'publish') { + wp_die('', 'Bad Request', array('response' => 400)); + } + + $wptp_content['popup'] = $this->popup_html($terms_page_id); - die(json_encode($wptp_content)); + wp_die(json_encode($wptp_content)); }
Exploit Outline
The exploit target is the `ajaxhandler_popup` or `ajaxhandler_css` AJAX functions, which are intended to serve popup content to unauthenticated users but lack server-side validation that the requested ID belongs to a public 'termpopup' post type. 1. **Nonce Acquisition**: An attacker visits the site's homepage or any page where the plugin is active. If the 'Load popups with JavaScript' setting is enabled, the plugin localizes a script containing the `wptp-ajaxhandler-nonce` in the `wptp_ajax_object.ajax_nonce` JavaScript variable. 2. **Unauthorized Request**: The attacker sends a POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `wptp_ajax_popup` (or `wptp_ajax_css`) - `wptp_nonce`: The extracted nonce value. - `termspageid`: The numeric ID of a target post or page (including private, draft, or password-protected content). 3. **Information Extraction**: Because the vulnerable versions (<= 2.10.0) do not check the post type or post status of the provided ID, the plugin will process the ID and return the HTML or CSS of that post in the JSON response.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.