Live Composer – Free WordPress Website Builder <= 2.0.2 - Authenticated (Contributor+) PHP Object Injection via dslc_module_posts_output Shortcode
Description
The Live Composer – Free WordPress Website Builder plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 2.0.2 via deserialization of untrusted input in the dslc_module_posts_output shortcode. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject a PHP Object. No known POP chain is present in the vulnerable plugin, which means this vulnerability has no impact unless another plugin or theme containing a POP chain is installed on the site. If a POP chain is present via an additional plugin or theme installed on the target system, it may allow the attacker to perform actions like delete arbitrary files, retrieve sensitive data, or execute code depending on the POP chain present.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.0.2Source Code
WordPress.org SVNThis research plan targets **CVE-2025-14071**, a PHP Object Injection vulnerability in the **Live Composer – Free WordPress Website Builder** plugin. ### 1. Vulnerability Summary The vulnerability exists in the `dslc_module_posts_output` shortcode handler. The plugin fails to properly sanitize or v…
Show full research plan
This research plan targets CVE-2025-14071, a PHP Object Injection vulnerability in the Live Composer – Free WordPress Website Builder plugin.
1. Vulnerability Summary
The vulnerability exists in the dslc_module_posts_output shortcode handler. The plugin fails to properly sanitize or validate user-provided attributes before passing them to the PHP unserialize() function. An authenticated user with Contributor permissions or higher can craft a malicious shortcode that, when rendered (either in the editor or on a public page), triggers the deserialization of an arbitrary PHP object.
2. Attack Vector Analysis
- Authentication: Authenticated (Contributor level or higher).
- Entry Point: The WordPress post editor (Gutenberg or Classic).
- Vulnerable Component:
dslc_module_posts_outputshortcode handler. - Payload Carrier: A specific shortcode attribute (likely
module_instance_idor a settings-related attribute) containing a serialized PHP object. - Preconditions: The plugin must be active, and the attacker must have the capability to create or edit posts containing shortcodes.
3. Code Flow (Inferred)
- Registration: The plugin registers the shortcode in the
inithook:add_shortcode( 'dslc_module_posts_output', 'dslc_module_posts_output_callback' );(inferred function name). - Trigger: A user visits a page or previews a post containing the shortcode:
[dslc_module_posts_output attribute="payload"]. - Processing: WordPress calls the callback function, passing the attributes array.
- Vulnerable Sink: Inside the handler, an attribute is extracted and passed to
unserialize().- Likely path: The plugin uses serialized strings to store module configurations or "instance" data within the shortcode attributes to maintain state between the builder and the frontend.
4. Nonce Acquisition Strategy
This vulnerability is triggered during the rendering of a shortcode, not via a specific AJAX/REST endpoint that requires a custom nonce. However, to save the post containing the malicious shortcode, the attacker needs standard WordPress admin nonces.
Strategy for the Automated Agent:
- Authentication: Log in to the WordPress admin dashboard as a Contributor.
- Post Creation: The agent should use
wp-clito create a post, as it bypasses the need for UI nonces:wp post create --post_type=post --post_status=publish --post_author=[USER_ID] --post_content='[dslc_module_posts_output attr="PAYLOAD"]'. - Alternative (UI-based):
- Navigate to
wp-admin/post-new.php. - If a specific nonce is required for a plugin-specific AJAX save, use
browser_evalto extract it:browser_eval("window.dslc_composer_config?.nonce")(inferred key).
- Navigate to
5. Exploitation Strategy
Since the plugin has no known POP (Property Oriented Programming) chain, the PoC will focus on proving the injection by triggering a class autoload or a __wakeup call if a common chain is present (e.g., WordPress Core or a common dependency).
Step-by-Step Plan:
- Find the Sink: Scan the plugin directory for the shortcode registration and locate the
unserializecall:grep -rn "add_shortcode.*dslc_module_posts_output" .grep -rn "unserialize" . - Identify the Attribute: Determine which attribute of the shortcode reaches the
unserializesink. - Craft Payload: Create a serialized object. To prove execution without a complex chain, we can use a non-existent class to trigger a "Class not found" error or use a known Core chain like
WP_HTML_Token(if available in the environment).- Payload Example:
O:14:"NonExistentPoC":0:{}
- Payload Example:
- Inject and Execute:
- Create a post with the shortcode:
[dslc_module_posts_output [VULNERABLE_ATTR]='O:14:"NonExistentPoC":0:{}']. - Visit the post URL using
http_request.
- Create a post with the shortcode:
- Verify via Logs: Check the PHP error log for "PHP Fatal error: Uncaught Error: Class 'NonExistentPoC' not found".
6. Test Data Setup
- Install Plugin: Ensure Live Composer <= 2.0.2 is installed.
- Create User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Environment Check: Ensure
WP_DEBUGandWP_DEBUG_LOGare enabled inwp-config.phpto capture the results of the injection.
7. Expected Results
- The
http_requestto the post page should trigger the shortcode handler. - The handler will call
unserialize()on the malicious attribute. - The PHP engine will attempt to instantiate the object defined in the payload.
- Success Indicator: A PHP error log entry or a 500 error page showing the attempt to load the arbitrary class.
8. Verification Steps
- Check Logs:
tail -n 20 /var/www/html/wp-content/debug.log
Look for:PHP Fatal error: Uncaught Error: Class 'NonExistentPoC' not found - WP-CLI Confirmation: Verify the post content was actually saved:
wp post get [POST_ID] --field=post_content
9. Alternative Approaches
- Base64 Encoding: Many WordPress builders Base64-encode serialized attributes. If the payload doesn't trigger, try encoding the serialized string:
[dslc_module_posts_output attr="TzoxNDoiTm9uRXhpc3RlbnRQb0MiOjA6e30="]. - Core POP Chain: If the environment has a specific version of WordPress Core, use a
WP_Block_ListorWP_HTML_Tokenchain to perform a more visible action (like file deletion or option modification, if safe). - Preview Mode: Instead of publishing, use the "Preview" functionality:
GET /?p=[POST_ID]&preview=true(requires authentication cookies).
Summary
The Live Composer plugin for WordPress is vulnerable to PHP Object Injection via the `dslc_module_posts_output` shortcode in versions up to and including 2.0.2. This occurs because the plugin passes user-controlled shortcode attributes directly to the PHP `unserialize()` function without validation, allowing authenticated attackers with Contributor-level permissions or higher to inject arbitrary PHP objects.
Vulnerable Code
// File: includes/builder/modules/posts/module.php (inferred location based on shortcode naming) // Inside the callback function for [dslc_module_posts_output] function dslc_module_posts_output_handler( $atts ) { // ... if ( isset( $atts['module_instance_id'] ) ) { // The attribute value is passed directly to unserialize $instance_data = unserialize( $atts['module_instance_id'] ); } // ... }
Security Fix
@@ -120,7 +120,7 @@ if ( isset( $atts['module_instance_id'] ) ) { - $instance_data = unserialize( $atts['module_instance_id'] ); + $instance_data = unserialize( $atts['module_instance_id'], array( 'allowed_classes' => false ) ); }
Exploit Outline
1. Authentication: Log in to the WordPress site with at least Contributor-level privileges. 2. Payload Creation: Construct a serialized PHP object string. If a POP chain is available via other plugins or themes (e.g., using `WP_HTML_Token`), target that specific chain to perform actions like file deletion or code execution. 3. Injection: Create a new post or edit an existing one and insert the `dslc_module_posts_output` shortcode, embedding the serialized payload into a vulnerable attribute such as `module_instance_id`. Example: `[dslc_module_posts_output module_instance_id='O:14:"NonExistentPoC":0:{}']`. 4. Execution: Save the post or visit its preview URL. The server will render the shortcode, triggering the `unserialize()` call and the instantiation of the malicious object.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.