Abstract
During a black-box penetration test, an instance of EzGED3 (1) is discovered exposed to the internet. The application reveals critical security weaknesses that allow full admin compromise without prior authentication (CVE-2025-51539). Directory listing is enabled on a publicly accessible folder, revealing files that disclose internal implementation details. One of these files points to a PHP script that permits arbitrary file reading due to missing access controls and lack of input validation.
Sensitive files, including database credentials, become accessible. This access leads to privilege escalation scenarios where user data, admin reset tokens, and weak password hashes are retrieved (CVE-2025-51540).
Vulnerable version < 3.5.72.27183

Write-up
1. Initial discovery : Directory Listing
During the initial reconnaissance phase, the application reveals that directory listing is enabled on the /data/
path. Accessing https://<target>/data/
returns a raw index of files and subdirectories hosted in that location. Among the listed files are several .html
and .php
files.

One particular HTML file (ezOpenFile
.html
) includes embedded PHP code that is not executed by the server. As a result, the raw source is displayed in the browser, exposing internal logic and a particularly interesting line :
<a class="MenuItem" href="showparaphdocs.php?download=0&path='.$path.'">[Cliquez ici pour afficher le document]</a>
The showparaphdocs.php file can be used to view (download=0) or download (download=1) other files.
2. Authentication bypass
The next step is to try reading the same PHP file found in the directory listing, since it’s confirmed to exist and might reveal how the script works. Looking at the code, no authentication is enforced.

The script checks if sessionid
or token
are set, but since they are not, the condition fails silently and the rest of the code runs anyway.
if(isset($_REQUEST["token"],$_REQUEST["sessionid"])) {
if($_REQUEST["token"] == "<redacted>") {
$sessionid = $_REQUEST["sessionid"];
$params = Authentication::authenticate(array("sessionid" => $sessionid));
if(!$params) {
die("Requested authentication by session failed.");
}
}
}
This only runs if both token
and sessionid
are provided in the request. If either parameter is missing, the entire block is skipped, including the authentication logic.
In the code, the value of the path
parameter is used directly in a call to @readfile($path)
without any sanitization or restriction. This function instructs PHP to read the file specified by $path
from the server’s filesystem and output its contents directly to the HTTP response. Because there is no validation of the file path, it becomes possible to perform path traversal attacks, such as supplying ../../../../etc/passwd
or pointing to application files like config.php
, database dumps, or other sensitive resources.
Because the software can run on either Windows or Linux servers, it will depends on the context.
To extract the entire source code of the folder, we can use the following one liner :
for i in $(cat files.txt); do
curl -k -s "https://<ip>/data/showparaphdocs.php?download=0&path=$i" > $i;
done
3. Database access
While analyzing the contents of the files, a reference is found pointing to a local configuration file:
nchp/etc/nchp/ezged/instance.conf
This file contains sensitive database configuration, including:
Some server have a phpMyAdmin interface exposed on the target system, and these credentials can be used to log in directly as the root user, giving access to all user data, including hashed passwords stored in internal tables.
Neat Trick: Reading MySQL Data Files Directly
With the following information:
-
Arbitrary file read capability
-
Known location of the MySQL data directory
-
Known name of the database
…it becomes possible to read the raw storage files used by MySQL to persist table data.
MySQL stores its data (depending on configuration) in the following structure:
mysql/data/<database_name>/<table_name>.<extension>
Relevant file extensions include .ibd
, .frm
, .myd
, .opt
, .sql
, and .cnf
.
In this case, the table responsible for storing users and password hashes is named _secusr
, and in InnoDB storage format, this table maps to:
mysql/data/<database_name>/_secusr.ibd
By retrieving this file via the arbitrary file read, a raw dump of the user table is obtained:

The raw content of the file is sufficient to extract user credentials. Passwords in EzGED3 are stored using the weak construct md5(md5(password))
, which provides very little protection against offline cracking.
However, in this case, brute-forcing the hashes is not even necessary to achieve full administrative access.
The application provides a password reset mechanism. Tokens used for password recovery are stored in the same file.
Once a valid reset token is retrieved, it becomes possible to initiate a password reset without knowing the original password or having access to the admin’s email address.
This bypass allows full administrative takeover of the system, purely through file reads, with no need for brute-force or privilege escalation via code execution.
Timeline
- 2024-11-14 - Discovery of the vulnerability
- 2024-11-15 - Report of the vulnerability to the editor
- 2024-12-05 - EZDEV validates the report
- 2025-02-17 - Follow-up
- 2025-05-16 - CVE declaration
- 2025-08-13 - Article released
Resources
- (1) https://www.ezged.org