lib/msf/core/exploit/remote/vim_soap.rb
# -*- coding: binary -*-
module Msf
module Exploit::Remote::VIMSoap
include Msf::Exploit::Remote::HttpClient
def vim_soap_envelope(body)
soap_data = '<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">'
soap_data << '<env:Body>'
soap_data << body
soap_data << '</env:Body></env:Envelope>'
end
def vim_soap_propset(type,path,all = false)
soap_data = '<propSet xsi:type="PropertySpec">'
soap_data << '<type>' + type + '</type>'
if all
soap_data << '<all>true</all>'
else
soap_data << '<pathSet>' + path + '</pathSet>'
end
soap_data << '</propSet>'
end
def vim_soap_objset(type, ref)
soap_data = '<objectSet>'
soap_data << '<obj type="' + type + '">' + ref + '</obj>'
soap_data << '</objectSet>'
end
def vim_soap_specset(path,type,ref,all=false)
soap_data = '<specSet>'
soap_data << vim_soap_propset(type,path,all)
soap_data << vim_soap_objset(type,ref)
soap_data << '</specSet>'
end
def vim_soap_retrieve_properties(path,type,ref,all=false)
soap_data = '<RetrieveProperties xmlns="urn:vim25">'
soap_data << '<_this type="PropertyCollector">' + @server_objects['propertyCollector'] + '</_this>'
soap_data << vim_soap_specset(path,type,ref,all)
soap_data << '</RetrieveProperties>'
end
def vim_soap_retrieve_service_content
soap_data = '<RetrieveServiceContent xmlns="urn:vim25">'
soap_data << '<_this type="ServiceInstance">ServiceInstance</_this>'
soap_data << '</RetrieveServiceContent>'
end
def vim_soap_login(user,pass)
soap_data = '<Login xmlns="urn:vim25">'
soap_data << '<_this type="SessionManager">' + @server_objects['sessionManager'] + '</_this>'
soap_data << '<userName>' + user + '</userName>'
soap_data << '<password>' + pass + '</password>'
soap_data << '</Login>'
end
def vim_soap_session_active?(key, user)
soap_data = '<SessionIsActive xmlns="urn:vim25">'
soap_data << '<_this type="SessionManager">' + @server_objects['sessionManager'] + '</_this>'
soap_data << '<sessionID>' + key+ '</sessionID>'
soap_data << '<userName>' + user + '</userName>'
soap_data << '</SessionIsActive>'
end
def vim_soap_terminate_session(key)
soap_data = '<TerminateSession xmlns="urn:vim25">'
soap_data << '<_this xsi:type="ManagedObjectReference" type="SessionManager" >' + @server_objects['sessionManager'] + '</_this>'
soap_data << '<sessionId>' + key + '</sessionId>'
soap_data << '</TerminateSession>'
end
def vim_soap_retrieve_usergroups(domain=nil)
soap_data = '<RetrieveUserGroups xmlns="urn:internalvim25">'
soap_data << '<_this xsi:type="ManagedObjectReference" type="UserDirectory">' + @server_objects['userDirectory'] + '</_this>'
soap_data << '<domain>' + domain + '</domain>' if domain
soap_data << '<searchStr></searchStr><exactMatch>false</exactMatch><findUsers>true</findUsers><findGroups>true</findGroups>'
soap_data << '</RetrieveUserGroups>'
end
def vim_soap_log_user_event_vm(vm_ref,msg)
soap_data = '<LogUserEvent xmlns="urn:vim25">'
soap_data << '<_this type="EventManager">' + @server_objects['eventManager'] + '</_this>'
soap_data << '<entity type="VirtualMachine">' + vm_ref + '</entity>'
soap_data << '<msg>' + msg + '</msg>'
soap_data << '</LogUserEvent>'
end
def vim_soap_retrieve_all_permissions
soap_data = '<RetrieveAllPermissions xmlns="urn:vim25">'
soap_data << '<_this type="AuthorizationManager">' + @server_objects['authorizationManager'] + '</_this>'
soap_data << '</RetrieveAllPermissions>'
end
def vim_soap_find_child_byname(type,entity,name)
soap_data = '<FindChild xmlns="urn:vim25">'
soap_data << '<_this type="SearchIndex">' + @server_objects['searchIndex'] + '</_this>'
soap_data << '<entity type="' + type + '">' + entity + '</entity>'
soap_data << '<name>' + name + '</name>'
soap_data << '</FindChild>'
end
def vim_soap_power_on_vm(vm_ref)
soap_data = '<PowerOnVM_Task xmlns="urn:vim25">'
soap_data << '<_this type="VirtualMachine">' + vm_ref + '</_this>'
soap_data << '</PowerOnVM_Task>'
end
def vim_soap_power_off_vm(vm_ref)
soap_data = '<PowerOffVM_Task xmlns="urn:vim25">'
soap_data << '<_this type="VirtualMachine">' + vm_ref + '</_this>'
soap_data << '</PowerOffVM_Task>'
end
def vim_soap_create_screenshot(vm_ref)
soap_data = '<CreateScreenshot_Task xmlns="urn:vim25">'
soap_data << '<_this type="VirtualMachine">' + vm_ref + '</_this>'
soap_data << '</CreateScreenshot_Task>'
end
def vim_send_soap_request(soap_data)
res = send_request_cgi({
'uri' => '/sdk',
'method' => 'POST',
'agent' => 'VMware VI Client',
'cookie' => @vim_cookie,
'data' => soap_data,
'headers' => { 'SOAPAction' => @soap_action}
}, 25)
return :noresponse unless res
if res.body.include? "NotAuthenticatedFault"
return :expired
elsif res.body.include? "<faultstring>"
@vim_soap_error = res.body.match(/<faultstring>(.+?)<\/faultstring>/m)[1]
return :error
elsif res.code != 200
@vim_soap_error = "An unknown error was encountered"
return :error
else
return Hash.from_xml(res.body)['Envelope']['Body']
end
end
def vim_get_session
soap_data = vim_soap_envelope(vim_soap_retrieve_service_content)
res = send_request_cgi({
'uri' => '/sdk',
'method' => 'POST',
'agent' => 'VMware VI Client',
'data' => soap_data,
'headers' => { 'SOAPAction' => @soap_action}
}, 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']
@vim_cookie = res.headers['Set-Cookie']
return true
else
return false
end
end
def vim_do_login(user, pass)
unless vim_get_session
return false
end
soap_data = vim_soap_envelope(vim_soap_login(user,pass))
res = send_request_cgi({
'uri' => '/sdk',
'method' => 'POST',
'agent' => 'VMware VI Client',
'cookie' => @vim_cookie,
'data' => soap_data,
'headers' => { 'SOAPAction' => @soap_action}
}, 25)
if res.code == 200
return :success
else
return :fail
end
end
def vim_get_session_list
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('sessionList','SessionManager', @server_objects['sessionManager']))
res = vim_send_soap_request(soap_data)
if res.class == Hash
session_list = []
session_list << res['RetrievePropertiesResponse']['returnval']['propSet']['val']['UserSession']
return session_list.flatten.compact
else
return res
end
end
def vim_session_is_active(key, username)
soap_data = vim_soap_envelope(vim_soap_session_active?(key,username))
res = vim_send_soap_request(soap_data)
print_status "Error: #{@vim_soap_error}"
if res.class == Hash
active = res['SessionIsActiveResponse']['returnval']
return active
else
return res
end
end
def vim_terminate_session(key)
soap_data = vim_soap_envelope(vim_soap_terminate_session(key))
res = vim_send_soap_request(soap_data)
if res.class == Hash
return :success
else
return res
end
end
def vim_get_domains
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('domainList', 'UserDirectory', @server_objects['userDirectory']))
res = vim_send_soap_request(soap_data)
if res.class == Hash
domains = []
domains << res['RetrievePropertiesResponse']['returnval']['propSet']['val']['string']
return domains.flatten.compact
else
return res
end
end
def vim_get_user_list(domain=nil)
soap_data = vim_soap_envelope(vim_soap_retrieve_usergroups(domain))
res = vim_send_soap_request(soap_data)
if res.class == Hash
return nil unless res['RetrieveUserGroupsResponse']['returnval']
user_list = []
user_list << res['RetrieveUserGroupsResponse']['returnval']
return user_list.flatten.compact
else
return res
end
end
def vim_log_event_vm(vm_ref, msg)
soap_data = vim_soap_envelope(vim_soap_log_user_event_vm(vm_ref,msg))
res = vim_send_soap_request(soap_data)
if res.class == Hash
return :success
else
return res
end
end
def vim_get_all_permissions
soap_data = vim_soap_envelope(vim_soap_retrieve_all_permissions)
res = vim_send_soap_request(soap_data)
if res.class == Hash
permissions = []
permissions << res['RetrieveAllPermissionsResponse']['returnval']
return permissions.flatten.compact
else
return res
end
end
def vim_get_roles
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('roleList', 'AuthorizationManager', @server_objects['authorizationManager']))
res = vim_send_soap_request(soap_data)
if res.class == Hash
roles = []
roles << res['RetrievePropertiesResponse']['returnval']['propSet']['val']['AuthorizationRole']
return roles.flatten.compact
else
return res
end
end
def vim_get_dc_name(dc)
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('name','Datacenter',dc))
res = vim_send_soap_request(soap_data)
if res.class == Hash
return res['RetrievePropertiesResponse']['returnval']['propSet']['val']
else
return res
end
end
def vim_get_dcs
soap_data = vim_soap_envelope(vim_soap_retrieve_service_content)
res = vim_send_soap_request(soap_data)
if res.class == Hash
@server_objects.merge!(res['RetrieveServiceContentResponse']['returnval'])
else
return res
end
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('content', 'ServiceInstance', 'ServiceInstance'))
res = vim_send_soap_request(soap_data)
if res.class == Hash
hash = res['RetrievePropertiesResponse']['returnval']['propSet']['val']
hash.delete('xsi:type')
@server_objects.merge!(hash)
else
return res
end
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('childEntity', 'Folder', @server_objects['rootFolder']))
res = vim_send_soap_request(soap_data)
if res.class == Hash
tmp_dcs = []
tmp_dcs << res['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
tmp_dcs.flatten!
tmp_dcs.each{|dc| @dcs << { 'name' => vim_get_dc_name(dc) , 'ref' => dc}}
else
return res
end
end
def vim_get_hosts(datacenter)
dc_hosts = []
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('hostFolder', 'Datacenter' , datacenter))
res = vim_send_soap_request(soap_data)
if res.class == Hash
host_folders = []
host_folders << res['RetrievePropertiesResponse']['returnval']['propSet']['val']
host_folders.flatten!
else
return res
end
compute_refs = []
host_folders.each do |folder|
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('childEntity', 'Folder' , folder))
res = vim_send_soap_request(soap_data)
if res.class == Hash
ref = res['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
unless ref.nil?
compute_refs << ref
end
else
return res
end
end
compute_refs.flatten!
compute_refs.each do |ref|
next if ref.start_with? "group-"
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('host', 'ComputeResource' , ref))
res = vim_send_soap_request(soap_data)
if res.class == Hash
dc_hosts << res['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
else
return res
end
end
dc_hosts.flatten!
return dc_hosts
end
def vim_get_all_hosts
@dcs.each{|dc| @hosts << vim_get_hosts(dc['ref'])}
@hosts.flatten!
end
def vim_get_host_hw(host)
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('hardware', 'HostSystem' , host))
res = vim_send_soap_request(soap_data)
if res.class == Hash
return res['RetrievePropertiesResponse']['returnval']['propSet']['val']
else
return res
end
end
def vim_get_all_host_summary(hw=false)
vim_setup_references
summaries = []
@hosts.each do |host|
details = {}
details[host] = vim_get_host_summary(host)
if details and hw
details.merge!(vim_get_host_hw(host))
end
summaries << details
end
return summaries.flatten.compact
end
def vim_get_vm_datastore(vm)
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('datastore', 'VirtualMachine' , vm))
res = vim_send_soap_request(soap_data)
if res.class == Hash
datastore_refs = []
datastore_refs << res['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
datastore_refs.flatten!
datastore_refs.compact!
datastores = []
else
return res
end
datastore_refs.each do |datastore_ref|
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('info', 'Datastore' , datastore_ref))
res = vim_send_soap_request(soap_data)
if res.class == Hash
datastore_name = res['RetrievePropertiesResponse']['returnval']['propSet']['val']['name']
datastore = { 'name' => datastore_name, 'ref' => datastore_ref}
datastores << datastore
else
return res
end
end
return datastores
end
def vim_find_vm_by_name(name)
vim_setup_references
@dcs.each do |dc|
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('vmFolder', 'Datacenter' , dc['ref']))
res = vim_send_soap_request(soap_data)
if res.class == Hash
vm_folders = []
vm_folders << res['RetrievePropertiesResponse']['returnval']['propSet']['val']
vm_folders.flatten!
vm_folders.compact!
else
return res
end
vm_folders.each do |vm_folder|
soap_data = vim_soap_envelope(vim_soap_find_child_byname('Folder', vm_folder, name))
res = vim_send_soap_request(soap_data)
if res.class == Hash
vmref = res['FindChildResponse']['returnval']
if vmref
return vmref
else
next
end
else
return res
end
end
end
return nil
end
def vim_powerON_vm(vm_ref)
soap_data = vim_soap_envelope(vim_soap_power_on_vm(vm_ref))
res = vim_send_soap_request(soap_data)
if res.class == Hash
task_id = res['PowerOnVM_TaskResponse']['returnval']
else
return res
end
state= "running"
while state == "running"
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('info', 'Task', task_id))
res = vim_send_soap_request(soap_data)
if res.class == Hash
state = res['RetrievePropertiesResponse']['returnval']['propSet']['val']['state']
case state
when 'running'
select(nil, nil, nil, 5)
when 'error'
if res['RetrievePropertiesResponse']['returnval']['propSet']['val']['error']['fault']['existingState'] == 'poweredOn'
return 'alreadyON'
end
end
else
return res
end
end
return state
end
def vim_powerOFF_vm(vm_ref)
soap_data = vim_soap_envelope(vim_soap_power_off_vm(vm_ref))
res = vim_send_soap_request(soap_data)
if res.class == Hash
task_id = res['PowerOffVM_TaskResponse']['returnval']
else
return res
end
state= "running"
while state == "running"
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('info', 'Task', task_id))
res = vim_send_soap_request(soap_data)
if res.class == Hash
state = res['RetrievePropertiesResponse']['returnval']['propSet']['val']['state']
case state
when 'running'
select(nil, nil, nil, 5)
when 'error'
if res['RetrievePropertiesResponse']['returnval']['propSet']['val']['error']['fault']['existingState'] == 'poweredOn'
return 'alreadyON'
end
end
else
return res
end
end
return state
end
def vim_take_screenshot(vm, user, pass)
soap_data = vim_soap_envelope(vim_soap_create_screenshot(vm['ref']))
res = vim_send_soap_request(soap_data)
if res.class == Hash
task_id = res['CreateScreenshot_TaskResponse']['returnval']
else
return res
end
state= "running"
while state == "running"
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('info', 'Task', task_id))
res = vim_send_soap_request(soap_data)
if res.class == Hash
state = res['RetrievePropertiesResponse']['returnval']['propSet']['val']['state']
screenshot_file = res['RetrievePropertiesResponse']['returnval']['propSet']['val']['result']
else
return res
end
end
unless screenshot_file
return :error
end
(ss_folder, ss_file) = screenshot_file.split('/').last(2)
ss_folder = Rex::Text.uri_encode(ss_folder)
ss_file = Rex::Text.uri_encode(ss_file)
ss_path = "#{ss_folder}/#{ss_file}"
datastores = vim_get_vm_datastore(vm['ref'])
user_pass = Rex::Text.encode_base64(user + ":" + pass)
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
def vim_get_host_summary(host)
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('summary', 'HostSystem', host))
res = vim_send_soap_request(soap_data)
if res.class == Hash
hash = res['RetrievePropertiesResponse']['returnval']['propSet']['val']
hash['runtime'].delete('healthSystemRuntime')
hash.delete('xsi:type')
hash.delete('host')
return hash
else
return res
end
end
def vim_get_vms
vim_setup_references
@vmrefs = []
vmlist= []
@dcs.each do |dc|
dc_vm_refs = vim_get_dc_vms(dc['ref'])
next if dc_vm_refs.nil? or dc_vm_refs.empty?
dc_vm_refs.flatten!
dc_vm_refs.compact!
next if dc_vm_refs.nil? or dc_vm_refs.empty?
print_status "#{datastore['RHOST']} - DataCenter: #{dc['name']} Found a Total of #{dc_vm_refs.length} VMs"
print_status "#{datastore['RHOST']} - DataCenter: #{dc['name']} Estimated Time: #{((dc_vm_refs.length * 7) /60)} Minutes"
dc_vm_refs.each do |ref|
print_status "#{datastore['RHOST']} - DataCenter: #{dc['name']} - Getting Data for VM: #{ref}..."
details = vim_get_vm_info(ref)
if details
details['ref'] = ref
details['dc_ref'] = dc['ref']
details['dc_name'] = dc['name']
vmlist << details
end
end
end
return vmlist
end
def vim_get_dc_vms(datacenter)
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('vmFolder', 'Datacenter', datacenter))
res = vim_send_soap_request(soap_data)
if res.class == Hash
vmfolder = res['RetrievePropertiesResponse']['returnval']['propSet']['val']
else
return res
end
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('childEntity', 'Folder', vmfolder))
res = vim_send_soap_request(soap_data)
if res.class == Hash
vm_index_array = res['RetrievePropertiesResponse']['returnval']['propSet']['val']['ManagedObjectReference']
vm_index_array.delete_if{|ref| ref.start_with? "group"} unless vm_index_array.nil? or vm_index_array.empty? or vm_index_array.class != Array
return vm_index_array
else
return res
end
end
def vim_get_vm_info(vm_ref)
vim_setup_references
soap_data = vim_soap_envelope(vim_soap_retrieve_properties('summary', 'VirtualMachine', vm_ref))
res = vim_send_soap_request(soap_data)
if res.class == Hash
hash = res['RetrievePropertiesResponse']['returnval']['propSet']['val']
vm = hash['config']
vm['runtime'] = hash['runtime']
vm['guest'] = hash['guest']
vm['quickStats'] = hash['quickStats']
return vm
else
return res
end
end
def vim_logged_in?
return true if @vim_cookie
return false
end
def vim_instance_vars_set?
return false if @server_objects.nil? or @server_objects.empty?
return false if @host.nil? or @host.empty?
return true
end
def vim_setup_references
unless vim_instance_vars_set?
@dcs = []
@hosts = []
vim_get_dcs
vim_get_all_hosts
@hosts.flatten!
@hosts.compact!
end
end
end
end