session logging support

git-svn-id: file:///home/svn/incoming/trunk@2938 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
Matt Miller 2005-10-02 03:21:26 +00:00
parent fd38a7e39f
commit db40a55547
11 changed files with 198 additions and 16 deletions

View File

@ -26,8 +26,8 @@ X - meta information
X - stager/stage calling conventions
X - stack requirements
X - make payload prepend target specific
- sessions
- logging session activity
X - sessions
X - logging session activity
- handler sharing
- exploits using the same payload/handler can share (ref count)
- modules needing ports (above other modules)

View File

@ -27,12 +27,61 @@ class Logging
[
'rex',
'core',
'base',
].each { |src|
register_log_source(src, f)
}
end
end
#
# Enables a log source.
#
def self.enable_log_source(src)
f = Rex::Logging::Sinks::Flatfile.new(
Msf::Config.log_directory + File::SEPARATOR + "#{src}.log")
register_log_source(src, f)
end
#
# Stops logging for a given log source.
#
def self.disable_log_source(src)
deregister_log_source(src)
end
#
# Sets whether or not session logging is to be enabled.
#
def self.enable_session_logging(tf)
@session_logging = tf
end
#
# Returns whether or not session logging is enabled.
#
def self.session_logging_enabled?
@session_logging || false
end
#
# Starts logging for a given session.
#
def self.start_session_log(session)
f = Rex::Logging::Sinks::Flatfile.new(
Msf::Config.session_log_directory + File::SEPARATOR + "#{session.log_file_name}.log")
register_log_source(session.log_source, f)
end
#
# Stops logging for a given session.
#
def self.stop_session_log(session)
deregister_log_source(session.log_source)
end
end
end

View File

@ -66,12 +66,14 @@ class Meterpreter < Rex::Post::Meterpreter::Client
#
def init_ui(input, output)
console.init_ui(input, output)
console.set_log_source(log_source)
end
#
# Resets the console's I/O handles
#
def reset_ui
console.unset_log_source
console.reset_ui
end

View File

@ -104,6 +104,38 @@ module Session
"#{(tunnel_local || '??').to_s} -> #{(tunnel_peer || '??').to_s}"
end
##
#
# Logging
#
##
#
# Returns the suggested name of the log file for this session.
#
def log_file_name
dt = Time.now
dstr = sprintf("%.4d%.2d%.2d", dt.year, dt.mon, dt.mday)
("#{dstr}_" + tunnel_to_s + "_#{name.to_s}_#{(type || 'unknown').downcase}").gsub(/\s/, '_').gsub(/->/, 'to')
end
#
# Returns the log source that should be used for this session.
#
def log_source
"session_#{name.to_s}"
end
def log_from_remote(buf)
rlog(buf, log_source)
end
def log_from_local(buf)
rlog(buf, log_source)
end
##
#
# Core interface

View File

@ -354,7 +354,7 @@ class Core
value = args[1]
# If the driver indicates that the value is not valid, bust out.
if (driver.on_variable_set(name, value) == false)
if (driver.on_variable_set(global, name, value) == false)
print_error("The value specified for #{name} is not valid.")
return true
end
@ -446,7 +446,7 @@ class Core
end
while ((val = args.shift))
if (driver.on_variable_unset(val) == false)
if (driver.on_variable_unset(global, val) == false)
print_error("The variable #{val} cannot be unset at this time.")
next
end

View File

@ -21,6 +21,7 @@ module Console
###
class Driver < Msf::Ui::Driver
ConfigCore = "framework/core"
ConfigGroup = "framework/ui/console"
#
@ -47,11 +48,17 @@ class Driver < Msf::Ui::Driver
# Register event handlers
register_event_handlers
# Process things before we actually display the prompt and get rocking
on_startup
# Temporarily disable output
self.disable_output = true
# Load console-specific configuration
load_config
# Re-enable output
self.disable_output = false
# Process things before we actually display the prompt and get rocking
on_startup
# Process the resource script
process_rc_file
@ -71,12 +78,21 @@ class Driver < Msf::Ui::Driver
# If we have configuration, process it
if (conf.group?(ConfigGroup))
conf[ConfigGroup].each_pair { |k, v|
case k
when "ActiveModule"
case k.downcase
when "activemodule"
run_single("use #{v}")
end
}
end
if (conf.group?(ConfigCore))
conf[ConfigCore].each_pair { |k, v|
case k.downcase
when "sessionlogging"
handle_session_logging(v)
end
}
end
end
#
@ -125,12 +141,14 @@ class Driver < Msf::Ui::Driver
# some other kind of task. If this routine returns false it will indicate
# that the variable is not being set to a valid value.
#
def on_variable_set(var, val)
def on_variable_set(glob, var, val)
case var.downcase
when "payload"
if (framework.modules.valid?(val) == false)
return false
end
when "sessionlogging"
handle_session_logging(val) if (glob)
end
end
@ -138,7 +156,11 @@ class Driver < Msf::Ui::Driver
# Called when a variable is unset. If this routine returns false it is an
# indication that the variable should not be allowed to be unset.
#
def on_variable_unset(var)
def on_variable_unset(glob, var)
case var.downcase
when "sessionlogging"
handle_session_logging('0') if (glob)
end
end
attr_reader :framework
@ -147,7 +169,25 @@ class Driver < Msf::Ui::Driver
protected
attr_writer :framework
##
#
# Handlers for various global configuration values
#
##
#
# SessionLogging
#
def handle_session_logging(val)
if (val =~ /^(yes|y|true|t|1)/i)
Msf::Logging.enable_session_logging(true)
print_line("Session logging will be enabled for future sessions.")
else
Msf::Logging.enable_session_logging(false)
print_line("Session logging will be disabled for future sessions.")
end
end
end
end

View File

@ -33,6 +33,12 @@ module FrameworkEventManager
#
def on_session_open(session)
output.print_status("#{session.desc} session #{session.name} opened (#{session.tunnel_to_s})")
if (Msf::Logging.session_logging_enabled? == true)
Msf::Logging.start_session_log(session)
output.print_status("Started logging session interaction.")
end
end
#
@ -43,6 +49,9 @@ module FrameworkEventManager
output.print_line
end
# If logging had been enabled for this session, stop it now.
Msf::Logging::stop_session_log(session)
output.print_status("#{session.desc} session #{session.name} closed.")
end

View File

@ -125,7 +125,7 @@ def register_log_source(src, sink)
$dispatcher[src] = sink
end
def deregister_log_source(src, sink)
def deregister_log_source(src)
$dispatcher.delete(src)
end

View File

@ -20,6 +20,8 @@ class Output::Buffer < Rex::Ui::Text::Output
def print(msg = '')
self.buf += msg || ''
msg
end
def reset

View File

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

View File

@ -28,7 +28,7 @@ module Shell
attr_accessor :prompt, :output
def pgets
output.print(prompt)
_print_prompt(prompt)
gets
end
end
@ -79,6 +79,20 @@ module Shell
init_ui
end
#
# Sets the log source that should be used for logging input and output.
#
def set_log_source(log_source)
self.log_source = log_source
end
#
# Unsets the log source so that logging becomes disabled.
#
def unset_log_source
set_log_source(nil)
end
#
# Performs tab completion on the supplied string
#
@ -93,6 +107,8 @@ module Shell
stop_flag = false
while ((line = input.pgets))
log_output(input.prompt)
# If a block was passed in, pass the line to it. If it returns true,
# break out of the shell loop.
if (block)
@ -177,6 +193,13 @@ module Shell
def colorize(*color)
# This check is busted atm...
#return (supports_color? == false) ? '' : Rex::Ui::Text::Color.ansi(color)
return do_colorize(*color)
end
#
# Colorize regardless of terminal support
#
def do_colorize(*color)
return Rex::Ui::Text::Color.ansi(*color)
end
@ -186,25 +209,25 @@ module Shell
def print_error(msg)
# Errors are not subject to disabled output
output.print_error(msg)
log_output(output.print_error(msg))
end
def print_status(msg)
return if (disable_output == true)
output.print_status(msg)
log_output(output.print_status(msg))
end
def print_line(msg)
return if (disable_output == true)
output.print_line(msg)
log_output(output.print_line(msg))
end
def print(msg)
return if (disable_output == true)
output.print(msg)
log_output(output.print(msg))
end
attr_accessor :disable_output
@ -216,6 +239,8 @@ protected
# Parse a line into an array of arguments
#
def parse_line(line)
log_input(line)
line.gsub!(/(\r|\n)/, '')
begin
@ -227,10 +252,31 @@ protected
return []
end
#
# Print the prompt, but do not log it.
#
def _print_prompt(prompt)
output.print(prompt)
end
#
# Writes the supplied input to the log source if one has been registered.
#
def log_input(buf)
rlog(do_colorize("red") + buf + do_colorize("clear"), log_source) if (log_source)
end
#
# Writes the supplied output to the log source if one has been registered.
#
def log_output(buf)
rlog(do_colorize("blue") + buf + do_colorize("clear"), log_source) if (log_source)
end
attr_writer :input, :output
attr_accessor :stop_flag, :init_prompt
attr_accessor :prompt_char, :tab_complete_proc
attr_accessor :log_source
end