workin on integrating meterp client

git-svn-id: file:///home/svn/incoming/trunk@2790 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Matt Miller 2005-07-18 04:07:56 +00:00
parent 98244e5000
commit 7f8db62b9c
13 changed files with 360 additions and 113 deletions

View File

@ -0,0 +1,86 @@
require 'msf/base'
require 'rex/post/meterpreter'
module Msf
module Sessions
###
#
# Meterpreter
# -----------
#
# This class represents a session compatible interface to a meterpreter server
# instance running on a remote machine. It provides the means of interacting
# with the server instance both at an API level as well as at a console level.
#
###
class Meterpreter < Rex::Post::Meterpreter::Client
#
# The meterpreter session is interactive
#
include Msf::Session
include Msf::Session::Interactive
def initialize(rstream)
super
#
# Create the console instance
#
self.console = Rex::Post::Meterpreter::Ui::Console.new
end
##
#
# Msf::Session overrides
#
##
def desc
"Meterpreter"
end
def type
"meterpreter"
end
##
#
# Msf::Session::Interactive implementors
#
##
#
# Initializes the console's I/O handles
#
def init_ui(input, output)
console.init_ui(user_input, user_output)
end
#
# Resets the console's I/O handles
#
def reset_ui
console.reset_ui
end
#
# Interacts with the meterpreter client at a user interface level
#
def _interact
# Call the console interaction subsystem of the meterpreter client and
# pass it a block that returns whether or not we should still be
# interacting. This will allow the shell to abort if interaction is
# canceled.
console.interact { self.interacting }
end
protected
attr_accessor :rstream, :console
end
end
end

View File

@ -347,12 +347,19 @@ protected
# two
if (info[name].kind_of?(Array) == false)
curr = info[name]
info[name] = [ curr, val ] if (val != curr)
# Otherwise, just append this item to the array entry
else
if (info[name].include?(val) == false)
info[name] << val
end
info[name] = [ curr ]
end
# If the value being merged is an array, add each one
if (val.kind_of?(Array) == true)
val.each { |v|
if (info[name].include?(v) == false)
info[name] << v
end
}
# Otherwise just add the value
elsif (info[name].include?(val) == false)
info[name] << val
end
# Otherwise, just set the value equal if no current value
# exists

View File

@ -15,13 +15,6 @@ module Basic
include Session
include Interactive
#
# Initialize's the raw session
#
def initialize(rstream)
self.rstream = rstream
end
#
# Returns that, yes, indeed, this session supports going interactive with
# the user.
@ -44,79 +37,6 @@ module Basic
"basic"
end
#
# Returns the local information
#
def tunnel_local
rstream.localinfo
end
#
# Returns the remote peer information
#
def tunnel_peer
rstream.peerinfo
end
#
# Closes rstream.
#
def cleanup
rstream.close if (rstream)
rstream = nil
end
#
# Starts interacting with the session at the most raw level, simply
# forwarding input from user_input to rstream and forwarding input from
# rstream to user_output.
#
def interact
# Call the parent in case it has some work to do
super
eof = false
# Handle suspend notifications
handle_suspend
callcc { |ctx|
# As long as we're interacting...
while (self.interacting == true)
begin
_interact
# If we get an interrupt exception, ask the user if they want to
# abort the interaction. If they do, then we return out of
# the interact function and call it a day.
rescue Interrupt
if (user_want_abort? == true)
eof = true
ctx.call
end
rescue EOFError
dlog("Session #{name} got EOF, closing.", 'core', LEV_1)
eof = true
ctx.call
end
end
}
# Restore the suspend handler
restore_suspend
# If we hit end-of-file, then that means we should finish off this
# session and call it a day.
framework.sessions.deregister(self) if (eof == true)
# Return whether or not EOF was reached
return eof
end
#
# The remote stream handle. Must inherit from Rex::IO::Stream.
#
attr_accessor :rstream
protected
#

View File

@ -18,6 +18,13 @@ module Interactive
#
include Rex::Ui::Subscriber
#
# Initialize's the session
#
def initialize(rstream)
self.rstream = rstream
end
#
# Returns that, yes, indeed, this session supports going interactive with
# the user.
@ -27,12 +34,77 @@ module Interactive
end
#
# Starts interacting with the session.
# Returns the local information
#
def tunnel_local
rstream.localinfo
end
#
# Returns the remote peer information
#
def tunnel_peer
rstream.peerinfo
end
#
# Closes rstream.
#
def cleanup
rstream.close if (rstream)
rstream = nil
end
#
# Starts interacting with the session at the most raw level, simply
# forwarding input from user_input to rstream and forwarding input from
# rstream to user_output.
#
def interact
self.interacting = true
eof = false
# Handle suspend notifications
handle_suspend
callcc { |ctx|
# As long as we're interacting...
while (self.interacting == true)
begin
_interact
# If we get an interrupt exception, ask the user if they want to
# abort the interaction. If they do, then we return out of
# the interact function and call it a day.
rescue Interrupt
if (user_want_abort? == true)
eof = true
ctx.call
end
# If we reach EOF or the connection is reset...
rescue EOFError, Errno::ECONNRESET
dlog("Session #{name} got EOF, closing.", 'core', LEV_1)
eof = true
ctx.call
end
end
}
# Restore the suspend handler
restore_suspend
# If we hit end-of-file, then that means we should finish off this
# session and call it a day.
framework.sessions.deregister(self) if (eof == true)
# Return whether or not EOF was reached
return eof
end
#
# The remote stream handle. Must inherit from Rex::IO::Stream.
#
attr_accessor :rstream
#
# Whether or not the session is currently being interacted with
#
@ -46,6 +118,12 @@ protected
#
attr_accessor :orig_suspend
#
# Stub method that is meant to handler interaction
#
def _interact
end
#
# Checks to see if the user wants to abort
#

View File

@ -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, driver.output)
session.init_ui(driver.input.dup, driver.output.dup)
# Interact
session.interact()

View File

@ -0,0 +1,60 @@
require 'rex/ui'
require 'rex/post/meterpreter'
module Rex
module Post
###
#
# Console
# -------
#
# This class provides a shell driven interface to the meterpreter client API.
#
###
class Meterpreter::Console
def initialize
# Initialize the pseudo-shell
shell = Rex::Ui::Text::Shell.new("%bmeterpreter%c ")
# 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
end
#
# Called when someone wants to interact with the meterpreter client. It's
# assumed that init_ui has been called prior.
#
def interact(&block)
shell.run { |line, args|
#
# If a block was supplied, call it, otherwise return false
if (block)
block.call
else
false
end
}
end
end
end
end

View File

@ -16,6 +16,7 @@ class Output::Stdio < Rex::Ui::Text::Output
def print(msg = '')
$stdout.print(msg)
$stdout.flush
end
end

View File

@ -34,23 +34,6 @@ module Shell
end
def initialize(prompt, prompt_char = '>')
# Initialize the input and output methods
self.input = Input::Stdio.new
self.output = Output::Stdio.new
begin
self.input = Input::Readline.new(lambda { |str| tab_complete(str) })
rescue
end
# Extend the input medium as an input shell if the input medium
# isn't intrinsicly a shell.
if (self.input.intrinsic_shell? == false)
self.input.extend(InputShell)
end
self.input.output = self.output
# Set the stop flag to false
self.stop_flag = false
self.disable_output = false
@ -58,10 +41,44 @@ module Shell
# Initialize the prompt
self.init_prompt = prompt
self.prompt_char = prompt_char
# Initialize the user interface handles
init_ui(Input::Stdio.new, Output::Stdio.new)
end
#
# Initializes the user interface input/output classes.
#
def init_ui(in_input = nil, in_output = nil)
# Initialize the input and output methods
self.input = in_input
self.output = in_output
if (self.input)
begin
self.input = Input::Readline.new(lambda { |str| tab_complete(str) })
rescue
end
# Extend the input medium as an input shell if the input medium
# isn't intrinsicly a shell.
if (self.input.intrinsic_shell? == false)
self.input.extend(InputShell)
end
self.input.output = self.output
end
update_prompt
end
#
# Resets the user interface
#
def reset_ui
init_ui
end
#
# Performs tab completion on the supplied string
#
@ -72,12 +89,21 @@ module Shell
#
# Run the command processing loop
#
def run
def run(&block)
stop_flag = false
while ((line = input.pgets))
run_single(line)
# 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)))
# Otherwise, call what should be an overriden instance method to
# process the line.
else
run_single(line)
end
# If the stop flag was set or we've hit EOF, break out
break if (input.eof? or self.stop_flag)
end
end
@ -115,7 +141,7 @@ module Shell
new_prompt.gsub!(/%dwhi/, colorize('dark', 'white'))
new_prompt.gsub!(/%dmag/, colorize('dark', 'magenta'))
self.input.prompt = new_prompt
self.input.prompt = new_prompt if (self.input)
self.prompt_char = new_prompt_char if (new_prompt_char)
end

View File

@ -17,7 +17,7 @@ class Exploits::Test::Multi::Aggressive < Msf::Exploit::Remote
{
'Space' => 1000,
'MaxNops' => 0,
# 'BadChars' => "\x00",
'BadChars' => "\x00",
},
'Targets' =>
[

View File

@ -20,6 +20,7 @@ module Shell
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseTcp,
'Session' => Msf::Sessions::CommandShell,
'Payload' =>
{
'Offsets' =>

View File

@ -184,12 +184,26 @@ module DllInject
register_options(
[
OptPath.new('DLL', [ true, "The local path to the DLL to upload" ]),
], Msf::Payloads::Stages::Windows::DllInject)
], DllInject)
register_advanced_options(
[
OptString.new('LibraryName', [ false, "The symbolic name of the library to upload", "msf.dll" ])
], Msf::Payloads::Stages::Windows::DllInject)
], DllInject)
end
#
# Returns the library name
#
def library_name
datastore['LibraryName'] || 'msf.dll'
end
#
# Returns the library path
#
def library_path
datastore['DLL']
end
#
@ -200,14 +214,15 @@ module DllInject
# Call the parent so that the stage gets sent
super
data = (datastore['LibraryName'] || 'msf.dll') + "\x00"
data = library_name + "\x00"
begin
data += IO.readlines(datastore['DLL']).join
data += IO.readlines(library_path).join
rescue
print_error("Failed to load DLL: #{$!}.")
# TODO: exception
conn.close
return
end

View File

@ -0,0 +1,52 @@
require 'msf/core'
require 'msf/base/sessions/meterpreter'
module Msf
module Payloads
module Stages
module Windows
###
#
# Meterpreter
# -----------
#
# Injects the meterpreter server instance DLL.
#
###
module Meterpreter
include DllInject
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows Meterpreter',
'Version' => '$Revision$',
'Description' => 'Inject the meterpreter server DLL',
'Author' => 'skape',
'Session' => Msf::Sessions::Meterpreter))
sep = File::SEPARATOR
# Override the DLL path with the path to the meterpreter server DLL
register_options(
[
OptPath.new('DLL',
[
true,
"The local path to the DLL to upload",
Msf::Config.install_root + "#{sep}data#{sep}meterpreter#{sep}metsrv.dll"
]),
], Meterpreter)
# Don't let people set the library name option
options.remove_option('LibraryName')
end
def library_name
"metsrv.dll"
end
end
end end end end

View File

@ -17,6 +17,7 @@ module Shell
'Author' => 'hdm',
'Platform' => 'win',
'Arch' => ARCH_X86,
'Session' => Msf::Sessions::CommandShell,
'Stage' =>
{
'Offsets' =>