more meterp action
git-svn-id: file:///home/svn/incoming/trunk@2791 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
7f8db62b9c
commit
4679586c49
|
@ -28,7 +28,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
#
|
||||
# Create the console instance
|
||||
#
|
||||
self.console = Rex::Post::Meterpreter::Ui::Console.new
|
||||
self.console = Rex::Post::Meterpreter::Ui::Console.new(self)
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -55,7 +55,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
# Initializes the console's I/O handles
|
||||
#
|
||||
def init_ui(input, output)
|
||||
console.init_ui(user_input, user_output)
|
||||
console.init_ui(input, output)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -74,6 +74,10 @@ class Meterpreter < Rex::Post::Meterpreter::Client
|
|||
# interacting. This will allow the shell to abort if interaction is
|
||||
# canceled.
|
||||
console.interact { self.interacting }
|
||||
|
||||
# If the stop flag has been set, then that means the user exited. Raise
|
||||
# the EOFError so we can drop this bitch like a bad habit.
|
||||
raise EOFError if (console.stopped? == true)
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -92,25 +92,11 @@ module Handler
|
|||
# Handles an established connection supplied in the in and out
|
||||
# handles. The handles are passed as parameters in case this
|
||||
# handler is capable of handling multiple simultaneous
|
||||
# connections. The default implementation simply creates a
|
||||
# session using the payload's session factory reference and
|
||||
# the supplied stream.
|
||||
# connections. The default behavior is to attempt to create a session for
|
||||
# the payload. This path will not be taken for mutli-staged payloads.
|
||||
#
|
||||
def handle_connection(conn)
|
||||
# If the payload we merged in with has an associated session factory,
|
||||
# allocate a new session.
|
||||
if (self.session)
|
||||
s = self.session.new(conn)
|
||||
|
||||
# Pass along the framework context
|
||||
s.framework = framework
|
||||
|
||||
# If the session is valid, register it with the framework and
|
||||
# notify any waiters we may have.
|
||||
if (s)
|
||||
register_session(s)
|
||||
end
|
||||
end
|
||||
create_session(conn)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -138,6 +124,28 @@ module Handler
|
|||
|
||||
protected
|
||||
|
||||
#
|
||||
# Creates a session, if necessary, for the connection that's been handled.
|
||||
# Sessions are only created if the payload that's been mixed in has an
|
||||
# associated session.
|
||||
#
|
||||
def create_session(conn)
|
||||
# If the payload we merged in with has an associated session factory,
|
||||
# allocate a new session.
|
||||
if (self.session)
|
||||
s = self.session.new(conn)
|
||||
|
||||
# Pass along the framework context
|
||||
s.framework = framework
|
||||
|
||||
# If the session is valid, register it with the framework and
|
||||
# notify any waiters we may have.
|
||||
if (s)
|
||||
register_session(s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Registers a session with the framework and notifies any waiters of the
|
||||
# new session.
|
||||
|
|
|
@ -53,8 +53,18 @@ module Msf::Payload::Stager
|
|||
print_status("Sending stage (#{p.length} bytes)")
|
||||
|
||||
conn.put(p)
|
||||
|
||||
super
|
||||
|
||||
# Give the stages a chance to handle the connection
|
||||
handle_connection_stage(conn)
|
||||
end
|
||||
|
||||
#
|
||||
# Called by handle_connection to allow the stage to process
|
||||
# whatever it is it needs to process. The default is to simply attempt to
|
||||
# create a session.
|
||||
#
|
||||
def handle_connection_stage(conn)
|
||||
create_session(conn)
|
||||
end
|
||||
|
||||
# Aliases
|
||||
|
|
|
@ -4,29 +4,12 @@ module Console
|
|||
|
||||
module CommandDispatcher
|
||||
|
||||
def initialize(in_driver)
|
||||
self.driver = in_driver
|
||||
self.tab_complete_items = []
|
||||
end
|
||||
include Rex::Ui::Text::DispatcherShell::CommandDispatcher
|
||||
|
||||
def print_error(msg = '')
|
||||
driver.print_error(msg)
|
||||
end
|
||||
def initialize(driver)
|
||||
super
|
||||
|
||||
def print_status(msg = '')
|
||||
driver.print_status(msg)
|
||||
end
|
||||
|
||||
def print_line(msg = '')
|
||||
driver.print_line(msg)
|
||||
end
|
||||
|
||||
def print(msg = '')
|
||||
driver.print(msg)
|
||||
end
|
||||
|
||||
def update_prompt(prompt)
|
||||
driver.update_prompt(prompt)
|
||||
self.driver = driver
|
||||
end
|
||||
|
||||
def framework
|
||||
|
@ -48,13 +31,6 @@ module CommandDispatcher
|
|||
dlog("Call stack:\n#{$@.join("\n")}", 'core', LEV_1)
|
||||
end
|
||||
|
||||
#
|
||||
# No tab completion items by default
|
||||
#
|
||||
attr_accessor :tab_complete_items
|
||||
|
||||
protected
|
||||
|
||||
attr_accessor :driver
|
||||
|
||||
end
|
||||
|
|
|
@ -271,7 +271,7 @@ class Core
|
|||
print_status("Starting interaction with #{session.name}...\n") if (quiet == false)
|
||||
|
||||
# Set the session's input and output handles
|
||||
session.init_ui(driver.input.dup, driver.output.dup)
|
||||
session.init_ui(driver.input, driver.output)
|
||||
|
||||
# Interact
|
||||
session.interact()
|
||||
|
|
|
@ -3,7 +3,6 @@ require 'msf/base'
|
|||
require 'msf/ui'
|
||||
require 'msf/ui/console/framework_event_manager'
|
||||
require 'msf/ui/console/command_dispatcher'
|
||||
require 'msf/ui/console/shell'
|
||||
require 'msf/ui/console/table'
|
||||
require 'find'
|
||||
|
||||
|
@ -32,12 +31,14 @@ class Driver < Msf::Ui::Driver
|
|||
#
|
||||
# The console driver is a command shell.
|
||||
#
|
||||
include Msf::Ui::Console::Shell
|
||||
include Rex::Ui::Text::DispatcherShell
|
||||
|
||||
def initialize(prompt = "%umsf", prompt_char = ">%c")
|
||||
# Call the parent
|
||||
super
|
||||
|
||||
# Initialize attributes
|
||||
self.framework = Msf::Simple::Framework.create
|
||||
self.dispatcher_stack = []
|
||||
self.framework = Msf::Simple::Framework.create
|
||||
|
||||
# Initialize config
|
||||
Msf::Config.init
|
||||
|
@ -46,9 +47,6 @@ class Driver < Msf::Ui::Driver
|
|||
# stack
|
||||
enstack_dispatcher(CommandDispatcher::Core)
|
||||
|
||||
# Initialize the super
|
||||
super
|
||||
|
||||
# Register event handlers
|
||||
register_event_handlers
|
||||
|
||||
|
@ -130,80 +128,12 @@ class Driver < Msf::Ui::Driver
|
|||
run_single("banner")
|
||||
end
|
||||
|
||||
#
|
||||
# Performs tab completion on shell input if supported
|
||||
#
|
||||
def tab_complete(str)
|
||||
items = []
|
||||
|
||||
# Next, try to match internal command or value completion
|
||||
# Enumerate each entry in the dispatcher stack
|
||||
dispatcher_stack.each { |dispatcher|
|
||||
# If it supports commands, query them all
|
||||
if (dispatcher.respond_to?('commands'))
|
||||
items.concat(dispatcher.commands.to_a.map { |x| x[0] })
|
||||
end
|
||||
|
||||
# If the dispatcher has custom tab completion items, use them
|
||||
items.concat(dispatcher.tab_complete_items || [])
|
||||
}
|
||||
|
||||
items.find_all { |e|
|
||||
e =~ /^#{str}/
|
||||
}
|
||||
end
|
||||
|
||||
# Run a single command line
|
||||
def run_single(line)
|
||||
arguments = parse_line(line)
|
||||
method = arguments.shift
|
||||
found = false
|
||||
|
||||
reset_color if (supports_color?)
|
||||
|
||||
if (method)
|
||||
entries = dispatcher_stack.length
|
||||
|
||||
dispatcher_stack.each { |dispatcher|
|
||||
begin
|
||||
if (dispatcher.respond_to?('cmd_' + method))
|
||||
eval("
|
||||
dispatcher.#{'cmd_' + method}(*arguments)
|
||||
found = true")
|
||||
end
|
||||
rescue
|
||||
output.print_error("Error while running command #{method}: #{$!}\n#{$@.join("\n")}\n.")
|
||||
end
|
||||
|
||||
# If the dispatcher stack changed as a result of this command,
|
||||
# break out
|
||||
break if (dispatcher_stack.length != entries)
|
||||
}
|
||||
|
||||
if (!found)
|
||||
output.print_error("Unknown command: #{method}.")
|
||||
end
|
||||
end
|
||||
|
||||
return found
|
||||
end
|
||||
|
||||
# Push a dispatcher to the front of the stack
|
||||
def enstack_dispatcher(dispatcher)
|
||||
self.dispatcher_stack.unshift(dispatcher.new(self))
|
||||
end
|
||||
|
||||
# Pop a dispatcher from the front of the stacker
|
||||
def destack_dispatcher
|
||||
self.dispatcher_stack.shift
|
||||
end
|
||||
|
||||
attr_reader :dispatcher_stack, :framework
|
||||
attr_reader :framework
|
||||
attr_accessor :active_module
|
||||
|
||||
protected
|
||||
|
||||
attr_writer :dispatcher_stack, :framework
|
||||
attr_writer :framework
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
require 'msf/ui'
|
||||
|
||||
module Msf
|
||||
module Ui
|
||||
module Console
|
||||
|
||||
###
|
||||
#
|
||||
# Shell
|
||||
# -----
|
||||
#
|
||||
# The shell class provides a command-prompt style interface in a
|
||||
# generic fashion. This wrapper is just here in case we want to do custom
|
||||
# shell extensions that don't make sense to throw in the rex shell.
|
||||
#
|
||||
###
|
||||
module Shell
|
||||
|
||||
include Rex::Ui::Text::Shell
|
||||
|
||||
end
|
||||
|
||||
end end end
|
|
@ -1,3 +1,4 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'rex/post/meterpreter/client'
|
||||
require 'rex/post/meterpreter/ui/console'
|
||||
|
|
|
@ -3,6 +3,8 @@ require 'rex/post/meterpreter'
|
|||
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
module Ui
|
||||
|
||||
###
|
||||
#
|
||||
|
@ -12,28 +14,26 @@ module Post
|
|||
# This class provides a shell driven interface to the meterpreter client API.
|
||||
#
|
||||
###
|
||||
class Meterpreter::Console
|
||||
class Console
|
||||
|
||||
def initialize
|
||||
# Initialize the pseudo-shell
|
||||
shell = Rex::Ui::Text::Shell.new("%bmeterpreter%c ")
|
||||
include Rex::Ui::Text::DispatcherShell
|
||||
|
||||
# Dispatchers
|
||||
require 'rex/post/meterpreter/ui/console/core'
|
||||
|
||||
#
|
||||
# Initialize the meterpreter console
|
||||
#
|
||||
def initialize(client)
|
||||
super("%bmeterpreter%c")
|
||||
|
||||
# The meterpreter client context
|
||||
self.client = client
|
||||
|
||||
# Point the input/output handles elsewhere
|
||||
reset_ui
|
||||
end
|
||||
|
||||
#
|
||||
# Initialize's the shells I/O handles
|
||||
#
|
||||
def init_ui(input, output)
|
||||
shell.init_ui(input, output)
|
||||
end
|
||||
|
||||
#
|
||||
# Resets the shell's I/O handles
|
||||
#
|
||||
def reset_ui
|
||||
shell.reset_ui
|
||||
enstack_dispatcher(Console::Core)
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -41,9 +41,9 @@ class Meterpreter::Console
|
|||
# assumed that init_ui has been called prior.
|
||||
#
|
||||
def interact(&block)
|
||||
shell.run { |line, args|
|
||||
|
||||
#
|
||||
run { |line|
|
||||
# Run the command
|
||||
run_single(line)
|
||||
|
||||
# If a block was supplied, call it, otherwise return false
|
||||
if (block)
|
||||
|
@ -54,7 +54,15 @@ class Meterpreter::Console
|
|||
}
|
||||
end
|
||||
|
||||
attr_reader :client
|
||||
|
||||
protected
|
||||
|
||||
attr_writer :client
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
require 'rex/parser/arguments'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module Meterpreter
|
||||
module Ui
|
||||
|
||||
###
|
||||
#
|
||||
# Core
|
||||
# ----
|
||||
#
|
||||
# Core meterpreter client commands.
|
||||
#
|
||||
###
|
||||
class Console::Core
|
||||
|
||||
include Rex::Ui::Text::DispatcherShell::CommandDispatcher
|
||||
|
||||
@@use_opts = Rex::Parser::Arguments.new(
|
||||
"-m" => [ true, "The name of the module or modules to load (Ex: stdapi)." ],
|
||||
"-h" => [ false, "Help banner." ])
|
||||
|
||||
#
|
||||
# List of supported commands
|
||||
#
|
||||
def commands
|
||||
{
|
||||
"exit" => "Terminate the meterpreter session",
|
||||
"use" => "Load a one or more meterpreter extensions",
|
||||
"quit" => "Terminate the meterpreter session",
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Terminates the meterpreter session
|
||||
#
|
||||
def cmd_exit(*args)
|
||||
shell.stop
|
||||
end
|
||||
|
||||
alias cmd_quit cmd_exit
|
||||
|
||||
#
|
||||
# Loads one or more meterpreter extensions
|
||||
#
|
||||
def cmd_use(*args)
|
||||
if (args.length == 0)
|
||||
args.unshift("-h")
|
||||
end
|
||||
|
||||
@@use_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when "-m"
|
||||
mod = val
|
||||
when "-h"
|
||||
print(
|
||||
"Usage: use [options]\n\n" +
|
||||
"Loads a meterpreter extension module or modules.\n" +
|
||||
@use_opts.usage)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,6 +10,7 @@ require 'rex/ui/progress_tracker'
|
|||
# Text-based user interfaces
|
||||
require 'rex/ui/text/input'
|
||||
require 'rex/ui/text/shell'
|
||||
require 'rex/ui/text/dispatcher_shell'
|
||||
|
||||
require 'rex/ui/text/color'
|
||||
require 'rex/ui/text/table'
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
require 'rex/ui'
|
||||
|
||||
module Rex
|
||||
module Ui
|
||||
module Text
|
||||
|
||||
###
|
||||
#
|
||||
# DispatcherShell
|
||||
# ---------------
|
||||
#
|
||||
# The dispatcher shell class is designed to provide a generic means
|
||||
# of processing various shell commands that may be located in
|
||||
# different modules or chunks of codes. These chunks are referred
|
||||
# to as command dispatchers. The only requirement for command dispatchers is
|
||||
# that they prefix every method that they wish to be mirrored as a command
|
||||
# with the cmd_ prefix.
|
||||
#
|
||||
###
|
||||
module DispatcherShell
|
||||
|
||||
###
|
||||
#
|
||||
# CommandDispatcher
|
||||
# -----------------
|
||||
#
|
||||
# Empty template base class for command dispatchers
|
||||
#
|
||||
###
|
||||
module CommandDispatcher
|
||||
|
||||
def initialize(shell)
|
||||
self.shell = shell
|
||||
self.tab_complete_items = []
|
||||
end
|
||||
|
||||
def commands
|
||||
end
|
||||
|
||||
def print_error(msg = '')
|
||||
shell.print_error(msg)
|
||||
end
|
||||
|
||||
def print_status(msg = '')
|
||||
shell.print_status(msg)
|
||||
end
|
||||
|
||||
def print_line(msg = '')
|
||||
shell.print_line(msg)
|
||||
end
|
||||
|
||||
def print(msg = '')
|
||||
shell.print(msg)
|
||||
end
|
||||
|
||||
def update_prompt(prompt)
|
||||
shell.update_prompt(prompt)
|
||||
end
|
||||
|
||||
#
|
||||
# No tab completion items by default
|
||||
#
|
||||
attr_accessor :shell, :tab_complete_items
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
# DispatcherShell derives from shell
|
||||
#
|
||||
include Shell
|
||||
|
||||
#
|
||||
# Initialize the dispatcher shell
|
||||
#
|
||||
def initialize(prompt, prompt_char = '>')
|
||||
super
|
||||
|
||||
self.dispatcher_stack = []
|
||||
end
|
||||
|
||||
#
|
||||
# Performs tab completion on shell input if supported
|
||||
#
|
||||
def tab_complete(str)
|
||||
items = []
|
||||
|
||||
# Next, try to match internal command or value completion
|
||||
# Enumerate each entry in the dispatcher stack
|
||||
dispatcher_stack.each { |dispatcher|
|
||||
# If it supports commands, query them all
|
||||
if (dispatcher.respond_to?('commands'))
|
||||
items.concat(dispatcher.commands.to_a.map { |x| x[0] })
|
||||
end
|
||||
|
||||
# If the dispatcher has custom tab completion items, use them
|
||||
items.concat(dispatcher.tab_complete_items || [])
|
||||
}
|
||||
|
||||
items.find_all { |e|
|
||||
e =~ /^#{str}/
|
||||
}
|
||||
end
|
||||
|
||||
# Run a single command line
|
||||
def run_single(line)
|
||||
arguments = parse_line(line)
|
||||
method = arguments.shift
|
||||
found = false
|
||||
|
||||
reset_color if (supports_color?)
|
||||
|
||||
if (method)
|
||||
entries = dispatcher_stack.length
|
||||
|
||||
dispatcher_stack.each { |dispatcher|
|
||||
begin
|
||||
if (dispatcher.respond_to?('cmd_' + method))
|
||||
eval("
|
||||
dispatcher.#{'cmd_' + method}(*arguments)
|
||||
found = true")
|
||||
end
|
||||
rescue
|
||||
output.print_error("Error while running command #{method}: #{$!}")
|
||||
end
|
||||
|
||||
# If the dispatcher stack changed as a result of this command,
|
||||
# break out
|
||||
break if (dispatcher_stack.length != entries)
|
||||
}
|
||||
|
||||
if (found == false)
|
||||
unknown_command(method, line)
|
||||
end
|
||||
end
|
||||
|
||||
return found
|
||||
end
|
||||
|
||||
#
|
||||
# If the command is unknown...
|
||||
#
|
||||
def unknown_command(method, line)
|
||||
output.print_error("Unknown command: #{method}.")
|
||||
end
|
||||
|
||||
# Push a dispatcher to the front of the stack
|
||||
def enstack_dispatcher(dispatcher)
|
||||
self.dispatcher_stack.unshift(dispatcher.new(self))
|
||||
end
|
||||
|
||||
# Pop a dispatcher from the front of the stacker
|
||||
def destack_dispatcher
|
||||
self.dispatcher_stack.shift
|
||||
end
|
||||
|
||||
|
||||
|
||||
attr_accessor :dispatcher_stack
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -96,7 +96,7 @@ module Shell
|
|||
# If a block was passed in, pass the line to it. If it returns true,
|
||||
# break out of the shell loop.
|
||||
if (block)
|
||||
break if (block.call(line, parse_line(line)))
|
||||
break if (block.call(line))
|
||||
# Otherwise, call what should be an overriden instance method to
|
||||
# process the line.
|
||||
else
|
||||
|
@ -115,6 +115,13 @@ module Shell
|
|||
self.stop_flag = true
|
||||
end
|
||||
|
||||
#
|
||||
# Checks to see if the shell has stopped
|
||||
#
|
||||
def stopped?
|
||||
self.stop_flag
|
||||
end
|
||||
|
||||
#
|
||||
# Change the input prompt
|
||||
#
|
||||
|
|
|
@ -210,10 +210,7 @@ module DllInject
|
|||
# Transmits the DLL injection payload and its associated DLL to the remote
|
||||
# computer so that it can be loaded into memory.
|
||||
#
|
||||
def handle_connection(conn)
|
||||
# Call the parent so that the stage gets sent
|
||||
super
|
||||
|
||||
def handle_connection_stage(conn)
|
||||
data = library_name + "\x00"
|
||||
|
||||
begin
|
||||
|
@ -226,6 +223,10 @@ module DllInject
|
|||
return
|
||||
end
|
||||
|
||||
# Give the stage a second or so, just so it doesn't try
|
||||
# to read in the DLL as part of the stage...
|
||||
Rex::ThreadSafe.sleep(1.5)
|
||||
|
||||
print_status("Uploading DLL (#{data.length} bytes)...")
|
||||
|
||||
# Send the size of the thing we're transferring
|
||||
|
@ -234,6 +235,9 @@ module DllInject
|
|||
conn.put(data)
|
||||
|
||||
print_status("Upload completed.")
|
||||
|
||||
# Call the parent so the session gets created.
|
||||
super
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue