2012-06-29 05:18:28 +00:00
|
|
|
# -*- coding: binary -*-
|
2010-12-27 17:56:29 +00:00
|
|
|
require 'msf/core'
|
|
|
|
require 'msf/core/module'
|
|
|
|
|
|
|
|
module Msf
|
2012-05-17 22:13:25 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# A mixin used for providing Modules with post-exploitation options and helper methods
|
|
|
|
#
|
|
|
|
module PostMixin
|
2010-12-27 17:56:29 +00:00
|
|
|
|
|
|
|
include Msf::Auxiliary::Report
|
|
|
|
|
2011-03-17 05:39:30 +00:00
|
|
|
include Msf::Module::HasActions
|
|
|
|
|
2010-12-27 17:56:29 +00:00
|
|
|
def initialize(info={})
|
|
|
|
super
|
|
|
|
|
|
|
|
register_options( [
|
|
|
|
OptInt.new('SESSION', [ true, "The session to run this module on." ])
|
|
|
|
] , Msf::Post)
|
2011-01-17 20:50:30 +00:00
|
|
|
|
|
|
|
# Default stance is active
|
|
|
|
self.passive = (info['Passive'] and info['Passive'] == true) || false
|
2010-12-27 17:56:29 +00:00
|
|
|
end
|
|
|
|
|
2011-01-06 21:28:00 +00:00
|
|
|
#
|
|
|
|
# Grabs a session object from the framework or raises OptionValidateError
|
2011-02-23 04:40:21 +00:00
|
|
|
# if one doesn't exist. Initializes user input and output on the session.
|
2011-01-06 21:28:00 +00:00
|
|
|
#
|
2010-12-27 17:56:29 +00:00
|
|
|
def setup
|
2011-02-23 04:40:21 +00:00
|
|
|
if not session
|
2010-12-27 17:56:29 +00:00
|
|
|
raise Msf::OptionValidateError.new(["SESSION"])
|
|
|
|
end
|
2012-05-17 22:13:25 +00:00
|
|
|
|
|
|
|
super
|
|
|
|
|
2011-10-12 21:34:03 +00:00
|
|
|
check_for_session_readiness() if session.type == "meterpreter"
|
2011-10-12 21:25:56 +00:00
|
|
|
|
2010-12-27 17:56:29 +00:00
|
|
|
@session.init_ui(self.user_input, self.user_output)
|
2012-05-17 22:13:25 +00:00
|
|
|
@sysinfo = nil
|
2010-12-27 17:56:29 +00:00
|
|
|
end
|
|
|
|
|
2011-11-20 01:10:08 +00:00
|
|
|
# Meterpreter sometimes needs a little bit of extra time to
|
2011-10-12 21:25:56 +00:00
|
|
|
# actually be responsive for post modules. Default tries
|
|
|
|
# and retries for 5 seconds.
|
2012-04-17 01:56:55 +00:00
|
|
|
def check_for_session_readiness(tries=6)
|
2011-10-12 21:25:56 +00:00
|
|
|
session_ready_count = 0
|
|
|
|
session_ready = false
|
|
|
|
until session.sys or session_ready_count > tries
|
|
|
|
session_ready_count += 1
|
2012-04-17 01:56:55 +00:00
|
|
|
back_off_period = (session_ready_count**2)/10.0
|
|
|
|
select(nil,nil,nil,back_off_period)
|
2011-10-12 21:25:56 +00:00
|
|
|
end
|
|
|
|
session_ready = !!session.sys
|
|
|
|
raise "Could not get a hold of the session." unless session_ready
|
|
|
|
return session_ready
|
|
|
|
end
|
|
|
|
|
2010-12-27 17:56:29 +00:00
|
|
|
#
|
|
|
|
# Default cleanup handler does nothing
|
|
|
|
#
|
|
|
|
def cleanup
|
|
|
|
end
|
|
|
|
|
2011-02-23 04:40:21 +00:00
|
|
|
#
|
|
|
|
# Return the associated session or nil if there isn't one
|
|
|
|
#
|
2010-12-27 17:56:29 +00:00
|
|
|
def session
|
2011-02-23 04:40:21 +00:00
|
|
|
# Try the cached one
|
|
|
|
return @session if @session and not session_changed?
|
|
|
|
|
|
|
|
if datastore["SESSION"]
|
|
|
|
@session = framework.sessions[datastore["SESSION"].to_i]
|
|
|
|
else
|
|
|
|
@session = nil
|
|
|
|
end
|
2010-12-27 17:56:29 +00:00
|
|
|
|
|
|
|
@session
|
|
|
|
end
|
|
|
|
|
2011-02-23 04:40:21 +00:00
|
|
|
alias :client :session
|
2010-12-27 17:56:29 +00:00
|
|
|
|
2011-11-20 01:10:08 +00:00
|
|
|
#
|
2010-12-27 17:56:29 +00:00
|
|
|
# Cached sysinfo, returns nil for non-meterpreter sessions
|
|
|
|
#
|
|
|
|
def sysinfo
|
|
|
|
begin
|
|
|
|
@sysinfo ||= session.sys.config.sysinfo
|
|
|
|
rescue NoMethodError
|
|
|
|
@sysinfo = nil
|
|
|
|
end
|
|
|
|
@sysinfo
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Can be overridden by individual modules to add new commands
|
|
|
|
#
|
|
|
|
def post_commands
|
|
|
|
{}
|
|
|
|
end
|
|
|
|
|
2011-01-17 20:50:30 +00:00
|
|
|
def passive?
|
|
|
|
self.passive
|
2010-12-27 17:56:29 +00:00
|
|
|
end
|
|
|
|
|
2011-02-23 04:40:21 +00:00
|
|
|
#
|
|
|
|
# Return a (possibly empty) list of all compatible sessions
|
|
|
|
#
|
2010-12-27 17:56:29 +00:00
|
|
|
def compatible_sessions
|
|
|
|
sessions = []
|
|
|
|
framework.sessions.each do |sid, s|
|
2011-02-23 04:40:21 +00:00
|
|
|
sessions << sid if session_compatible?(s)
|
2010-12-27 17:56:29 +00:00
|
|
|
end
|
|
|
|
sessions
|
|
|
|
end
|
2011-11-20 01:10:08 +00:00
|
|
|
|
2011-07-02 00:39:16 +00:00
|
|
|
|
2011-02-23 04:40:21 +00:00
|
|
|
#
|
|
|
|
# Return false if the given session is not compatible with this module
|
|
|
|
#
|
|
|
|
# Checks the session's type against this module's
|
|
|
|
# +module_info["SessionTypes"]+ as well as examining platform
|
|
|
|
# compatibility. +sess_or_sid+ can be a Session object, Fixnum, or String.
|
|
|
|
# In the latter cases it sould be a key in in +framework.sessions+.
|
|
|
|
#
|
|
|
|
# NOTE: because it errs on the side of compatibility, a true return value
|
|
|
|
# from this method does not guarantee the module will work with the
|
|
|
|
# session.
|
|
|
|
#
|
|
|
|
def session_compatible?(sess_or_sid)
|
|
|
|
# Normalize the argument to an actual Session
|
|
|
|
case sess_or_sid
|
|
|
|
when ::Fixnum, ::String
|
|
|
|
s = framework.sessions[sess_or_sid.to_i]
|
|
|
|
when ::Msf::Session
|
|
|
|
s = sess_or_sid
|
|
|
|
end
|
|
|
|
|
|
|
|
# Can't do anything without a session
|
|
|
|
return false if s.nil?
|
|
|
|
|
|
|
|
# Can't be compatible if it's the wrong type
|
|
|
|
if self.module_info["SessionTypes"]
|
|
|
|
return false unless self.module_info["SessionTypes"].include?(s.type)
|
|
|
|
end
|
|
|
|
|
2011-07-01 23:41:49 +00:00
|
|
|
# XXX: Special-case java and php for now. This sucks and Session
|
|
|
|
# should have a method to auto-detect the underlying platform of
|
|
|
|
# platform-independent sessions such as these.
|
|
|
|
plat = s.platform
|
|
|
|
if plat =~ /php|java/ and sysinfo and sysinfo["OS"]
|
|
|
|
plat = sysinfo["OS"]
|
|
|
|
end
|
|
|
|
|
|
|
|
# Types are okay, now check the platform. This is kind of a ghetto
|
2011-02-23 04:40:21 +00:00
|
|
|
# workaround for session platforms being ad-hoc and Platform being
|
|
|
|
# inflexible.
|
|
|
|
if self.platform and self.platform.kind_of?(Msf::Module::PlatformList)
|
|
|
|
[
|
|
|
|
# Add as necessary
|
|
|
|
"win", "linux", "osx"
|
|
|
|
].each do |name|
|
2011-07-01 23:41:49 +00:00
|
|
|
if plat =~ /#{name}/
|
2011-02-23 04:40:21 +00:00
|
|
|
p = Msf::Module::PlatformList.transform(name)
|
|
|
|
return false unless self.platform.supports? p
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elsif self.platform and self.platform.kind_of?(Msf::Module::Platform)
|
|
|
|
p_klass = Msf::Module::Platform
|
2011-07-01 23:41:49 +00:00
|
|
|
case plat.downcase
|
2011-02-23 04:40:21 +00:00
|
|
|
when /win/
|
|
|
|
return false unless self.platform.kind_of?(p_klass::Windows)
|
|
|
|
when /osx/
|
|
|
|
return false unless self.platform.kind_of?(p_klass::OSX)
|
|
|
|
when /linux/
|
|
|
|
return false unless self.platform.kind_of?(p_klass::Linux)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# If we got here, we haven't found anything that definitely
|
|
|
|
# disqualifies this session. Assume that means we can use it.
|
|
|
|
return true
|
|
|
|
end
|
2010-12-27 17:56:29 +00:00
|
|
|
|
2011-03-17 05:39:30 +00:00
|
|
|
#
|
|
|
|
# True when this module is passive, false when active
|
|
|
|
#
|
2011-01-17 20:50:30 +00:00
|
|
|
attr_reader :passive
|
2011-03-17 05:39:30 +00:00
|
|
|
|
2011-01-17 20:50:30 +00:00
|
|
|
protected
|
2011-03-17 05:39:30 +00:00
|
|
|
|
2011-01-17 20:50:30 +00:00
|
|
|
attr_writer :passive
|
2010-12-27 17:56:29 +00:00
|
|
|
|
2011-02-23 04:40:21 +00:00
|
|
|
def session_changed?
|
|
|
|
@ds_session ||= datastore["SESSION"]
|
|
|
|
|
|
|
|
if (@ds_session != datastore["SESSION"])
|
|
|
|
@ds_session = nil
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
2010-12-27 17:56:29 +00:00
|
|
|
end
|
2012-05-17 22:13:25 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# A Post-exploitation module
|
|
|
|
#
|
|
|
|
#
|
|
|
|
class Post < Msf::Module
|
|
|
|
include PostMixin
|
|
|
|
|
2012-06-06 21:55:44 +00:00
|
|
|
def setup; end
|
|
|
|
|
2012-05-17 22:13:25 +00:00
|
|
|
def type
|
|
|
|
MODULE_POST
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.type
|
|
|
|
MODULE_POST
|
|
|
|
end
|
|
|
|
|
|
|
|
#
|
|
|
|
# Create an anonymous module not tied to a file. Only useful for IRB.
|
|
|
|
#
|
|
|
|
def self.create(session)
|
|
|
|
mod = new
|
|
|
|
mod.instance_variable_set(:@session, session)
|
|
|
|
# Have to override inspect because for whatever reason, +type+ is coming
|
|
|
|
# from the wrong scope and i can't figure out how to fix it.
|
|
|
|
mod.instance_eval do
|
|
|
|
def inspect
|
|
|
|
"#<Msf::Post anonymous>"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
mod.class.refname = "anonymous"
|
|
|
|
|
|
|
|
mod
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-12-27 17:56:29 +00:00
|
|
|
end
|
|
|
|
|