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.



107
108
109
110
111
# File 'lib/metasploit/credential/exporter/core.rb', line 107

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 either Login or Core objects depending on #mode

Returns:

  • (ActiveRecord::Relation)


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

def export_data
  @export_data
end

#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
# File 'lib/metasploit/credential/exporter/core.rb', line 80

def data
  return export_data if whitelist_ids.blank?
  export_data.select{ |datum| whitelist_ids.include? datum.id }
end

#export!void

This method returns an undefined value.

Perform the export, creating the CSV and the zip file



87
88
89
90
# File 'lib/metasploit/credential/exporter/core.rb', line 87

def export!
  render_manifest_output_and_keys
  render_zip
end

#header_lineArray<Symbol>

Returns the CSV header line, which is dependent on mode

Returns:

  • (Array<Symbol>)


115
116
117
118
119
120
121
122
# File 'lib/metasploit/credential/exporter/core.rb', line 115

def header_line
  case mode
    when LOGIN_MODE
      Metasploit::Credential::Importer::Core::VALID_LONG_CSV_HEADERS
    when CORE_MODE
      Metasploit::Credential::Importer::Core::VALID_LONG_CSV_HEADERS
  end
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)


154
155
156
157
158
159
160
161
162
# File 'lib/metasploit/credential/exporter/core.rb', line 154

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.

Parameters:

Returns:

  • (Hash)


140
141
142
143
144
145
146
147
148
# File 'lib/metasploit/credential/exporter/core.rb', line 140

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

#outputIO

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

Returns:

  • (IO)


166
167
168
# File 'lib/metasploit/credential/exporter/core.rb', line 166

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)


172
173
174
175
176
177
178
179
# File 'lib/metasploit/credential/exporter/core.rb', line 172

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)


183
184
185
# File 'lib/metasploit/credential/exporter/core.rb', line 183

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)


189
190
191
# File 'lib/metasploit/credential/exporter/core.rb', line 189

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)


127
128
129
130
131
132
# File 'lib/metasploit/credential/exporter/core.rb', line 127

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)


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/metasploit/credential/exporter/core.rb', line 196

def render_manifest_output_and_keys
  CSV.open(output, 'wb') do |csv|
    csv << header_line
    data.each do |datum|
      line = self.send("line_for_#{mode}", 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

#render_zipvoid

This method returns an undefined value.

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



216
217
218
219
220
221
222
223
224
225
226
# File 'lib/metasploit/credential/exporter/core.rb', line 216

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



231
232
233
234
235
# File 'lib/metasploit/credential/exporter/core.rb', line 231

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)


239
240
241
# File 'lib/metasploit/credential/exporter/core.rb', line 239

def zip_filename
  output_final_subdirectory_name + ".zip"
end