CP Contact Form with Paypal <= 1.3.61 - Authenticated (Contributor+) SQL Injection
Description
The CP Contact Form with Paypal plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.3.61 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with contributor-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=1.3.61What Changed in the Fix
Changes introduced in v1.3.62
Source Code
WordPress.org SVNThis exploitation research plan targets an authenticated SQL injection vulnerability in the **CP Contact Form with PayPal** plugin (versions <= 1.3.61). The vulnerability arises from the plugin's data management logic, which processes user-supplied parameters in raw SQL queries without using `$wpdb-…
Show full research plan
This exploitation research plan targets an authenticated SQL injection vulnerability in the CP Contact Form with PayPal plugin (versions <= 1.3.61). The vulnerability arises from the plugin's data management logic, which processes user-supplied parameters in raw SQL queries without using $wpdb->prepare().
1. Vulnerability Summary
- Vulnerability: Authenticated SQL Injection
- Affected Parameter:
ids(oruids) used in CSV export or message management. - Vulnerable Sink:
cp_contactformpp_data_management_loaded()incp_contactformpp_functions.php. - Reason: The plugin uses string concatenation to build a
SELECTquery with anINclause using the user-suppliedidsparameter. It fails to sanitize the input or use prepared statements, allowing an attacker to break out of the query. - Privilege Level: Contributor or higher. While the settings page is limited to
manage_options, the data processing logic inwp_loadedoften checks for theedit_postscapability, which Contributors possess.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/index.phpor/(triggered via thewp_loadedhook). - Action:
cp_contact_form_paypal_export_csv. - HTTP Parameter:
ids(sent via GET or POST). - Authentication: Required (Contributor-level session).
- Preconditions: At least one entry must exist in the
cp_contact_form_paypal_poststable for the query to return results or for the time-based injection to be clearly observable.
3. Code Flow
- Entry Point: The plugin registers
cp_contactformpp_data_management_loadedon thewp_loadedhook incp_contactformpp.php.add_action('wp_loaded', 'cp_contactformpp_data_management_loaded' ); - Logic Dispatch: Inside
cp_contactformpp_functions.php, the functioncp_contactformpp_data_management_loaded()checks for theactionparameter.function cp_contactformpp_data_management_loaded() { if (isset($_GET['action']) && $_GET['action'] == 'cp_contact_form_paypal_export_csv') { // Capability check (often edit_posts or missing) if (current_user_can('edit_posts')) { cp_contact_form_paypal_export_csv(); } } } - The Sink: The export function retrieves the
idsparameter and concatenates it into a SQL query.function cp_contact_form_paypal_export_csv() { global $wpdb; $ids = $_GET['ids']; // SINK: Directly from $_GET $table = $wpdb->prefix . "cp_contact_form_paypal_posts"; // Vulnerable Query $results = $wpdb->get_results("SELECT * FROM $table WHERE id IN ($ids)"); // ... processes $results into CSV ... }
4. Nonce Acquisition Strategy
In many versions of this plugin, the wp_loaded actions for CSV export
Summary
The CP Contact Form with PayPal plugin is vulnerable to authenticated SQL Injection because it concatenates user-controlled variables like 'id' directly into SQL queries without using $wpdb->prepare() or integer casting. Attackers with Contributor-level access or higher can exploit this to extract sensitive database information via time-based or boolean-based blind injection techniques.
Vulnerable Code
// cp_contactformpp_functions.php line 310 if ($id != '') $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id ); --- // cp_contactformpp_functions.php line 1509 else { $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id ); if (count($myrows)) { $value = $myrows[0]->$field; $cp_contactformpp_option_buffered_item = $myrows[0]; $cp_contactformpp_option_buffered_id = $id; } }
Security Fix
@@ -310,8 +310,8 @@ $CP_CPP_global_form_count = "_".$CP_CFPP_global_form_count_number; if (!defined('CP_AUTH_INCLUDE')) define('CP_AUTH_INCLUDE', true); - if ($id != '') - $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id ); + if ($id != '') + $myrows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=%d", $id) ); else $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE ); if ($id == '') $id = $myrows[0]->id; @@ -1503,12 +1508,13 @@ } if ($id == '') $id = CP_CONTACTFORMPP_ID; + $id = intval($id); global $wpdb, $cp_contactformpp_option_buffered_item, $cp_contactformpp_option_buffered_id; if ($cp_contactformpp_option_buffered_id == $id) $value = (property_exists($cp_contactformpp_option_buffered_item, $field) && isset($cp_contactformpp_option_buffered_item->$field) ? @$cp_contactformpp_option_buffered_item->$field : ''); else { - $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id ); + $myrows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=%d", $id) ); if (count($myrows)) {
Exploit Outline
The exploit targets endpoints that process the 'id' or 'ids' parameters, such as form settings retrieval or CSV data export. An authenticated user (Contributor or higher) sends a request (GET or POST) containing a malicious SQL payload in place of the expected integer ID. For example, setting 'id=1 OR SLEEP(5)' in a request that triggers form data retrieval allows an attacker to confirm the vulnerability via a time-based delay. Since the plugin fails to sanitize these inputs before appending them to the WHERE clause, standard SQL injection payloads can be used to exfiltrate data from the 'wp_users' table or other sensitive tables.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.