CVE-2025-69411

ionCube Tester Plus <= 1.3 - Unauthenticated Arbitrary File Download

criticalImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
9.1
CVSS Score
9.1
CVSS Score
critical
Severity
1.4
Patched in
9d
Time to patch

Description

The ionCube Tester Plus plugin for WordPress is vulnerable to Path Traversal in all versions up to, and including, 1.3. This makes it possible for unauthenticated attackers to read the contents of arbitrary files on the server, which can contain sensitive information.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.3
PublishedMarch 4, 2026
Last updatedMarch 12, 2026
Affected pluginioncube-tester-plus

What Changed in the Fix

Changes introduced in v1.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-69411 (ionCube Tester Plus Path Traversal) ## 1. Vulnerability Summary The **ionCube Tester Plus** plugin (version <= 1.3) includes a standalone utility script `loader-wizard.php`. This script is intended to help users install ionCube loaders by generating con…

Show full research plan

Exploitation Research Plan: CVE-2025-69411 (ionCube Tester Plus Path Traversal)

1. Vulnerability Summary

The ionCube Tester Plus plugin (version <= 1.3) includes a standalone utility script loader-wizard.php. This script is intended to help users install ionCube loaders by generating configuration files (like php.ini) and offering them for download. However, the script is directly accessible, does not load the WordPress environment (and thus lacks WordPress security controls), and contains a path traversal vulnerability in its file-handling logic. An unauthenticated attacker can use traversal sequences (../) to download arbitrary files from the server, such as wp-config.php.

2. Attack Vector Analysis

  • Target File: wp-content/plugins/ioncube-tester-plus/loader-wizard.php
  • Vulnerable Parameters: file or download (inferred from common ionCube wizard vulnerabilities and the "Arbitrary File Download" description).
  • Authentication: None required (Unauthenticated).
  • Preconditions: The plugin must be installed. The web server must allow direct execution of PHP files within the wp-content/plugins/ directory.

3. Code Flow

  1. Entry Point: A direct HTTP GET request is made to loader-wizard.php.
  2. Initialization: The script defines various constants and immediately calls the run() function (Line 115 in loader-wizard.php).
  3. Execution Path:
    • The run() function (logic contained in the truncated portion of the source) processes global variables like $_GET.
    • It identifies an action (likely via a page or action parameter, or a direct download parameter).
    • When a download action is triggered, the script retrieves a file path from a user-provided parameter (e.g., $_GET['file']).
    • Vulnerable Sink: The script passes this unsanitized path directly to a file-reading function such as readfile(), file_get_contents(), or include().
    • Because the script is standalone and does not call wp-load.php, no WordPress nonces or capability checks (current_user_can) are performed.

4. Nonce Acquisition Strategy

No nonce is required.
The script loader-wizard.php is a standalone "wizard" designed to run even if the WordPress environment is not fully functional (e.g., during loader installation). It does not include wp-load.php or wp-config.php, meaning WordPress-specific functions like wp_create_nonce() and wp_verify_nonce() are unavailable and not used.

5. Exploitation Strategy

The goal is to read the wp-config.php file located at the WordPress root.

Step 1: Discover the Vulnerable Parameter

Since the source for the run() function logic is truncated, the agent must test the two most likely traversal patterns used in ionCube wizard scripts.

Step 2: Test Pattern A (Direct Parameter)

Request:

GET /wp-content/plugins/ioncube-tester-plus/loader-wizard.php?download=../../../../wp-config.php HTTP/1.1
Host: [TARGET_HOST]

Step 3: Test Pattern B (Action/Page Pattern)

Request:

GET /wp-content/plugins/ioncube-tester-plus/loader-wizard.php?page=download&file=../../../../wp-config.php HTTP/1.1
Host: [TARGET_HOST]

Step 4: Analysis of Response

  • A successful exploit will return the raw contents of wp-config.php.
  • Look for DB_NAME, DB_USER, DB_PASSWORD, and AUTH_KEY in the response body.

6. Test Data Setup

  1. Install the ioncube-tester-plus plugin (version 1.3) in the test environment.
  2. Ensure the plugin directory is ioncube-tester-plus.
  3. Verify that wp-config.php exists in the standard location (ABSPATH).

7. Expected Results

  • Success: The HTTP response contains the PHP source code of wp-config.php. The Content-Type header may be application/octet-stream or text/html depending on the exact sink implementation.
  • Failure: The response is a 404 (file not found), 403 (forbidden by server config), or the wizard's default HTML interface without the file content.

8. Verification Steps

After the HTTP request, verify the content retrieved:

  1. Use http_request to fetch the file.
  2. Check the response body for the string: define( 'DB_NAME'.
  3. (Optional) Use wp-cli to verify the actual database name matches the one found in the downloaded file:
    wp config get DB_NAME --allow-root
    

9. Alternative Approaches

If the patterns above fail, try:

  1. LFI via page: ?page=../../../../wp-config.php (sometimes wizards use include for templating).
  2. Log Download: Check if the wizard has a log viewing feature (e.g., ?page=log&file=...).
  3. Double Encoding: If a basic filter exists, try %2e%2e%2f instead of ../.
  4. Different Root Depth: If the site is installed in a subdirectory, adjust the traversal depth (e.g., ../../../../../wp-config.php).
Research Findings
Static analysis — not yet PoC-verified

Summary

The ionCube Tester Plus plugin includes a standalone script `loader-wizard.php` that is accessible without authentication and outside the WordPress security context. It fails to sanitize the 'ininame' parameter during file download operations, allowing unauthenticated attackers to use path traversal sequences to download arbitrary sensitive files from the server, such as 'wp-config.php'.

Vulnerable Code

// loader-wizard.php line 3243 in version 1.3
    $download = get_request_parameter('download');
    $ini_file_name = '';
    if (!empty($download)) {
        $ini_file_name = get_request_parameter('ininame');
        if (empty($ini_file_name)) {
            $ini_file_name = ini_file_name();
        }
    }

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/ioncube-tester-plus/1.3/loader-wizard.php /home/deploy/wp-safety.org/data/plugin-versions/ioncube-tester-plus/1.4/loader-wizard.php
--- /home/deploy/wp-safety.org/data/plugin-versions/ioncube-tester-plus/1.3/loader-wizard.php	2013-05-30 06:39:12.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/ioncube-tester-plus/1.4/loader-wizard.php	2026-01-06 15:24:30.000000000 +0000
@@ -1,5 +1,19 @@
 <?php // -*- c++ -*-
 
+// --- BEGIN SECURITY PATCH ---
+// Load WordPress environment to check authentication
+$wp_load = dirname(dirname(dirname(dirname(__FILE__)))) . '/wp-load.php';
+if ( file_exists( $wp_load ) ) {
+    require_once( $wp_load );
+}
+
+// Block access if not a logged-in Administrator
+if ( ! defined( 'ABSPATH' ) || ! current_user_can( 'manage_options' ) ) {
+    header( 'HTTP/1.0 403 Forbidden' );
+    die( 'Access Denied: You must be a logged-in Administrator to use this tool.' );
+}
+// --- END SECURITY PATCH ---
+
 /** 
  * ionCube Loader install Wizard
  *
@@ -3229,7 +3243,8 @@
     $download = get_request_parameter('download');
     $ini_file_name = '';
     if (!empty($download)) {
-        $ini_file_name = get_request_parameter('ininame');
+        // Security Fix: basename() prevents path traversal attacks (e.g. ../../)
+		$ini_file_name = basename( get_request_parameter('ininame') );
         if (empty($ini_file_name)) {
             $ini_file_name = ini_file_name();
         }

Exploit Outline

The exploit targets the standalone `loader-wizard.php` script located in the plugin directory. 1. Target Endpoint: `/wp-content/plugins/ioncube-tester-plus/loader-wizard.php` 2. Required Parameters: - `download`: Any non-empty value to trigger the download logic. - `ininame`: A path traversal payload (e.g., `../../../../wp-config.php`) pointing to the desired file relative to the plugin directory. 3. Authentication: None required. The script does not initialize the WordPress environment and lacks any capabilities checks in the vulnerable version. 4. Execution: The attacker makes a GET request with these parameters, and the server responds with the raw contents of the file specified in the `ininame` parameter.

Check if your site is affected.

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