Merge staging/great-backport to master
Conflicts: spec/lib/msf/core/module_spec.rbbug/bundler_fix
commit
1fd8fe57df
|
@ -20,17 +20,17 @@ class ReadableText
|
|||
# @return [String] formatted text output of the dump.
|
||||
def self.dump_module(mod, indent = " ")
|
||||
case mod.type
|
||||
when MODULE_PAYLOAD
|
||||
when Msf::MODULE_PAYLOAD
|
||||
return dump_payload_module(mod, indent)
|
||||
when MODULE_NOP
|
||||
when Msf::MODULE_NOP
|
||||
return dump_basic_module(mod, indent)
|
||||
when MODULE_ENCODER
|
||||
when Msf::MODULE_ENCODER
|
||||
return dump_basic_module(mod, indent)
|
||||
when MODULE_EXPLOIT
|
||||
when Msf::MODULE_EXPLOIT
|
||||
return dump_exploit_module(mod, indent)
|
||||
when MODULE_AUX
|
||||
when Msf::MODULE_AUX
|
||||
return dump_auxiliary_module(mod, indent)
|
||||
when MODULE_POST
|
||||
when Msf::MODULE_POST
|
||||
return dump_post_module(mod, indent)
|
||||
else
|
||||
return dump_generic_module(mod, indent)
|
||||
|
|
|
@ -54,12 +54,12 @@ module Framework
|
|||
|
||||
ModuleSimplifiers =
|
||||
{
|
||||
MODULE_ENCODER => Msf::Simple::Encoder,
|
||||
MODULE_EXPLOIT => Msf::Simple::Exploit,
|
||||
MODULE_NOP => Msf::Simple::Nop,
|
||||
MODULE_PAYLOAD => Msf::Simple::Payload,
|
||||
MODULE_AUX => Msf::Simple::Auxiliary,
|
||||
MODULE_POST => Msf::Simple::Post,
|
||||
Msf::MODULE_ENCODER => Msf::Simple::Encoder,
|
||||
Msf::MODULE_EXPLOIT => Msf::Simple::Exploit,
|
||||
Msf::MODULE_NOP => Msf::Simple::Nop,
|
||||
Msf::MODULE_PAYLOAD => Msf::Simple::Payload,
|
||||
Msf::MODULE_AUX => Msf::Simple::Auxiliary,
|
||||
Msf::MODULE_POST => Msf::Simple::Post,
|
||||
}
|
||||
|
||||
#
|
||||
|
|
|
@ -18,6 +18,16 @@ require 'rex'
|
|||
require 'rex/ui'
|
||||
|
||||
module Msf
|
||||
autoload :Author, 'msf/core/author'
|
||||
autoload :Platform, 'msf/core/platform'
|
||||
autoload :Reference, 'msf/core/reference'
|
||||
autoload :SiteReference, 'msf/core/site_reference'
|
||||
autoload :Target, 'msf/core/target'
|
||||
|
||||
#
|
||||
# Constants
|
||||
#
|
||||
|
||||
LogSource = "core"
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
|
||||
###
|
||||
#
|
||||
# This data type represents an author of a piece of code in either
|
||||
# the framework, a module, a script, or something entirely unrelated.
|
||||
#
|
||||
###
|
||||
class Msf::Author
|
||||
|
||||
# A hash of known author names
|
||||
Known =
|
||||
{
|
||||
'amaloteaux' => 'alex_maloteaux' + 0x40.chr + 'metasploit.com',
|
||||
'anonymous' => 'Unknown',
|
||||
'bannedit' => 'bannedit' + 0x40.chr + 'metasploit.com',
|
||||
'Carlos Perez' => 'carlos_perez' + 0x40.chr + 'darkoperator.com',
|
||||
'cazz' => 'bmc' + 0x40.chr + 'shmoo.com',
|
||||
'CG' => 'cg' + 0x40.chr + 'carnal0wnage.com',
|
||||
'ddz' => 'ddz' + 0x40.chr + 'theta44.org',
|
||||
'egypt' => 'egypt' + 0x40.chr + 'metasploit.com',
|
||||
'et' => 'et' + 0x40.chr + 'metasploit.com',
|
||||
'Christian Mehlmauer' => 'FireFart' + 0x40.chr + 'gmail.com',
|
||||
'hdm' => 'hdm' + 0x40.chr + 'metasploit.com',
|
||||
'I)ruid' => 'druid' + 0x40.chr + 'caughq.org',
|
||||
'jcran' => 'jcran' + 0x40.chr + 'metasploit.com',
|
||||
'jduck' => 'jduck' + 0x40.chr + 'metasploit.com',
|
||||
'joev' => 'joev' + 0x40.chr + 'metasploit.com',
|
||||
'juan vazquez' => 'juan.vazquez' + 0x40.chr + 'metasploit.com',
|
||||
'kf' => 'kf_list' + 0x40.chr + 'digitalmunition.com',
|
||||
'kris katterjohn' => 'katterjohn' + 0x40.chr + 'gmail.com',
|
||||
'MC' => 'mc' + 0x40.chr + 'metasploit.com',
|
||||
'Ben Campbell' => 'eat_meatballs' + 0x40.chr + 'hotmail.co.uk',
|
||||
'msmith' => 'msmith' + 0x40.chr + 'metasploit.com',
|
||||
'mubix' => 'mubix' + 0x40.chr + 'hak5.org',
|
||||
'natron' => 'natron' + 0x40.chr + 'metasploit.com',
|
||||
'optyx' => 'optyx' + 0x40.chr + 'no$email.com',
|
||||
'patrick' => 'patrick' + 0x40.chr + 'osisecurity.com.au',
|
||||
'pusscat' => 'pusscat' + 0x40.chr + 'metasploit.com',
|
||||
'Ramon de C Valle' => 'rcvalle' + 0x40.chr + 'metasploit.com',
|
||||
'sf' => 'stephen_fewer' + 0x40.chr + 'harmonysecurity.com',
|
||||
'sinn3r' => 'sinn3r' + 0x40.chr + 'metasploit.com',
|
||||
'skape' => 'mmiller' + 0x40.chr + 'hick.org',
|
||||
'skylined' => 'skylined' + 0x40.chr + 'edup.tudelft.nl',
|
||||
'spoonm' => 'spoonm' + 0x40.chr + 'no$email.com',
|
||||
'stinko' => 'vinnie' + 0x40.chr + 'metasploit.com',
|
||||
'theLightCosine' => 'theLightCosine' + 0x40.chr + 'metasploit.com',
|
||||
'todb' => 'todb' + 0x40.chr + 'metasploit.com',
|
||||
'vlad902' => 'vlad902' + 0x40.chr + 'gmail.com',
|
||||
'wvu' => 'wvu' + 0x40.chr + 'metasploit.com'
|
||||
}
|
||||
|
||||
#
|
||||
# Class method that translates a string to an instance of the Author class,
|
||||
# if it's of the right format, and returns the Author class instance
|
||||
#
|
||||
def self.from_s(str)
|
||||
instance = self.new
|
||||
|
||||
# If the serialization fails...
|
||||
if (instance.from_s(str) == false)
|
||||
return nil
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
#
|
||||
# Transforms the supplied source into an array of authors
|
||||
#
|
||||
def self.transform(src)
|
||||
Rex::Transformer.transform(src, Array, [ self ], 'Author')
|
||||
end
|
||||
|
||||
def initialize(name = nil, email = nil)
|
||||
self.name = name
|
||||
self.email = email || Known[name]
|
||||
end
|
||||
|
||||
#
|
||||
# Compares authors
|
||||
#
|
||||
def ==(tgt)
|
||||
return (tgt.to_s == to_s)
|
||||
end
|
||||
|
||||
#
|
||||
# Serialize the author object to a string in form:
|
||||
#
|
||||
# name <email>
|
||||
#
|
||||
def to_s
|
||||
str = "#{name}"
|
||||
|
||||
if (email and not email.empty?)
|
||||
str += " <#{email}>"
|
||||
end
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
#
|
||||
# Translate the author from the supplied string which may
|
||||
# have either just a name or also an email address
|
||||
#
|
||||
def from_s(str)
|
||||
|
||||
|
||||
# Supported formats:
|
||||
# known_name
|
||||
# user [at/@] host [dot/.] tld
|
||||
# Name <user [at/@] host [dot/.] tld>
|
||||
|
||||
|
||||
if ((m = str.match(/^\s*([^<]+)<([^>]+)>\s*$/)))
|
||||
self.name = m[1].sub(/<.*/, '')
|
||||
self.email = m[2].sub(/\s*\[at\]\s*/, '@').sub(/\s*\[dot\]\s*/, '.')
|
||||
else
|
||||
if (Known[str])
|
||||
self.email = Known[str]
|
||||
self.name = str
|
||||
else
|
||||
self.email = str.sub(/\s*\[at\]\s*/, '@').sub(/\s*\[dot\]\s*/, '.').gsub(/^<|>$/, '')
|
||||
m = self.email.match(/([^@]+)@/)
|
||||
self.name = m ? m[1] : nil
|
||||
if !(self.email and self.email.index('@'))
|
||||
self.name = self.email
|
||||
self.email = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.name.strip! if self.name
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# Sets the name of the author and updates the email if it's a known author.
|
||||
#
|
||||
def name=(name)
|
||||
self.email = Known[name] if (Known[name])
|
||||
@name = name
|
||||
end
|
||||
|
||||
attr_accessor :email
|
||||
attr_reader :name
|
||||
end
|
|
@ -21,14 +21,14 @@ class Auxiliary < Msf::Module
|
|||
# Returns MODULE_AUX to indicate that this is an auxiliary module.
|
||||
#
|
||||
def self.type
|
||||
MODULE_AUX
|
||||
Msf::MODULE_AUX
|
||||
end
|
||||
|
||||
#
|
||||
# Returns MODULE_AUX to indicate that this is an auxiliary module.
|
||||
#
|
||||
def type
|
||||
MODULE_AUX
|
||||
Msf::MODULE_AUX
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -162,14 +162,14 @@ class Encoder < Module
|
|||
# Returns MODULE_ENCODER to indicate that this is an encoder module.
|
||||
#
|
||||
def self.type
|
||||
return MODULE_ENCODER
|
||||
return Msf::MODULE_ENCODER
|
||||
end
|
||||
|
||||
#
|
||||
# Returns MODULE_ENCODER to indicate that this is an encoder module.
|
||||
#
|
||||
def type
|
||||
return MODULE_ENCODER
|
||||
return Msf::MODULE_ENCODER
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -621,14 +621,14 @@ class Exploit < Msf::Module
|
|||
# Returns MODULE_EXPLOIT to indicate that this is an exploit module.
|
||||
#
|
||||
def self.type
|
||||
MODULE_EXPLOIT
|
||||
Msf::MODULE_EXPLOIT
|
||||
end
|
||||
|
||||
#
|
||||
# Returns MODULE_EXPLOIT to indicate that this is an exploit module.
|
||||
#
|
||||
def type
|
||||
MODULE_EXPLOIT
|
||||
Msf::MODULE_EXPLOIT
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -69,7 +69,7 @@ class Framework
|
|||
def initialize(opts={})
|
||||
|
||||
# Allow specific module types to be loaded
|
||||
types = opts[:module_types] || MODULE_TYPES
|
||||
types = opts[:module_types] || Msf::MODULE_TYPES
|
||||
|
||||
self.threads = ThreadManager.new(self)
|
||||
self.events = EventDispatcher.new(self)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,46 @@
|
|||
module Msf::Module::Arch
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @!attribute arch
|
||||
# The array of zero or more architectures.
|
||||
attr_reader :arch
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Return whether or not the module supports the supplied architecture.
|
||||
#
|
||||
def arch?(what)
|
||||
if (what == ARCH_ANY)
|
||||
true
|
||||
else
|
||||
arch.index(what) != nil
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Return a comma separated list of supported architectures, if any.
|
||||
#
|
||||
def arch_to_s
|
||||
arch.join(", ")
|
||||
end
|
||||
|
||||
#
|
||||
# Enumerate each architecture.
|
||||
#
|
||||
def each_arch(&block)
|
||||
arch.each(&block)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
attr_writer :arch
|
||||
end
|
|
@ -1,149 +1,36 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
module Msf::Module::Author
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
###
|
||||
#
|
||||
# This data type represents an author of a piece of code in either
|
||||
# the framework, a module, a script, or something entirely unrelated.
|
||||
#
|
||||
###
|
||||
class Msf::Module::Author
|
||||
|
||||
# A hash of known author names
|
||||
Known =
|
||||
{
|
||||
'amaloteaux' => 'alex_maloteaux' + 0x40.chr + 'metasploit.com',
|
||||
'anonymous' => 'Unknown',
|
||||
'bannedit' => 'bannedit' + 0x40.chr + 'metasploit.com',
|
||||
'Carlos Perez' => 'carlos_perez' + 0x40.chr + 'darkoperator.com',
|
||||
'cazz' => 'bmc' + 0x40.chr + 'shmoo.com',
|
||||
'CG' => 'cg' + 0x40.chr + 'carnal0wnage.com',
|
||||
'ddz' => 'ddz' + 0x40.chr + 'theta44.org',
|
||||
'egypt' => 'egypt' + 0x40.chr + 'metasploit.com',
|
||||
'et' => 'et' + 0x40.chr + 'metasploit.com',
|
||||
'Christian Mehlmauer' => 'FireFart' + 0x40.chr + 'gmail.com',
|
||||
'hdm' => 'hdm' + 0x40.chr + 'metasploit.com',
|
||||
'I)ruid' => 'druid' + 0x40.chr + 'caughq.org',
|
||||
'jcran' => 'jcran' + 0x40.chr + 'metasploit.com',
|
||||
'jduck' => 'jduck' + 0x40.chr + 'metasploit.com',
|
||||
'joev' => 'joev' + 0x40.chr + 'metasploit.com',
|
||||
'juan vazquez' => 'juan.vazquez' + 0x40.chr + 'metasploit.com',
|
||||
'kf' => 'kf_list' + 0x40.chr + 'digitalmunition.com',
|
||||
'kris katterjohn' => 'katterjohn' + 0x40.chr + 'gmail.com',
|
||||
'MC' => 'mc' + 0x40.chr + 'metasploit.com',
|
||||
'Ben Campbell' => 'eat_meatballs' + 0x40.chr + 'hotmail.co.uk',
|
||||
'msmith' => 'msmith' + 0x40.chr + 'metasploit.com',
|
||||
'mubix' => 'mubix' + 0x40.chr + 'hak5.org',
|
||||
'natron' => 'natron' + 0x40.chr + 'metasploit.com',
|
||||
'optyx' => 'optyx' + 0x40.chr + 'no$email.com',
|
||||
'patrick' => 'patrick' + 0x40.chr + 'osisecurity.com.au',
|
||||
'pusscat' => 'pusscat' + 0x40.chr + 'metasploit.com',
|
||||
'Ramon de C Valle' => 'rcvalle' + 0x40.chr + 'metasploit.com',
|
||||
'sf' => 'stephen_fewer' + 0x40.chr + 'harmonysecurity.com',
|
||||
'sinn3r' => 'sinn3r' + 0x40.chr + 'metasploit.com',
|
||||
'skape' => 'mmiller' + 0x40.chr + 'hick.org',
|
||||
'skylined' => 'skylined' + 0x40.chr + 'edup.tudelft.nl',
|
||||
'spoonm' => 'spoonm' + 0x40.chr + 'no$email.com',
|
||||
'stinko' => 'vinnie' + 0x40.chr + 'metasploit.com',
|
||||
'theLightCosine' => 'theLightCosine' + 0x40.chr + 'metasploit.com',
|
||||
'todb' => 'todb' + 0x40.chr + 'metasploit.com',
|
||||
'vlad902' => 'vlad902' + 0x40.chr + 'gmail.com',
|
||||
'wvu' => 'wvu' + 0x40.chr + 'metasploit.com'
|
||||
}
|
||||
# @!attribute author
|
||||
# The array of zero or more authors.
|
||||
attr_reader :author
|
||||
|
||||
#
|
||||
# Class method that translates a string to an instance of the Author class,
|
||||
# if it's of the right format, and returns the Author class instance
|
||||
# Instance Methods
|
||||
#
|
||||
def self.from_s(str)
|
||||
instance = self.new
|
||||
|
||||
# If the serialization fails...
|
||||
if (instance.from_s(str) == false)
|
||||
return nil
|
||||
end
|
||||
|
||||
return instance
|
||||
#
|
||||
# Return a comma separated list of author for this module.
|
||||
#
|
||||
def author_to_s
|
||||
author.collect { |author| author.to_s }.join(", ")
|
||||
end
|
||||
|
||||
#
|
||||
# Transforms the supplied source into an array of authors
|
||||
# Enumerate each author.
|
||||
#
|
||||
def self.transform(src)
|
||||
Rex::Transformer.transform(src, Array, [ self ], 'Author')
|
||||
def each_author(&block)
|
||||
author.each(&block)
|
||||
end
|
||||
|
||||
def initialize(name = nil, email = nil)
|
||||
self.name = name
|
||||
self.email = email || Known[name]
|
||||
end
|
||||
protected
|
||||
|
||||
#
|
||||
# Compares authors
|
||||
# Attributes
|
||||
#
|
||||
def ==(tgt)
|
||||
return (tgt.to_s == to_s)
|
||||
end
|
||||
|
||||
#
|
||||
# Serialize the author object to a string in form:
|
||||
#
|
||||
# name <email>
|
||||
#
|
||||
def to_s
|
||||
str = "#{name}"
|
||||
|
||||
if (email and not email.empty?)
|
||||
str += " <#{email}>"
|
||||
end
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
#
|
||||
# Translate the author from the supplied string which may
|
||||
# have either just a name or also an email address
|
||||
#
|
||||
def from_s(str)
|
||||
|
||||
|
||||
# Supported formats:
|
||||
# known_name
|
||||
# user [at/@] host [dot/.] tld
|
||||
# Name <user [at/@] host [dot/.] tld>
|
||||
|
||||
|
||||
if ((m = str.match(/^\s*([^<]+)<([^>]+)>\s*$/)))
|
||||
self.name = m[1].sub(/<.*/, '')
|
||||
self.email = m[2].sub(/\s*\[at\]\s*/, '@').sub(/\s*\[dot\]\s*/, '.')
|
||||
else
|
||||
if (Known[str])
|
||||
self.email = Known[str]
|
||||
self.name = str
|
||||
else
|
||||
self.email = str.sub(/\s*\[at\]\s*/, '@').sub(/\s*\[dot\]\s*/, '.').gsub(/^<|>$/, '')
|
||||
m = self.email.match(/([^@]+)@/)
|
||||
self.name = m ? m[1] : nil
|
||||
if !(self.email and self.email.index('@'))
|
||||
self.name = self.email
|
||||
self.email = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.name.strip! if self.name
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# Sets the name of the author and updates the email if it's a known author.
|
||||
#
|
||||
def name=(name)
|
||||
self.email = Known[name] if (Known[name])
|
||||
@name = name
|
||||
end
|
||||
|
||||
attr_accessor :email
|
||||
attr_reader :name
|
||||
# @!attribute [w] author
|
||||
attr_writer :author
|
||||
end
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
module Msf::Module::Compatibility
|
||||
#
|
||||
# Returns the hash that describes this module's compatibilities.
|
||||
#
|
||||
def compat
|
||||
module_info['Compat'] || {}
|
||||
end
|
||||
|
||||
#
|
||||
# Returns whether or not this module is compatible with the supplied
|
||||
# module.
|
||||
#
|
||||
def compatible?(mod)
|
||||
ch = nil
|
||||
|
||||
# Invalid module? Shoot, we can't compare that.
|
||||
return true if (mod == nil)
|
||||
|
||||
# Determine which hash to used based on the supplied module type
|
||||
if (mod.type == Msf::MODULE_ENCODER)
|
||||
ch = self.compat['Encoder']
|
||||
elsif (mod.type == Msf::MODULE_NOP)
|
||||
ch = self.compat['Nop']
|
||||
elsif (mod.type == Msf::MODULE_PAYLOAD)
|
||||
ch = self.compat['Payload']
|
||||
if self.respond_to?("target") and self.target and self.target['Payload'] and self.target['Payload']['Compat']
|
||||
ch = ch.merge(self.target['Payload']['Compat'])
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
||||
# Enumerate each compatibility item in our hash to find out
|
||||
# if we're compatible with this sucker.
|
||||
ch.each_pair do |k,v|
|
||||
|
||||
# Get the value of the current key from the module, such as
|
||||
# the ConnectionType for a stager (ws2ord, for instance).
|
||||
mval = mod.module_info[k]
|
||||
|
||||
# Reject a filled compat item on one side, but not the other
|
||||
if (v and not mval)
|
||||
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{v}")
|
||||
return false
|
||||
end
|
||||
|
||||
# Track how many of our values matched the module
|
||||
mcnt = 0
|
||||
|
||||
# Values are whitespace separated
|
||||
sv = v.split(/\s+/)
|
||||
mv = mval.split(/\s+/)
|
||||
|
||||
sv.each do |x|
|
||||
|
||||
dlog("Checking compat [#{mod.refname} with #{self.refname}]: #{x} to #{mv.join(", ")}", 'core', LEV_3)
|
||||
|
||||
# Verify that any negate values are not matched
|
||||
if (x[0,1] == '-' and mv.include?(x[1, x.length-1]))
|
||||
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{x}, value was #{mval}", 'core', LEV_1)
|
||||
return false
|
||||
end
|
||||
|
||||
mcnt += 1 if mv.include?(x)
|
||||
end
|
||||
|
||||
# No values matched, reject this module
|
||||
if (mcnt == 0)
|
||||
dlog("Module #{mod.refname} is incompatible with #{self.refname} for #{k}: limiter was #{v}, value was #{mval}", 'core', LEV_1)
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
dlog("Module #{mod.refname} is compatible with #{self.refname}", "core", LEV_1)
|
||||
|
||||
|
||||
# If we get here, we're compatible.
|
||||
return true
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# This method initializes the module's compatibility hashes by normalizing
|
||||
# them into one single hash. As it stands, modules can define
|
||||
# compatibility in their supplied info hash through:
|
||||
#
|
||||
# Compat:: direct compat definitions
|
||||
# PayloadCompat:: payload compatibilities
|
||||
# EncoderCompat:: encoder compatibilities
|
||||
# NopCompat:: nop compatibilities
|
||||
#
|
||||
# In the end, the module specific compatibilities are merged as sub-hashes
|
||||
# of the primary Compat hash key to make checks more uniform.
|
||||
#
|
||||
def init_compat
|
||||
c = module_info['Compat']
|
||||
|
||||
if (c == nil)
|
||||
c = module_info['Compat'] = Hash.new
|
||||
end
|
||||
|
||||
# Initialize the module sub compatibilities
|
||||
c['Payload'] = Hash.new if (c['Payload'] == nil)
|
||||
c['Encoder'] = Hash.new if (c['Encoder'] == nil)
|
||||
c['Nop'] = Hash.new if (c['Nop'] == nil)
|
||||
|
||||
# Update the compat-derived module specific compatibilities from
|
||||
# the specific ones to make a uniform view of compatibilities
|
||||
c['Payload'].update(module_info['PayloadCompat'] || {})
|
||||
c['Encoder'].update(module_info['EncoderCompat'] || {})
|
||||
c['Nop'].update(module_info['NopCompat'] || {})
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
module Msf::Module::DataStore
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @attribute [r] datastore
|
||||
# The module-specific datastore instance.
|
||||
#
|
||||
# @return [Hash{String => String}]
|
||||
attr_reader :datastore
|
||||
|
||||
#
|
||||
# Imports default options into the module's datastore, optionally clearing
|
||||
# all of the values currently set in the datastore.
|
||||
#
|
||||
def import_defaults(clear_datastore = true)
|
||||
# Clear the datastore if the caller asked us to
|
||||
self.datastore.clear if clear_datastore
|
||||
|
||||
self.datastore.import_options(self.options, 'self', true)
|
||||
|
||||
# If there are default options, import their values into the datastore
|
||||
if (module_info['DefaultOptions'])
|
||||
self.datastore.import_options_from_hash(module_info['DefaultOptions'], true, 'self')
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Overrides the class' own datastore with the one supplied. This is used
|
||||
# to allow modules to share datastores, such as a payload sharing an
|
||||
# exploit module's datastore.
|
||||
#
|
||||
def share_datastore(ds)
|
||||
self.datastore = ds
|
||||
self.datastore.import_options(self.options)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_writer :datastore
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
# Constants indicating the reason for an unsuccessful module attempt
|
||||
module Msf::Module::Failure
|
||||
# The exploit settings were incorrect
|
||||
BadConfig = 'bad-config'
|
||||
|
||||
# The network service disconnected us mid-attempt
|
||||
Disconnected = 'disconnected'
|
||||
|
||||
# The application replied indication we do not have access
|
||||
NoAccess = 'no-access'
|
||||
|
||||
# No confidence in success or failure
|
||||
None = 'none'
|
||||
|
||||
# The target is not compatible with this exploit or settings
|
||||
NoTarget = 'no-target'
|
||||
|
||||
# The application endpoint or specific service was not found
|
||||
NotFound = 'not-found'
|
||||
|
||||
# The application response indicated it was not vulnerable
|
||||
NotVulnerable = 'not-vulnerable'
|
||||
|
||||
# The payload was delivered but no session was opened (AV, network, etc)
|
||||
PayloadFailed = 'payload-failed'
|
||||
|
||||
# The exploit triggered some form of timeout
|
||||
TimeoutExpired = 'timeout-expired'
|
||||
|
||||
# The application replied in an unexpected fashion
|
||||
UnexpectedReply = 'unexpected-reply'
|
||||
|
||||
# No confidence in success or failure
|
||||
Unknown = 'unknown'
|
||||
|
||||
# The network service was unreachable (connection refused, etc)
|
||||
Unreachable = 'unreachable'
|
||||
|
||||
# The exploit was interrupted by the user
|
||||
UserInterrupt = 'user-interrupt'
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
# @note {Msf::Module::ModuleInfo#name} is unrelated to {#fullname} and should instead be thought of as the title or
|
||||
# summary of the module.
|
||||
#
|
||||
# Names related to {#fullname}, such as {#fullname}, {#refname}, and {#shortname}.
|
||||
module Msf::Module::FullName
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
|
||||
# @attribute refname
|
||||
# The module's name that is assigned it it by the framework
|
||||
# or derived from the path that the module is loaded from.
|
||||
attr_accessor :refname
|
||||
|
||||
#
|
||||
# Class Methods
|
||||
#
|
||||
|
||||
def fullname
|
||||
type + '/' + refname
|
||||
end
|
||||
|
||||
def shortname
|
||||
refname.split('/').last
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Returns the module's framework full reference name. This is the
|
||||
# short name that end-users work with (refname) plus the type
|
||||
# of module prepended. Ex:
|
||||
#
|
||||
# payloads/windows/shell/reverse_tcp
|
||||
#
|
||||
def fullname
|
||||
self.class.fullname
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the module's framework reference name. This is the
|
||||
# short name that end-users work with. Ex:
|
||||
#
|
||||
# windows/shell/reverse_tcp
|
||||
#
|
||||
def refname
|
||||
self.class.refname
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the module's framework short name. This is a
|
||||
# possibly conflicting name used for things like console
|
||||
# prompts.
|
||||
#
|
||||
# reverse_tcp
|
||||
#
|
||||
def shortname
|
||||
self.class.shortname
|
||||
end
|
||||
end
|
|
@ -0,0 +1,220 @@
|
|||
module Msf::Module::ModuleInfo
|
||||
#
|
||||
# CONSTANTS
|
||||
#
|
||||
|
||||
# The list of options that support merging in an information hash.
|
||||
UpdateableOptions = [ "Name", "Description", "Alias", "PayloadCompat" ]
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Returns the module's alias, if it has one. Otherwise, the module's
|
||||
# name is returned.
|
||||
#
|
||||
def alias
|
||||
module_info['Alias']
|
||||
end
|
||||
|
||||
#
|
||||
# Return the module's description.
|
||||
#
|
||||
def description
|
||||
module_info['Description']
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the disclosure date, if known.
|
||||
#
|
||||
def disclosure_date
|
||||
date_str = Date.parse(module_info['DisclosureDate'].to_s) rescue nil
|
||||
end
|
||||
|
||||
#
|
||||
# Return the module's name from the module information hash.
|
||||
#
|
||||
def name
|
||||
module_info['Name']
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @!attribute module_info
|
||||
attr_accessor :module_info
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Register options with a specific owning class.
|
||||
#
|
||||
def info_fixups
|
||||
# Each reference should be an array consisting of two elements
|
||||
refs = module_info['References']
|
||||
if(refs and not refs.empty?)
|
||||
refs.each_index do |i|
|
||||
if !(refs[i].respond_to?('[]') and refs[i].length == 2)
|
||||
refs[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Purge invalid references
|
||||
refs.delete(nil)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Checks and merges the supplied key/value pair in the supplied hash.
|
||||
#
|
||||
def merge_check_key(info, name, val)
|
||||
if (self.respond_to?("merge_info_#{name.downcase}"))
|
||||
eval("merge_info_#{name.downcase}(info, val)")
|
||||
else
|
||||
# If the info hash already has an entry for this name
|
||||
if (info[name])
|
||||
# If it's not an array, convert it to an array and merge the
|
||||
# two
|
||||
if (info[name].kind_of?(Array) == false)
|
||||
curr = info[name]
|
||||
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
|
||||
else
|
||||
info[name] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Merges options in the info hash in a sane fashion, as some options
|
||||
# require special attention.
|
||||
#
|
||||
def merge_info(info, opts)
|
||||
opts.each_pair { |name, val|
|
||||
merge_check_key(info, name, val)
|
||||
}
|
||||
|
||||
info
|
||||
end
|
||||
|
||||
#
|
||||
# Merges advanced options.
|
||||
#
|
||||
def merge_info_advanced_options(info, val)
|
||||
merge_info_options(info, val, true, false)
|
||||
end
|
||||
|
||||
#
|
||||
# Merge aliases with an underscore delimiter.
|
||||
#
|
||||
def merge_info_alias(info, val)
|
||||
merge_info_string(info, 'Alias', val, '_')
|
||||
end
|
||||
|
||||
#
|
||||
# Merges the module description.
|
||||
#
|
||||
def merge_info_description(info, val)
|
||||
merge_info_string(info, 'Description', val, ". ", true)
|
||||
end
|
||||
|
||||
#
|
||||
# Merges advanced options.
|
||||
#
|
||||
def merge_info_evasion_options(info, val)
|
||||
merge_info_options(info, val, false, true)
|
||||
end
|
||||
|
||||
#
|
||||
# Merges the module name.
|
||||
#
|
||||
def merge_info_name(info, val)
|
||||
merge_info_string(info, 'Name', val, ', ', true)
|
||||
end
|
||||
|
||||
#
|
||||
# Merges options.
|
||||
#
|
||||
def merge_info_options(info, val, advanced = false, evasion = false)
|
||||
|
||||
key_name = ((advanced) ? 'Advanced' : (evasion) ? 'Evasion' : '') + 'Options'
|
||||
|
||||
new_cont = Msf::OptionContainer.new
|
||||
new_cont.add_options(val, advanced, evasion)
|
||||
cur_cont = Msf::OptionContainer.new
|
||||
cur_cont.add_options(info[key_name] || [], advanced, evasion)
|
||||
|
||||
new_cont.each_option { |name, option|
|
||||
next if (cur_cont.get(name))
|
||||
|
||||
info[key_name] = [] if (!info[key_name])
|
||||
info[key_name] << option
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
# Merges a given key in the info hash with a delimiter.
|
||||
#
|
||||
def merge_info_string(info, key, val, delim = ', ', inverse = false)
|
||||
if (info[key])
|
||||
if (inverse == true)
|
||||
info[key] = info[key] + delim + val
|
||||
else
|
||||
info[key] = val + delim + info[key]
|
||||
end
|
||||
else
|
||||
info[key] = val
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Merge the module version.
|
||||
#
|
||||
def merge_info_version(info, val)
|
||||
merge_info_string(info, 'Version', val)
|
||||
end
|
||||
|
||||
#
|
||||
# Updates information in the supplied info hash and merges other
|
||||
# information. This method is used to override things like Name, Version,
|
||||
# and Description without losing the ability to merge architectures,
|
||||
# platforms, and options.
|
||||
#
|
||||
def update_info(info, opts)
|
||||
opts.each_pair { |name, val|
|
||||
# If the supplied option name is one of the ones that we should
|
||||
# override by default
|
||||
if (UpdateableOptions.include?(name) == true)
|
||||
# Only if the entry is currently nil do we use our value
|
||||
if (info[name] == nil)
|
||||
info[name] = val
|
||||
end
|
||||
# Otherwise, perform the merge operation like normal
|
||||
else
|
||||
merge_check_key(info, name, val)
|
||||
end
|
||||
}
|
||||
|
||||
return info
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
module Msf::Module::ModuleStore
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
#
|
||||
# A generic hash used for passing additional information to modules
|
||||
#
|
||||
attr_accessor :module_store
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Read a value from the module store
|
||||
#
|
||||
def [](k)
|
||||
self.module_store[k]
|
||||
end
|
||||
|
||||
#
|
||||
# Store a value into the module
|
||||
#
|
||||
def []=(k,v)
|
||||
self.module_store[k] = v
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
module Msf::Module::Network
|
||||
#
|
||||
# The default communication subsystem for this module. We may need to move
|
||||
# this somewhere else.
|
||||
#
|
||||
def comm
|
||||
Rex::Socket::Comm::Local
|
||||
end
|
||||
|
||||
#
|
||||
# Indicates whether the module supports IPv6. This is true by default,
|
||||
# but certain modules require additional work to be compatible or are
|
||||
# hardcoded in terms of application support and should be skipped.
|
||||
#
|
||||
def support_ipv6?
|
||||
true
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the address of the last target host (rough estimate)
|
||||
#
|
||||
def target_host
|
||||
self.respond_to?('rhost') ? rhost : self.datastore['RHOST']
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the address of the last target port (rough estimate)
|
||||
#
|
||||
def target_port
|
||||
self.respond_to?('rport') ? rport : self.datastore['RPORT']
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
# Register, deregister, and validate {#options}.
|
||||
module Msf::Module::Options
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @attribute [r] options
|
||||
# The module-specific options.
|
||||
attr_reader :options
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# This method ensures that the options associated with this module all
|
||||
# have valid values according to each required option in the option
|
||||
# container.
|
||||
#
|
||||
def validate
|
||||
self.options.validate(self.datastore)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Removes the supplied options from the module's option container
|
||||
# and data store.
|
||||
#
|
||||
def deregister_options(*names)
|
||||
names.each { |name|
|
||||
self.options.remove_option(name)
|
||||
self.datastore.delete(name)
|
||||
}
|
||||
end
|
||||
|
||||
attr_writer :options
|
||||
|
||||
#
|
||||
# Register advanced options with a specific owning class.
|
||||
#
|
||||
def register_advanced_options(options, owner = self.class)
|
||||
self.options.add_advanced_options(options, owner)
|
||||
self.datastore.import_options(self.options, 'self', true)
|
||||
import_defaults(false)
|
||||
end
|
||||
|
||||
#
|
||||
# Register evasion options with a specific owning class.
|
||||
#
|
||||
def register_evasion_options(options, owner = self.class)
|
||||
self.options.add_evasion_options(options, owner)
|
||||
self.datastore.import_options(self.options, 'self', true)
|
||||
import_defaults(false)
|
||||
end
|
||||
|
||||
#
|
||||
# Register options with a specific owning class.
|
||||
#
|
||||
def register_options(options, owner = self.class)
|
||||
self.options.add_options(options, owner)
|
||||
self.datastore.import_options(self.options, 'self', true)
|
||||
import_defaults(false)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
module Msf::Module::Privileged
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @!attribute [r] privileged
|
||||
# Whether or not this module requires privileged access.
|
||||
attr_reader :privileged
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Returns whether or not the module requires or grants high privileges.
|
||||
#
|
||||
def privileged?
|
||||
privileged == true
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @!attribute [w] privileged
|
||||
attr_writer :priveli
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
module Msf::Module::Ranking
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
#
|
||||
# Returns this module's ranking.
|
||||
#
|
||||
def rank
|
||||
(const_defined?('Rank')) ? const_get('Rank') : Msf::NormalRanking
|
||||
end
|
||||
|
||||
#
|
||||
# Returns this module's ranking as a string for display.
|
||||
#
|
||||
def rank_to_h
|
||||
rank_to_s.gsub('Rank', '').downcase
|
||||
end
|
||||
|
||||
#
|
||||
# Returns this module's ranking as a string representation.
|
||||
#
|
||||
def rank_to_s
|
||||
Msf::RankingName[rank]
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Returns the module's rank.
|
||||
#
|
||||
def rank
|
||||
self.class.rank
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the module's rank in display format.
|
||||
#
|
||||
def rank_to_h
|
||||
self.class.rank_to_h
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the module's rank in string format.
|
||||
#
|
||||
def rank_to_s
|
||||
self.class.rank_to_s
|
||||
end
|
||||
end
|
|
@ -0,0 +1,109 @@
|
|||
module Msf::Module::Search
|
||||
#
|
||||
# This provides a standard set of search filters for every module.
|
||||
# The search terms are in the form of:
|
||||
# {
|
||||
# "text" => [ [ "include_term1", "include_term2", ...], [ "exclude_term1", "exclude_term2"], ... ],
|
||||
# "cve" => [ [ "include_term1", "include_term2", ...], [ "exclude_term1", "exclude_term2"], ... ]
|
||||
# }
|
||||
#
|
||||
# Returns true on no match, false on match
|
||||
#
|
||||
def search_filter(search_string)
|
||||
return false if not search_string
|
||||
|
||||
search_string += " "
|
||||
|
||||
# Split search terms by space, but allow quoted strings
|
||||
terms = search_string.split(/\"/).collect{|t| t.strip==t ? t : t.split(' ')}.flatten
|
||||
terms.delete('')
|
||||
|
||||
# All terms are either included or excluded
|
||||
res = {}
|
||||
|
||||
terms.each do |t|
|
||||
f,v = t.split(":", 2)
|
||||
if not v
|
||||
v = f
|
||||
f = 'text'
|
||||
end
|
||||
next if v.length == 0
|
||||
f.downcase!
|
||||
v.downcase!
|
||||
res[f] ||=[ [], [] ]
|
||||
if v[0,1] == "-"
|
||||
next if v.length == 1
|
||||
res[f][1] << v[1,v.length-1]
|
||||
else
|
||||
res[f][0] << v
|
||||
end
|
||||
end
|
||||
|
||||
k = res
|
||||
|
||||
refs = self.references.map{|x| [x.ctx_id, x.ctx_val].join("-") }
|
||||
is_server = (self.respond_to?(:stance) and self.stance == "aggressive")
|
||||
is_client = (self.respond_to?(:stance) and self.stance == "passive")
|
||||
|
||||
[0,1].each do |mode|
|
||||
match = false
|
||||
k.keys.each do |t|
|
||||
next if k[t][mode].length == 0
|
||||
|
||||
k[t][mode].each do |w|
|
||||
# Reset the match flag for each keyword for inclusive search
|
||||
match = false if mode == 0
|
||||
|
||||
# Convert into a case-insensitive regex
|
||||
r = Regexp.new(Regexp.escape(w), true)
|
||||
|
||||
case t
|
||||
when 'text'
|
||||
terms = [self.name, self.fullname, self.description] + refs + self.author.map{|x| x.to_s}
|
||||
if self.respond_to?(:targets) and self.targets
|
||||
terms = terms + self.targets.map{|x| x.name}
|
||||
end
|
||||
match = [t,w] if terms.any? { |x| x =~ r }
|
||||
when 'name'
|
||||
match = [t,w] if self.name =~ r
|
||||
when 'path'
|
||||
match = [t,w] if self.fullname =~ r
|
||||
when 'author'
|
||||
match = [t,w] if self.author.map{|x| x.to_s}.any? { |a| a =~ r }
|
||||
when 'os', 'platform'
|
||||
match = [t,w] if self.platform_to_s =~ r or self.arch_to_s =~ r
|
||||
if not match and self.respond_to?(:targets) and self.targets
|
||||
match = [t,w] if self.targets.map{|x| x.name}.any? { |t| t =~ r }
|
||||
end
|
||||
when 'port'
|
||||
match = [t,w] if self.datastore['RPORT'].to_s =~ r
|
||||
when 'type'
|
||||
match = [t,w] if Msf::MODULE_TYPES.any? { |modt| w == modt and self.type == modt }
|
||||
when 'app'
|
||||
match = [t,w] if (w == "server" and is_server)
|
||||
match = [t,w] if (w == "client" and is_client)
|
||||
when 'cve'
|
||||
match = [t,w] if refs.any? { |ref| ref =~ /^cve\-/i and ref =~ r }
|
||||
when 'bid'
|
||||
match = [t,w] if refs.any? { |ref| ref =~ /^bid\-/i and ref =~ r }
|
||||
when 'osvdb'
|
||||
match = [t,w] if refs.any? { |ref| ref =~ /^osvdb\-/i and ref =~ r }
|
||||
when 'edb'
|
||||
match = [t,w] if refs.any? { |ref| ref =~ /^edb\-/i and ref =~ r }
|
||||
end
|
||||
break if match
|
||||
end
|
||||
# Filter this module if no matches for a given keyword type
|
||||
if mode == 0 and not match
|
||||
return true
|
||||
end
|
||||
end
|
||||
# Filter this module if we matched an exclusion keyword (-value)
|
||||
if mode == 1 and match
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
module Msf::Module::Type
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
#
|
||||
# Class method to figure out what type of module this is
|
||||
#
|
||||
def type
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
#
|
||||
# Returns true if this module is an auxiliary module.
|
||||
#
|
||||
def auxiliary?
|
||||
(type == Msf::MODULE_AUX)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this module is an encoder module.
|
||||
#
|
||||
def encoder?
|
||||
(type == Msf::MODULE_ENCODER)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this module is an exploit module.
|
||||
#
|
||||
def exploit?
|
||||
(type == Msf::MODULE_EXPLOIT)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this module is a nop module.
|
||||
#
|
||||
def nop?
|
||||
(type == Msf::MODULE_NOP)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this module is a payload module.
|
||||
#
|
||||
def payload?
|
||||
(type == Msf::MODULE_PAYLOAD)
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if this module is an post-exploitation module.
|
||||
#
|
||||
def post?
|
||||
(type == Msf::MODULE_POST)
|
||||
end
|
||||
|
||||
#
|
||||
# Return the module's abstract type.
|
||||
#
|
||||
def type
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
module Msf::Module::UI
|
||||
autoload :Line, 'msf/core/module/ui/line'
|
||||
autoload :Message, 'msf/core/module/ui/message'
|
||||
|
||||
# Modules can subscribe to a user-interface, and as such they include the
|
||||
# UI subscriber module. This provides methods like print, print_line, etc.
|
||||
# User interfaces are designed to be medium independent, and as such the
|
||||
# user interface subscribes are designed to provide a flexible way of
|
||||
# interacting with the user, n stuff.
|
||||
include Rex::Ui::Subscriber
|
||||
|
||||
# Overwrite the {Rex::UI::Subscriber#print_line} to do custom prefixes
|
||||
include Msf::Module::UI::Line
|
||||
# Overwrite the {Rex::Ui::Subscriber} print_(status|error|good) to do time stamps
|
||||
include Msf::Module::UI::Message
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
module Msf::Module::UI::Line
|
||||
autoload :Verbose, 'msf/core/module/ui/line/verbose'
|
||||
|
||||
include Msf::Module::UI::Line::Verbose
|
||||
|
||||
def print_line(msg='')
|
||||
super(print_line_prefix + msg)
|
||||
end
|
||||
|
||||
def print_line_prefix
|
||||
datastore['CustomPrintPrefix'] || framework.datastore['CustomPrintPrefix'] || ''
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
module Msf::Module::UI::Line::Verbose
|
||||
# Verbose version of #print_line
|
||||
def vprint_line(msg)
|
||||
print_line(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
# Methods for print messages with status indicators
|
||||
module Msf::Module::UI::Message
|
||||
autoload :Verbose, 'msf/core/module/ui/message/verbose'
|
||||
|
||||
include Msf::Module::UI::Message::Verbose
|
||||
|
||||
def print_error(msg='')
|
||||
super(print_prefix + msg)
|
||||
end
|
||||
|
||||
def print_good(msg='')
|
||||
super(print_prefix + msg)
|
||||
end
|
||||
|
||||
def print_prefix
|
||||
ret = ''
|
||||
if (datastore['TimestampOutput'] =~ /^(t|y|1)/i) || (
|
||||
framework && framework.datastore['TimestampOutput'] =~ /^(t|y|1)/i
|
||||
)
|
||||
prefix = "[#{Time.now.strftime("%Y.%m.%d-%H:%M:%S")}] "
|
||||
|
||||
xn ||= datastore['ExploitNumber']
|
||||
xn ||= framework.datastore['ExploitNumber']
|
||||
if xn.is_a?(Fixnum)
|
||||
prefix << "[%04d] " % xn
|
||||
end
|
||||
|
||||
ret = prefix
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
def print_status(msg='')
|
||||
super(print_prefix + msg)
|
||||
end
|
||||
|
||||
def print_warning(msg='')
|
||||
super(print_prefix + msg)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
module Msf::Module::UI::Message::Verbose
|
||||
# Verbose version of #print_debug
|
||||
def vprint_debug(msg)
|
||||
print_debug(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']
|
||||
end
|
||||
|
||||
# Verbose version of #print_error
|
||||
def vprint_error(msg)
|
||||
print_error(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']
|
||||
end
|
||||
|
||||
# Verbose version of #print_good
|
||||
def vprint_good(msg)
|
||||
print_good(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']
|
||||
end
|
||||
|
||||
# Verbose version of #print_status
|
||||
def vprint_status(msg)
|
||||
print_status(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']
|
||||
end
|
||||
|
||||
# Verbose version of #print_warning
|
||||
def vprint_warning(msg)
|
||||
print_warning(msg) if datastore['VERBOSE'] || framework.datastore['VERBOSE']
|
||||
end
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
module Msf::Module::UUID
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @!attribute [r] uuid
|
||||
# A unique identifier for this module instance
|
||||
attr_reader :uuid
|
||||
|
||||
protected
|
||||
|
||||
#
|
||||
# Attributes
|
||||
#
|
||||
|
||||
# @!attribute [w] uuid
|
||||
attr_writer :uuid
|
||||
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
def generate_uuid
|
||||
self.uuid = Rex::Text.rand_text_alphanumeric(8).downcase
|
||||
end
|
||||
end
|
|
@ -14,14 +14,14 @@ class Nop < Msf::Module
|
|||
# Returns MODULE_NOP to indicate that this is a NOP module.
|
||||
#
|
||||
def self.type
|
||||
return MODULE_NOP
|
||||
return Msf::MODULE_NOP
|
||||
end
|
||||
|
||||
#
|
||||
# Returns MODULE_NOP to indicate that this is a NOP module.
|
||||
#
|
||||
def type
|
||||
return MODULE_NOP
|
||||
return Msf::MODULE_NOP
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -102,14 +102,14 @@ class Payload < Msf::Module
|
|||
# Returns MODULE_PAYLOAD to indicate that this is a payload module.
|
||||
#
|
||||
def self.type
|
||||
return MODULE_PAYLOAD
|
||||
return Msf::MODULE_PAYLOAD
|
||||
end
|
||||
|
||||
#
|
||||
# Returns MODULE_PAYLOAD to indicate that this is a payload module.
|
||||
#
|
||||
def type
|
||||
return MODULE_PAYLOAD
|
||||
return Msf::MODULE_PAYLOAD
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -21,7 +21,7 @@ class PayloadSet < ModuleSet
|
|||
# set class that has custom handling for payloads.
|
||||
#
|
||||
def initialize
|
||||
super(MODULE_PAYLOAD)
|
||||
super(Msf::MODULE_PAYLOAD)
|
||||
|
||||
# A hash of each of the payload types that holds an array
|
||||
# for all of the associated modules
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Msf::Platform = Msf::Module::Platform
|
|
@ -0,0 +1 @@
|
|||
Msf::Reference = Msf::Module::Reference
|
|
@ -0,0 +1 @@
|
|||
Msf::SiteReference = Msf::Module::SiteReference
|
|
@ -0,0 +1 @@
|
|||
Msf::Target = Msf::Module::Target
|
|
@ -2355,17 +2355,17 @@ class Core
|
|||
dispatcher = nil
|
||||
|
||||
case mod.type
|
||||
when MODULE_ENCODER
|
||||
when Msf::MODULE_ENCODER
|
||||
dispatcher = Msf::Ui::Console::CommandDispatcher::Encoder
|
||||
when MODULE_EXPLOIT
|
||||
when Msf::MODULE_EXPLOIT
|
||||
dispatcher = Msf::Ui::Console::CommandDispatcher::Exploit
|
||||
when MODULE_NOP
|
||||
when Msf::MODULE_NOP
|
||||
dispatcher = Msf::Ui::Console::CommandDispatcher::Nop
|
||||
when MODULE_PAYLOAD
|
||||
when Msf::MODULE_PAYLOAD
|
||||
dispatcher = Msf::Ui::Console::CommandDispatcher::Payload
|
||||
when MODULE_AUX
|
||||
when Msf::MODULE_AUX
|
||||
dispatcher = Msf::Ui::Console::CommandDispatcher::Auxiliary
|
||||
when MODULE_POST
|
||||
when Msf::MODULE_POST
|
||||
dispatcher = Msf::Ui::Console::CommandDispatcher::Post
|
||||
else
|
||||
print_error("Unsupported module type: #{mod.type}")
|
||||
|
|
|
@ -1,7 +1,28 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Msf::Author do
|
||||
it 'is an alias for Msf::Module::Author' do
|
||||
expect(described_class.name).to eq('Msf::Module::Author')
|
||||
context 'Known' do
|
||||
subject(:known) {
|
||||
described_class::Known
|
||||
}
|
||||
|
||||
it { is_expected.to be_a Hash }
|
||||
end
|
||||
|
||||
it { is_expected.to respond_to :== }
|
||||
it { is_expected.to respond_to :email }
|
||||
it { is_expected.to respond_to :email= }
|
||||
it { is_expected.to respond_to :from_s }
|
||||
it { is_expected.to respond_to :name }
|
||||
it { is_expected.to respond_to :name= }
|
||||
it { is_expected.to respond_to :to_s }
|
||||
|
||||
context 'class' do
|
||||
subject {
|
||||
described_class
|
||||
}
|
||||
|
||||
it { is_expected.to respond_to :from_s }
|
||||
it { is_expected.to respond_to :transform }
|
||||
end
|
||||
end
|
|
@ -1,141 +1,41 @@
|
|||
# -*- coding:binary -*-
|
||||
require 'spec_helper'
|
||||
require 'msf/core/module'
|
||||
require 'msf/core/module/platform_list'
|
||||
|
||||
shared_examples "search_filter" do |opts|
|
||||
accept = opts[:accept] || []
|
||||
reject = opts[:reject] || []
|
||||
|
||||
accept.each do |query|
|
||||
it "should accept a query containing '#{query}'" do
|
||||
# if the subject matches, search_filter returns false ("don't filter me out!")
|
||||
subject.search_filter(query).should be_falsey
|
||||
end
|
||||
|
||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||
it "should reject a query containing '-#{query}'" do
|
||||
subject.search_filter("-#{query}").should be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reject.each do |query|
|
||||
it "should reject a query containing '#{query}'" do
|
||||
# if the subject doesn't matches, search_filter returns true ("filter me out!")
|
||||
subject.search_filter(query).should be_truthy
|
||||
end
|
||||
|
||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||
it "should accept a query containing '-#{query}'" do
|
||||
subject.search_filter("-#{query}").should be_truthy # what? why?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
REF_TYPES = %w(CVE BID OSVDB EDB)
|
||||
|
||||
describe Msf::Module do
|
||||
subject(:msf_module) {
|
||||
described_class.new
|
||||
}
|
||||
|
||||
it { is_expected.to respond_to :[] }
|
||||
it { is_expected.to respond_to :[]= }
|
||||
it { is_expected.to respond_to :alias }
|
||||
it { is_expected.to respond_to :arch? }
|
||||
it { is_expected.to respond_to :arch_to_s }
|
||||
it { is_expected.to respond_to :author_to_s }
|
||||
it { is_expected.to respond_to :auxiliary? }
|
||||
it { is_expected.to respond_to :check }
|
||||
it { is_expected.to respond_to :comm }
|
||||
it { is_expected.to respond_to :compat }
|
||||
it { is_expected.to respond_to :compatible? }
|
||||
it { is_expected.to respond_to :debugging? }
|
||||
it { is_expected.to respond_to :description }
|
||||
it { is_expected.to respond_to :disclosure_date }
|
||||
it { is_expected.to respond_to :each_arch }
|
||||
it { is_expected.to respond_to :each_author }
|
||||
it { is_expected.to respond_to :encoder? }
|
||||
it { is_expected.to respond_to :exploit? }
|
||||
it { is_expected.to respond_to_protected :derived_implementor? }
|
||||
it { is_expected.to respond_to :fail_with }
|
||||
it { is_expected.to respond_to :file_path }
|
||||
it { is_expected.to respond_to :framework }
|
||||
it { is_expected.to respond_to :fullname }
|
||||
it { is_expected.to respond_to :import_defaults }
|
||||
it { is_expected.to respond_to :name }
|
||||
it { is_expected.to respond_to :nop? }
|
||||
it { is_expected.to respond_to :orig_cls }
|
||||
it { is_expected.to respond_to :owner }
|
||||
it { is_expected.to respond_to :payload? }
|
||||
it { is_expected.to respond_to :platform? }
|
||||
it { is_expected.to respond_to :platform_to_s }
|
||||
it { is_expected.to respond_to :post? }
|
||||
it { is_expected.to respond_to :print_error }
|
||||
it { is_expected.to respond_to :print_good }
|
||||
it { is_expected.to respond_to :print_line }
|
||||
it { is_expected.to respond_to :print_line_prefix }
|
||||
it { is_expected.to respond_to :print_prefix }
|
||||
it { is_expected.to respond_to :print_status }
|
||||
it { is_expected.to respond_to :print_warning }
|
||||
it { is_expected.to respond_to :privileged? }
|
||||
it { is_expected.to respond_to :rank }
|
||||
it { is_expected.to respond_to :rank_to_h }
|
||||
it { is_expected.to respond_to :rank_to_s }
|
||||
it { is_expected.to respond_to :refname }
|
||||
it { is_expected.to respond_to :register_parent }
|
||||
it { is_expected.to respond_to :replicant }
|
||||
it { is_expected.to respond_to :share_datastore }
|
||||
it { is_expected.to respond_to :shortname }
|
||||
it { is_expected.to respond_to :support_ipv6? }
|
||||
it { is_expected.to respond_to :target_host }
|
||||
it { is_expected.to respond_to :target_port }
|
||||
it { is_expected.to respond_to :type }
|
||||
it { is_expected.to respond_to :validate }
|
||||
it { is_expected.to respond_to :vprint_debug }
|
||||
it { is_expected.to respond_to :vprint_error }
|
||||
it { is_expected.to respond_to :vprint_good }
|
||||
it { is_expected.to respond_to :vprint_line }
|
||||
it { is_expected.to respond_to :vprint_status }
|
||||
it { is_expected.to respond_to :vprint_warning }
|
||||
it { is_expected.to respond_to_protected :set_defaults }
|
||||
it { is_expected.to respond_to :workspace }
|
||||
|
||||
[
|
||||
:deregister_options,
|
||||
:derived_implementor?,
|
||||
:generate_uuid,
|
||||
:info_fixups,
|
||||
:init_compat,
|
||||
:merge_check_key,
|
||||
:merge_info,
|
||||
:merge_info_advanced_options,
|
||||
:merge_info_alias,
|
||||
:merge_info_description,
|
||||
:merge_info_evasion_options,
|
||||
:merge_info_name,
|
||||
:merge_info_options,
|
||||
:merge_info_string,
|
||||
:merge_info_version,
|
||||
:register_advanced_options,
|
||||
:register_evasion_options,
|
||||
:register_options,
|
||||
:set_defaults,
|
||||
:update_info,
|
||||
|
||||
].each do |sym|
|
||||
it "should respond to protected method #{sym}" do
|
||||
expect { subject.respond_to?(sym, true) }.to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'CONSTANTS' do
|
||||
context 'UpdateableOptions' do
|
||||
subject(:updateable_options) {
|
||||
described_class::UpdateableOptions
|
||||
}
|
||||
|
||||
it { is_expected.to match_array(%w{Name Description Alias PayloadCompat})}
|
||||
end
|
||||
end
|
||||
it_should_behave_like 'Msf::Module::Arch'
|
||||
it_should_behave_like 'Msf::Module::Compatibility'
|
||||
it_should_behave_like 'Msf::Module::DataStore'
|
||||
it_should_behave_like 'Msf::Module::FullName'
|
||||
it_should_behave_like 'Msf::Module::ModuleInfo'
|
||||
it_should_behave_like 'Msf::Module::ModuleStore'
|
||||
it_should_behave_like 'Msf::Module::Network'
|
||||
it_should_behave_like 'Msf::Module::Options'
|
||||
it_should_behave_like 'Msf::Module::Privileged'
|
||||
it_should_behave_like 'Msf::Module::Ranking'
|
||||
it_should_behave_like 'Msf::Module::Search'
|
||||
it_should_behave_like 'Msf::Module::Type'
|
||||
it_should_behave_like 'Msf::Module::UI'
|
||||
it_should_behave_like 'Msf::Module::UUID'
|
||||
|
||||
context 'class' do
|
||||
subject {
|
||||
|
@ -143,146 +43,6 @@ describe Msf::Module do
|
|||
}
|
||||
|
||||
it { is_expected.to respond_to :cached? }
|
||||
it { is_expected.to respond_to :fullname }
|
||||
it { is_expected.to respond_to :is_usable }
|
||||
it { is_expected.to respond_to :rank }
|
||||
it { is_expected.to respond_to :rank_to_h }
|
||||
it { is_expected.to respond_to :rank_to_s }
|
||||
it { is_expected.to respond_to :shortname }
|
||||
it { is_expected.to respond_to :type }
|
||||
end
|
||||
|
||||
describe '#search_filter' do
|
||||
let(:opts) { Hash.new }
|
||||
before { subject.stub(:fullname => '/module') }
|
||||
subject { Msf::Module.new(opts) }
|
||||
accept = []
|
||||
reject = []
|
||||
|
||||
context 'on a blank query' do
|
||||
it_should_behave_like 'search_filter', :accept => [''], :test_inverse => false
|
||||
end
|
||||
|
||||
context 'on a client module' do
|
||||
before { subject.stub(:stance => 'passive') }
|
||||
accept = %w(app:client)
|
||||
reject = %w(app:server)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a server module' do
|
||||
before { subject.stub(:stance => 'aggressive') }
|
||||
accept = %w(app:server)
|
||||
reject = %w(app:client)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with the author "joev"' do
|
||||
let(:opts) { ({ 'Author' => ['joev'] }) }
|
||||
accept = %w(author:joev author:joe)
|
||||
reject = %w(author:unrelated)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with the authors "joev" and "blarg"' do
|
||||
let(:opts) { ({ 'Author' => ['joev', 'blarg'] }) }
|
||||
accept = %w(author:joev author:joe)
|
||||
reject = %w(author:sinn3r)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the osx platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(osx) }) }
|
||||
accept = %w(platform:osx os:osx)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the linux platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(linux) }) }
|
||||
accept = %w(platform:linux os:linux)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the windows platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(windows) }) }
|
||||
accept = %w(platform:windows os:windows)
|
||||
reject = %w(platform:bsd platform:osx platform:unix os:bsd os:osx os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the osx and linux platforms' do
|
||||
let(:opts) { ({ 'Platform' => %w(osx linux) }) }
|
||||
accept = %w(platform:osx platform:linux os:osx os:linux)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the windows and irix platforms' do
|
||||
let(:opts) { ({ 'Platform' => %w(windows irix) }) }
|
||||
accept = %w(platform:windows platform:irix os:windows os:irix)
|
||||
reject = %w(platform:bsd platform:osx platform:linux os:bsd os:osx os:linux)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with a default RPORT of 5555' do
|
||||
before { subject.stub(:datastore => { 'RPORT' => 5555 }) }
|
||||
accept = %w(port:5555)
|
||||
reject = %w(port:5556)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with a #name of "blah"' do
|
||||
let(:opts) { ({ 'Name' => 'blah' }) }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
it_should_behave_like 'search_filter', :accept => %w(name:blah), :reject => %w(name:foo)
|
||||
end
|
||||
|
||||
context 'on a module with a #fullname of "blah"' do
|
||||
before { subject.stub(:fullname => '/c/d/e/blah') }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
it_should_behave_like 'search_filter', :accept => %w(path:blah), :reject => %w(path:foo)
|
||||
end
|
||||
|
||||
context 'on a module with a #description of "blah"' do
|
||||
let(:opts) { ({ 'Description' => 'blah' }) }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
end
|
||||
|
||||
context 'when filtering by module #type' do
|
||||
all_module_types = Msf::MODULE_TYPES
|
||||
all_module_types.each do |mtype|
|
||||
context "on a #{mtype} module" do
|
||||
before(:each) { subject.stub(:type => mtype) }
|
||||
|
||||
accept = ["type:#{mtype}"]
|
||||
reject = all_module_types.reject { |t| t == mtype }.map { |t| "type:#{t}" }
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
REF_TYPES.each do |ref_type|
|
||||
ref_num = '1234-1111'
|
||||
context 'on a module with reference #{ref_type}-#{ref_num}' do
|
||||
let(:opts) { ({ 'References' => [[ref_type, ref_num]] }) }
|
||||
accept = ["#{ref_type.downcase}:#{ref_num}"]
|
||||
reject = %w(1235-1111 1234-1112 bad).map { |n| "#{ref_type.downcase}:#{n}" }
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
RSpec::Matchers.define :respond_to_protected do |method_name|
|
||||
protected_and_private = true
|
||||
|
||||
match do |receiver|
|
||||
receiver.respond_to?(method_name, protected_and_private)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
shared_examples_for 'Msf::Module::Arch' do
|
||||
it { is_expected.to respond_to :arch }
|
||||
it { is_expected.to respond_to :arch? }
|
||||
it { is_expected.to respond_to :arch_to_s }
|
||||
it { is_expected.to respond_to :each_arch }
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
shared_examples_for 'Msf::Module::Author' do
|
||||
it { is_expected.to respond_to :author }
|
||||
it { is_expected.to respond_to :author_to_s }
|
||||
it { is_expected.to respond_to :each_author }
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
shared_examples_for 'Msf::Module::Compatibility' do
|
||||
it { is_expected.to respond_to :compat }
|
||||
it { is_expected.to respond_to :compatible? }
|
||||
it { is_expected.to respond_to_protected :init_compat }
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
shared_examples_for 'Msf::Module::DataStore' do
|
||||
it { is_expected.to respond_to :datastore }
|
||||
it { is_expected.to respond_to :import_defaults }
|
||||
it { is_expected.to respond_to :share_datastore }
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
shared_examples_for 'Msf::Module::FullName' do
|
||||
it { is_expected.to respond_to :fullname }
|
||||
it { is_expected.to respond_to :refname }
|
||||
it { is_expected.to respond_to :shortname }
|
||||
|
||||
context 'class' do
|
||||
subject {
|
||||
described_class
|
||||
}
|
||||
|
||||
it { is_expected.to respond_to :fullname }
|
||||
it { is_expected.to respond_to :refname }
|
||||
it { is_expected.to respond_to :refname= }
|
||||
it { is_expected.to respond_to :shortname }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
shared_examples_for 'Msf::Module::ModuleInfo' do
|
||||
context 'CONSTANTS' do
|
||||
context 'UpdateableOptions' do
|
||||
subject(:updateable_options) {
|
||||
described_class::UpdateableOptions
|
||||
}
|
||||
|
||||
it { is_expected.to match_array(%w{Name Description Alias PayloadCompat})}
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to respond_to :alias }
|
||||
it { is_expected.to respond_to :description }
|
||||
it { is_expected.to respond_to :disclosure_date }
|
||||
it { is_expected.to respond_to_protected :info_fixups }
|
||||
it { is_expected.to respond_to_protected :merge_check_key }
|
||||
it { is_expected.to respond_to_protected :merge_info }
|
||||
it { is_expected.to respond_to_protected :merge_info_advanced_options }
|
||||
it { is_expected.to respond_to_protected :merge_info_alias }
|
||||
it { is_expected.to respond_to_protected :merge_info_description }
|
||||
it { is_expected.to respond_to_protected :merge_info_evasion_options }
|
||||
it { is_expected.to respond_to_protected :merge_info_name }
|
||||
it { is_expected.to respond_to_protected :merge_info_options }
|
||||
it { is_expected.to respond_to_protected :merge_info_string }
|
||||
it { is_expected.to respond_to_protected :merge_info_version }
|
||||
it { is_expected.to respond_to :name }
|
||||
it { is_expected.to respond_to_protected :update_info }
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
shared_examples_for 'Msf::Module::ModuleStore' do
|
||||
it { is_expected.to respond_to :[] }
|
||||
it { is_expected.to respond_to :[]= }
|
||||
it { is_expected.to respond_to :module_store }
|
||||
it { is_expected.to respond_to :module_store= }
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
shared_examples_for 'Msf::Module::Network' do
|
||||
it { is_expected.to respond_to :comm }
|
||||
it { is_expected.to respond_to :support_ipv6? }
|
||||
it { is_expected.to respond_to :target_host }
|
||||
it { is_expected.to respond_to :target_port }
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
shared_examples_for 'Msf::Module::Options' do
|
||||
it { is_expected.to respond_to_protected :deregister_options }
|
||||
it { is_expected.to respond_to :options }
|
||||
it { is_expected.to respond_to :validate }
|
||||
it { is_expected.to respond_to_protected :register_advanced_options }
|
||||
it { is_expected.to respond_to_protected :register_evasion_options }
|
||||
it { is_expected.to respond_to_protected :register_options }
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
shared_examples_for 'Msf::Module::Privileged' do
|
||||
it { is_expected.to respond_to :privileged }
|
||||
it { is_expected.to respond_to :privileged? }
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
shared_examples_for 'Msf::Module::Ranking' do
|
||||
it { is_expected.to respond_to :rank }
|
||||
it { is_expected.to respond_to :rank_to_h }
|
||||
it { is_expected.to respond_to :rank_to_s }
|
||||
|
||||
context 'class' do
|
||||
subject {
|
||||
described_class
|
||||
}
|
||||
|
||||
it { is_expected.to respond_to :rank }
|
||||
it { is_expected.to respond_to :rank_to_h }
|
||||
it { is_expected.to respond_to :rank_to_s }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,168 @@
|
|||
shared_examples_for 'Msf::Module::Search' do
|
||||
describe '#search_filter' do
|
||||
REF_TYPES = %w(CVE BID OSVDB EDB)
|
||||
|
||||
shared_examples "search_filter" do |opts|
|
||||
accept = opts[:accept] || []
|
||||
reject = opts[:reject] || []
|
||||
|
||||
accept.each do |query|
|
||||
it "should accept a query containing '#{query}'" do
|
||||
# if the subject matches, search_filter returns false ("don't filter me out!")
|
||||
subject.search_filter(query).should be_falsey
|
||||
end
|
||||
|
||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||
it "should reject a query containing '-#{query}'" do
|
||||
subject.search_filter("-#{query}").should be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reject.each do |query|
|
||||
it "should reject a query containing '#{query}'" do
|
||||
# if the subject doesn't matches, search_filter returns true ("filter me out!")
|
||||
subject.search_filter(query).should be_truthy
|
||||
end
|
||||
|
||||
unless opts.has_key?(:test_inverse) and not opts[:test_inverse]
|
||||
it "should accept a query containing '-#{query}'" do
|
||||
subject.search_filter("-#{query}").should be_truthy # what? why?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:opts) { Hash.new }
|
||||
before { subject.stub(:fullname => '/module') }
|
||||
subject { Msf::Module.new(opts) }
|
||||
accept = []
|
||||
reject = []
|
||||
|
||||
context 'on a blank query' do
|
||||
it_should_behave_like 'search_filter', :accept => [''], :test_inverse => false
|
||||
end
|
||||
|
||||
context 'on a client module' do
|
||||
before { subject.stub(:stance => 'passive') }
|
||||
accept = %w(app:client)
|
||||
reject = %w(app:server)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a server module' do
|
||||
before { subject.stub(:stance => 'aggressive') }
|
||||
accept = %w(app:server)
|
||||
reject = %w(app:client)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with the author "joev"' do
|
||||
let(:opts) { ({ 'Author' => ['joev'] }) }
|
||||
accept = %w(author:joev author:joe)
|
||||
reject = %w(author:unrelated)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with the authors "joev" and "blarg"' do
|
||||
let(:opts) { ({ 'Author' => ['joev', 'blarg'] }) }
|
||||
accept = %w(author:joev author:joe)
|
||||
reject = %w(author:sinn3r)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the osx platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(osx) }) }
|
||||
accept = %w(platform:osx os:osx)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the linux platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(linux) }) }
|
||||
accept = %w(platform:linux os:linux)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the windows platform' do
|
||||
let(:opts) { ({ 'Platform' => %w(windows) }) }
|
||||
accept = %w(platform:windows os:windows)
|
||||
reject = %w(platform:bsd platform:osx platform:unix os:bsd os:osx os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the osx and linux platforms' do
|
||||
let(:opts) { ({ 'Platform' => %w(osx linux) }) }
|
||||
accept = %w(platform:osx platform:linux os:osx os:linux)
|
||||
reject = %w(platform:bsd platform:windows platform:unix os:bsd os:windows os:unix)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module that supports the windows and irix platforms' do
|
||||
let(:opts) { ({ 'Platform' => %w(windows irix) }) }
|
||||
accept = %w(platform:windows platform:irix os:windows os:irix)
|
||||
reject = %w(platform:bsd platform:osx platform:linux os:bsd os:osx os:linux)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with a default RPORT of 5555' do
|
||||
before { subject.stub(:datastore => { 'RPORT' => 5555 }) }
|
||||
accept = %w(port:5555)
|
||||
reject = %w(port:5556)
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
|
||||
context 'on a module with a #name of "blah"' do
|
||||
let(:opts) { ({ 'Name' => 'blah' }) }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
it_should_behave_like 'search_filter', :accept => %w(name:blah), :reject => %w(name:foo)
|
||||
end
|
||||
|
||||
context 'on a module with a #fullname of "blah"' do
|
||||
before { subject.stub(:fullname => '/c/d/e/blah') }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
it_should_behave_like 'search_filter', :accept => %w(path:blah), :reject => %w(path:foo)
|
||||
end
|
||||
|
||||
context 'on a module with a #description of "blah"' do
|
||||
let(:opts) { ({ 'Description' => 'blah' }) }
|
||||
it_should_behave_like 'search_filter', :accept => %w(text:blah), :reject => %w(text:foo)
|
||||
end
|
||||
|
||||
context 'when filtering by module #type' do
|
||||
all_module_types = Msf::MODULE_TYPES
|
||||
all_module_types.each do |mtype|
|
||||
context "on a #{mtype} module" do
|
||||
before(:each) { subject.stub(:type => mtype) }
|
||||
|
||||
accept = ["type:#{mtype}"]
|
||||
reject = all_module_types.reject { |t| t == mtype }.map { |t| "type:#{t}" }
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
REF_TYPES.each do |ref_type|
|
||||
ref_num = '1234-1111'
|
||||
context 'on a module with reference #{ref_type}-#{ref_num}' do
|
||||
let(:opts) { ({ 'References' => [[ref_type, ref_num]] }) }
|
||||
accept = ["#{ref_type.downcase}:#{ref_num}"]
|
||||
reject = %w(1235-1111 1234-1112 bad).map { |n| "#{ref_type.downcase}:#{n}" }
|
||||
|
||||
it_should_behave_like 'search_filter', :accept => accept, :reject => reject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
shared_examples_for 'Msf::Module::Type' do
|
||||
it { is_expected.to respond_to :auxiliary? }
|
||||
it { is_expected.to respond_to :encoder? }
|
||||
it { is_expected.to respond_to :exploit? }
|
||||
it { is_expected.to respond_to :nop? }
|
||||
it { is_expected.to respond_to :payload? }
|
||||
it { is_expected.to respond_to :post? }
|
||||
it { is_expected.to respond_to :type }
|
||||
|
||||
context 'class' do
|
||||
subject {
|
||||
described_class
|
||||
}
|
||||
|
||||
it { is_expected.to respond_to :type }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
shared_examples_for 'Msf::Module::UI' do
|
||||
it_should_behave_like 'Msf::Module::UI::Line'
|
||||
it_should_behave_like 'Msf::Module::UI::Message'
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
shared_examples_for 'Msf::Module::UI::Line' do
|
||||
it_should_behave_like 'Msf::Module::UI::Line::Verbose'
|
||||
|
||||
it { is_expected.to respond_to :print_line }
|
||||
it { is_expected.to respond_to :print_line_prefix }
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
shared_examples_for 'Msf::Module::UI::Line::Verbose' do
|
||||
it { is_expected.to respond_to :vprint_line }
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
shared_examples_for 'Msf::Module::UI::Message' do
|
||||
it_should_behave_like 'Msf::Module::UI::Message::Verbose'
|
||||
|
||||
it { is_expected.to respond_to :print_error }
|
||||
it { is_expected.to respond_to :print_good }
|
||||
it { is_expected.to respond_to :print_prefix }
|
||||
it { is_expected.to respond_to :print_status }
|
||||
it { is_expected.to respond_to :print_warning }
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
shared_examples_for 'Msf::Module::UI::Message::Verbose' do
|
||||
it { is_expected.to respond_to :vprint_debug }
|
||||
it { is_expected.to respond_to :vprint_error }
|
||||
it { is_expected.to respond_to :vprint_good }
|
||||
it { is_expected.to respond_to :vprint_status }
|
||||
it { is_expected.to respond_to :vprint_warning }
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
shared_examples_for 'Msf::Module::UUID' do
|
||||
it { is_expected.to respond_to :uuid }
|
||||
end
|
Loading…
Reference in New Issue