Class: Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Core
- Inherits:
-
Object
- Object
- Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Core
- Defined in:
- lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb
Overview
Core meterpreter client commands that provide only the required set of commands for having a functional meterpreter client<->server instance.
Constant Summary collapse
- @@use_opts =
Rex::Parser::Arguments.new( "-l" => [ false, "List all available extensions" ], "-h" => [ false, "Help menu." ])
- @@channel_opts =
Displays information about active channels
Rex::Parser::Arguments.new( "-l" => [ false, "List active channels." ], "-h" => [ false, "Help menu." ])
- @@write_opts =
Writes data to a channel.
Rex::Parser::Arguments.new( "-f" => [ true, "Write the contents of a file on disk" ], "-h" => [ false, "Help menu." ])
- @@client_extension_search_paths =
[ ::File.join(Rex::Root, "post", "meterpreter", "ui", "console", "command_dispatcher") ]
Instance Attribute Summary
Attributes included from Ui::Text::DispatcherShell::CommandDispatcher
Class Method Summary collapse
Instance Method Summary collapse
- #cmd_background ⇒ Object
-
#cmd_bgkill(*args) ⇒ Object
Kill a background job.
-
#cmd_bglist(*args) ⇒ Object
List background jobs.
-
#cmd_bgrun(*args) ⇒ Object
Executes a script in the context of the meterpreter session in the background.
-
#cmd_bgrun_tabs(*args) ⇒ Object
Map this to the normal run command tab completion.
-
#cmd_channel(*args) ⇒ Object
Performs operations on the supplied channel.
-
#cmd_close(*args) ⇒ Object
Closes a supplied channel.
-
#cmd_exit(*args) ⇒ Object
(also: #cmd_quit)
Terminates the meterpreter session.
-
#cmd_info(*args) ⇒ Object
Show info for a given Post module.
- #cmd_info_tabs(*args) ⇒ Object
-
#cmd_interact(*args) ⇒ Object
Interacts with a channel.
-
#cmd_irb(*args) ⇒ Object
Runs the IRB scripting shell.
-
#cmd_migrate(*args) ⇒ Object
Migrates the server to the supplied process identifier.
-
#cmd_read(*args) ⇒ Object
Reads data from a channel.
- #cmd_resource(*args) ⇒ Object
- #cmd_resource_tabs(str, words) ⇒ Object
-
#cmd_run(*args) ⇒ Object
Executes a script in the context of the meterpreter session.
- #cmd_run_help ⇒ Object
- #cmd_run_tabs(str, words) ⇒ Object
-
#cmd_use(*args) ⇒ Object
Loads one or more meterpreter extensions.
- #cmd_use_tabs(str, words) ⇒ Object
- #cmd_write(*args) ⇒ Object
-
#commands ⇒ Object
List of supported commands.
-
#initialize(shell) ⇒ Core
constructor
Initializes an instance of the core command set using the supplied shell for interactivity.
- #msf_loaded? ⇒ Boolean
-
#name ⇒ Object
Core baby.
Methods included from Rex::Post::Meterpreter::Ui::Console::CommandDispatcher
check_hash, #client, #log_error, set_hash
Methods included from Ui::Text::DispatcherShell::CommandDispatcher
#cmd_help, #cmd_help_tabs, #print, #print_error, #print_good, #print_line, #print_status, #tab_complete_filenames, #update_prompt
Constructor Details
#initialize(shell) ⇒ Core
Initializes an instance of the core command set using the supplied shell for interactivity.
23 24 25 26 27 28 29 30 31 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 23 def initialize(shell) super self.extensions = [] self.bgjobs = [] self.bgjob_id = 0 @msf_loaded = nil end |
Class Method Details
.add_client_extension_search_path(path) ⇒ Object
647 648 649 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 647 def self.add_client_extension_search_path(path) @@client_extension_search_paths << path unless @@client_extension_search_paths.include?(path) end |
.client_extension_search_paths ⇒ Object
650 651 652 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 650 def self.client_extension_search_paths @@client_extension_search_paths end |
Instance Method Details
#cmd_background ⇒ Object
88 89 90 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 88 def cmd_background client.interacting = false end |
#cmd_bgkill(*args) ⇒ Object
Kill a background job
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 461 def cmd_bgkill(*args) if args.length == 0 print_line("Usage: bgkill [id]") return end args.each do |jid| jid = jid.to_i if self.bgjobs[jid] print_status("Killing background job #{jid}...") self.bgjobs[jid].kill self.bgjobs[jid] = nil else print_error("Job #{jid} was not running") end end end |
#cmd_bglist(*args) ⇒ Object
List background jobs
482 483 484 485 486 487 488 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 482 def cmd_bglist(*args) self.bgjobs.each_index do |jid| if self.bgjobs[jid] print_status("Job #{jid}: #{self.bgjobs[jid][:args].inspect}") end end end |
#cmd_bgrun(*args) ⇒ Object
Executes a script in the context of the meterpreter session in the background
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 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 422 def cmd_bgrun(*args) if args.length == 0 print_line( "Usage: bgrun <script> [arguments]\n\n" + "Executes a ruby script in the context of the meterpreter session.") return true end jid = self.bgjob_id self.bgjob_id += 1 # Get the script name self.bgjobs[jid] = Rex::ThreadFactory.spawn("MeterpreterBGRun(#{args[0]})-#{jid}", false, jid, args) do |myjid,xargs| ::Thread.current[:args] = xargs.dup begin # the rest of the arguments get passed in through the binding client.execute_script(args.shift, args) rescue ::Exception print_error("Error in script: #{$!.class} #{$!}") elog("Error in script: #{$!.class} #{$!}") dlog("Callstack: #{$@.join("\n")}") end self.bgjobs[myjid] = nil print_status("Background script with Job ID #{myjid} has completed (#{::Thread.current[:args].inspect})") end print_status("Executed Meterpreter with Job ID #{jid}") end |
#cmd_bgrun_tabs(*args) ⇒ Object
Map this to the normal run command tab completion
454 455 456 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 454 def cmd_bgrun_tabs(*args) cmd_run_tabs(*args) end |
#cmd_channel(*args) ⇒ Object
Performs operations on the supplied channel.
102 103 104 105 106 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 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 102 def cmd_channel(*args) if (args.length == 0) args.unshift("-h") end mode = nil # Parse options @@channel_opts.parse(args) { |opt, idx, val| case opt when "-h" print( "Usage: channel [options]\n\n" + "Displays information about active channels.\n" + @@channel_opts.usage) return true when "-l" mode = 'list' end } # No mode, no service. if (mode == nil) return true elsif (mode == 'list') tbl = Rex::Ui::Text::Table.new( 'Indent' => 4, 'Columns' => [ 'Id', 'Class', 'Type' ]) items = 0 client.channels.each_pair { |cid, channel| tbl << [ cid, channel.class.cls, channel.type ] items += 1 } if (items == 0) print_line("No active channels.") else print("\n" + tbl.to_s + "\n") end end end |
#cmd_close(*args) ⇒ Object
Closes a supplied channel.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 153 def cmd_close(*args) if (args.length == 0) print_line( "Usage: close channel_id\n\n" + "Closes the supplied channel.") return true end cid = args[0].to_i channel = client.find_channel(cid) if (!channel) print_error("Invalid channel identifier specified.") return true else channel._close # Issue #410 print_status("Closed channel #{cid}.") end end |
#cmd_exit(*args) ⇒ Object Also known as: cmd_quit
Terminates the meterpreter session.
177 178 179 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 177 def cmd_exit(*args) shell.stop end |
#cmd_info(*args) ⇒ Object
Show info for a given Post module.
See also cmd_info
in lib/msf/ui/console/command_dispatcher/core.rb
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 495 def cmd_info(*args) return unless msf_loaded? if args.length != 1 print_error 'Usage: info <module>' return end module_name = args.shift mod = client.framework.modules.create(module_name); if mod.nil? print_error 'Invalid module: ' << module_name end if (mod) print_line ::Msf::Serializer::ReadableText.dump_module(mod) end end |
#cmd_info_tabs(*args) ⇒ Object
515 516 517 518 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 515 def cmd_info_tabs(*args) return unless msf_loaded? tab_complete_postmods end |
#cmd_interact(*args) ⇒ Object
Interacts with a channel.
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 186 def cmd_interact(*args) if (args.length == 0) print_line( "Usage: interact channel_id\n\n" + "Interacts with the supplied channel.") return true end cid = args[0].to_i channel = client.find_channel(cid) if (channel) print_line("Interacting with channel #{cid}...\n") shell.interact_with_channel(channel) else print_error("Invalid channel identifier specified.") end end |
#cmd_irb(*args) ⇒ Object
Runs the IRB scripting shell
209 210 211 212 213 214 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 209 def cmd_irb(*args) print_status("Starting IRB shell") print_status("The 'client' variable holds the meterpreter client\n") Rex::Ui::Text::IrbShell.new(binding).run end |
#cmd_migrate(*args) ⇒ Object
Migrates the server to the supplied process identifier.
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 219 def cmd_migrate(*args) if (args.length == 0) print_line( "Usage: migrate pid\n\n" + "Migrates the server instance to another process.\n" + "Note: Any open channels or other dynamic state will be lost.") return true end pid = args[0].to_i if(pid == 0) print_error("A process ID must be specified, not a process name") return end print_status("Migrating to #{pid}...") # Do this thang. client.core.migrate(pid) print_status("Migration completed successfully.") end |
#cmd_read(*args) ⇒ Object
Reads data from a channel.
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 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 318 def cmd_read(*args) if (args.length == 0) print_line( "Usage: read channel_id [length]\n\n" + "Reads data from the supplied channel.") return true end cid = args[0].to_i length = (args.length >= 2) ? args[1].to_i : 16384 channel = client.find_channel(cid) if (!channel) print_error("Channel #{cid} is not valid.") return true end data = channel.read(length) if (data and data.length) print("Read #{data.length} bytes from #{cid}:\n\n#{data}\n") else print_error("No data was returned.") end return true end |
#cmd_resource(*args) ⇒ Object
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 608 def cmd_resource(*args) if args.empty? print( "Usage: resource path1 path2" + "Run the commands stored in the supplied files.\n") return false end args.each do |glob| files = ::Dir.glob(::File.(glob)) if files.empty? print_error("No such file #{glob}") next end files.each do |filename| print_status("Reading #{filename}") if (not ::File.readable?(filename)) print_error("Could not read file #{filename}") next else ::File.open(filename, "r").each_line do |line| next if line.strip.length < 1 next if line[0,1] == "#" begin print_status("Running #{line}") client.console.run_single(line) rescue ::Exception => e print_error("Error Running Command #{line}: #{e.class} #{e}") end end end end end end |
#cmd_resource_tabs(str, words) ⇒ Object
602 603 604 605 606 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 602 def cmd_resource_tabs(str, words) return [] if words.length > 1 tab_complete_filenames(str, words) end |
#cmd_run(*args) ⇒ Object
Executes a script in the context of the meterpreter session.
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 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 358 def cmd_run(*args) if args.length == 0 cmd_run_help return true end # Get the script name begin script_name = args.shift # First try it as a Post module if we have access to the Metasploit # Framework instance. If we don't, or if no such module exists, # fall back to using the scripting interface. if (msf_loaded? and mod = client.framework.modules.create(script_name)) omod = mod mod = client.framework.modules.reload_module(mod) if (not mod) print_error("Failed to reload module: #{client.framework.modules.failed[omod.file_path]}") return end opts = (args + [ "SESSION=#{client.sid}" ]).join(',') mod.run_simple( #'RunAsJob' => true, 'LocalInput' => shell.input, 'LocalOutput' => shell.output, 'OptionStr' => opts ) else # the rest of the arguments get passed in through the binding client.execute_script(script_name, args) end rescue print_error("Error in script: #{$!.class} #{$!}") elog("Error in script: #{$!.class} #{$!}") dlog("Callstack: #{$@.join("\n")}") end end |
#cmd_run_help ⇒ Object
346 347 348 349 350 351 352 353 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 346 def cmd_run_help print_line "Usage: run <script> [arguments]" print_line print_line "Executes a ruby script or Metasploit Post module in the context of the" print_line "meterpreter session. Post modules can take arguments in var=val format." print_line "Example: run post/foo/bar BAZ=abcd" print_line end |
#cmd_run_tabs(str, words) ⇒ Object
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 395 def cmd_run_tabs(str, words) tabs = [] if(not words[1] or not words[1].match(/^\//)) begin if (msf_loaded?) tabs += tab_complete_postmods end [ ::Msf::Sessions::Meterpreter.script_base, ::Msf::Sessions::Meterpreter.user_script_base ].each do |dir| next if not ::File.exist? dir tabs += ::Dir.new(dir).find_all { |e| path = dir + ::File::SEPARATOR + e ::File.file?(path) and ::File.readable?(path) } end rescue Exception end end return tabs.map { |e| e.sub(/\.rb$/, '') } end |
#cmd_use(*args) ⇒ Object
Loads one or more meterpreter extensions.
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 298 299 300 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 245 def cmd_use(*args) if (args.length == 0) args.unshift("-h") end modules = nil @@use_opts.parse(args) { |opt, idx, val| case opt when "-l" exts = [] path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter') ::Dir.entries(path).each { |f| if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ ) exts.push($1) end } print(exts.sort.join("\n") + "\n") return true when "-h" print( "Usage: use ext1 ext2 ext3 ...\n\n" + "Loads a meterpreter extension module or modules.\n" + @@use_opts.usage) return true end } # Load each of the modules args.each { |m| md = m.downcase if (extensions.include?(md)) print_error("The '#{md}' extension has already been loaded.") next end print("Loading extension #{md}...") begin # Use the remote side, then load the client-side if (client.core.use(md) == true) add_extension_client(md) end rescue print_line log_error("Failed to load extension: #{$!}") next end print_line("success.") } return true end |
#cmd_use_tabs(str, words) ⇒ Object
302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 302 def cmd_use_tabs(str, words) tabs = [] path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter') ::Dir.entries(path).each { |f| if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ ) if (not extensions.include?($1)) tabs.push($1) end end } return tabs end |
#cmd_write(*args) ⇒ Object
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 527 def cmd_write(*args) if (args.length == 0) args.unshift("-h") end src_file = nil cid = nil @@write_opts.parse(args) { |opt, idx, val| case opt when "-h" print( "Usage: write [options] channel_id\n\n" + "Writes data to the supplied channel.\n" + @@write_opts.usage) return true when "-f" src_file = val else cid = val.to_i end } # Find the channel associated with this cid, assuming the cid is valid. if ((!cid) or (!(channel = client.find_channel(cid)))) print_error("Invalid channel identifier specified.") return true end # If they supplied a source file, read in its contents and write it to # the channel if (src_file) begin data = '' ::File.open(src_file, 'rb') { |f| data = f.read(f.stat.size) } rescue Errno::ENOENT print_error("Invalid source file specified: #{src_file}") return true end if (data and data.length > 0) channel.write(data) print_status("Wrote #{data.length} bytes to channel #{cid}.") else print_error("No data to send from file #{src_file}") return true end # Otherwise, read from the input descriptor until we're good to go. else print("Enter data followed by a '.' on an empty line:\n\n") data = '' # Keep truckin' while (s = shell.input.gets) break if (s =~ /^\.\r?\n?$/) data += s end if (!data or data.length == 0) print_error("No data to send.") else channel.write(data) print_status("Wrote #{data.length} bytes to channel #{cid}.") end end return true end |
#commands ⇒ Object
List of supported commands.
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 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 53 def commands c = { "?" => "Help menu", "background" => "Backgrounds the current session", "close" => "Closes a channel", "channel" => "Displays information about active channels", "exit" => "Terminate the meterpreter session", "help" => "Help menu", "interact" => "Interacts with a channel", "irb" => "Drop into irb scripting mode", "migrate" => "Migrate the server to another process", "use" => "Load a one or more meterpreter extensions", "quit" => "Terminate the meterpreter session", "resource" => "Run the commands stored in a file", "read" => "Reads data from a channel", "run" => "Executes a meterpreter script or Post module", "bgrun" => "Executes a meterpreter script as a background thread", "bgkill" => "Kills a background meterpreter script", "bglist" => "Lists running background scripts", "write" => "Writes data to a channel", } if (msf_loaded?) c["info"] = "Displays information about a Post module" end c end |
#msf_loaded? ⇒ Boolean
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 33 def msf_loaded? return @msf_loaded unless @msf_loaded.nil? # if we get here we must not have initialized yet if client.framework # We have a framework instance so the msf libraries should be # available. Load up the ones we're going to use require 'msf/base/serializer/readable_text' end @msf_loaded = !!(client.framework) @msf_loaded end |
#name ⇒ Object
Core baby.
84 85 86 |
# File 'lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb', line 84 def name "Core" end |