Class: Msf::Modules::Loader::Executable

Inherits:
Base
  • Object
show all
Defined in:
lib/msf/core/modules/loader/executable.rb

Overview

Concerns loading executables from a directory as modules

Constant Summary

Constants inherited from Base

Base::DIRECTORY_BY_TYPE, Base::MODULE_EXTENSION, Base::MODULE_SEPARATOR, Base::NAMESPACE_MODULE_CONTENT, Base::NAMESPACE_MODULE_LINE, Base::NAMESPACE_MODULE_NAMES, Base::TYPE_BY_DIRECTORY, Base::UNIT_TEST_REGEX

Instance Attribute Summary

Attributes inherited from Base

#module_manager

Instance Method Summary collapse

Methods inherited from Base

#create_namespace_module, #current_module, #initialize, #load_error, #load_module, #load_modules, #load_warning, #module_path?, #module_reference_name_from_path, #namespace_module_name, #namespace_module_names, #namespace_module_transaction, #reload_module, #restore_namespace_module, reverse_relative_name, #script_path?, typed_path, #typed_path

Constructor Details

This class inherits a constructor from Msf::Modules::Loader::Base

Instance Method Details

#each_module_reference_name(path, opts = {}) {|parent_path, type, module_reference_name| ... } ⇒ void (protected)

This method returns an undefined value.

Yields the module_reference_name for each module file found under the directory path.

Parameters:

  • path (String)

    The path to the directory.

  • opts (Hash) (defaults to: {})

    Input Hash.

Yields:

  • (parent_path, type, module_reference_name)

    Gives the path and the module_reference_name of the module found under the path.

Yield Parameters:

  • path (String)

    The path to the directory.

  • type (String)

    The type correlated with the directory under path.

  • module_reference_name (String)

    The canonical name for referencing the module.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/msf/core/modules/loader/executable.rb', line 56

def each_module_reference_name(path, opts={})
  whitelist = opts[:whitelist] || []
  ::Dir.foreach(path) do |entry|
    full_entry_path = ::File.join(path, entry)
    type = entry.singularize

    unless ::File.directory?(full_entry_path) && module_manager.type_enabled?(type)
      next
    end

    full_entry_pathname = Pathname.new(full_entry_path)

    # Try to load modules from all the files in the supplied path
    Rex::Find.find(full_entry_path) do |entry_descendant_path|
      # Assume that all modules are scripts for now, workaround
      # filesystems where all files are labeled as executable.
      if script_path?(entry_descendant_path)
        entry_descendant_pathname = Pathname.new(entry_descendant_path)
        relative_entry_descendant_pathname = entry_descendant_pathname.relative_path_from(full_entry_pathname)
        relative_entry_descendant_path = relative_entry_descendant_pathname.to_s
        next if File::basename(relative_entry_descendant_path).start_with?('example')
        # The module_reference_name doesn't have a file extension
        module_reference_name = File.join(File.dirname(relative_entry_descendant_path), File.basename(relative_entry_descendant_path, '.*'))

        yield path, type, module_reference_name
      end
    end
  end
end

#loadable?(path) ⇒ true, false

Returns true if the path is a directory

Parameters:

  • path (String)

    Path under which there are modules

Returns:

  • (true)

    if path is a directory

  • (false)

    otherwise



10
11
12
# File 'lib/msf/core/modules/loader/executable.rb', line 10

def loadable?(path)
  File.directory?(path)
end

#loadable_module?(parent_path, type, module_reference_name, cached_metadata: nil) ⇒ Boolean

Returns True this loader can load the module, false otherwise.

Parameters:

  • parent_path (String)

    Root directory to load modules from

  • type (String)

    Such as auxiliary, exploit, etc

  • module_reference_name (String)

    The module reference name, without the type prefix

  • cached_metadata (nil, Msf::Modules::Metadata::Obj) (defaults to: nil)

Returns:

  • (Boolean)

    True this loader can load the module, false otherwise



19
20
21
22
# File 'lib/msf/core/modules/loader/executable.rb', line 19

def loadable_module?(parent_path, type, module_reference_name, cached_metadata: nil)
  full_path = &.path || module_path(parent_path, type, module_reference_name)
  script_path?(full_path)
end

#module_path(parent_path, type, module_reference_name) ⇒ String (protected)

Returns the full path to the module file on disk.

Parameters:

  • parent_path (String)

    The path under which the module exists. This is not necessarily the same path as passed to Base#load_modules: it may just be derived from that path.

  • type (String)

    The type of module.

  • module_reference_name (String)

    The canonical name for referring to the module.

Returns:

  • (String)

    Path to module file on disk.



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/msf/core/modules/loader/executable.rb', line 90

def module_path(parent_path, type, module_reference_name)
  # The extension is lost on loading, hit the disk to recover :(
  partial_path = File.join(DIRECTORY_BY_TYPE[type], module_reference_name)
  full_path = File.join(parent_path, partial_path)

  Rex::Find.find(File.dirname(full_path)) do |mod|
    if File.basename(full_path, '.*') == File.basename(mod, '.*')
      return File.join(File.dirname(full_path), File.basename(mod))
    end
  end

  ''
end

#read_module_content(parent_path, type, module_reference_name) ⇒ String (protected)

Loads the module content from the on disk file.

Parameters:

  • parent_path (String)

    The path under which the module exists. This is not necessarily the same path as passed to Base#load_modules: it may just be derived from that path.

  • type (String)

    The type of module.

  • module_reference_name (String)

    The canonical name for referring to the module.

Returns:



108
109
110
111
112
# File 'lib/msf/core/modules/loader/executable.rb', line 108

def read_module_content(parent_path, type, module_reference_name)
  full_path = module_path(parent_path, type, module_reference_name)

  read_module_content_from_path(full_path)
end

#read_module_content_from_path(full_path) ⇒ String (protected)

Loads the module content from the on disk file.

Parameters:

  • full_path

    Path to the module to be read

Returns:



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/msf/core/modules/loader/executable.rb', line 118

def read_module_content_from_path(full_path)
  unless script_path?(full_path)
    load_error(full_path, Errno::ENOENT.new)
    return ''
  end
  unless script_runtime_available?(full_path)
    load_error(full_path, RuntimeError.new("Unable to load module as the following runtime was not found on the path: #{read_script_env_runtime(full_path)}"))
    return ''
  end

  begin
    content = Msf::Modules::External::Shim.generate(full_path, @module_manager.framework)
    if content
      return content
    else
      elog "Unable to load module #{full_path}, unknown module type"
      return ''
    end
  rescue LoadError => e
    load_error(full_path, e)
    return ''
  rescue ::Exception => e
    elog("Unable to load module #{full_path}", error: e)
    # XXX migrate this to a full load_error when we can tell the user why the
    # module did not load and/or how to resolve it.
    # load_error(full_path, e)
    ''
  end
end

#read_script_env_runtime(full_path) ⇒ Object (protected)



26
27
28
29
30
31
32
# File 'lib/msf/core/modules/loader/executable.rb', line 26

def read_script_env_runtime(full_path)
  # Extract the runtime from the first line of the script, i.e.
  #   #!/usr/bin/env python
  #   //usr/bin/env go run "$0" "$@"; exit "$?"
  first_line = File.open(full_path, 'rb') { |f| f.gets }
  first_line.to_s[%r{\A(?:#!|/)/usr/bin/env\s+(\w+)}, 1]
end

#script_runtime_available?(full_path) ⇒ Boolean (protected)

Returns True if the script’s required runtime is available on the host, false otherwise.

Parameters:

  • full_path (String)

    The full path to the module file.

Returns:

  • (Boolean)

    True if the script's required runtime is available on the host, false otherwise



36
37
38
39
40
41
42
43
44
45
# File 'lib/msf/core/modules/loader/executable.rb', line 36

def script_runtime_available?(full_path)
  return false unless script_path?(full_path)

  # Modules currently use /usr/bin/env - in the future absolute paths may need to be supported
  script_runtime = read_script_env_runtime(full_path)
  return !!Rex::FileUtils.find_full_path(script_runtime) if script_runtime

  # If the script runtime isn't known, we assume the script is executable
  true
end