commit
92d57ef37d
|
@ -137,7 +137,6 @@ require 'digest/sha1'
|
|||
nil
|
||||
end
|
||||
|
||||
|
||||
def self.to_win32pe(framework, code, opts={})
|
||||
|
||||
# For backward compatability, this is roughly equivalent to 'exe-small' fmt
|
||||
|
@ -366,8 +365,11 @@ require 'digest/sha1'
|
|||
|
||||
def self.to_winpe_only(framework, code, opts={}, arch="x86")
|
||||
|
||||
# Allow the user to specify their own EXE template
|
||||
if arch == ARCH_X86_64
|
||||
arch = ARCH_X64
|
||||
end
|
||||
|
||||
# Allow the user to specify their own EXE template
|
||||
set_template_default(opts, "template_"+arch+"_windows.exe")
|
||||
|
||||
pe = Rex::PeParsey::Pe.new_from_file(opts[:template], true)
|
||||
|
@ -400,7 +402,6 @@ require 'digest/sha1'
|
|||
return exe
|
||||
end
|
||||
|
||||
|
||||
def self.to_win32pe_old(framework, code, opts={})
|
||||
|
||||
payload = code.dup
|
||||
|
@ -469,7 +470,6 @@ require 'digest/sha1'
|
|||
return pe
|
||||
end
|
||||
|
||||
|
||||
def self.to_win64pe(framework, code, opts={})
|
||||
|
||||
# Allow the user to specify their own EXE template
|
||||
|
@ -1455,7 +1455,6 @@ End Sub
|
|||
return self.to_war(jspraw, opts)
|
||||
end
|
||||
|
||||
|
||||
# Creates a .NET DLL which loads data into memory
|
||||
# at a specified location with read/execute permissions
|
||||
# - the data will be loaded at: base+0x2065
|
||||
|
@ -1541,11 +1540,10 @@ End Sub
|
|||
api_call:
|
||||
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
||||
mov ebp, esp ; Create a new stack frame
|
||||
xor eax, eax ; Zero EDX
|
||||
mov eax, [fs:eax+48] ; Get a pointer to the PEB
|
||||
mov eax, [eax+12] ; Get PEB->Ldr
|
||||
mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list
|
||||
mov edx, eax
|
||||
xor edx, edx ; Zero EDX
|
||||
mov edx, [fs:edx+48] ; Get a pointer to the PEB
|
||||
mov edx, [edx+12] ; Get PEB->Ldr
|
||||
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
|
||||
next_mod: ;
|
||||
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
|
||||
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
|
||||
|
@ -1559,8 +1557,13 @@ End Sub
|
|||
not_lowercase: ;
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
;loop loop_modname ; Loop until we have read enough
|
||||
; The random jmps added below will occasionally make this offset
|
||||
; greater than will fit in a byte, so we have to use a regular jnz
|
||||
; instruction which can take a full 32-bits to accomodate the
|
||||
; bigger offset
|
||||
dec ecx
|
||||
jnz loop_modname ; Loop untill we have read enough
|
||||
jnz loop_modname ; Loop until we have read enough
|
||||
; We now have the module hash computed
|
||||
push edx ; Save the current position in the module list for later
|
||||
push edi ; Save the current module hash for later
|
||||
|
@ -1578,7 +1581,7 @@ End Sub
|
|||
add ebx, edx ; Add the modules base address
|
||||
; Computing the module hash + function hash
|
||||
get_next_func: ;
|
||||
test ecx, ecx ; (Changed from JECXZ to work around METASM)
|
||||
test ecx, ecx ; Changed from jecxz to accomodate the larger offset produced by random jmps below
|
||||
jz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
||||
dec ecx ; Decrement the function name counter
|
||||
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
||||
|
@ -1621,7 +1624,7 @@ End Sub
|
|||
pop edi ; Pop off the current (now the previous) modules hash
|
||||
pop edx ; Restore our position in the module list
|
||||
mov edx, [edx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
jmp next_mod ; Process this module
|
||||
^
|
||||
|
||||
stub_exit = %Q^
|
||||
|
@ -1654,7 +1657,7 @@ End Sub
|
|||
pop ebp ; Pop off the address of 'api_call' for calling later.
|
||||
|
||||
allocate_size:
|
||||
mov esi,PAYLOAD_SIZE
|
||||
mov esi, #{code.length}
|
||||
|
||||
allocate:
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
|
@ -1687,10 +1690,9 @@ End Sub
|
|||
get_payload:
|
||||
call got_payload
|
||||
payload:
|
||||
; Append an arbitary payload here
|
||||
; Append an arbitrary payload here
|
||||
^
|
||||
|
||||
|
||||
stub_alloc.gsub!('short', '')
|
||||
stub_alloc.gsub!('byte', '')
|
||||
|
||||
|
@ -1721,10 +1723,8 @@ End Sub
|
|||
wrapper << stub_final
|
||||
|
||||
enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded
|
||||
off = enc.offset_of_reloc('PAYLOAD_SIZE')
|
||||
res = enc.data + code
|
||||
|
||||
res[off,4] = [code.length].pack('V')
|
||||
res
|
||||
end
|
||||
|
||||
|
@ -1763,12 +1763,11 @@ End Sub
|
|||
not_lowercase: ;
|
||||
ror edi, 13 ; Rotate right our hash value
|
||||
add edi, eax ; Add the next byte of the name
|
||||
dec ecx
|
||||
jnz loop_modname ; Loop untill we have read enough
|
||||
loop loop_modname ; Loop until we have read enough
|
||||
; We now have the module hash computed
|
||||
push edx ; Save the current position in the module list for later
|
||||
push edi ; Save the current module hash for later
|
||||
; Proceed to itterate the export address table,
|
||||
; Proceed to iterate the export address table,
|
||||
mov edx, [edx+16] ; Get this modules base address
|
||||
mov eax, [edx+60] ; Get PE header
|
||||
add eax, edx ; Add the modules base address
|
||||
|
@ -1824,7 +1823,7 @@ End Sub
|
|||
pop edi ; Pop off the current (now the previous) modules hash
|
||||
pop edx ; Restore our position in the module list
|
||||
mov edx, [edx] ; Get the next module
|
||||
jmp next_mod ; Process this module
|
||||
jmp next_mod ; Process this module
|
||||
^
|
||||
|
||||
stub_exit = %Q^
|
||||
|
@ -1858,7 +1857,7 @@ End Sub
|
|||
pop ebp ; Pop off the address of 'api_call' for calling later.
|
||||
|
||||
allocate_size:
|
||||
mov esi,PAYLOAD_SIZE
|
||||
mov esi,#{code.length}
|
||||
|
||||
allocate:
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
|
@ -1904,7 +1903,7 @@ End Sub
|
|||
get_payload:
|
||||
call got_payload
|
||||
payload:
|
||||
; Append an arbitary payload here
|
||||
; Append an arbitrary payload here
|
||||
^
|
||||
|
||||
|
||||
|
@ -1946,11 +1945,9 @@ End Sub
|
|||
wrapper << stub_final
|
||||
|
||||
enc = Metasm::Shellcode.assemble(Metasm::Ia32.new, wrapper).encoded
|
||||
off = enc.offset_of_reloc('PAYLOAD_SIZE')
|
||||
soff = enc.data.index("\xe9\xff\xff\xff\xff") + 1
|
||||
res = enc.data + code
|
||||
|
||||
res[off,4] = [code.length].pack('V')
|
||||
if which_offset == 'start'
|
||||
res[soff,4] = [block_offset - (soff + 4)].pack('V')
|
||||
elsif which_offset == 'end'
|
||||
|
@ -1963,72 +1960,97 @@ End Sub
|
|||
|
||||
|
||||
#
|
||||
# This routine is shared between msfencode, rpc, and payload modules (use <payload>)
|
||||
# Generate an executable of a given format suitable for running on the
|
||||
# architecture/platform pair.
|
||||
#
|
||||
# It will return nil if it wasn't able to generate any output.
|
||||
# This routine is shared between msfencode, rpc, and payload modules (use
|
||||
# <payload>)
|
||||
#
|
||||
# @param framework [Framework]
|
||||
# @param arch [String] Architecture for the target format; one of the ARCH_*
|
||||
# constants
|
||||
# @param plat [#index] platform
|
||||
# @param code [String] The shellcode for the resulting executable to run
|
||||
# @param fmt [String] One of the executable formats as defined in
|
||||
# {.to_executable_fmt_formats}
|
||||
# @param exeopts [Hash] Passed directly to the approrpriate method for
|
||||
# generating an executable for the given +arch+/+plat+ pair.
|
||||
# @return [String] An executable appropriate for the given
|
||||
# architecture/platform pair.
|
||||
# @return [nil] If the format is unrecognized or the arch and plat don't
|
||||
# make sense together.
|
||||
def self.to_executable_fmt(framework, arch, plat, code, fmt, exeopts)
|
||||
|
||||
output = nil
|
||||
# For backwards compatibility with the way this gets called when
|
||||
# generating from Msf::Simple::Payload.generate_simple
|
||||
if arch.kind_of? Array
|
||||
output = nil
|
||||
arch.each do |a|
|
||||
output = to_executable_fmt(framework, a, plat, code, fmt, exeopts)
|
||||
break if output
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
case fmt
|
||||
when 'asp'
|
||||
output = Msf::Util::EXE.to_win32pe_asp(framework, code, exeopts)
|
||||
|
||||
when 'aspx'
|
||||
output = Msf::Util::EXE.to_win32pe_aspx(framework, code, exeopts)
|
||||
|
||||
when 'dll'
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_win32pe_dll(framework, code, exeopts)
|
||||
end
|
||||
|
||||
if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
|
||||
output = Msf::Util::EXE.to_win64pe_dll(framework, code, exeopts)
|
||||
end
|
||||
|
||||
output = case arch
|
||||
when ARCH_X86,nil then to_win32pe_dll(framework, code, exeopts)
|
||||
when ARCH_X86_64 then to_win64pe_dll(framework, code, exeopts)
|
||||
when ARCH_X64 then to_win64pe_dll(framework, code, exeopts)
|
||||
end
|
||||
when 'exe'
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_win32pe(framework, code, exeopts)
|
||||
end
|
||||
|
||||
if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
|
||||
output = Msf::Util::EXE.to_win64pe(framework, code, exeopts)
|
||||
end
|
||||
output = case arch
|
||||
when ARCH_X86,nil then to_win32pe(framework, code, exeopts)
|
||||
when ARCH_X86_64 then to_win64pe(framework, code, exeopts)
|
||||
when ARCH_X64 then to_win64pe(framework, code, exeopts)
|
||||
end
|
||||
|
||||
when 'exe-small'
|
||||
if(not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_win32pe_old(framework, code, exeopts)
|
||||
end
|
||||
output = case arch
|
||||
when ARCH_X86,nil then to_win32pe_old(framework, code, exeopts)
|
||||
end
|
||||
|
||||
when 'exe-only'
|
||||
if(not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_winpe_only(framework, code, exeopts)
|
||||
end
|
||||
|
||||
if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
|
||||
output = Msf::Util::EXE.to_winpe_only(framework, code, exeopts, "x64")
|
||||
end
|
||||
output = case arch
|
||||
when ARCH_X86,nil then to_winpe_only(framework, code, exeopts, arch)
|
||||
when ARCH_X86_64 then to_winpe_only(framework, code, exeopts, arch)
|
||||
when ARCH_X64 then to_winpe_only(framework, code, exeopts, arch)
|
||||
end
|
||||
|
||||
when 'elf'
|
||||
if (not plat or (plat.index(Msf::Module::Platform::Linux)))
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_linux_x86_elf(framework, code, exeopts)
|
||||
elsif (arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
|
||||
output = Msf::Util::EXE.to_linux_x64_elf(framework, code, exeopts)
|
||||
end
|
||||
output = case arch
|
||||
when ARCH_X86,nil then to_linux_x86_elf(framework, code, exeopts)
|
||||
when ARCH_X86_64 then to_linux_x64_elf(framework, code, exeopts)
|
||||
when ARCH_X64 then to_linux_x64_elf(framework, code, exeopts)
|
||||
when ARCH_ARMLE then to_linux_armle_elf(framework, code, exeopts)
|
||||
when ARCH_MIPSBE then to_linux_mipsbe_elf(framework, code, exeopts)
|
||||
when ARCH_MIPSLE then to_linux_mipsle_elf(framework, code, exeopts)
|
||||
end
|
||||
elsif(plat and (plat.index(Msf::Module::Platform::BSD)))
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_bsd_x86_elf(framework, code, exeopts)
|
||||
end
|
||||
output = case arch
|
||||
when ARCH_X86,nil then Msf::Util::EXE.to_bsd_x86_elf(framework, code, exeopts)
|
||||
end
|
||||
elsif(plat and (plat.index(Msf::Module::Platform::Solaris)))
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_solaris_x86_elf(framework, code, exeopts)
|
||||
end
|
||||
output = case arch
|
||||
when ARCH_X86,nil then to_solaris_x86_elf(framework, code, exeopts)
|
||||
end
|
||||
end
|
||||
|
||||
when 'macho'
|
||||
if (not arch or (arch.index(ARCH_X86)))
|
||||
output = Msf::Util::EXE.to_osx_x86_macho(framework, code, exeopts)
|
||||
end
|
||||
|
||||
if (arch and (arch.index(ARCH_X86_64) or arch.index(ARCH_X64)))
|
||||
output = Msf::Util::EXE.to_osx_x64_macho(framework, code, exeopts)
|
||||
end
|
||||
output = case arch
|
||||
when ARCH_X86,nil then to_osx_x86_macho(framework, code, exeopts)
|
||||
when ARCH_X86_64 then to_osx_x64_macho(framework, code, exeopts)
|
||||
when ARCH_X64 then to_osx_x64_macho(framework, code, exeopts)
|
||||
when ARCH_ARMLE then to_osx_arm_macho(framework, code, exeopts)
|
||||
when ARCH_PPC then to_osx_ppc_macho(framework, code, exeopts)
|
||||
end
|
||||
|
||||
when 'vba'
|
||||
output = Msf::Util::EXE.to_vba(framework, code, exeopts)
|
||||
|
@ -2043,12 +2065,6 @@ End Sub
|
|||
when 'loop-vbs'
|
||||
output = Msf::Util::EXE.to_win32pe_vbs(framework, code, exeopts.merge({ :persist => true }))
|
||||
|
||||
when 'asp'
|
||||
output = Msf::Util::EXE.to_win32pe_asp(framework, code, exeopts)
|
||||
|
||||
when 'aspx'
|
||||
output = Msf::Util::EXE.to_win32pe_aspx(framework, code, exeopts)
|
||||
|
||||
when 'war'
|
||||
arch ||= [ ARCH_X86 ]
|
||||
tmp_plat = plat.platforms if plat
|
||||
|
@ -2068,7 +2084,10 @@ End Sub
|
|||
end
|
||||
|
||||
def self.to_executable_fmt_formats
|
||||
['dll','exe','exe-small','exe-only','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war','psh','psh-net']
|
||||
[
|
||||
'dll','exe','exe-small','exe-only','elf','macho','vba','vba-exe',
|
||||
'vbs','loop-vbs','asp','aspx','war','psh','psh-net'
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -100,7 +100,7 @@ class OptsConsole
|
|||
options['DatabaseMigrationPaths'] ||= []
|
||||
options['DatabaseMigrationPaths'] << m
|
||||
end
|
||||
|
||||
|
||||
opts.on("-e", "--environment <production|development>", "Specify the database environment to load from the YAML") do |m|
|
||||
options['DatabaseEnv'] = m
|
||||
end
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'msf/base/simple'
|
||||
require 'spec_helper'
|
||||
|
||||
require 'support/shared/contexts/msf/util/exe'
|
||||
|
||||
describe Msf::Util::EXE do
|
||||
|
||||
|
@ -14,44 +17,23 @@ describe Msf::Util::EXE do
|
|||
'DisableDatabase' => true
|
||||
)
|
||||
|
||||
context '.to_executable_fmt' do
|
||||
describe '.win32_rwx_exec' do
|
||||
it "should contain the shellcode" do
|
||||
bin = subject.win32_rwx_exec("asdfjklASDFJKL")
|
||||
bin.should include("asdfjklASDFJKL")
|
||||
end
|
||||
end
|
||||
|
||||
describe '.to_executable_fmt' do
|
||||
it "should output nil when given a bogus format" do
|
||||
bin = subject.to_executable_fmt($framework, "", "", "", "does not exist", {})
|
||||
|
||||
bin.should == nil
|
||||
end
|
||||
|
||||
platform_format_map = {
|
||||
"windows" => [
|
||||
{ :format => "dll", :arch => "x86", :file_fp => /PE32 .*DLL/ },
|
||||
{ :format => "dll", :arch => "x64", :file_fp => /PE32\+.*DLL/ },
|
||||
{ :format => "exe", :arch => "x86", :file_fp => /PE32 / },
|
||||
{ :format => "exe", :arch => "x64", :file_fp => /PE32\+/ },
|
||||
{ :format => "exe-small", :arch => "x86", :file_fp => /PE32 / },
|
||||
# No template for 64-bit exe-small. That's fine, we probably
|
||||
# don't need one.
|
||||
#{ :format => "exe-small", :arch => "x64", :file_fp => /PE32\+/ },
|
||||
],
|
||||
"linux" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32.*SYSV/ },
|
||||
{ :format => "elf", :arch => "x64", :file_fp => /ELF 64.*SYSV/ },
|
||||
{ :format => "elf", :arch => "armle",:file_fp => /ELF 32.*ARM/, :pending => true },
|
||||
],
|
||||
"bsd" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32.*BSD/ },
|
||||
],
|
||||
"solaris" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32/ },
|
||||
],
|
||||
"osx" => [
|
||||
{ :format => "macho", :arch => "x86", :file_fp => /Mach-O.*i386/ },
|
||||
{ :format => "macho", :arch => "x64", :file_fp => /Mach-O 64/ },
|
||||
{ :format => "macho", :arch => "armle", :file_fp => /Mach-O.*acorn/, :pending => true },
|
||||
{ :format => "macho", :arch => "ppc", :file_fp => /Mach-O.*ppc/, :pending => true },
|
||||
]
|
||||
}
|
||||
include_context 'Msf::Util::Exe'
|
||||
|
||||
platform_format_map.each do |plat, formats|
|
||||
@platform_format_map.each do |plat, formats|
|
||||
context "with platform=#{plat}" do
|
||||
let(:platform) do
|
||||
Msf::Module::PlatformList.transform(plat)
|
||||
|
@ -65,6 +47,11 @@ describe Msf::Util::EXE do
|
|||
bin = subject.to_executable_fmt($framework, "asdf", platform, "\xcc", formats.first[:format], {})
|
||||
bin.should == nil
|
||||
end
|
||||
[ ARCH_X86, ARCH_X64, ARCH_X86_64, ARCH_PPC, ARCH_MIPSLE, ARCH_MIPSBE, ARCH_ARMLE ].each do |arch|
|
||||
it "returns nil when given bogus format for arch=#{arch}" do
|
||||
bin = subject.to_executable_fmt($framework, arch, platform, "\xcc", "asdf", {})
|
||||
end
|
||||
end
|
||||
|
||||
formats.each do |format_hash|
|
||||
fmt = format_hash[:format]
|
||||
|
@ -79,17 +66,7 @@ describe Msf::Util::EXE do
|
|||
bin = subject.to_executable_fmt($framework, arch, platform, "\xcc", fmt, {})
|
||||
bin.should be_a String
|
||||
|
||||
f = IO.popen("file -","w+")
|
||||
f.write(bin)
|
||||
f.close_write
|
||||
fp = f.read
|
||||
f.close
|
||||
fp.should =~ format_hash[:file_fp] if format_hash[:file_fp]
|
||||
end
|
||||
|
||||
it "returns nil when given bogus format for arch=#{arch}" do
|
||||
bin = subject.to_executable_fmt($framework, arch, platform, "\xcc", "asdf", {})
|
||||
bin.should == nil
|
||||
verify_bin_fingerprint(format_hash, bin)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
|
||||
require 'spec_helper'
|
||||
require 'msf/core'
|
||||
# doesn't end in .rb or .so, so have to load instead of require
|
||||
load File.join(Msf::Config.install_root, 'msfvenom')
|
||||
|
||||
shared_examples_for "nop dumper" do
|
||||
it "should list known nops" do
|
||||
%w!
|
||||
x86/opty2
|
||||
armle/simple
|
||||
!.each do |name|
|
||||
dump.should include(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "encoder dumper" do
|
||||
it "should list known encoders" do
|
||||
%w!
|
||||
generic/none
|
||||
x86/shikata_ga_nai
|
||||
x64/xor
|
||||
!.each do |name|
|
||||
dump.should include(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "payload dumper" do
|
||||
it "should list known payloads" do
|
||||
# Just a representative sample of some of the important ones.
|
||||
%w!
|
||||
cmd/unix/reverse
|
||||
java/meterpreter/reverse_tcp
|
||||
java/meterpreter/reverse_https
|
||||
linux/x86/shell/reverse_tcp
|
||||
linux/x86/shell_reverse_tcp
|
||||
linux/x64/shell/reverse_tcp
|
||||
linux/x64/shell_reverse_tcp
|
||||
linux/armle/shell/reverse_tcp
|
||||
linux/armle/shell_reverse_tcp
|
||||
linux/mipsbe/shell_reverse_tcp
|
||||
php/meterpreter/reverse_tcp
|
||||
windows/meterpreter/reverse_tcp
|
||||
windows/meterpreter/reverse_https
|
||||
!.each do |name|
|
||||
dump.should include(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe MsfVenom do
|
||||
|
||||
let(:stdin) { StringIO.new("", "rb") }
|
||||
let(:stdout) { StringIO.new("", "wb") }
|
||||
let(:stderr) { StringIO.new("", "wb") }
|
||||
subject(:venom) { described_class.new(stdin, stdout, stderr, framework) }
|
||||
before(:each) do
|
||||
conf_dir = Metasploit::Framework.root.join('spec', 'dummy', 'framework','config')
|
||||
conf_dir.mkpath
|
||||
end
|
||||
after(:each) do
|
||||
dummy_dir = Metasploit::Framework.root.join('spec', 'dummy')
|
||||
dummy_dir.rmtree
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
conf_dir = Metasploit::Framework.root.join('spec', 'dummy', 'framework','config')
|
||||
conf_dir.mkpath
|
||||
create_opts = {
|
||||
:module_types => [
|
||||
::Msf::MODULE_PAYLOAD, ::Msf::MODULE_ENCODER, ::Msf::MODULE_NOP
|
||||
],
|
||||
'ConfigDirectory' => conf_dir.to_s,
|
||||
'DisableDatabase' => true
|
||||
}
|
||||
@framework = ::Msf::Simple::Framework.create(create_opts)
|
||||
end
|
||||
|
||||
let(:framework) { @framework }
|
||||
describe "#dump_encoders" do
|
||||
it_behaves_like "encoder dumper" do
|
||||
let(:dump) { venom.dump_encoders }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#dump_nops" do
|
||||
it_behaves_like "nop dumper" do
|
||||
let(:dump) { venom.dump_nops }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#dump_payloads" do
|
||||
it_behaves_like "payload dumper" do
|
||||
let(:dump) { venom.dump_payloads }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#parse_args" do
|
||||
|
||||
context "help" do
|
||||
it "should raise UsageError" do
|
||||
expect { venom.parse_args(%w! -h !) }.to raise_error(MsfVenom::UsageError)
|
||||
expect { venom.parse_args(%w! --help !) }.to raise_error(MsfVenom::UsageError)
|
||||
expect { venom.parse_args(%w! --help-formats !) }.to raise_error(MsfVenom::UsageError)
|
||||
end
|
||||
end
|
||||
|
||||
context "with bad arguments" do
|
||||
|
||||
it "should raise UsageError with empty arguments" do
|
||||
expect { venom.parse_args([]) }.to raise_error(MsfVenom::UsageError)
|
||||
end
|
||||
|
||||
it "should raise with unexpected options" do
|
||||
expect { venom.parse_args(%w! --non-existent-option !) }.to raise_error(MsfVenom::UsageError)
|
||||
end
|
||||
|
||||
%w! --platform -a -b -c -f -p -n -s -i -x !.each do |required_arg|
|
||||
it "should raise UsageError with no arg for option #{required_arg}" do
|
||||
expect { venom.parse_args([required_arg]) }.to raise_error(MsfVenom::UsageError)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "#generate_raw_payload" do
|
||||
|
||||
before do
|
||||
venom.parse_args(args)
|
||||
end
|
||||
|
||||
context "with --options" do
|
||||
|
||||
context "and a payload" do
|
||||
let(:args) { %w! -o -p windows/meterpreter/reverse_tcp ! }
|
||||
it "should print options" do
|
||||
expect { venom.generate_raw_payload }.to_not raise_error
|
||||
output = stderr.string
|
||||
output.should include("LHOST")
|
||||
output.should include("LPORT")
|
||||
end
|
||||
context "and some datastore options" do
|
||||
it "should print options" do
|
||||
venom.parse_args %w! -o -p windows/meterpreter/reverse_tcp LPORT=1234!
|
||||
expect { venom.generate_raw_payload }.to_not raise_error
|
||||
output = stderr.string
|
||||
output.should include("LHOST")
|
||||
output.should match(/LPORT\s+1234/)
|
||||
end
|
||||
|
||||
it "should print options case-insensitively" do
|
||||
venom.parse_args %w! -o -p windows/meterpreter/reverse_tcp lPoRt=1234!
|
||||
expect { venom.generate_raw_payload }.to_not raise_error
|
||||
output = stderr.string
|
||||
output.should include("LHOST")
|
||||
output.should match(/LPORT\s+1234/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "and an invalid payload" do
|
||||
let(:args) { %w! -o -p asdf! }
|
||||
it "should raise" do
|
||||
expect { venom.generate_raw_payload }.to raise_error(MsfVenom::UsageError)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
[
|
||||
{ :format => "elf", :arch => "x86" },
|
||||
{ :format => "raw", :arch => "x86" },
|
||||
{ :format => "elf", :arch => "armle" },
|
||||
{ :format => "raw", :arch => "armle" },
|
||||
{ :format => "elf", :arch => "ppc" },
|
||||
{ :format => "raw", :arch => "ppc" },
|
||||
{ :format => "elf", :arch => "mipsle" },
|
||||
{ :format => "raw", :arch => "mipsle" },
|
||||
].each do |format_hash|
|
||||
format = format_hash[:format]
|
||||
arch = format_hash[:arch]
|
||||
|
||||
context "building #{format} with linux/#{arch}/shell_bind_tcp" do
|
||||
let(:args) { %W! -f #{format} -p linux/#{arch}/shell_bind_tcp ! }
|
||||
# We're not encoding, so should be testable here
|
||||
it "should contain /bin/sh" do
|
||||
output = venom.generate_raw_payload
|
||||
# Usually push'd in two instructions, so the whole string
|
||||
# isn't all together. Check for the two pieces seperately
|
||||
output.should include("/sh")
|
||||
output.should include("/bin")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "#generate" do
|
||||
include_context 'Msf::Util::Exe'
|
||||
|
||||
before { venom.parse_args(args) }
|
||||
|
||||
context "with --list" do
|
||||
|
||||
context "with invalid module type" do
|
||||
let(:args) { %w!--list asdf! }
|
||||
it "should raise UsageError" do
|
||||
expect { venom.generate }.to raise_error(MsfVenom::UsageError)
|
||||
end
|
||||
end
|
||||
|
||||
[ "nop", "encoder", "payload" ].each do |type|
|
||||
context "#{type}s" do
|
||||
let(:args) { %W!--list #{type}s! }
|
||||
it_behaves_like "#{type} dumper" do
|
||||
let(:dump) do
|
||||
venom.generate
|
||||
stderr.string
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "with invalid datastore option" do
|
||||
let(:args) { %w!-f exe -p windows/shell_reverse_tcp LPORT=asdf! }
|
||||
it "should fail validation" do
|
||||
expect { venom.generate }.to raise_error(Msf::OptionValidateError)
|
||||
end
|
||||
end
|
||||
|
||||
context "without required datastore option" do
|
||||
# Requires LHOST
|
||||
let(:args) { %w!-f exe -p windows/shell_reverse_tcp! }
|
||||
it "should fail validation" do
|
||||
expect { venom.generate }.to raise_error(Msf::OptionValidateError)
|
||||
end
|
||||
end
|
||||
|
||||
@platform_format_map.each do |plat, formats|
|
||||
formats.each do |format_hash|
|
||||
format = format_hash[:format]
|
||||
arch = format_hash[:arch]
|
||||
# Need a new context for each so the let() will work correctly
|
||||
context "with format=#{format} platform=#{plat} arch=#{arch}" do
|
||||
# This will build executables with no payload. They won't work
|
||||
# of course, but at least we can see that it is producing the
|
||||
# correct file format for the given arch and platform.
|
||||
let(:args) { %W! -p - -f #{format} -a #{arch} --platform #{plat} ! }
|
||||
it "should print a #{format} to stdout" do
|
||||
venom.generate
|
||||
output = stdout.string
|
||||
verify_bin_fingerprint(format_hash, output)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
|
||||
shared_context 'Msf::Util::Exe' do
|
||||
@platform_format_map = {
|
||||
"windows" => [
|
||||
{ :format => "dll", :arch => "x86", :file_fp => /PE32 .*DLL/ },
|
||||
{ :format => "dll", :arch => "x64", :file_fp => /PE32\+.*DLL/ },
|
||||
{ :format => "exe", :arch => "x86", :file_fp => /PE32 / },
|
||||
{ :format => "exe", :arch => "x64", :file_fp => /PE32\+/ },
|
||||
{ :format => "exe", :arch => "x86_64", :file_fp => /PE32\+/ },
|
||||
{ :format => "exe-small", :arch => "x86", :file_fp => /PE32 / },
|
||||
# No template for 64-bit exe-small. That's fine, we probably
|
||||
# don't need one.
|
||||
#{ :format => "exe-small", :arch => "x64", :file_fp => /PE32\+/ },
|
||||
{ :format => "exe-only", :arch => "x86", :file_fp => /PE32 / },
|
||||
{ :format => "exe-only", :arch => "x64", :file_fp => /PE32\+ / },
|
||||
{ :format => "exe-only", :arch => "x86_64", :file_fp => /PE32\+ / },
|
||||
],
|
||||
"linux" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32.*SYSV/ },
|
||||
{ :format => "elf", :arch => "x64", :file_fp => /ELF 64.*SYSV/ },
|
||||
{ :format => "elf", :arch => "armle", :file_fp => /ELF 32.*ARM/ },
|
||||
{ :format => "elf", :arch => "mipsbe", :file_fp => /ELF 32-bit MSB executable, MIPS/ },
|
||||
{ :format => "elf", :arch => "mipsle", :file_fp => /ELF 32-bit LSB executable, MIPS/ },
|
||||
],
|
||||
"bsd" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32.*BSD/ },
|
||||
],
|
||||
"solaris" => [
|
||||
{ :format => "elf", :arch => "x86", :file_fp => /ELF 32/ },
|
||||
],
|
||||
"osx" => [
|
||||
{ :format => "macho", :arch => "x86", :file_fp => /Mach-O.*i386/ },
|
||||
{ :format => "macho", :arch => "x64", :file_fp => /Mach-O 64/ },
|
||||
{ :format => "macho", :arch => "armle", :file_fp => /Mach-O.*(acorn|arm)/ },
|
||||
{ :format => "macho", :arch => "ppc", :file_fp => /Mach-O.*ppc/ },
|
||||
],
|
||||
}
|
||||
|
||||
def verify_bin_fingerprint(format_hash, bin)
|
||||
bin.should be_a(String)
|
||||
fp = IO.popen("file -","w+") do |io|
|
||||
io.write(bin)
|
||||
io.close_write
|
||||
io.read
|
||||
end
|
||||
if format_hash[:file_fp]
|
||||
fp.should =~ format_hash[:file_fp]
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue