Class: Metasploit::Credential::Exporter::Core

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/metasploit/credential/exporter/core.rb

Overview

This class is used to export Core information, optionally scoped to associated 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 SSHKey objects on the exported Core objects, the keys are exported to files inside a subdirectory of the zip file.

Examples:

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

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

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

Constant Summary collapse

CORE_MODE =

The symbol representation of the mode for exporting Core objects

:core
CREDS_DUMP_FILE_IDENTIFIER =

The pattern used to identify a creds dump zip or directory

"creds-dump"
LOGIN_MODE =

The symbol representation of the mode for exporting Login objects

:login
ALLOWED_MODES =

Valid modes

[LOGIN_MODE, CORE_MODE]
DEFAULT_MODE =

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

LOGIN_MODE
TEMP_ZIP_PATH_PREFIX =

An argument to ‘Dir::mktmpdir`

"metasploit-exports"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ Core

Returns a new instance of Core.



105
106
107
108
109
# 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

Instance Attribute Details

#export_dataActiveRecord::Relation

Returns an ‘Enumerable` full of Login and Core objects

Returns:

  • (ActiveRecord::Relation)


55
# File 'lib/metasploit/credential/exporter/core.rb', line 55

attr_writer :export_data

#finalized_zip_fileZip::File

The final output artifacts, zipped

Returns:

  • (Zip::File)


60
61
62
# File 'lib/metasploit/credential/exporter/core.rb', line 60

def finalized_zip_file
  @finalized_zip_file
end

#modeSymbol

One of ‘:login` or `:core`

Returns:

  • (Symbol)


65
66
67
# File 'lib/metasploit/credential/exporter/core.rb', line 65

def mode
  @mode
end

#whitelist_idsArray<Fixnum>

A list of primary key IDs used to filter the objects in #export_data

Returns:

  • (Array<Fixnum>)


70
71
72
# File 'lib/metasploit/credential/exporter/core.rb', line 70

def whitelist_ids
  @whitelist_ids
end

Instance Method Details

#dataArray

The munged data that will be iterated over for export

Returns:

  • (Array)


80
81
82
83
84
85
# 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!void

This method returns an undefined value.

Perform the export, creating the CSV and the zip file



89
90
91
92
# File 'lib/metasploit/credential/exporter/core.rb', line 89

def export!
  render_manifest_output_and_keys
  render_zip
end

#line_for_core(core) ⇒ Hash

Returns a lookup for cores containing data from the given Core object’s component types in order that it can be used as a CSV row.

Parameters:

Returns:

  • (Hash)


147
148
149
150
151
152
153
154
155
# 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) ⇒ Hash

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.

Parameters:

Returns:

  • (Hash)


130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/metasploit/credential/exporter/core.rb', line 130

def ()
  result = line_for_core(.core)
  result.merge({
    host_address: .service.host.address.to_s,
    service_port: .service.port,
    service_name: .service.try(:name),
    service_protocol: .service.proto,
    status: .status,
    access_level: .access_level,
    last_attempted_at: .last_attempted_at
  })
end

#outputIO

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

Returns:

  • (IO)


159
160
161
# 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_pathString

The platform-independent location of the export directory on disk, set in ‘Dir.tmpdir` by default

Returns:

  • (String)


165
166
167
168
169
170
171
172
# 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_nameString

The final fragment of the #output_final_directory_path

Returns:

  • (String)


176
177
178
# 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_pathString

The path to the finished ‘Zip::File` on disk

Returns:

  • (String)


182
183
184
# 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) ⇒ String

Returns a platform-agnostic filesystem path where the key data will be saved as a file

Parameters:

Returns:

  • (String)


114
115
116
117
118
119
# 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_keysCSV

Iterate over the #export_data and write lines to the CSV at #output, returning the completed CSV file.

Returns:

  • (CSV)


189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# 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_zipvoid

This method returns an undefined value.

Creates a ‘Zip::File` by recursively zipping up the contents of #output_final_directory_path



211
212
213
214
215
216
217
218
219
220
221
# 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) ⇒ void

This method returns an undefined value.

Parameters:

  • path (String)

    the filesystem path where the data will be written

  • data (String)

    the key data that will be written out at path



226
227
228
229
230
# 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_filenameString

Returns the basename of the #output_final_directory_path

Returns:

  • (String)


234
235
236
# File 'lib/metasploit/credential/exporter/core.rb', line 234

def zip_filename
  output_final_subdirectory_name + ".zip"
end