Module: Msf::Auxiliary::Report

Overview

This module provides methods for reporting data to the DB

Instance Method Summary collapse

Instance Method Details

#dbObject

Shortcut method for detecting when the DB is active


18
19
20
# File 'lib/msf/core/auxiliary/report.rb', line 18

def db
  framework.db.active
end

#get_client(opts = {}) ⇒ Object


86
87
88
89
90
# File 'lib/msf/core/auxiliary/report.rb', line 86

def get_client(opts={})
  return if not db
  opts = {:workspace => myworkspace}.merge(opts)
  framework.db.get_client(opts)
end

#get_host(opts) ⇒ Object


61
62
63
64
65
# File 'lib/msf/core/auxiliary/report.rb', line 61

def get_host(opts)
  return if not db
  opts = {:workspace => myworkspace}.merge(opts)
  framework.db.get_host(opts)
end

#initialize(info = {}) ⇒ Object


13
14
15
# File 'lib/msf/core/auxiliary/report.rb', line 13

def initialize(info = {})
  super
end

#inside_workspace_boundary?(ip) ⇒ Boolean


36
37
38
39
40
# File 'lib/msf/core/auxiliary/report.rb', line 36

def inside_workspace_boundary?(ip)
  return true if not framework.db.active
  allowed = myworkspace.allow_actions_on?(ip)
  return allowed
end

#mytaskObject


26
27
28
29
30
31
32
33
34
# File 'lib/msf/core/auxiliary/report.rb', line 26

def mytask
  if self[:task]
    return self[:task].record
  elsif @task && @task.class == Mdm::Task
    return @task
  else
    return nil
  end
end

#myworkspaceObject


22
23
24
# File 'lib/msf/core/auxiliary/report.rb', line 22

def myworkspace
  @myworkspace = framework.db.find_workspace(self.workspace)
end

#report_auth_info(opts = {}) ⇒ Object


113
114
115
116
117
118
119
120
# File 'lib/msf/core/auxiliary/report.rb', line 113

def report_auth_info(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_auth_info(opts)
end

#report_client(opts = {}) ⇒ Object

Report a client connection

opts must contain :host the address of the client connecting :ua_string a string that uniquely identifies this client opts can contain :ua_name a brief identifier for the client, e.g. “Firefox” :ua_ver the version number of the client, e.g. “3.0.11”


77
78
79
80
81
82
83
84
# File 'lib/msf/core/auxiliary/report.rb', line 77

def report_client(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_client(opts)
end

#report_exploit(opts = {}) ⇒ Object

This will simply log a deprecation warning, since report_exploit() is no longer implemented.


133
134
135
136
137
138
139
140
# File 'lib/msf/core/auxiliary/report.rb', line 133

def report_exploit(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_exploit(opts)
end

#report_host(opts) ⇒ Object

Report a host's liveness and attributes such as operating system and service pack

opts must contain :host, which is an IP address identifying the host you're reporting about

See data/sql/*.sql and lib/msf/core/db.rb for more info


52
53
54
55
56
57
58
59
# File 'lib/msf/core/auxiliary/report.rb', line 52

def report_host(opts)
  return if not db
  opts = {
    :workspace => myworkspace,
    :task => mytask
  }.merge(opts)
  framework.db.report_host(opts)
end

#report_loot(opts = {}) ⇒ Object


142
143
144
145
146
147
148
149
# File 'lib/msf/core/auxiliary/report.rb', line 142

def report_loot(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_loot(opts)
end

#report_note(opts = {}) ⇒ Object


104
105
106
107
108
109
110
111
# File 'lib/msf/core/auxiliary/report.rb', line 104

def report_note(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_note(opts)
end

#report_service(opts = {}) ⇒ Object

Report detection of a service


95
96
97
98
99
100
101
102
# File 'lib/msf/core/auxiliary/report.rb', line 95

def report_service(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_service(opts)
end

#report_vuln(opts = {}) ⇒ Object


122
123
124
125
126
127
128
129
# File 'lib/msf/core/auxiliary/report.rb', line 122

def report_vuln(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_vuln(opts)
end

#report_web_form(opts = {}) ⇒ Object


169
170
171
172
173
174
175
176
# File 'lib/msf/core/auxiliary/report.rb', line 169

def report_web_form(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_web_form(opts)
end

#report_web_page(opts = {}) ⇒ Object


160
161
162
163
164
165
166
167
# File 'lib/msf/core/auxiliary/report.rb', line 160

def report_web_page(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_web_page(opts)
end

#report_web_site(opts = {}) ⇒ Object


151
152
153
154
155
156
157
158
# File 'lib/msf/core/auxiliary/report.rb', line 151

def report_web_site(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_web_site(opts)
end

#report_web_vuln(opts = {}) ⇒ Object


178
179
180
181
182
183
184
185
# File 'lib/msf/core/auxiliary/report.rb', line 178

def report_web_vuln(opts={})
  return if not db
  opts = {
      :workspace => myworkspace,
      :task => mytask
  }.merge(opts)
  framework.db.report_web_vuln(opts)
end

#store_cred(opts = {}) ⇒ Object

Takes a credential from a script (shell or meterpreter), and sources it correctly to the originating user account or session. Note that the passed-in session ID should be the Session.local_id, which will be correlated with the Session.id


332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/msf/core/auxiliary/report.rb', line 332

def store_cred(opts={})
  if [opts[:port],opts[:sname]].compact.empty?
    raise ArgumentError, "Missing option: :sname or :port"
  end
  cred_opts = opts
  cred_opts = opts.merge(:workspace => myworkspace)
  cred_host = myworkspace.hosts.find_by_address(cred_opts[:host])
  unless opts[:port]
    possible_services = myworkspace.services.find_all_by_host_id_and_name(cred_host[:id],cred_opts[:sname])
    case possible_services.size
    when 0
      case cred_opts[:sname].downcase
      when "smb"
        cred_opts[:port] = 445
      when "ssh"
        cred_opts[:port] = 22
      when "telnet"
        cred_opts[:port] = 23
      when "snmp"
        cred_opts[:port] = 161
        cred_opts[:proto] = "udp"
      else
        raise ArgumentError, "No matching :sname found to store this cred."
      end
    when 1
      cred_opts[:port] = possible_services.first[:port]
    else # SMB should prefer 445. Everyone else, just take the first hit.
      if (cred_opts[:sname].downcase == "smb") && possible_services.map {|x| x[:port]}.include?(445)
        cred_opts[:port] = 445
      elsif (cred_opts[:sname].downcase == "ssh") && possible_services.map {|x| x[:port]}.include?(22)
        cred_opts[:port] = 22
      else
        cred_opts[:port] = possible_services.first[:port]
      end
    end
  end
  if opts[:collect_user]
    cred_service = cred_host.services.find_by_host_id(cred_host[:id])
    myworkspace.creds.sort {|a,b| a.created_at.to_f}.each do |cred|
      if(cred.user.downcase == opts[:collect_user].downcase &&
         cred.pass == opts[:collect_pass]
        )
        cred_opts[:source_id] ||= cred.id
        cred_opts[:source_type] ||= cred_opts[:collect_type]
        break
      end
    end
  end
  if opts[:collect_session]
    session = myworkspace.sessions.find_all_by_local_id(opts[:collect_session]).last
    if !session.nil?
      cred_opts[:source_id] = session.id
      cred_opts[:source_type] = "exploit"
    end
  end
  print_status "Collecting #{cred_opts[:user]}:#{cred_opts[:pass]}"
  framework.db.report_auth_info(cred_opts)
end

#store_local(ltype = nil, ctype = nil, data = nil, filename = nil) ⇒ Object

Store some locally-generated data as a file, similiar to store_loot. Sometimes useful for keeping artifacts of an exploit or auxiliary module, such as files from fileformat exploits. (TODO: actually implement this on file format modules.)

filenmae is the local file name.

data is the actual contents of the file

Also stores metadata about the file in the database when available. ltype is an OID-style loot type, e.g. “cisco.ios.config”. Ignored when no database is connected.

ctype is the Content-Type, e.g. “text/plain”. Ignored when no database is connected.


277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/msf/core/auxiliary/report.rb', line 277

def store_local(ltype=nil, ctype=nil, data=nil, filename=nil)
  if ! ::File.directory?(Msf::Config.local_directory)
    FileUtils.mkdir_p(Msf::Config.local_directory)
  end

  # Split by fname an extension
  if filename and not filename.empty?
    if filename =~ /(.*)\.(.*)/
      ext = $2
      fname = $1
    else
      fname = filename
    end
  else
    fname = ctype || "local_#{Time.now.utc.to_i}"
  end

  # Split by path seperator
  fname = ::File.split(fname).last

  case ctype # Probably could use more cases
  when "text/plain"
    ext ||= "txt"
  when "text/xml"
    ext ||= "xml"
  when "text/html"
    ext ||= "html"
  when "application/pdf"
    ext ||= "pdf"
  else
    ext ||= "bin"
  end

  fname.gsub!(/[^a-z0-9\.\_\-]+/i, '')
  fname << ".#{ext}"

  ltype.gsub!(/[^a-z0-9\.\_\-]+/i, '')

  path = File.join(Msf::Config.local_directory, fname)
  full_path = ::File.expand_path(path)
  File.open(full_path, "wb") { |fd| fd.write(data) }

  # This will probably evolve into a new database table
  report_note(
    :data => full_path.dup,
    :type => "#{ltype}.localpath"
  )

  return full_path.dup
end

#store_loot(ltype, ctype, host, data, filename = nil, info = nil, service = nil) ⇒ Object

Store some data stolen from a session as a file

Also stores metadata about the file in the database when available ltype is an OID-style loot type, e.g. “cisco.ios.config”. Ignored when no database is connected.

ctype is the Content-Type, e.g. “text/plain”. Affects the extension the file will be saved with.

host can be an String address or a Session object

data is the actual contents of the file

filename and info are only stored as metadata, and therefore both are ignored if there is no database


204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/msf/core/auxiliary/report.rb', line 204

def store_loot(ltype, ctype, host, data, filename=nil, info=nil, service=nil)
  if ! ::File.directory?(Msf::Config.loot_directory)
    FileUtils.mkdir_p(Msf::Config.loot_directory)
  end

  ext = 'bin'
  if filename
    parts = filename.to_s.split('.')
    if parts.length > 1 and parts[-1].length < 4
      ext = parts[-1]
    end
  end

  case ctype
  when "text/plain"
    ext = "txt"
  end
  # This method is available even if there is no database, don't bother checking
  host = framework.db.normalize_host(host)

  ws = (db ? myworkspace.name[0,16] : 'default')
  name =
    Time.now.strftime("%Y%m%d%H%M%S") + "_" + ws + "_" +
    (host || 'unknown') + '_' + ltype[0,16] + '_' +
    Rex::Text.rand_text_numeric(6) + '.' + ext

  name.gsub!(/[^a-z0-9\.\_]+/i, '')

  path = File.join(Msf::Config.loot_directory, name)
  full_path = ::File.expand_path(path)
  File.open(full_path, "wb") do |fd|
    fd.write(data)
  end

  if (db)
    # If we have a database we need to store it with all the available
    # metadata.
    conf = {}
    conf[:host] = host if host
    conf[:type] = ltype
    conf[:content_type] = ctype
    conf[:path] = full_path
    conf[:workspace] = myworkspace
    conf[:name] = filename if filename
    conf[:info] = info if info

    if service and service.kind_of?(::Mdm::Service)
      conf[:service] = service if service
    end

    framework.db.report_loot(conf)
  end

  return full_path.dup
end