import rex powershell

bug/bundler_fix
RageLtMan 2014-02-12 16:45:57 -05:00
parent b453362a52
commit 29bf296b61
1 changed files with 93 additions and 31 deletions

View File

@ -30,11 +30,36 @@ module Powershell
end
#
# Return a Base64 encoded powershell code
# Return a zlib compressed powershell code
#
def encode_code(eof = nil)
def deflate_code(eof = nil)
# Compress using the Deflate algorithm
compressed_stream = ::Zlib::Deflate.deflate(code,
::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 code output
#if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end
psh_expression << "echo '#{eof}';" if eof
# Convert expression to unicode
unicode_expression = Rex::Text.to_unicode(code)
unicode_expression = Rex::Text.to_unicode(psh_expression)
# Base64 encode the unicode expression
@code = Rex::Text.encode_base64(unicode_expression)
@ -42,10 +67,11 @@ module Powershell
return code
end
#
# Return a zlib compressed powershell code
# Return a gzip compressed powershell code
#
def compress_code(eof = nil)
def gzip_code(eof = nil)
# Compress using the Deflate algorithm
compressed_stream = Rex::Text.gzip(code)
@ -54,30 +80,51 @@ module Powershell
# Build the powershell expression
# Decode base64 encoded command and create a stream object
psh_expression = "IEX(New-Object IO.StreamReader("
psh_expression << "(New-Object IO.Compression.GzipStream("
psh_expression << "(New-Object IO.MemoryStream(,[Convert]::FromBase64String('#{encoded_stream}'))),"
psh_expression = "$stream = New-Object IO.MemoryStream(,"
psh_expression << "$([Convert]::FromBase64String('#{encoded_stream}')));"
# Uncompress and invoke the expression (execute)
psh_expression << "$(Invoke-Expression $(New-Object IO.StreamReader("
psh_expression << "$(New-Object IO.Compression.GzipStream("
psh_expression << "$stream,"
psh_expression << "[IO.Compression.CompressionMode]::Decompress)),"
psh_expression << "[Text.Encoding]::ASCII)).ReadToEnd();"
psh_expression << "[Text.Encoding]::ASCII)).ReadToEnd());"
# If eof is set, add a marker to signify end of code output
#if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end
psh_expression << "echo '#{eof}';" if eof
@code = psh_expression
# Convert expression to unicode
unicode_expression = Rex::Text.to_unicode(psh_expression)
return psh_expression
# Base64 encode the unicode expression
@code = Rex::Text.encode_base64(unicode_expression)
return code
end
#
# Compresses script contents with gzip or deflate
#
def compress_code(eof = nil, gzip = true, in_place = true)
code = gzip ? gzip_code(eof) : deflate_code(eof)
@code = code if in_place
return code
end
#
# Reverse the compression process
# Try gzip, inflate if that fails
#
def decompress_code
# Decode base64 and convert to ascii
raw = Rex::Text.decode_base64(code)
ascii_expression = Rex::Text.to_ascii(raw)
# Extract substring with payload
encoded_stream = ascii_expression.scan(/FromBase64String\('(.*)'/).flatten.first
# Decode and decompress the string
return Rex::Text.ungzip( Rex::Text.decode_base64(encoded_stream) )
# ::Zlib::Inflate.inflate( Rex::Text.decode_base64(encoded_stream) )
@code = ( Rex::Text.ungzip( Rex::Text.decode_base64(encoded_stream) ) ||
Rex::Text.zlib_inflate( Rex::Text.decode_base64(encoded_stream)) )
return code
end
end
@ -144,6 +191,7 @@ module Powershell
'$WhatIfPreference'
].map(&:downcase)
# return code.scan(/\$[a-zA-Z\-\_]+/).uniq.flatten - res_vars
our_vars = code.scan(/\$[a-zA-Z\-\_]+/).uniq.flatten.map(&:strip)
return our_vars.select {|v| !res_vars.include?(v)}
@ -243,7 +291,17 @@ module Powershell
# Multi line
code.gsub!(/<#(.*?)#>/m,'')
# Single line
code.gsub!(/^#.*$|^\s+#.*$/,'')
code.gsub!(/^\s*#(?!.*region)(.*$)/i,'')
end
#
# Remove empty lines
#
def strip_empty_lines
# Windows EOL
code.gsub!(/[\r\n]+/,"\r\n")
# UNIX EOL
code.gsub!(/[\n]+/,"\n")
end
#
@ -254,7 +312,6 @@ module Powershell
code.gsub!(/\s+/,' ')
end
#
# Identify variables and replace them
#
@ -349,7 +406,21 @@ module Powershell
# Pretend we are actually a string
extend Forwardable
# In case someone messes with String we delegate based on its instance methods
eval %Q|def_delegators :@code, :#{::String.instance_methods[0..(String.instance_methods.index(:class)-1)].join(', :')}|
#eval %Q|def_delegators :@code, :#{::String.instance_methods[0..(String.instance_methods.index(:class)-1)].join(', :')}|
def_delegators :@code, :each_line, :strip, :chars, :intern, :chr, :casecmp, :ascii_only?, :<, :tr_s,
:!=, :capitalize!, :ljust, :to_r, :sum, :private_methods, :gsub,:dump, :match, :to_sym,
:enum_for, :display, :tr_s!, :freeze, :gsub, :split, :rindex, :<<, :<=>, :+, :lstrip!,
:encoding, :start_with?, :swapcase, :lstrip!, :encoding, :start_with?, :swapcase,
:each_byte, :lstrip, :codepoints, :insert, :getbyte, :swapcase!, :delete, :rjust, :>=,
:!, :count, :slice, :clone, :chop!, :prepend, :succ!, :upcase, :include?, :frozen?,
:delete!, :chop, :lines, :replace, :next, :=~, :==, :rstrip!, :%, :upcase!, :each_char,
:hash, :rstrip, :length, :reverse, :setbyte, :bytesize, :squeeze, :>, :center, :[],
:<=, :to_c, :slice!, :chomp!, :next!, :downcase, :unpack, :crypt, :partition,
:between?, :squeeze!, :to_s, :chomp, :bytes, :clear, :!~, :to_i, :valid_encoding?, :===,
:tr, :downcase!, :scan, :sub!, :each_codepoint, :reverse!, :class, :size, :empty?, :byteslice,
:initialize_clone, :to_str, :to_enum,:tap, :tr!, :trust, :encode!, :sub, :oct, :succ, :index,
:[]=, :encode, :*, :hex, :to_f, :strip!, :rpartition, :ord, :capitalize, :upto, :force_encoding,
:end_with?
# def method_missing(meth, *args, &block)
# code.send(meth,*args,&block) || (raise NoMethodError.new, meth)
@ -379,12 +450,11 @@ module Powershell
##
#
# Convert binary to byte array, read from file if able
# Build a byte array to load into powershell code
#
def self.to_byte_array(input_data,var_name="buf")
return "[Byte[]]$#{name} = ''" if input_data.nil? or input_data.empty?
code = input_data.unpack('C*')
def self.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|
@ -394,16 +464,7 @@ module Powershell
lines.push ",0x#{code[byte].to_s(16)}"
end
end
return psh << lines.join("") + "\r\n"
end
#
# Build a byte array to load into powershell code
#
def self.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
return to_byte_array(input_data,var_name)
psh << lines.join("") + "\r\n"
end
def self.psp_funcs(dir)
@ -423,3 +484,4 @@ module Powershell
end
end
end