session logging support
git-svn-id: file:///home/svn/incoming/trunk@2938 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
fd38a7e39f
commit
db40a55547
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ class Output::Buffer < Rex::Ui::Text::Output
|
|||
|
||||
def print(msg = '')
|
||||
self.buf += msg || ''
|
||||
|
||||
msg
|
||||
end
|
||||
|
||||
def reset
|
||||
|
|
|
@ -17,6 +17,8 @@ class Output::Stdio < Rex::Ui::Text::Output
|
|||
def print(msg = '')
|
||||
$stdout.print(msg)
|
||||
$stdout.flush
|
||||
|
||||
msg
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue