workin on integrating meterp client
git-svn-id: file:///home/svn/incoming/trunk@2790 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
98244e5000
commit
7f8db62b9c
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -16,6 +16,7 @@ class Output::Stdio < Rex::Ui::Text::Output
|
|||
|
||||
def print(msg = '')
|
||||
$stdout.print(msg)
|
||||
$stdout.flush
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class Exploits::Test::Multi::Aggressive < Msf::Exploit::Remote
|
|||
{
|
||||
'Space' => 1000,
|
||||
'MaxNops' => 0,
|
||||
# 'BadChars' => "\x00",
|
||||
'BadChars' => "\x00",
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
|
|
|
@ -20,6 +20,7 @@ module Shell
|
|||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseTcp,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'Payload' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -17,6 +17,7 @@ module Shell
|
|||
'Author' => 'hdm',
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Session' => Msf::Sessions::CommandShell,
|
||||
'Stage' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
|
|
Loading…
Reference in New Issue