class Metasploit::Credential::Exporter::Core

This class is used to export {Metasploit::Credential::Core} information, optionally scoped to associated {Metasploit::Credential::Login} objects. In the case of exporting Login objects, the associated `Mdm::Host` and `Mdm::Server` information is exported as well. Exported data can be optionally scoped to include only a certain whitelist of database IDs.

The {#export!} method creates a zip file on disk containing a CSV with the data. If the `workspace` contains {Metasploit::Credential::SSHKey} objects on the exported {Metasploit::Credential::Core} objects, the keys are exported to files inside a subdirectory of the zip file. @example Exporting all Cores

core_exporter = Metasploit::Credential::Exporter::Core.new(workspace: workspace, mode: :core)
core_exporter.export!
core_exporter.output_zipfile_path # => location of finished zip file

@example Exporting all Logins

core_exporter = Metasploit::Credential::Exporter::Login.new(workspace: workspace, mode: :login)
core_exporter.export!
core_exporter.output_zipfile_path # => location of finished zip file

@example Exporting with whitelist

core_exporter = Metasploit::Credential::Exporter::Login.new(workspace: workspace, mode: :login, whitelist_ids: whitelist_ids)
core_exporter.export!
core_exporter.output_zipfile_path # => location of finished zip file

Constants

ALLOWED_MODES

Valid modes

CORE_MODE

The symbol representation of the mode for exporting {Metasploit::Credential::Core} objects

CREDS_DUMP_FILE_IDENTIFIER

The pattern used to identify a creds dump zip or directory

DEFAULT_MODE

The downcased and Symbolized name of the default object type to export

LOGIN_MODE

The symbol representation of the mode for exporting {Metasploit::Credential::Login} objects

TEMP_ZIP_PATH_PREFIX

An argument to `Dir::mktmpdir`

Attributes

export_data[W]

@!attribute [rw] #export_data

Holds the raw information from the database before it is formatted into the {#data} attribute
@return [Array]
finalized_zip_file[RW]

@!attribute #finalized_zip_file

The final output artifacts, zipped
@return [Zip::File]
mode[RW]

@!attribute mode

One of %x`:login` or %x`:core`
@return [Symbol]
whitelist_ids[RW]

@!attribute #whitelist_ids

A list of primary key IDs used to filter the objects in {#export_data}
@return [Array<Fixnum>]

Public Class Methods

new(args) click to toggle source
# File lib/metasploit/credential/exporter/core.rb, line 105
def initialize(args)
  @mode = args[:mode].present? ? args.fetch(:mode) : DEFAULT_MODE
  fail "Invalid mode" unless ALLOWED_MODES.include?(mode)
  super args
end

Public Instance Methods

data() click to toggle source

The munged data that will be iterated over for export @return [Array]

# File lib/metasploit/credential/exporter/core.rb, line 80
def data
  if whitelist_ids.present?
    export_data[:core] = export_data[:core].select{ |datum| whitelist_ids.include? datum.id }
  end
  export_data
end
export!() click to toggle source

Perform the export, creating the CSV and the zip file @return [void]

# File lib/metasploit/credential/exporter/core.rb, line 89
def export!
  render_manifest_output_and_keys
  render_zip
end
export_data() click to toggle source

Returns an `Enumerable` full of {Metasploit::Credential::Login} and {Metasploit::Credential::Core} objects @return [ActiveRecord::Relation]

# File lib/metasploit/credential/exporter/core.rb, line 96
def export_data
  unless instance_variable_defined? :@export_data
    @export_data = {}
    @export_data[:login] = Metasploit::Credential::Login.in_workspace_including_hosts_and_services(workspace)
    @export_data[:core]  = Metasploit::Credential::Core.workspace_id(workspace.id)
  end
  @export_data
end
line_for_core(core) click to toggle source

Returns a lookup for cores containing data from the given {Metasploit::Credential::Core} object's component types in order that it can be used as a CSV row. @param core [Metasploit::Credential::Core] @return [Hash]

# File lib/metasploit/credential/exporter/core.rb, line 147
def line_for_core(core)
  {
    username: core.public.try(:username),
    private_type: core.private.try(:type),
    private_data: core.private.try(:data),
    realm_key: core.realm.try(:key),
    realm_value: core.realm.try(:value)
  }
end
line_for_login(login) click to toggle source

Take a login and return a [Hash] that will be used for a CSV row. The hashes returned by this method will contain credentials for networked devices which may or may not successfully authenticate to those devices. Note that the order of columns here must match the order in Metasploit::Credential::Importer::Core::VALID_LONG_CSV_HEADERS or the headers and row values will be mismatched and break import. @param login [Metasploit::Credential::Login] @return [Hash]

# File lib/metasploit/credential/exporter/core.rb, line 130
def line_for_login(login)
  result = line_for_core(login.core)
  result.merge({
    host_address: login.service.host.address.to_s,
    service_port: login.service.port,
    service_name: login.service.try(:name),
    service_protocol: login.service.proto,
    status: login.status,
    access_level: login.access_level,
    last_attempted_at: login.last_attempted_at
  })
end
output() click to toggle source

The IO object representing the manifest CSV that contains the exported data (other than SSH keys) @return [IO]

# File lib/metasploit/credential/exporter/core.rb, line 159
def output
  @output ||= File.open(File.join(output_final_directory_path, Metasploit::Credential::Importer::Zip::MANIFEST_FILE_NAME), 'w')
end
output_final_directory_path() click to toggle source

The platform-independent location of the export directory on disk, set in `Dir.tmpdir` by default @return [String]

# File lib/metasploit/credential/exporter/core.rb, line 165
def output_final_directory_path
  unless instance_variable_defined? :@output_final_directory_path
    tmp_path  = Dir.mktmpdir(TEMP_ZIP_PATH_PREFIX)
    @output_final_directory_path = File.join(tmp_path, output_final_subdirectory_name)
    FileUtils.mkdir_p @output_final_directory_path
  end
  @output_final_directory_path
end
output_final_subdirectory_name() click to toggle source

The final fragment of the {#output_final_directory_path} @return [String]

# File lib/metasploit/credential/exporter/core.rb, line 176
def output_final_subdirectory_name
  @output_final_subdiretory_name ||= "#{CREDS_DUMP_FILE_IDENTIFIER}-dump-#{workspace.id}-#{Time.now.to_i}"
end
output_zipfile_path() click to toggle source

The path to the finished `Zip::File` on disk @return [String]

# File lib/metasploit/credential/exporter/core.rb, line 182
def output_zipfile_path
  Pathname.new(output_final_directory_path).dirname.to_s + '/' + zip_filename
end
path_for_key(datum) click to toggle source

Returns a platform-agnostic filesystem path where the key data will be saved as a file @param line [Hash] the result of {#line_for_login} or {#line_for_core} @return [String]

# File lib/metasploit/credential/exporter/core.rb, line 114
def path_for_key(datum)
  core = datum.is_a?(Metasploit::Credential::Core) ? datum : datum.core
  dir_path = File.join(output_final_directory_path, Metasploit::Credential::Importer::Zip::KEYS_SUBDIRECTORY_NAME)
  FileUtils.mkdir_p(dir_path)
  File.join(dir_path,"#{core.public.username}-#{core.private.id}")
end
render_manifest_output_and_keys() click to toggle source

Iterate over the {#export_data} and write lines to the CSV at {#output}, returning the completed CSV file. @return [CSV]

# File lib/metasploit/credential/exporter/core.rb, line 189
def render_manifest_output_and_keys
  CSV.open(output, 'wb') do |csv|
    csv << Metasploit::Credential::Importer::Core::VALID_LONG_CSV_HEADERS
    data.each do |type_key, creds|
      creds.each do |datum|
        line = self.send("line_for_#{type_key}", datum)

        # Special-case any SSHKeys in the import
        if line[:private_type] == Metasploit::Credential::SSHKey.name
          key_path = path_for_key(datum)
          write_key_file(key_path, line[:private_data])
          line[:private_data] = File.basename(key_path)
        end

        csv << line.values
      end
    end
  end
end
render_zip() click to toggle source

Creates a `Zip::File` by recursively zipping up the contents of {#output_final_directory_path} @return [void]

# File lib/metasploit/credential/exporter/core.rb, line 211
def render_zip
  zip_dir_path = Pathname.new(output_final_directory_path)

  Zip::File.open(output_zipfile_path, Zip::File::CREATE) do |zipfile|
    Dir[File.join(output_final_directory_path, '**', '**')].each do |file|
      file_path = Pathname.new(file)
      path_in_zip = file_path.relative_path_from(zip_dir_path)
      zipfile.add(path_in_zip, file)
    end
  end
end
write_key_file(path, data) click to toggle source

@param path [String] the filesystem path where the data will be written @param data [String] the key data that will be written out at path @return [void]

# File lib/metasploit/credential/exporter/core.rb, line 226
def write_key_file(path, data)
  File.open(path, 'w') do |file|
    file << data
  end
end
zip_filename() click to toggle source

Returns the basename of the {#output_final_directory_path} @return [String]

# File lib/metasploit/credential/exporter/core.rb, line 234
def zip_filename
  output_final_subdirectory_name + ".zip"
end