More spec
parent
162b6a8ab9
commit
6ab85027a4
|
@ -1,6 +1,5 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
require 'zlib'
|
|
||||||
require 'rex/text'
|
require 'rex/text'
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
|
@ -13,21 +12,23 @@ module Powershell
|
||||||
#
|
#
|
||||||
# Create hash of string substitutions
|
# Create hash of string substitutions
|
||||||
#
|
#
|
||||||
|
# @param strings [Array] array of strings to generate unique names
|
||||||
|
#
|
||||||
|
# @return [Hash] map of strings with new unique names
|
||||||
def sub_map_generate(strings)
|
def sub_map_generate(strings)
|
||||||
map = {}
|
map = {}
|
||||||
strings.flatten.each do |str|
|
strings.flatten.each do |str|
|
||||||
map[str] = "$#{Rex::Text.rand_text_alpha(rand(2)+2)}"
|
@rig.init_var(str)
|
||||||
# Ensure our variables are unique
|
map[str] = @rig[str]
|
||||||
while not map.values.uniq == map.values
|
|
||||||
map[str] = "$#{Rex::Text.rand_text_alpha(rand(2)+2)}"
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return map
|
map
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Remove comments
|
# Remove comments
|
||||||
#
|
#
|
||||||
|
# @return [String] code without comments
|
||||||
def strip_comments
|
def strip_comments
|
||||||
# Multi line
|
# Multi line
|
||||||
code.gsub!(/<#(.*?)#>/m,'')
|
code.gsub!(/<#(.*?)#>/m,'')
|
||||||
|
@ -38,6 +39,7 @@ module Powershell
|
||||||
#
|
#
|
||||||
# Remove empty lines
|
# Remove empty lines
|
||||||
#
|
#
|
||||||
|
# @return [String] code without empty lines
|
||||||
def strip_empty_lines
|
def strip_empty_lines
|
||||||
# Windows EOL
|
# Windows EOL
|
||||||
code.gsub!(/[\r\n]+/,"\r\n")
|
code.gsub!(/[\r\n]+/,"\r\n")
|
||||||
|
@ -49,6 +51,7 @@ module Powershell
|
||||||
# Remove whitespace
|
# Remove whitespace
|
||||||
# This can break some codes using inline .NET
|
# This can break some codes using inline .NET
|
||||||
#
|
#
|
||||||
|
# @return [String] code with whitespace stripped
|
||||||
def strip_whitespace
|
def strip_whitespace
|
||||||
code.gsub!(/\s+/,' ')
|
code.gsub!(/\s+/,' ')
|
||||||
end
|
end
|
||||||
|
@ -56,6 +59,7 @@ module Powershell
|
||||||
#
|
#
|
||||||
# Identify variables and replace them
|
# Identify variables and replace them
|
||||||
#
|
#
|
||||||
|
# @return [String] code with variable names replaced with unique values
|
||||||
def sub_vars
|
def sub_vars
|
||||||
# Get list of variables, remove reserved
|
# Get list of variables, remove reserved
|
||||||
vars = get_var_names
|
vars = get_var_names
|
||||||
|
@ -68,6 +72,8 @@ module Powershell
|
||||||
#
|
#
|
||||||
# Identify function names and replace them
|
# Identify function names and replace them
|
||||||
#
|
#
|
||||||
|
# @return [String] code with function names replaced with unique
|
||||||
|
# values
|
||||||
def sub_funcs
|
def sub_funcs
|
||||||
# Find out function names, make map
|
# Find out function names, make map
|
||||||
# Sub map keys for values
|
# Sub map keys for values
|
||||||
|
@ -79,6 +85,7 @@ module Powershell
|
||||||
#
|
#
|
||||||
# Perform standard substitutions
|
# Perform standard substitutions
|
||||||
#
|
#
|
||||||
|
# @return [String] code with standard substitution methods applied
|
||||||
def standard_subs(subs = %w{strip_comments strip_whitespace sub_funcs sub_vars} )
|
def standard_subs(subs = %w{strip_comments strip_whitespace sub_funcs sub_vars} )
|
||||||
# Save us the trouble of breaking injected .NET and such
|
# Save us the trouble of breaking injected .NET and such
|
||||||
subs.delete('strip_whitespace') unless string_literals.empty?
|
subs.delete('strip_whitespace') unless string_literals.empty?
|
||||||
|
@ -87,7 +94,8 @@ module Powershell
|
||||||
self.send(modifier)
|
self.send(modifier)
|
||||||
end
|
end
|
||||||
code.gsub!(/^$|^\s+$/,'')
|
code.gsub!(/^$|^\s+$/,'')
|
||||||
return code
|
|
||||||
|
code
|
||||||
end
|
end
|
||||||
|
|
||||||
end # Obfu
|
end # Obfu
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
require 'zlib'
|
|
||||||
require 'rex/text'
|
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
module Exploitation
|
module Exploitation
|
||||||
|
|
||||||
|
@ -69,26 +66,35 @@ module Powershell
|
||||||
#
|
#
|
||||||
# Get variable names from code, removes reserved names from return
|
# Get variable names from code, removes reserved names from return
|
||||||
#
|
#
|
||||||
|
# @return [Array] variable names
|
||||||
def get_var_names
|
def get_var_names
|
||||||
our_vars = code.scan(/\$[a-zA-Z\-\_]+/).uniq.flatten.map(&:strip)
|
our_vars = code.scan(/\$[a-zA-Z\-\_0-9]+/).uniq.flatten.map(&:strip)
|
||||||
return our_vars.select {|v| !RESERVED_VARIABLE_NAMES.include?(v.downcase)}
|
our_vars.select {|v| !RESERVED_VARIABLE_NAMES.include?(v.downcase)}
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get function names from code
|
# Get function names from code
|
||||||
#
|
#
|
||||||
|
# @return [Array] function names
|
||||||
def get_func_names
|
def get_func_names
|
||||||
return code.scan(/function\s([a-zA-Z\-\_]+)/).uniq.flatten
|
code.scan(/function\s([a-zA-Z\-\_0-9]+)/).uniq.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
# Attempt to find string literals in PSH expression
|
# Attempt to find string literals in PSH expression
|
||||||
|
#
|
||||||
|
# @return [Array] string literals
|
||||||
def get_string_literals
|
def get_string_literals
|
||||||
code.scan(/@"(.*)"@|@'(.*)'@/)
|
code.scan(/@"(.+?)"@|@'(.+?)'@/m)
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Scan code and return matches with index
|
# Scan code and return matches with index
|
||||||
#
|
#
|
||||||
|
# @param str [String] string to match in code
|
||||||
|
# @param source [String] source code to match, defaults to @code
|
||||||
|
#
|
||||||
|
# @return [Array[String,Integer]] matched items with index
|
||||||
def scan_with_index(str,source=code)
|
def scan_with_index(str,source=code)
|
||||||
::Enumerator.new do |y|
|
::Enumerator.new do |y|
|
||||||
source.scan(str) do
|
source.scan(str) do
|
||||||
|
@ -100,6 +106,9 @@ module Powershell
|
||||||
#
|
#
|
||||||
# Return matching bracket type
|
# Return matching bracket type
|
||||||
#
|
#
|
||||||
|
# @param char [String] opening bracket character
|
||||||
|
#
|
||||||
|
# @return [String] matching closing bracket
|
||||||
def match_start(char)
|
def match_start(char)
|
||||||
case char
|
case char
|
||||||
when '{'
|
when '{'
|
||||||
|
@ -110,6 +119,8 @@ module Powershell
|
||||||
']'
|
']'
|
||||||
when '<'
|
when '<'
|
||||||
'>'
|
'>'
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Unknown starting bracket"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -120,7 +131,16 @@ module Powershell
|
||||||
# Once the balanced matching bracket is found, all script content
|
# Once the balanced matching bracket is found, all script content
|
||||||
# between idx and the index of the matching bracket is returned
|
# between idx and the index of the matching bracket is returned
|
||||||
#
|
#
|
||||||
|
# @param idx [Integer] index of opening bracket
|
||||||
|
#
|
||||||
|
# @return [String] content between matching brackets
|
||||||
def block_extract(idx)
|
def block_extract(idx)
|
||||||
|
raise ArgumentError unless idx
|
||||||
|
|
||||||
|
if idx < 0 || idx >= code.length
|
||||||
|
raise ArgumentError, "Invalid index"
|
||||||
|
end
|
||||||
|
|
||||||
start = code[idx]
|
start = code[idx]
|
||||||
stop = match_start(start)
|
stop = match_start(start)
|
||||||
delims = scan_with_index(/#{Regexp.escape(start)}|#{Regexp.escape(stop)}/,code[idx+1..-1])
|
delims = scan_with_index(/#{Regexp.escape(start)}|#{Regexp.escape(stop)}/,code[idx+1..-1])
|
||||||
|
@ -128,19 +148,36 @@ module Powershell
|
||||||
c = 1
|
c = 1
|
||||||
sidx = nil
|
sidx = nil
|
||||||
# Go through delims till we balance, get idx
|
# Go through delims till we balance, get idx
|
||||||
while not c == 0 and x = delims.shift do
|
while ((c != 0) && (x = delims.shift)) do
|
||||||
sidx = x[1]
|
sidx = x[1]
|
||||||
x[0] == stop ? c -=1 : c+=1
|
x[0] == stop ? c -=1 : c+=1
|
||||||
end
|
end
|
||||||
return code[idx..sidx]
|
|
||||||
|
code[idx..sidx]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Extract a block of function code
|
||||||
|
#
|
||||||
|
# @param func_name [String] function name
|
||||||
|
# @param delete [Boolean] delete the function from the code
|
||||||
|
#
|
||||||
|
# @return [String] function block
|
||||||
def get_func(func_name, delete = false)
|
def get_func(func_name, delete = false)
|
||||||
start = code.index(func_name)
|
start = code.index(func_name)
|
||||||
|
|
||||||
|
return nil unless start
|
||||||
|
|
||||||
idx = code[start..-1].index('{') + start
|
idx = code[start..-1].index('{') + start
|
||||||
func_txt = block_extract(idx)
|
func_txt = block_extract(idx)
|
||||||
code.delete(ftxt) if delete
|
|
||||||
return Function.new(func_name,func_txt)
|
if delete
|
||||||
|
delete_code = code[0..idx]
|
||||||
|
delete_code << code[(idx+func_txt.length)..-1]
|
||||||
|
@code = delete_code
|
||||||
|
end
|
||||||
|
|
||||||
|
Function.new(func_name,func_txt)
|
||||||
end
|
end
|
||||||
end # Parser
|
end # Parser
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# -*- coding: binary -*-
|
# -*- coding: binary -*-
|
||||||
|
|
||||||
require 'zlib'
|
require 'rex'
|
||||||
require 'rex/text'
|
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
module Exploitation
|
module Exploitation
|
||||||
|
@ -36,6 +35,8 @@ module Powershell
|
||||||
|
|
||||||
def initialize(code)
|
def initialize(code)
|
||||||
@code = ''
|
@code = ''
|
||||||
|
@rig = Rex::RandomIdentifierGenerator.new()
|
||||||
|
|
||||||
begin
|
begin
|
||||||
# Open code file for reading
|
# Open code file for reading
|
||||||
fd = ::File.new(code, 'rb')
|
fd = ::File.new(code, 'rb')
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/exploitation/powershell'
|
||||||
|
|
||||||
|
describe Rex::Exploitation::Powershell::Obfu do
|
||||||
|
|
||||||
|
let(:example_script_without_literal) do
|
||||||
|
"""
|
||||||
|
function Find-4624Logons
|
||||||
|
{
|
||||||
|
|
||||||
|
if (-not ($NewLogonAccountDomain -cmatch \"NT\\sAUTHORITY\" -or $NewLogonAccountDomain -cmatch \"Window\\sManager\"))
|
||||||
|
{
|
||||||
|
$Key = $AccountName + $AccountDomain + $NewLogonAccountName + $NewLogonAccountDomain + $LogonType + $WorkstationName + $SourceNetworkAddress + $SourcePort
|
||||||
|
if (-not $ReturnInfo.ContainsKey($Key))
|
||||||
|
{
|
||||||
|
$Properties = @{
|
||||||
|
LogType = 4624
|
||||||
|
LogSource = \"Security\"
|
||||||
|
SourceAccountName = $AccountName
|
||||||
|
SourceDomainName = $AccountDomain
|
||||||
|
NewLogonAccountName = $NewLogonAccountName
|
||||||
|
NewLogonAccountDomain = $NewLogonAccountDomain
|
||||||
|
LogonType = $LogonType
|
||||||
|
WorkstationName = $WorkstationName
|
||||||
|
SourceNetworkAddress = $SourceNetworkAddress
|
||||||
|
SourcePort = $SourcePort
|
||||||
|
Count = 1
|
||||||
|
Times = @($Logon.TimeGenerated)
|
||||||
|
}
|
||||||
|
|
||||||
|
$ResultObj = New-Object PSObject -Property $Properties
|
||||||
|
$ReturnInfo.Add($Key, $ResultObj)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ReturnInfo[$Key].Count++
|
||||||
|
$ReturnInfo[$Key].Times += ,$Logon.TimeGenerated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:example_script) do
|
||||||
|
"""
|
||||||
|
function Find-4624Logons
|
||||||
|
{
|
||||||
|
$some_literal = @\"
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
namespace $kernel32 {
|
||||||
|
public class func {
|
||||||
|
[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }
|
||||||
|
[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }
|
||||||
|
[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }
|
||||||
|
[DllImport(\"kernel32.dll\")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||||
|
[DllImport(\"kernel32.dll\")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||||
|
[DllImport(\"kernel32.dll\")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\"@
|
||||||
|
if (-not ($NewLogonAccountDomain -cmatch \"NT\\sAUTHORITY\" -or $NewLogonAccountDomain -cmatch \"Window\\sManager\"))
|
||||||
|
{
|
||||||
|
$Key = $AccountName + $AccountDomain + $NewLogonAccountName + $NewLogonAccountDomain + $LogonType + $WorkstationName + $SourceNetworkAddress + $SourcePort
|
||||||
|
if (-not $ReturnInfo.ContainsKey($Key))
|
||||||
|
{
|
||||||
|
$Properties = @{
|
||||||
|
LogType = 4624
|
||||||
|
LogSource = \"Security\"
|
||||||
|
SourceAccountName = $AccountName
|
||||||
|
SourceDomainName = $AccountDomain
|
||||||
|
NewLogonAccountName = $NewLogonAccountName
|
||||||
|
NewLogonAccountDomain = $NewLogonAccountDomain
|
||||||
|
LogonType = $LogonType
|
||||||
|
WorkstationName = $WorkstationName
|
||||||
|
SourceNetworkAddress = $SourceNetworkAddress
|
||||||
|
SourcePort = $SourcePort
|
||||||
|
Count = 1
|
||||||
|
Times = @($Logon.TimeGenerated)
|
||||||
|
}
|
||||||
|
$literal2 = @\"parp\"@
|
||||||
|
$ResultObj = New-Object PSObject -Property $Properties
|
||||||
|
$ReturnInfo.Add($Key, $ResultObj)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ReturnInfo[$Key].Count++
|
||||||
|
$ReturnInfo[$Key].Times += ,$Logon.TimeGenerated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:subject) do
|
||||||
|
Rex::Exploitation::Powershell::Script.new(example_script)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:subject_no_literal) do
|
||||||
|
Rex::Exploitation::Powershell::Script.new(example_script_without_literal)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::sub_map_generate" do
|
||||||
|
it 'should return some unique variable names' do
|
||||||
|
map = subject.sub_map_generate(['blah','parp'])
|
||||||
|
map.should be
|
||||||
|
map.should be_kind_of Hash
|
||||||
|
map.empty?.should be_false
|
||||||
|
map.should eq map.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not match upper or lowercase reserved names' do
|
||||||
|
initial_vars = subject.get_var_names
|
||||||
|
subject.code << "\r\n$SHELLID"
|
||||||
|
subject.code << "\r\n$ShellId"
|
||||||
|
subject.code << "\r\n$shellid"
|
||||||
|
after_vars = subject.get_var_names
|
||||||
|
initial_vars.should eq after_vars
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
# -*- coding:binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'rex/exploitation/powershell'
|
||||||
|
|
||||||
|
describe Rex::Exploitation::Powershell::Parser do
|
||||||
|
|
||||||
|
let(:example_script) do
|
||||||
|
"""
|
||||||
|
function Find-4624Logons
|
||||||
|
{
|
||||||
|
$some_literal = @\"
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
namespace $kernel32 {
|
||||||
|
public class func {
|
||||||
|
[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }
|
||||||
|
[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }
|
||||||
|
[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }
|
||||||
|
[DllImport(\"kernel32.dll\")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||||
|
[DllImport(\"kernel32.dll\")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||||
|
[DllImport(\"kernel32.dll\")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\"@
|
||||||
|
if (-not ($NewLogonAccountDomain -cmatch \"NT\\sAUTHORITY\" -or $NewLogonAccountDomain -cmatch \"Window\\sManager\"))
|
||||||
|
{
|
||||||
|
$Key = $AccountName + $AccountDomain + $NewLogonAccountName + $NewLogonAccountDomain + $LogonType + $WorkstationName + $SourceNetworkAddress + $SourcePort
|
||||||
|
if (-not $ReturnInfo.ContainsKey($Key))
|
||||||
|
{
|
||||||
|
$Properties = @{
|
||||||
|
LogType = 4624
|
||||||
|
LogSource = \"Security\"
|
||||||
|
SourceAccountName = $AccountName
|
||||||
|
SourceDomainName = $AccountDomain
|
||||||
|
NewLogonAccountName = $NewLogonAccountName
|
||||||
|
NewLogonAccountDomain = $NewLogonAccountDomain
|
||||||
|
LogonType = $LogonType
|
||||||
|
WorkstationName = $WorkstationName
|
||||||
|
SourceNetworkAddress = $SourceNetworkAddress
|
||||||
|
SourcePort = $SourcePort
|
||||||
|
Count = 1
|
||||||
|
Times = @($Logon.TimeGenerated)
|
||||||
|
}
|
||||||
|
$literal2 = @\"parp\"@
|
||||||
|
$ResultObj = New-Object PSObject -Property $Properties
|
||||||
|
$ReturnInfo.Add($Key, $ResultObj)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ReturnInfo[$Key].Count++
|
||||||
|
$ReturnInfo[$Key].Times += ,$Logon.TimeGenerated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:subject) do
|
||||||
|
Rex::Exploitation::Powershell::Script.new(example_script)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::get_var_names" do
|
||||||
|
it 'should return some variable names' do
|
||||||
|
vars = subject.get_var_names
|
||||||
|
vars.should be
|
||||||
|
vars.should be_kind_of Array
|
||||||
|
vars.length.should be > 0
|
||||||
|
vars.include?('$ResultObj').should be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not match upper or lowercase reserved names' do
|
||||||
|
initial_vars = subject.get_var_names
|
||||||
|
subject.code << "\r\n$SHELLID"
|
||||||
|
subject.code << "\r\n$ShellId"
|
||||||
|
subject.code << "\r\n$shellid"
|
||||||
|
after_vars = subject.get_var_names
|
||||||
|
initial_vars.should eq after_vars
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::get_func_names" do
|
||||||
|
it 'should return some function names' do
|
||||||
|
funcs = subject.get_func_names
|
||||||
|
funcs.should be
|
||||||
|
funcs.should be_kind_of Array
|
||||||
|
funcs.length.should be > 0
|
||||||
|
funcs.include?('Find-4624Logons').should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::get_string_literals" do
|
||||||
|
it 'should return some string literals' do
|
||||||
|
literals = subject.get_string_literals
|
||||||
|
literals.should be
|
||||||
|
literals.should be_kind_of Array
|
||||||
|
literals.length.should be > 0
|
||||||
|
literals[0].include?('parp').should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::scan_with_index" do
|
||||||
|
it 'should scan code and return the items with an index' do
|
||||||
|
scan = subject.scan_with_index('DllImport')
|
||||||
|
scan.should be
|
||||||
|
scan.should be_kind_of Array
|
||||||
|
scan.length.should be > 0
|
||||||
|
scan[0].should be_kind_of Array
|
||||||
|
scan[0][0].should be_kind_of String
|
||||||
|
scan[0][1].should be_kind_of Integer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::match_start" do
|
||||||
|
it 'should match the correct brackets' do
|
||||||
|
subject.match_start('{').should eq '}'
|
||||||
|
subject.match_start('(').should eq ')'
|
||||||
|
subject.match_start('[').should eq ']'
|
||||||
|
subject.match_start('<').should eq '>'
|
||||||
|
expect { subject.match_start('p') }.to raise_exception(ArgumentError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::block_extract" do
|
||||||
|
it 'should extract a block between brackets given an index' do
|
||||||
|
idx = subject.code.index('{')
|
||||||
|
block = subject.block_extract(idx)
|
||||||
|
block.should be
|
||||||
|
block.should be_kind_of String
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should raise a runtime error if given an invalid index' do
|
||||||
|
expect { subject.block_extract(nil) }.to raise_error(ArgumentError)
|
||||||
|
expect { subject.block_extract(-1) }.to raise_error(ArgumentError)
|
||||||
|
expect { subject.block_extract(subject.code.length) }.to raise_error(ArgumentError)
|
||||||
|
expect { subject.block_extract(59) }.to raise_error(ArgumentError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "::get_func" do
|
||||||
|
it 'should extract a function from the code' do
|
||||||
|
function = subject.get_func('Find-4624Logons')
|
||||||
|
function.should be
|
||||||
|
function.should be_kind_of Rex::Exploitation::Powershell::Function
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return nil if function doesnt exist' do
|
||||||
|
function = subject.get_func(Rex::Text.rand_text_alpha(5))
|
||||||
|
function.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should delete the function if delete is true' do
|
||||||
|
function = subject.get_func('Find-4624Logons', true)
|
||||||
|
subject.code.include?('DllImport').should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue