# -*- coding: binary -*- module Msf module Exploit::Remote::VIMSoap include Msf::Exploit::Remote::HttpClient def vim_soap_envelope(body) soap_data = '' soap_data << '' soap_data << body soap_data << '' end def vim_soap_propset(type,path,all = false) soap_data = '' soap_data << '' + type + '' if all soap_data << 'true' else soap_data << '' + path + '' end soap_data << '' end def vim_soap_objset(type, ref) soap_data = '' soap_data << '' + ref + '' soap_data << '' end def vim_soap_specset(path,type,ref,all=false) soap_data = '' soap_data << vim_soap_propset(type,path,all) soap_data << vim_soap_objset(type,ref) soap_data << '' end def vim_soap_retrieve_properties(path,type,ref,all=false) soap_data = '' soap_data << '<_this type="PropertyCollector">' + @server_objects['propertyCollector'] + '' soap_data << vim_soap_specset(path,type,ref,all) soap_data << '' end def vim_soap_retrieve_service_content soap_data = '' soap_data << '<_this type="ServiceInstance">ServiceInstance' soap_data << '' end def vim_soap_login(user,pass) soap_data = '' soap_data << '<_this type="SessionManager">' + @server_objects['sessionManager'] + '' soap_data << '' + user + '' soap_data << '' + pass + '' soap_data << '' end def vim_soap_session_active?(key, user) soap_data = '' soap_data << '<_this type="SessionManager">' + @server_objects['sessionManager'] + '' soap_data << '' + key+ '' soap_data << '' + user + '' soap_data << '' end def vim_soap_terminate_session(key) soap_data = '' soap_data << '<_this xsi:type="ManagedObjectReference" type="SessionManager" >' + @server_objects['sessionManager'] + '' soap_data << '' + key + '' soap_data << '' end def vim_soap_retrieve_usergroups(domain=nil) soap_data = '' soap_data << '<_this xsi:type="ManagedObjectReference" type="UserDirectory">' + @server_objects['userDirectory'] + '' soap_data << '' + domain + '' if domain soap_data << 'falsetruetrue' soap_data << '' end def vim_soap_log_user_event_vm(vm_ref,msg) soap_data = '' soap_data << '<_this type="EventManager">' + @server_objects['eventManager'] + '' soap_data << '' + vm_ref + '' soap_data << '' + msg + '' soap_data << '' end def vim_soap_retrieve_all_permissions soap_data = '' soap_data << '<_this type="AuthorizationManager">' + @server_objects['authorizationManager'] + '' soap_data << '' end def vim_soap_find_child_byname(type,entity,name) soap_data = '' soap_data << '<_this type="SearchIndex">' + @server_objects['searchIndex'] + '' soap_data << '' + entity + '' soap_data << '' + name + '' soap_data << '' end def vim_soap_power_on_vm(vm_ref) soap_data = '' soap_data << '<_this type="VirtualMachine">' + vm_ref + '' soap_data << '' end def vim_soap_power_off_vm(vm_ref) soap_data = '' soap_data << '<_this type="VirtualMachine">' + vm_ref + '' soap_data << '' end def vim_soap_create_screenshot(vm_ref) soap_data = '' soap_data << '<_this type="VirtualMachine">' + vm_ref + '' soap_data << '' 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? "" @vim_soap_error = res.body.match(/([^\c ]+?)<\/faultstring>/)[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