Module: Msf::ModuleManager::Cache

Extended by:
ActiveSupport::Concern
Included in:
Msf::ModuleManager
Defined in:
lib/msf/core/module_manager/cache.rb

Overview

Concerns the module cache maintained by the Msf::ModuleManager.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#module_info_by_pathObject (protected)


140
141
142
# File 'lib/msf/core/module_manager/cache.rb', line 140

def module_info_by_path
  @module_info_by_path
end

Instance Method Details

#cache_empty?true, false

Returns whether the cache is empty

Returns:

  • (true)

    if the cache has no entries.

  • (false)

    if the cache has any entries.


16
17
18
# File 'lib/msf/core/module_manager/cache.rb', line 16

def cache_empty?
  module_info_by_path.empty?
end

#cache_in_memory(class_or_module, options = {}) ⇒ void

Note:

path, reference_name, and type must be passed as options because when class_or_module is a payload Module, those attributes will either not be set or not exist on the module.

This method returns an undefined value.

Updates the in-memory cache so that Loading#file_changed? will report false if the module is loaded again.

Parameters:

  • class_or_module (Class<Msf::Module>, ::Module)

    either a module Class or a payload Module.

  • options (Hash{Symbol => String}) (defaults to: {})

Options Hash (options):

  • :path (String)

    the path to the file from which class_or_module was loaded.

  • :reference_name (String)

    the reference name for class_or_module.

  • :type (String)

    the module type

Raises:

  • (KeyError)

    unless :path is given.

  • (KeyError)

    unless :reference_name is given.

  • (KeyError)

    unless :type is given.


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/msf/core/module_manager/cache.rb', line 38

def cache_in_memory(class_or_module, options={})
  options.assert_valid_keys(:path, :reference_name, :type)

  path = options.fetch(:path)

  begin
    modification_time = File.mtime(path)
  rescue Errno::ENOENT => error
    log_lines = []
    log_lines << "Could not find the modification of time of #{path}:"
    log_lines << error.class.to_s
    log_lines << error.to_s
    log_lines << "Call stack:"
    log_lines += error.backtrace

    log_message = log_lines.join("\n")
    elog(log_message)
  else
    parent_path = class_or_module.parent.parent_path
    reference_name = options.fetch(:reference_name)
    type = options.fetch(:type)

    module_info_by_path[path] = {
        :modification_time => modification_time,
        :parent_path => parent_path,
        :reference_name => reference_name,
        :type => type
    }
  end
end

#load_cached_module(type, reference_name) ⇒ false, true

Forces loading of the module with the given type and module reference name from the cache.

Parameters:

  • type (String)

    the type of the module.

  • reference_name (String)

    the module reference name.

Returns:

  • (false)

    if a module with the given type and reference name does not exist in the cache.

  • (false)

    if :force is false and parent_path has not changed.

  • (false)

    if exception encountered while parsing module content

  • (false)

    if the module is incompatible with the Core or API version.

  • (false)

    if the module does not implement a Metasploit class.

  • (false)

    if the module's is_usable method returns false.

  • (true)

    if all those condition pass and the module is successfully loaded.


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/msf/core/module_manager/cache.rb', line 75

def load_cached_module(type, reference_name)
  loaded = false

  module_info = self.module_info_by_path.values.find { |inner_info|
    inner_info[:type] == type and inner_info[:reference_name] == reference_name
  }

  if module_info
    parent_path = module_info[:parent_path]

    # XXX borked
    loaders.each do |loader|
      if loader.loadable?(parent_path)
        type = module_info[:type]
        reference_name = module_info[:reference_name]

        loaded = loader.load_module(parent_path, type, reference_name, :force => true)

        break if loaded
      end
    end
  end

  loaded
end

#module_info_by_path_from_database!(allowed_paths = [""]) ⇒ Hash{String => Hash{Symbol => Object}} (protected)

Note:

Also sets module_set(module_type) to Msf::SymbolicModule if it is not already set.

Return a module info from Msf::Modules::Metadata::Obj.

Returns:

  • (Hash{String => Hash{Symbol => Object}})

    Maps path (Mdm::Module::Detail#file) to module information. Module information is a Hash derived from Mdm::Module::Detail. It includes :modification_time, :parent_path, :type, :reference_name.


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/msf/core/module_manager/cache.rb', line 149

def module_info_by_path_from_database!(allowed_paths=[""])
  self.module_info_by_path = {}

  allowed_paths = allowed_paths.map{|x| x + "/"}

   = Msf::Modules::Metadata::Cache.instance.
  .each do ||
    path = .path
    type = .type
    reference_name = .ref_name

    # Skip cached modules that are not in our allowed load paths
    next if allowed_paths.select{|x| path.index(x) == 0}.empty?

    # The load path is assumed to be the next level above the type directory
    type_dir = File.join('', Mdm::Module::Detail::DIRECTORY_BY_TYPE[type], '')
    parent_path = path.split(type_dir)[0..-2].join(type_dir) # TODO: rewrite

    module_info_by_path[path] = {
        :reference_name => reference_name,
        :type => type,
        :parent_path => parent_path,
        :modification_time => .mod_time
    }
    .aliases.each do |a|
      self.aliases[a] = .fullname
    end
    self.inv_aliases[.fullname] = .aliases unless .aliases.empty?

    typed_module_set = module_set(type)

    # Don't want to trigger as {Msf::ModuleSet#create} so check for
    # key instead of using ||= which would call {Msf::ModuleSet#[]}
    # which would potentially call {Msf::ModuleSet#create}.
    if typed_module_set
      unless typed_module_set.has_key?(reference_name)
        typed_module_set[reference_name] = Msf::SymbolicModule
      end
    end
  end

  self.module_info_by_path
end

#refresh_cache_from_database(allowed_paths = [""]) ⇒ void

This method returns an undefined value.

Refreshes the in-memory cache from the database cache.


132
133
134
# File 'lib/msf/core/module_manager/cache.rb', line 132

def refresh_cache_from_database(allowed_paths=[""])
  self.module_info_by_path_from_database!(allowed_paths)
end

#refresh_cache_from_module_filesvoid #refresh_cache_from_module_files(module_class_or_instance) ⇒ void

Overloads:

  • #refresh_cache_from_module_filesvoid

    This method returns an undefined value.

    Rebuilds module metadata store and in-memory cache for all modules.

  • #refresh_cache_from_module_files(module_class_or_instance) ⇒ void

    This method returns an undefined value.

    Rebuilds database and in-memory cache for given module_class_or_instance.


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/msf/core/module_manager/cache.rb', line 110

def refresh_cache_from_module_files(module_class_or_instance = nil)
  if module_class_or_instance
    Msf::Modules::Metadata::Cache.instance.(module_class_or_instance)
  else
    module_sets =
        [
            ['exploit', @framework.exploits],
            ['auxiliary', @framework.auxiliary],
            ['post', @framework.post],
            ['payload', @framework.payloads],
            ['encoder', @framework.encoders],
            ['nop', @framework.nops],
            ['evasion', @framework.evasion]
        ]
    Msf::Modules::Metadata::Cache.instance.(module_sets)
  end
  refresh_cache_from_database(self.module_paths)
end