240 lines
5.1 KiB
Ruby
240 lines
5.1 KiB
Ruby
#!/usr/bin/env ruby
|
|
|
|
require 'socket'
|
|
require 'rex/script'
|
|
require 'rex/post/meterpreter/client_core'
|
|
require 'rex/post/meterpreter/channel'
|
|
require 'rex/post/meterpreter/channel_container'
|
|
require 'rex/post/meterpreter/dependencies'
|
|
require 'rex/post/meterpreter/object_aliases'
|
|
require 'rex/post/meterpreter/packet'
|
|
require 'rex/post/meterpreter/packet_parser'
|
|
require 'rex/post/meterpreter/packet_dispatcher'
|
|
|
|
module Rex
|
|
module Post
|
|
module Meterpreter
|
|
|
|
#
|
|
# Just to get it in there...
|
|
#
|
|
module Extensions
|
|
end
|
|
|
|
###
|
|
#
|
|
# This class represents a logical meterpreter client class. This class
|
|
# provides an interface that is compatible with the Rex post-exploitation
|
|
# interface in terms of the feature set that it attempts to expose. This
|
|
# class is meant to drive a single meterpreter client session.
|
|
#
|
|
###
|
|
class Client
|
|
|
|
include Rex::Post::Meterpreter::PacketDispatcher
|
|
include Rex::Post::Meterpreter::ChannelContainer
|
|
|
|
#
|
|
# Extension name to class hash.
|
|
#
|
|
@@ext_hash = {}
|
|
|
|
#
|
|
# Checks the extension hash to see if a class has already been associated
|
|
# with the supplied extension name.
|
|
#
|
|
def self.check_ext_hash(name)
|
|
@@ext_hash[name]
|
|
end
|
|
|
|
#
|
|
# Stores the name to class association for the supplied extension name.
|
|
#
|
|
def self.set_ext_hash(name, klass)
|
|
@@ext_hash[name] = klass
|
|
end
|
|
|
|
#
|
|
# Initializes the client context with the supplied socket through
|
|
# which communication with the server will be performed.
|
|
#
|
|
def initialize(sock, to = self.class.default_timeout)
|
|
init_meterpreter(sock, to)
|
|
end
|
|
|
|
#
|
|
# Cleans up the meterpreter instance, terminating the dispatcher thread.
|
|
#
|
|
def cleanup_meterpreter
|
|
dispatcher_thread.kill if dispatcher_thread
|
|
end
|
|
|
|
#
|
|
# Initializes the meterpreter client instance
|
|
#
|
|
def init_meterpreter(sock, to = self.class.default_timeout)
|
|
self.sock = sock
|
|
self.parser = PacketParser.new
|
|
self.ext = ObjectAliases.new
|
|
self.ext_aliases = ObjectAliases.new
|
|
|
|
self.response_timeout = to
|
|
|
|
register_extension_alias('core', ClientCore.new(self))
|
|
|
|
initialize_inbound_handlers
|
|
initialize_channels
|
|
|
|
# Register the channel inbound packet handler
|
|
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
|
|
|
monitor_socket
|
|
end
|
|
|
|
#
|
|
# Loads the contents of the supplied file and executes it as a script using
|
|
# the binding context of the session
|
|
#
|
|
def execute_file(file, in_binding = nil)
|
|
client = self
|
|
|
|
Rex::Script.execute_file(file, in_binding ? in_binding : binding)
|
|
end
|
|
|
|
##
|
|
#
|
|
# Accessors
|
|
#
|
|
##
|
|
|
|
#
|
|
# Returns the default timeout that request packets will use when
|
|
# waiting for a response.
|
|
#
|
|
def Client.default_timeout
|
|
return 30
|
|
end
|
|
|
|
##
|
|
#
|
|
# Alias processor
|
|
#
|
|
##
|
|
|
|
#
|
|
# Translates unhandled methods into registered extension aliases
|
|
# if a matching extension alias exists for the supplied symbol.
|
|
#
|
|
def method_missing(symbol, *args)
|
|
self.ext_aliases.aliases[symbol.to_s]
|
|
end
|
|
|
|
##
|
|
#
|
|
# Extension registration
|
|
#
|
|
##
|
|
|
|
#
|
|
# Loads the client half of the supplied extension and initializes it as a
|
|
# registered extension that can be reached through client.ext.[extension].
|
|
#
|
|
def add_extension(name)
|
|
# Check to see if this extension has already been loaded.
|
|
if ((klass = self.class.check_ext_hash(name.downcase)) == nil)
|
|
old = Rex::Post::Meterpreter::Extensions.constants
|
|
require("rex/post/meterpreter/extensions/#{name.downcase}/#{name.downcase}")
|
|
new = Rex::Post::Meterpreter::Extensions.constants
|
|
|
|
# No new constants added?
|
|
if ((diff = new - old).empty?)
|
|
return false
|
|
end
|
|
|
|
klass = Rex::Post::Meterpreter::Extensions.const_get(diff[0]).const_get(diff[0])
|
|
|
|
# Save the module name to class association now that the code is
|
|
# loaded.
|
|
self.class.set_ext_hash(name.downcase, klass)
|
|
end
|
|
|
|
# Create a new instance of the extension
|
|
inst = klass.new(self)
|
|
|
|
self.ext.aliases[inst.name] = inst
|
|
|
|
return true
|
|
end
|
|
|
|
#
|
|
# Deregisters an extension alias of the supplied name.
|
|
#
|
|
def deregister_extension(name)
|
|
self.ext.aliases.delete(name)
|
|
end
|
|
|
|
#
|
|
# Enumerates all of the loaded extensions.
|
|
#
|
|
def each_extension(&block)
|
|
self.ext.aliases.each(block)
|
|
end
|
|
|
|
#
|
|
# Registers an aliased extension that can be referenced through
|
|
# client.name.
|
|
#
|
|
def register_extension_alias(name, ext)
|
|
self.ext_aliases.aliases[name] = ext
|
|
end
|
|
|
|
#
|
|
# Registers zero or more aliases that are provided in an array.
|
|
#
|
|
def register_extension_aliases(aliases)
|
|
aliases.each { |a|
|
|
register_extension_alias(a['name'], a['ext'])
|
|
}
|
|
end
|
|
|
|
#
|
|
# Deregisters a previously registered extension alias.
|
|
#
|
|
def deregister_extension_alias(name)
|
|
self.ext_aliases.aliases.delete(name)
|
|
end
|
|
|
|
#
|
|
# Dumps the extension tree.
|
|
#
|
|
def dump_extension_tree()
|
|
items = []
|
|
items.concat(self.ext.dump_alias_tree('client.ext'))
|
|
items.concat(self.ext_aliases.dump_alias_tree('client'))
|
|
|
|
return items.sort
|
|
end
|
|
|
|
#
|
|
# The extension alias under which all extensions can be accessed by name.
|
|
# For example:
|
|
#
|
|
# client.ext.stdapi
|
|
#
|
|
#
|
|
attr_reader :ext
|
|
#
|
|
# The socket the client is communicating over.
|
|
#
|
|
attr_reader :sock
|
|
#
|
|
# The timeout value to use when waiting for responses.
|
|
#
|
|
attr_accessor :response_timeout
|
|
protected
|
|
attr_accessor :parser, :ext_aliases # :nodoc:
|
|
attr_writer :ext, :sock # :nodoc:
|
|
end
|
|
|
|
end; end; end
|