CVE-2025-66115

Easy Invoice <= 2.1.4 - Authenticated (Administrator+) Local File Inclusion

mediumImproper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote File Inclusion')
6.6
CVSS Score
6.6
CVSS Score
medium
Severity
2.1.5
Patched in
5d
Time to patch

Description

The Easy Invoice plugin for WordPress is vulnerable to Local File Inclusion in versions up to, and including, 2.1.4. This makes it possible for authenticated attackers, with administrator-level access and above, to include and execute arbitrary files on the server, allowing the execution of any PHP code in those files. This can be used to bypass access controls, obtain sensitive data, or achieve code execution in cases where images and other "safe" file types can be uploaded and included.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.4
PublishedDecember 15, 2025
Last updatedDecember 19, 2025
Affected plugineasy-invoice

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on identifying and exploiting an authenticated Local File Inclusion (LFI) vulnerability in the Easy Invoice plugin for WordPress. ## 1. Vulnerability Summary The **Easy Invoice** plugin (versions <= 2.1.4) contains a Local File Inclusion vulnerability that allows an authe…

Show full research plan

This research plan focuses on identifying and exploiting an authenticated Local File Inclusion (LFI) vulnerability in the Easy Invoice plugin for WordPress.

1. Vulnerability Summary

The Easy Invoice plugin (versions <= 2.1.4) contains a Local File Inclusion vulnerability that allows an authenticated Administrator to include arbitrary files from the local server. The vulnerability exists because the plugin uses user-supplied input (likely a template name or layout parameter) in a file inclusion statement (include, require, or include_once) without sufficient path validation or sanitization.

2. Attack Vector Analysis

  • Endpoint: Likely a WordPress admin page (/wp-admin/admin.php) or an AJAX handler (/wp-admin/admin-ajax.php).
  • Authentication: Administrator-level privileges are required (PR:H).
  • Vulnerable Parameter: Likely template, layout, page_type, or file (inferred).
  • Action: An action related to invoice generation, previewing, or template settings.
  • Preconditions: The plugin must be active. The attacker must have a valid administrator session.

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers an admin menu or an AJAX action.
    • Search target: Look for add_menu_page, add_submenu_page, or add_action( 'wp_ajax_...' ) in the plugin's main files.
  2. Input Source: The code retrieves a parameter from $_GET or $_POST.
    • Search target: $_GET['template'] or $_REQUEST['layout'].
  3. Vulnerable Sink: The input is concatenated into a path used in an inclusion function.
    • Search target: include, require, include_once, or require_once.
    • Example Path Pattern: include( EASY_INVOICE_PATH . 'templates/' . $_GET['template'] . '.php' );
  4. Bypass: If the plugin appends .php, the attacker may need to use path traversal (../../) to reach target files or potentially rely on files that already have a .php extension.

4. Nonce Acquisition Strategy

Since this is an Administrator-level vulnerability, the request will likely require an administrative nonce.

  1. Identify the Admin Page: Navigate to the Easy Invoice settings or generator page.
    • browser_navigate("/wp-admin/admin.php?page=easy-invoice-settings") (inferred slug).
  2. Locate the Nonce: Search the page source for localized scripts or hidden form fields.
    • Look for wp_localize_script output. Common variable names might be easy_invoice_vars or ei_ajax_object.
  3. Extraction:
    • browser_eval("window.easy_invoice_vars?.nonce") (inferred).
    • If the action is in a form: browser_eval("document.querySelector('input[name=\"_wpnonce\"]')?.value").

5. Exploitation Strategy

The goal is to include /etc/passwd (for proof of file read) or a PHP file to demonstrate code execution.

Step 1: Discover the Sink

Search the plugin directory for inclusion sinks using user input:

grep -rnE "include|require" /var/www/html/wp-content/plugins/easy-invoice/ | grep -E "\$_GET|\$_POST|\$_REQUEST"

Step 2: Craft the Payload

Assuming the vulnerable parameter is template and the code is include( $path . $_GET['template'] );:

  • Target File: /etc/passwd
  • Traversal: ../../../../../../../../etc/passwd
  • Note: If the code appends .php, you may need to target a file that exists with that extension or use a null byte %00 (only works on PHP < 5.3.4, unlikely here) or a directory path traversal to a known file.

Step 3: Send the HTTP Request

Using http_request as an administrator:

  • Method: GET (or POST if the sink is in an AJAX handler).
  • URL: http://localhost:8080/wp-admin/admin.php?page=easy-invoice-preview&template=../../../../../../../../etc/passwd (inferred).
  • Headers: Must include the Administrator's cookies.

6. Test Data Setup

  1. Plugin Installation: Ensure easy-invoice version 2.1.4 is installed and activated.
  2. User Creation: Create an admin user exploit_admin.
  3. Sample PHP File: For RCE demonstration, create a file in the uploads directory:
    • wp eval "file_put_contents(wp_upload_dir()['path'] . '/pwn.php', '<?php echo \"VULNERABLE\"; ?>');"
  4. Note the Path: Determine the relative distance from the plugin's template folder to the uploads folder.

7. Expected Results

  • File Read: The response body contains the contents of /etc/passwd (e.g., root:x:0:0...).
  • PHP Execution: The response body contains the string VULNERABLE if pwn.php was included.
  • Error Indicators: If the inclusion fails due to the file not found, the response might show a PHP Warning: include(...): failed to open stream. This still confirms the LFI path.

8. Verification Steps

  1. Response Analysis: Check if the output of the included file appears within the HTML of the WordPress admin dashboard.
  2. WP-CLI Confirmation: Use WP-CLI to verify the file being targeted exists:
    ls -la /etc/passwd
    
  3. Logs: Check /var/log/apache2/error.log for include errors to confirm the path being attempted.

9. Alternative Approaches

  • Log Poisoning: If file uploads are restricted, try to include the Apache error log or access log after injecting PHP into the User-Agent header.
    • Path: ../../../../../../../../var/log/apache2/access.log
  • Wrapper Exploitation: Try using PHP wrappers if traversal is blocked:
    • php://filter/convert.base64-encode/resource=../../wp-config.php (To read sensitive configuration data).
  • Default Templates: Check if the plugin allows specifying templates via post meta. If so, an admin might be able to trigger LFI by modifying a post's metadata and then viewing that post.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Easy Invoice plugin for WordPress is vulnerable to Local File Inclusion in versions up to and including 2.1.4. This vulnerability allows authenticated administrators to include arbitrary files from the server, potentially leading to sensitive data exposure or remote code execution if the attacker can point the inclusion to an uploaded file containing PHP code.

Vulnerable Code

// File: easy-invoice/includes/admin/preview.php (Inferred)

$template = $_GET['template'];
if (isset($template)) {
    include( EASY_INVOICE_PATH . 'templates/' . $template . '.php' );
}

Security Fix

--- easy-invoice/includes/admin/preview.php
+++ easy-invoice/includes/admin/preview.php
@@ -1,5 +1,6 @@
-$template = $_GET['template'];
+$template = isset($_GET['template']) ? basename(sanitize_text_field($_GET['template'])) : '';
 if (isset($template)) {
-    include( EASY_INVOICE_PATH . 'templates/' . $template . '.php' );
+    $template_file = EASY_INVOICE_PATH . 'templates/' . $template . '.php';
+    if (file_exists($template_file)) {
+        include( $template_file );
+    }
 }

Exploit Outline

An attacker with Administrator privileges identifies a plugin page that renders invoice previews or allows template selection (e.g., /wp-admin/admin.php?page=easy-invoice-preview). By manipulating the 'template' or 'layout' parameter with directory traversal sequences such as '../../../../../../etc/passwd', the attacker can force the server to include and output the contents of sensitive local files. If the attacker first uploads a 'safe' file containing PHP code (like an image file), they can execute that code by traversing to the upload directory and including the malicious file.

Check if your site is affected.

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