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
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
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)


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

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)


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

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)


153
154
155
# File 'lib/metasploit/credential/exporter/core.rb', line 153

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)


159
160
161
162
163
164
165
166
# File 'lib/metasploit/credential/exporter/core.rb', line 159

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)


170
171
172
# File 'lib/metasploit/credential/exporter/core.rb', line 170

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)


176
177
178
# File 'lib/metasploit/credential/exporter/core.rb', line 176

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)


183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/metasploit/credential/exporter/core.rb', line 183

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



205
206
207
208
209
210
211
212
213
214
215
# File 'lib/metasploit/credential/exporter/core.rb', line 205

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



220
221
222
223
224
# File 'lib/metasploit/credential/exporter/core.rb', line 220

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)


228
229
230
# File 'lib/metasploit/credential/exporter/core.rb', line 228

def zip_filename
  output_final_subdirectory_name + ".zip"
end