PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/msf/core/db.rb

https://bitbucket.org/jrossi/metasploit
Ruby | 4759 lines | 3391 code | 586 blank | 782 comment | 634 complexity | a0f00401a3aa688c88dfb996dbc9b9e1 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. require 'rex/parser/nmap_xml'
  2. require 'rex/parser/nexpose_xml'
  3. require 'rex/parser/retina_xml'
  4. require 'rex/parser/netsparker_xml'
  5. require 'rex/parser/nessus_xml'
  6. require 'rex/parser/ip360_xml'
  7. require 'rex/parser/ip360_aspl_xml'
  8. require 'rex/socket'
  9. require 'zip'
  10. require 'packetfu'
  11. require 'uri'
  12. require 'tmpdir'
  13. require 'fileutils'
  14. module Msf
  15. ###
  16. #
  17. # The states that a host can be in.
  18. #
  19. ###
  20. module HostState
  21. #
  22. # The host is alive.
  23. #
  24. Alive = "alive"
  25. #
  26. # The host is dead.
  27. #
  28. Dead = "down"
  29. #
  30. # The host state is unknown.
  31. #
  32. Unknown = "unknown"
  33. end
  34. ###
  35. #
  36. # The states that a service can be in.
  37. #
  38. ###
  39. module ServiceState
  40. Open = "open"
  41. Closed = "closed"
  42. Filtered = "filtered"
  43. Unknown = "unknown"
  44. end
  45. ###
  46. #
  47. # Events that can occur in the host/service database.
  48. #
  49. ###
  50. module DatabaseEvent
  51. #
  52. # Called when an existing host's state changes
  53. #
  54. def on_db_host_state(host, ostate)
  55. end
  56. #
  57. # Called when an existing service's state changes
  58. #
  59. def on_db_service_state(host, port, ostate)
  60. end
  61. #
  62. # Called when a new host is added to the database. The host parameter is
  63. # of type Host.
  64. #
  65. def on_db_host(host)
  66. end
  67. #
  68. # Called when a new client is added to the database. The client
  69. # parameter is of type Client.
  70. #
  71. def on_db_client(client)
  72. end
  73. #
  74. # Called when a new service is added to the database. The service
  75. # parameter is of type Service.
  76. #
  77. def on_db_service(service)
  78. end
  79. #
  80. # Called when an applicable vulnerability is found for a service. The vuln
  81. # parameter is of type Vuln.
  82. #
  83. def on_db_vuln(vuln)
  84. end
  85. #
  86. # Called when a new reference is created.
  87. #
  88. def on_db_ref(ref)
  89. end
  90. end
  91. class DBImportError < RuntimeError
  92. end
  93. ###
  94. #
  95. # The DB module ActiveRecord definitions for the DBManager
  96. #
  97. ###
  98. class DBManager
  99. def rfc3330_reserved(ip)
  100. case ip.class.to_s
  101. when "PacketFu::Octets"
  102. ip_x = ip.to_x
  103. ip_i = ip.to_i
  104. when "String"
  105. if ipv4_validator(ip)
  106. ip_x = ip
  107. ip_i = Rex::Socket.addr_atoi(ip)
  108. else
  109. raise ArgumentError, "Invalid IP address: #{ip.inspect}"
  110. end
  111. when "Fixnum"
  112. if (0..2**32-1).include? ip
  113. ip_x = Rex::Socket.addr_itoa(ip)
  114. ip_i = ip
  115. else
  116. raise ArgumentError, "Invalid IP address: #{ip.inspect}"
  117. end
  118. else
  119. raise ArgumentError, "Invalid IP address: #{ip.inspect}"
  120. end
  121. return true if Rex::Socket::RangeWalker.new("0.0.0.0-0.255.255.255").include? ip_x
  122. return true if Rex::Socket::RangeWalker.new("127.0.0.0-127.255.255.255").include? ip_x
  123. return true if Rex::Socket::RangeWalker.new("169.254.0.0-169.254.255.255").include? ip_x
  124. return true if Rex::Socket::RangeWalker.new("224.0.0.0-239.255.255.255").include? ip_x
  125. return true if Rex::Socket::RangeWalker.new("255.255.255.255-255.255.255.255").include? ip_x
  126. return false
  127. end
  128. def ipv4_validator(addr)
  129. return false unless addr.kind_of? String
  130. addr =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
  131. end
  132. # Takes a space-delimited set of ips and ranges, and subjects
  133. # them to RangeWalker for validation. Returns true or false.
  134. def validate_ips(ips)
  135. ret = true
  136. begin
  137. ips.split(' ').each {|ip|
  138. unless Rex::Socket::RangeWalker.new(ip).ranges
  139. ret = false
  140. break
  141. end
  142. }
  143. rescue
  144. ret = false
  145. end
  146. return ret
  147. end
  148. #
  149. # Determines if the database is functional
  150. #
  151. def check
  152. res = Host.find(:first)
  153. end
  154. def default_workspace
  155. Workspace.default
  156. end
  157. def find_workspace(name)
  158. Workspace.find_by_name(name)
  159. end
  160. #
  161. # Creates a new workspace in the database
  162. #
  163. def add_workspace(name)
  164. Workspace.find_or_create_by_name(name)
  165. end
  166. def workspaces
  167. Workspace.find(:all)
  168. end
  169. #
  170. # Wait for all pending write to finish
  171. #
  172. def sync
  173. task = queue( Proc.new { } )
  174. task.wait
  175. end
  176. #
  177. # Find a host. Performs no database writes.
  178. #
  179. def get_host(opts)
  180. if opts.kind_of? Host
  181. return opts
  182. elsif opts.kind_of? String
  183. raise RuntimeError, "This invokation of get_host is no longer supported: #{caller}"
  184. else
  185. address = opts[:addr] || opts[:address] || opts[:host] || return
  186. return address if address.kind_of? Host
  187. end
  188. wspace = opts.delete(:workspace) || workspace
  189. host = wspace.hosts.find_by_address(address)
  190. return host
  191. end
  192. #
  193. # Exactly like report_host but waits for the database to create a host and returns it.
  194. #
  195. def find_or_create_host(opts)
  196. report_host(opts.merge({:wait => true}))
  197. end
  198. #
  199. # Report a host's attributes such as operating system and service pack
  200. #
  201. # The opts parameter MUST contain
  202. # :host -- the host's ip address
  203. #
  204. # The opts parameter can contain:
  205. # :state -- one of the Msf::HostState constants
  206. # :os_name -- one of the Msf::OperatingSystems constants
  207. # :os_flavor -- something like "XP" or "Gentoo"
  208. # :os_sp -- something like "SP2"
  209. # :os_lang -- something like "English", "French", or "en-US"
  210. # :arch -- one of the ARCH_* constants
  211. # :mac -- the host's MAC address
  212. #
  213. def report_host(opts)
  214. return if not active
  215. addr = opts.delete(:host) || return
  216. # Sometimes a host setup through a pivot will see the address as "Remote Pipe"
  217. if addr.eql? "Remote Pipe"
  218. return
  219. end
  220. # Ensure the host field updated_at is changed on each report_host()
  221. if addr.kind_of? Host
  222. queue( Proc.new { addr.updated_at = addr.created_at; addr.save! } )
  223. return addr
  224. end
  225. addr = normalize_host(addr)
  226. wait = opts.delete(:wait)
  227. wspace = opts.delete(:workspace) || workspace
  228. if opts[:host_mac]
  229. opts[:mac] = opts.delete(:host_mac)
  230. end
  231. unless ipv4_validator(addr)
  232. raise ::ArgumentError, "Invalid IP address in report_host(): #{addr}"
  233. end
  234. ret = {}
  235. task = queue( Proc.new {
  236. if opts[:comm] and opts[:comm].length > 0
  237. host = wspace.hosts.find_or_initialize_by_address_and_comm(addr, opts[:comm])
  238. else
  239. host = wspace.hosts.find_or_initialize_by_address(addr)
  240. end
  241. opts.each { |k,v|
  242. if (host.attribute_names.include?(k.to_s))
  243. host[k] = v unless host.attribute_locked?(k.to_s)
  244. else
  245. dlog("Unknown attribute for Host: #{k}")
  246. end
  247. }
  248. host.info = host.info[0,Host.columns_hash["info"].limit] if host.info
  249. # Set default fields if needed
  250. host.state = HostState::Alive if not host.state
  251. host.comm = '' if not host.comm
  252. host.workspace = wspace if not host.workspace
  253. # Always save the host, helps track updates
  254. msf_import_timestamps(opts,host)
  255. host.save!
  256. ret[:host] = host
  257. } )
  258. if wait
  259. return nil if task.wait != :done
  260. return ret[:host]
  261. end
  262. return task
  263. end
  264. #
  265. # Iterates over the hosts table calling the supplied block with the host
  266. # instance of each entry.
  267. #
  268. def each_host(wspace=workspace, &block)
  269. wspace.hosts.each do |host|
  270. block.call(host)
  271. end
  272. end
  273. #
  274. # Returns a list of all hosts in the database
  275. #
  276. def hosts(wspace = workspace, only_up = false, addresses = nil)
  277. conditions = {}
  278. conditions[:state] = [Msf::HostState::Alive, Msf::HostState::Unknown] if only_up
  279. conditions[:address] = addresses if addresses
  280. wspace.hosts.all(:conditions => conditions, :order => :address)
  281. end
  282. def find_or_create_service(opts)
  283. report_service(opts.merge({:wait => true}))
  284. end
  285. #
  286. # Record a service in the database.
  287. #
  288. # opts must contain
  289. # :host -- the host where this service is running
  290. # :port -- the port where this service listens
  291. # :proto -- the transport layer protocol (e.g. tcp, udp)
  292. #
  293. # opts may contain
  294. # :name -- the application layer protocol (e.g. ssh, mssql, smb)
  295. #
  296. def report_service(opts)
  297. return if not active
  298. addr = opts.delete(:host) || return
  299. hname = opts.delete(:host_name)
  300. hmac = opts.delete(:host_mac)
  301. wait = opts.delete(:wait)
  302. wspace = opts.delete(:workspace) || workspace
  303. hopts = {:workspace => wspace, :host => addr}
  304. hopts[:name] = hname if hname
  305. hopts[:mac] = hmac if hmac
  306. report_host(hopts)
  307. ret = {}
  308. task = queue(Proc.new {
  309. host = get_host(:workspace => wspace, :address => addr)
  310. if host
  311. host.updated_at = host.created_at
  312. host.state = HostState::Alive
  313. host.save!
  314. end
  315. proto = opts[:proto] || 'tcp'
  316. opts[:name].downcase! if (opts[:name])
  317. service = host.services.find_or_initialize_by_port_and_proto(opts[:port].to_i, proto)
  318. opts.each { |k,v|
  319. if (service.attribute_names.include?(k.to_s))
  320. service[k] = v
  321. else
  322. dlog("Unknown attribute for Service: #{k}")
  323. end
  324. }
  325. if (service.state == nil)
  326. service.state = ServiceState::Open
  327. end
  328. if (service and service.changed?)
  329. msf_import_timestamps(opts,service)
  330. service.save!
  331. end
  332. ret[:service] = service
  333. })
  334. if wait
  335. return nil if task.wait() != :done
  336. return ret[:service]
  337. end
  338. return task
  339. end
  340. def get_service(wspace, host, proto, port)
  341. host = get_host(:workspace => wspace, :address => host)
  342. return if not host
  343. return host.services.find_by_proto_and_port(proto, port)
  344. end
  345. #
  346. # Iterates over the services table calling the supplied block with the
  347. # service instance of each entry.
  348. #
  349. def each_service(wspace=workspace, &block)
  350. services(wspace).each do |service|
  351. block.call(service)
  352. end
  353. end
  354. #
  355. # Returns a list of all services in the database
  356. #
  357. def services(wspace = workspace, only_up = false, proto = nil, addresses = nil, ports = nil, names = nil)
  358. conditions = {}
  359. conditions[:state] = [ServiceState::Open] if only_up
  360. conditions[:proto] = proto if proto
  361. conditions["hosts.address"] = addresses if addresses
  362. conditions[:port] = ports if ports
  363. conditions[:name] = names if names
  364. wspace.services.all(:include => :host, :conditions => conditions, :order => "hosts.address, port")
  365. end
  366. def get_client(opts)
  367. wspace = opts.delete(:workspace) || workspace
  368. host = get_host(:workspace => wspace, :host => opts[:host]) || return
  369. client = host.clients.find(:first, :conditions => {:ua_string => opts[:ua_string]})
  370. return client
  371. end
  372. def find_or_create_client(opts)
  373. report_client(opts.merge({:wait => true}))
  374. end
  375. #
  376. # Report a client running on a host.
  377. #
  378. # opts must contain
  379. # :ua_string -- the value of the User-Agent header
  380. # :host -- the host where this client connected from, can be an ip address or a Host object
  381. #
  382. # opts can contain
  383. # :ua_name -- one of the Msf::HttpClients constants
  384. # :ua_ver -- detected version of the given client
  385. # :campaign -- an id or Campaign object
  386. #
  387. # Returns a Client.
  388. #
  389. def report_client(opts)
  390. return if not active
  391. addr = opts.delete(:host) || return
  392. wspace = opts.delete(:workspace) || workspace
  393. report_host(:workspace => wspace, :host => addr)
  394. wait = opts.delete(:wait)
  395. ret = {}
  396. task = queue(Proc.new {
  397. host = get_host(:workspace => wspace, :host => addr)
  398. client = host.clients.find_or_initialize_by_ua_string(opts[:ua_string])
  399. campaign = opts.delete(:campaign)
  400. if campaign
  401. case campaign
  402. when Campaign
  403. opts[:campaign_id] = campaign.id
  404. else
  405. opts[:campaign_id] = campaign
  406. end
  407. end
  408. opts.each { |k,v|
  409. if (client.attribute_names.include?(k.to_s))
  410. client[k] = v
  411. else
  412. dlog("Unknown attribute for Client: #{k}")
  413. end
  414. }
  415. if (client and client.changed?)
  416. client.save!
  417. end
  418. ret[:client] = client
  419. })
  420. if wait
  421. return nil if task.wait() != :done
  422. return ret[:client]
  423. end
  424. return task
  425. end
  426. #
  427. # This method iterates the vulns table calling the supplied block with the
  428. # vuln instance of each entry.
  429. #
  430. def each_vuln(wspace=workspace,&block)
  431. wspace.vulns.each do |vulns|
  432. block.call(vulns)
  433. end
  434. end
  435. #
  436. # This methods returns a list of all vulnerabilities in the database
  437. #
  438. def vulns(wspace=workspace)
  439. wspace.vulns
  440. end
  441. #
  442. # This methods returns a list of all credentials in the database
  443. #
  444. def creds(wspace=workspace)
  445. Cred.find(
  446. :all,
  447. :include => {:service => :host}, # That's some magic right there.
  448. :conditions => ["hosts.workspace_id = ?", wspace.id]
  449. )
  450. end
  451. #
  452. # This method returns a list of all exploited hosts in the database.
  453. #
  454. def exploited_hosts(wspace=workspace)
  455. wspace.exploited_hosts
  456. end
  457. #
  458. # This method iterates the notes table calling the supplied block with the
  459. # note instance of each entry.
  460. #
  461. def each_note(wspace=workspace, &block)
  462. wspace.notes.each do |note|
  463. block.call(note)
  464. end
  465. end
  466. #
  467. # Find or create a note matching this type/data
  468. #
  469. def find_or_create_note(opts)
  470. report_note(opts.merge({:wait => true}))
  471. end
  472. #
  473. # Report a Note to the database. Notes can be tied to a Workspace, Host, or Service.
  474. #
  475. # opts MUST contain
  476. # :data -- whatever it is you're making a note of
  477. # :type -- The type of note, e.g. smb_peer_os
  478. #
  479. # opts can contain
  480. # :workspace -- the workspace to associate with this Note
  481. # :host -- an IP address or a Host object to associate with this Note
  482. # :service -- a Service object to associate with this Note
  483. # :port -- along with :host and proto, a service to associate with this Note
  484. # :proto -- along with :host and port, a service to associate with this Note
  485. # :update -- what to do in case a similar Note exists, see below
  486. #
  487. # The :update option can have the following values:
  488. # :unique -- allow only a single Note per +host+/+type+ pair
  489. # :unique_data -- like :uniqe, but also compare +data+
  490. # :insert -- always insert a new Note even if one with identical values exists
  491. #
  492. # If the provided :host is an IP address and does not exist in the
  493. # database, it will be created. If :workspace, :host and :service are all
  494. # omitted, the new Note will be associated with the current workspace.
  495. #
  496. def report_note(opts)
  497. return if not active
  498. wait = opts.delete(:wait)
  499. wspace = opts.delete(:workspace) || workspace
  500. seen = opts.delete(:seen) || false
  501. crit = opts.delete(:critical) || false
  502. host = nil
  503. addr = nil
  504. # Report the host so it's there for the Proc to use below
  505. if opts[:host]
  506. if opts[:host].kind_of? Host
  507. host = opts[:host]
  508. else
  509. report_host({:workspace => wspace, :host => opts[:host]})
  510. addr = normalize_host(opts[:host])
  511. end
  512. # Do the same for a service if that's also included.
  513. if (opts[:port])
  514. proto = nil
  515. sname = nil
  516. case opts[:proto].to_s.downcase # Catch incorrect usages
  517. when 'tcp','udp'
  518. proto = opts[:proto]
  519. sname = opts[:sname] if opts[:sname]
  520. when 'dns','snmp','dhcp'
  521. proto = 'udp'
  522. sname = opts[:proto]
  523. else
  524. proto = 'tcp'
  525. sname = opts[:proto]
  526. end
  527. sopts = {
  528. :workspace => wspace,
  529. :host => opts[:host],
  530. :port => opts[:port],
  531. :proto => proto
  532. }
  533. sopts[:name] = sname if sname
  534. report_service(sopts)
  535. end
  536. end
  537. # Update Modes can be :unique, :unique_data, :insert
  538. mode = opts[:update] || :unique
  539. ret = {}
  540. task = queue(Proc.new {
  541. if addr and not host
  542. host = get_host(:workspace => wspace, :host => addr)
  543. end
  544. if host and (opts[:port] and opts[:proto])
  545. service = get_service(wspace, host, opts[:proto], opts[:port])
  546. elsif opts[:service] and opts[:service].kind_of? Service
  547. service = opts[:service]
  548. end
  549. if host
  550. host.updated_at = host.created_at
  551. host.state = HostState::Alive
  552. host.save!
  553. end
  554. ntype = opts.delete(:type) || opts.delete(:ntype) || (raise RuntimeError, "A note :type or :ntype is required")
  555. data = opts[:data] || (raise RuntimeError, "Note :data is required")
  556. method = nil
  557. args = []
  558. note = nil
  559. conditions = { :ntype => ntype }
  560. conditions[:host_id] = host[:id] if host
  561. conditions[:service_id] = service[:id] if service
  562. notes = wspace.notes.find(:all, :conditions => conditions)
  563. case mode
  564. when :unique
  565. # Only one note of this type should exist, make a new one if it
  566. # isn't there. If it is, grab it and overwrite its data.
  567. if notes.empty?
  568. note = wspace.notes.new(conditions)
  569. else
  570. note = notes[0]
  571. end
  572. note.data = data
  573. when :unique_data
  574. # Don't make a new Note with the same data as one that already
  575. # exists for the given: type and (host or service)
  576. notes.each do |n|
  577. # Compare the deserialized data from the table to the raw
  578. # data we're looking for. Because of the serialization we
  579. # can't do this easily or reliably in SQL.
  580. if n.data == data
  581. note = n
  582. break
  583. end
  584. end
  585. if not note
  586. # We didn't find one with the data we're looking for, make
  587. # a new one.
  588. note = wspace.notes.new(conditions.merge(:data => data))
  589. end
  590. else
  591. # Otherwise, assume :insert, which means always make a new one
  592. note = wspace.notes.new
  593. if host
  594. note.host_id = host[:id]
  595. end
  596. if opts[:service] and opts[:service].kind_of? Service
  597. note.service_id = opts[:service][:id]
  598. end
  599. note.seen = seen
  600. note.critical = crit
  601. note.ntype = ntype
  602. note.data = data
  603. end
  604. msf_import_timestamps(opts,note)
  605. note.save!
  606. ret[:note] = note
  607. })
  608. if wait
  609. return nil if task.wait() != :done
  610. return ret[:note]
  611. end
  612. return task
  613. end
  614. #
  615. # This methods returns a list of all notes in the database
  616. #
  617. def notes(wspace=workspace)
  618. wspace.notes
  619. end
  620. # This is only exercised by MSF3 XML importing for now. Needs the wait
  621. # conditions and return hash as well.
  622. def report_host_tag(opts)
  623. name = opts.delete(:name)
  624. raise DBImportError.new("Missing required option :name") unless name
  625. addr = opts.delete(:addr)
  626. raise DBImportError.new("Missing required option :addr") unless addr
  627. wspace = opts.delete(:wspace)
  628. raise DBImportError.new("Missing required option :wspace") unless wspace
  629. host = nil
  630. report_host(:workspace => wspace, :address => addr)
  631. task = queue( Proc.new {
  632. host = get_host(:workspace => wspace, :address => addr)
  633. desc = opts.delete(:desc)
  634. summary = opts.delete(:summary)
  635. detail = opts.delete(:detail)
  636. crit = opts.delete(:crit)
  637. possible_tag = Tag.find(:all,
  638. :include => :hosts,
  639. :conditions => ["hosts.workspace_id = ? and tags.name = ?",
  640. wspace.id,
  641. name
  642. ]
  643. ).first
  644. tag = possible_tag || Tag.new
  645. tag.name = name
  646. tag.desc = desc
  647. tag.report_summary = !!summary
  648. tag.report_detail = !!detail
  649. tag.critical = !!crit
  650. tag.hosts = tag.hosts | [host]
  651. tag.save! if tag.changed?
  652. })
  653. return task
  654. end
  655. # report_auth_info used to create a note, now it creates
  656. # an entry in the creds table. It's much more akin to
  657. # report_vuln() now.
  658. #
  659. # opts must contain
  660. # :host -- an IP address
  661. # :port -- a port number
  662. #
  663. # opts can contain
  664. # :user -- the username
  665. # :pass -- the password, or path to ssh_key
  666. # :ptype -- the type of password (password, hash, or ssh_key)
  667. # :proto -- a transport name for the port
  668. # :sname -- service name
  669. # :active -- by default, a cred is active, unless explicitly false
  670. # :proof -- data used to prove the account is actually active.
  671. #
  672. # Sources: Credentials can be sourced from another credential, or from
  673. # a vulnerability. For example, if an exploit was used to dump the
  674. # smb_hashes, and this credential comes from there, the source_id would
  675. # be the Vuln id (as reported by report_vuln) and the type would be "Vuln".
  676. #
  677. # :source_id -- The Vuln or Cred id of the source of this cred.
  678. # :source_type -- Either Vuln or Cred
  679. #
  680. # TODO: This is written somewhat host-centric, when really the
  681. # Service is the thing. Need to revisit someday.
  682. def report_auth_info(opts={})
  683. return if not active
  684. raise ArgumentError.new("Missing required option :host") if opts[:host].nil?
  685. raise ArgumentError.new("Invalid address for :host") unless validate_ips(opts[:host])
  686. raise ArgumentError.new("Missing required option :port") if opts[:port].nil?
  687. host = opts.delete(:host)
  688. ptype = opts.delete(:type) || "password"
  689. token = [opts.delete(:user), opts.delete(:pass)]
  690. sname = opts.delete(:sname)
  691. port = opts.delete(:port)
  692. proto = opts.delete(:proto) || "tcp"
  693. proof = opts.delete(:proof)
  694. source_id = opts.delete(:source_id)
  695. source_type = opts.delete(:source_type)
  696. duplicate_ok = opts.delete(:duplicate_ok)
  697. # Nil is true for active.
  698. active = (opts[:active] || opts[:active].nil?) ? true : false
  699. wait = opts.delete(:wait)
  700. wspace = opts.delete(:workspace) || workspace
  701. # Service management; assume the user knows what
  702. # he's talking about.
  703. unless service = get_service(wspace, host, proto, port)
  704. report_service(:host => host, :port => port, :proto => proto, :name => sname, :workspace => wspace)
  705. end
  706. ret = {}
  707. task = queue( Proc.new {
  708. # Get the service
  709. service ||= get_service(wspace, host, proto, port)
  710. # If duplicate usernames are okay, find by both user and password (allows
  711. # for actual duplicates to get modified updated_at, sources, etc)
  712. if duplicate_ok
  713. cred = service.creds.find_or_initialize_by_user_and_ptype_and_pass(token[0] || "", ptype, token[1] || "")
  714. else
  715. # Create the cred by username only (so we can change passwords)
  716. cred = service.creds.find_or_initialize_by_user_and_ptype(token[0] || "", ptype)
  717. end
  718. # Update with the password
  719. cred.pass = (token[1] || "")
  720. # Annotate the credential
  721. cred.ptype = ptype
  722. cred.active = active
  723. # Update the source ID only if there wasn't already one.
  724. if source_id and !cred.source_id
  725. cred.source_id = source_id
  726. cred.source_type = source_type if source_type
  727. end
  728. # Safe proof (lazy way) -- doesn't chop expanded
  729. # characters correctly, but shouldn't ever be a problem.
  730. unless proof.nil?
  731. proof = Rex::Text.to_hex_ascii(proof)
  732. proof = proof[0,4096]
  733. end
  734. cred.proof = proof
  735. # Update the timestamp
  736. if cred.changed?
  737. msf_import_timestamps(opts,cred)
  738. cred.save!
  739. end
  740. # Ensure the updated_at is touched any time report_auth_info is called
  741. # except when it's set explicitly (as it is for imports)
  742. unless opts[:updated_at] || opts["updated_at"]
  743. cred.updated_at = Time.now.utc
  744. cred.save!
  745. end
  746. ret[:cred] = cred
  747. })
  748. if wait
  749. return nil if task.wait() != :done
  750. return ret[:cred]
  751. end
  752. return task
  753. end
  754. alias :report_cred :report_auth_info
  755. alias :report_auth :report_auth_info
  756. #
  757. # Find or create a credential matching this type/data
  758. #
  759. def find_or_create_cred(opts)
  760. report_auth_info(opts.merge({:wait => true}))
  761. end
  762. #
  763. # This method iterates the creds table calling the supplied block with the
  764. # cred instance of each entry.
  765. #
  766. def each_cred(wspace=workspace,&block)
  767. wspace.creds.each do |cred|
  768. block.call(cred)
  769. end
  770. end
  771. def each_exploited_host(wspace=workspace,&block)
  772. wspace.exploited_hosts.each do |eh|
  773. block.call(eh)
  774. end
  775. end
  776. #
  777. # Find or create a vuln matching this service/name
  778. #
  779. def find_or_create_vuln(opts)
  780. report_vuln(opts.merge({:wait => true}))
  781. end
  782. #
  783. # opts must contain
  784. # :host -- the host where this vulnerability resides
  785. # :name -- the scanner-specific id of the vuln (e.g. NEXPOSE-cifs-acct-password-never-expires)
  786. #
  787. # opts can contain
  788. # :info -- a human readable description of the vuln, free-form text
  789. # :refs -- an array of Ref objects or string names of references
  790. #
  791. def report_vuln(opts)
  792. return if not active
  793. raise ArgumentError.new("Missing required option :host") if opts[:host].nil?
  794. raise ArgumentError.new("Deprecated data column for vuln, use .info instead") if opts[:data]
  795. name = opts[:name] || return
  796. info = opts[:info]
  797. wait = opts.delete(:wait)
  798. wspace = opts.delete(:workspace) || workspace
  799. rids = nil
  800. if opts[:refs]
  801. rids = []
  802. opts[:refs].each do |r|
  803. if r.respond_to? :ctx_id
  804. r = r.ctx_id + '-' + r.ctx_val
  805. end
  806. rids << find_or_create_ref(:name => r)
  807. end
  808. end
  809. host = nil
  810. addr = nil
  811. if opts[:host].kind_of? Host
  812. host = opts[:host]
  813. else
  814. report_host({:workspace => wspace, :host => opts[:host]})
  815. addr = normalize_host(opts[:host])
  816. end
  817. ret = {}
  818. task = queue( Proc.new {
  819. if host
  820. host.updated_at = host.created_at
  821. host.state = HostState::Alive
  822. host.save!
  823. else
  824. host = get_host(:workspace => wspace, :address => addr)
  825. end
  826. if info
  827. vuln = host.vulns.find_or_initialize_by_name_and_info(name, info, :include => :refs)
  828. else
  829. vuln = host.vulns.find_or_initialize_by_name(name, :include => :refs)
  830. end
  831. if opts[:port]
  832. proto = nil
  833. case opts[:proto].to_s.downcase # Catch incorrect usages, as in report_note
  834. when 'tcp','udp'
  835. proto = opts[:proto]
  836. when 'dns','snmp','dhcp'
  837. proto = 'udp'
  838. sname = opts[:proto]
  839. else
  840. proto = 'tcp'
  841. sname = opts[:proto]
  842. end
  843. vuln.service = host.services.find_or_create_by_port_and_proto(opts[:port], proto)
  844. end
  845. if rids
  846. vuln.refs << (rids - vuln.refs)
  847. end
  848. if vuln.changed?
  849. msf_import_timestamps(opts,vuln)
  850. vuln.save!
  851. end
  852. ret[:vuln] = vuln
  853. })
  854. if wait
  855. return nil if task.wait() != :done
  856. return ret[:vuln]
  857. end
  858. return task
  859. end
  860. def get_vuln(wspace, host, service, name, data='')
  861. raise RuntimeError, "Not workspace safe: #{caller.inspect}"
  862. vuln = nil
  863. if (service)
  864. vuln = Vuln.find(:first, :conditions => [ "name = ? and service_id = ? and host_id = ?", name, service.id, host.id])
  865. else
  866. vuln = Vuln.find(:first, :conditions => [ "name = ? and host_id = ?", name, host.id])
  867. end
  868. return vuln
  869. end
  870. #
  871. # Find or create a reference matching this name
  872. #
  873. def find_or_create_ref(opts)
  874. ret = {}
  875. ret[:ref] = get_ref(opts[:name])
  876. return ret[:ref] if ret[:ref]
  877. task = queue(Proc.new {
  878. ref = Ref.find_or_initialize_by_name(opts[:name])
  879. if ref and ref.changed?
  880. ref.save!
  881. end
  882. ret[:ref] = ref
  883. })
  884. return nil if task.wait() != :done
  885. return ret[:ref]
  886. end
  887. def get_ref(name)
  888. Ref.find_by_name(name)
  889. end
  890. def report_exploit(opts={})
  891. return if not active
  892. raise ArgumentError.new("Missing required option :host") if opts[:host].nil?
  893. wait = opts[:wait]
  894. wspace = opts.delete(:workspace) || workspace
  895. host = nil
  896. addr = nil
  897. sname = opts.delete(:sname)
  898. port = opts.delete(:port)
  899. proto = opts.delete(:proto) || "tcp"
  900. name = opts.delete(:name)
  901. payload = opts.delete(:payload)
  902. session_uuid = opts.delete(:session_uuid)
  903. if opts[:host].kind_of? Host
  904. host = opts[:host]
  905. else
  906. report_host({:workspace => wspace, :host => opts[:host]})
  907. addr = normalize_host(opts[:host])
  908. end
  909. if opts[:service].kind_of? Service
  910. service = opts[:service]
  911. elsif port
  912. report_service(:host => host, :port => port, :proto => proto, :name => sname)
  913. service = get_service(wspace, host, proto, port)
  914. else
  915. service = nil
  916. end
  917. ret = {}
  918. task = queue(
  919. Proc.new {
  920. if host
  921. host.updated_at = host.created_at
  922. host.state = HostState::Alive
  923. host.save!
  924. else
  925. host = get_host(:workspace => wspace, :address => addr)
  926. end
  927. exploit_info = {
  928. :workspace => wspace,
  929. :host_id => host.id,
  930. :name => name,
  931. :payload => payload,
  932. }
  933. exploit_info[:service_id] = service.id if service
  934. exploit_info[:session_uuid] = session_uuid if session_uuid
  935. exploit_record = ExploitedHost.create(exploit_info)
  936. exploit_record.save!
  937. ret[:exploit] = exploit_record
  938. }
  939. )
  940. if wait
  941. return nil if task.wait() != :done
  942. return ret[:exploit]
  943. end
  944. return task
  945. end
  946. #
  947. # Deletes a host and associated data matching this address/comm
  948. #
  949. def del_host(wspace, address, comm='')
  950. host = wspace.hosts.find_by_address_and_comm(address, comm)
  951. host.destroy if host
  952. end
  953. #
  954. # Deletes a port and associated vulns matching this port
  955. #
  956. def del_service(wspace, address, proto, port, comm='')
  957. host = get_host(:workspace => wspace, :address => address)
  958. return unless host
  959. host.services.all(:conditions => {:proto => proto, :port => port}).each { |s| s.destroy }
  960. end
  961. #
  962. # Find a reference matching this name
  963. #
  964. def has_ref?(name)
  965. Ref.find_by_name(name)
  966. end
  967. #
  968. # Find a vulnerability matching this name
  969. #
  970. def has_vuln?(name)
  971. Vuln.find_by_name(name)
  972. end
  973. #
  974. # Look for an address across all comms
  975. #
  976. def has_host?(wspace,addr)
  977. wspace.hosts.find_by_address(addr)
  978. end
  979. def events(wspace=workspace)
  980. wspace.events.find :all, :order => 'created_at ASC'
  981. end
  982. def report_event(opts = {})
  983. return if not active
  984. wspace = opts.delete(:workspace) || workspace
  985. uname = opts.delete(:username)
  986. if opts[:host]
  987. report_host(:workspace => wspace, :host => opts[:host])
  988. end
  989. framework.db.queue(Proc.new {
  990. opts[:host] = get_host(:workspace => wspace, :host => opts[:host]) if opts[:host]
  991. Event.create(opts.merge(:workspace_id => wspace[:id], :username => uname))
  992. })
  993. end
  994. #
  995. # Loot collection
  996. #
  997. #
  998. # This method iterates the loot table calling the supplied block with the
  999. # instance of each entry.
  1000. #
  1001. def each_loot(wspace=workspace, &block)
  1002. wspace.loots.each do |note|
  1003. block.call(note)
  1004. end
  1005. end
  1006. #
  1007. # Find or create a loot matching this type/data
  1008. #
  1009. def find_or_create_loot(opts)
  1010. report_loot(opts.merge({:wait => true}))
  1011. end
  1012. def report_loot(opts)
  1013. return if not active
  1014. wait = opts.delete(:wait)
  1015. wspace = opts.delete(:workspace) || workspace
  1016. path = opts.delete(:path) || (raise RuntimeError, "A loot :path is required")
  1017. host = nil
  1018. addr = nil
  1019. # Report the host so it's there for the Proc to use below
  1020. if opts[:host]
  1021. if opts[:host].kind_of? Host
  1022. host = opts[:host]
  1023. else
  1024. report_host({:workspace => wspace, :host => opts[:host]})
  1025. addr = normalize_host(opts[:host])
  1026. end
  1027. end
  1028. ret = {}
  1029. task = queue(Proc.new {
  1030. if addr and not host
  1031. host = get_host(:workspace => wspace, :host => addr)
  1032. end
  1033. ltype = opts.delete(:type) || opts.delete(:ltype) || (raise RuntimeError, "A loot :type or :ltype is required")
  1034. ctype = opts.delete(:ctype) || opts.delete(:content_type) || 'text/plain'
  1035. name = opts.delete(:name)
  1036. info = opts.delete(:info)
  1037. data = opts[:data]
  1038. loot = wspace.loots.new
  1039. if host
  1040. loot.host_id = host[:id]
  1041. end
  1042. if opts[:service] and opts[:service].kind_of? Service
  1043. loot.service_id = opts[:service][:id]
  1044. end
  1045. loot.path = path
  1046. loot.ltype = ltype
  1047. loot.content_type = ctype
  1048. loot.data = data
  1049. loot.name = name if name
  1050. loot.info = info if info
  1051. msf_import_timestamps(opts,loot)
  1052. loot.save!
  1053. if !opts[:created_at]
  1054. if host
  1055. host.updated_at = host.created_at
  1056. host.state = HostState::Alive
  1057. host.save!
  1058. end
  1059. end
  1060. ret[:loot] = loot
  1061. })
  1062. if wait
  1063. return nil if task.wait() != :done
  1064. return ret[:loot]
  1065. end
  1066. return task
  1067. end
  1068. #
  1069. # This methods returns a list of all loot in the database
  1070. #
  1071. def loots(wspace=workspace)
  1072. wspace.loots
  1073. end
  1074. #
  1075. # Find or create a task matching this type/data
  1076. #
  1077. def find_or_create_task(opts)
  1078. report_task(opts.merge({:wait => true}))
  1079. end
  1080. def report_task(opts)
  1081. return if not active
  1082. wait = opts.delete(:wait)
  1083. wspace = opts.delete(:workspace) || workspace
  1084. path = opts.delete(:path) || (raise RuntimeError, "A task :path is required")
  1085. ret = {}
  1086. this_task = queue(Proc.new {
  1087. user = opts.delete(:user)
  1088. desc = opts.delete(:desc)
  1089. error = opts.delete(:error)
  1090. info = opts.delete(:info)
  1091. mod = opts.delete(:mod)
  1092. options = opts.delete(:options)
  1093. prog = opts.delete(:prog)
  1094. result = opts.delete(:result)
  1095. completed_at = opts.delete(:completed_at)
  1096. task = wspace.tasks.new
  1097. task.created_by = user
  1098. task.description = desc
  1099. task.error = error if error
  1100. task.info = info
  1101. task.module = mod
  1102. task.options = options
  1103. task.path = path
  1104. task.progress = prog
  1105. task.result = result if result
  1106. msf_import_timestamps(opts,task)
  1107. # Having blank completed_ats, while accurate, will cause unstoppable tasks.
  1108. if completed_at.nil? || completed_at.empty?
  1109. task.completed_at = opts[:updated_at]
  1110. else
  1111. task.completed_at = completed_at
  1112. end
  1113. task.save!
  1114. ret[:task] = task
  1115. })
  1116. if wait
  1117. return nil if this_task.wait() != :done
  1118. return ret[:task]
  1119. end
  1120. return this_task
  1121. end
  1122. #
  1123. # This methods returns a list of all tasks in the database
  1124. #
  1125. def tasks(wspace=workspace)
  1126. wspace.tasks
  1127. end
  1128. #
  1129. # Find or create a task matching this type/data
  1130. #
  1131. def find_or_create_report(opts)
  1132. report_report(opts.merge({:wait => true}))
  1133. end
  1134. def report_report(opts)
  1135. return if not active
  1136. wait = opts.delete(:wait)
  1137. wspace = opts.delete(:workspace) || workspace
  1138. path = opts.delete(:path) || (raise RuntimeError, "A report :path is required")
  1139. ret = {}
  1140. this_task = queue(Proc.new {
  1141. user = opts.delete(:user)
  1142. options = opts.delete(:options)
  1143. rtype = opts.delete(:rtype)
  1144. report = wspace.reports.new
  1145. report.created_by = user
  1146. report.options = options
  1147. report.rtype = rtype
  1148. report.path = path
  1149. msf_import_timestamps(opts,report)
  1150. report.save!
  1151. ret[:task] = report
  1152. })
  1153. if wait
  1154. return nil if this_task.wait() != :done
  1155. return ret[:task]
  1156. end
  1157. return this_task
  1158. end
  1159. #
  1160. # This methods returns a list of all reports in the database
  1161. #
  1162. def reports(wspace=workspace)
  1163. wspace.reports
  1164. end
  1165. #
  1166. # WMAP
  1167. # Support methods
  1168. #
  1169. #
  1170. # Report a Web Site to the database. WebSites must be tied to an existing Service
  1171. #
  1172. # opts MUST contain
  1173. # :service* -- the service object this site should be associated with
  1174. # :vhost -- the virtual host name for this particular web site`
  1175. # If service is NOT specified, the following values are mandatory
  1176. # :host -- the ip address of the server hosting the web site
  1177. # :port -- the port number of the associated web site
  1178. # :ssl -- whether or not SSL is in use on this port
  1179. #
  1180. # These values will be used to create new host and service records
  1181. #
  1182. # opts can contain
  1183. # :options -- a hash of options for accessing this particular web site
  1184. #
  1185. # Duplicate records for a given host, port, vhost combination will be overwritten
  1186. #
  1187. def report_web_site(opts)
  1188. return if not active
  1189. wait = opts.delete(:wait)
  1190. wspace = opts.delete(:workspace) || workspace
  1191. vhost = opts.delete(:vhost)
  1192. addr = nil
  1193. port = nil
  1194. name = nil
  1195. serv = nil
  1196. if opts[:service] and opts[:service].kind_of?(Service)
  1197. serv = opts[:service]
  1198. else
  1199. addr = opts[:host]
  1200. port = opts[:port]
  1201. name = opts[:ssl] ? 'https' : 'http'
  1202. if not (addr and port)
  1203. raise ArgumentError, "report_web_site requires service OR host/port/ssl"
  1204. end
  1205. # Force addr to be the address and not hostname
  1206. addr = Rex::Socket.getaddress(addr)
  1207. end
  1208. ret = {}
  1209. task = queue(Proc.new {
  1210. host = serv ? serv.host : find_or_create_host(
  1211. :workspace => wspace,
  1212. :host => addr,
  1213. :state => Msf::HostState::Alive
  1214. )
  1215. if host.name.to_s.empty?
  1216. host.name = vhost
  1217. host.save!
  1218. end
  1219. serv = serv ? serv : find_or_create_service(
  1220. :workspace => wspace,
  1221. :host => host,
  1222. :port => port,
  1223. :proto => 'tcp',
  1224. :state => 'open'
  1225. )
  1226. # Change the service name if it is blank or it has
  1227. # been explicitly specified.
  1228. if opts.keys.include?(:ssl) or serv.name.to_s.empty?
  1229. name = opts[:ssl] ? 'https' : 'http'
  1230. serv.name = name
  1231. serv.save!
  1232. end
  1233. host.updated_at = host.created_at
  1234. host.state = HostState::Alive
  1235. host.save!
  1236. vhost ||= host.address
  1237. site = WebSite.find_or_initialize_by_vhost_and_service_id(vhost, serv[:id])
  1238. site.options = opts[:options] if opts[:options]
  1239. # XXX:
  1240. msf_import_timestamps(opts, site)
  1241. site.save!
  1242. ret[:web_site] = site
  1243. })
  1244. if wait
  1245. return nil if task.wait() != :done
  1246. return ret[:web_site]
  1247. end
  1248. return task
  1249. end
  1250. #
  1251. # Report a Web Page to the database. WebPage must be tied to an existing Web Site
  1252. #
  1253. # opts MUST contain
  1254. # :web_site* -- the web site object that this page should be associated with
  1255. # :path -- the virtual host name for this particular web site
  1256. # :code -- the http status code from requesting this page
  1257. # :headers -- this is a HASH of headers (lowercase name as key) of ARRAYs of values
  1258. # :body -- the document body of the server response
  1259. # :query -- the query string after the path
  1260. # If web_site is NOT specified, the following values are mandatory
  1261. # :host -- the ip address of the server hosting the web site
  1262. # :port -- the port number of the associated web site
  1263. # :vhost -- the virtual host for this particular web site
  1264. # :ssl -- whether or not SSL is in use on this port
  1265. #
  1266. # These values will be used to create new host, service, and web_site records
  1267. #
  1268. # opts can contain
  1269. # :cookie -- the Set-Cookie headers, merged into a string
  1270. # :auth -- the Authorization headers, merged into a string
  1271. # :ctype -- the Content-Type headers, merged into a string
  1272. # :mtime -- the timestamp returned from the server of the last modification time
  1273. # :location -- the URL that a redirect points to
  1274. #
  1275. # Duplicate records for a given web_site, path, and query combination will be overwritten
  1276. #
  1277. def report_web_page(opts)
  1278. return if not active
  1279. wait = opts.delete(:wait)
  1280. wspace = opts.delete(:workspace) || workspace
  1281. path = opts[:path]
  1282. code = opts[:code].to_i
  1283. body = opts[:body].to_s
  1284. query = opts[:query].to_s
  1285. headers = opts[:headers]
  1286. site = nil
  1287. if not (path and code and body and headers)
  1288. raise ArgumentError, "report_web_page requires the path, query, code, body, and headers parameters"
  1289. end
  1290. if opts[:web_site] and opts[:web_site].kind_of?(WebSite)
  1291. site = opts.delete(:web_site)
  1292. else
  1293. site = report_web_site(
  1294. :workspace => wspace,
  1295. :host => opts[:host], :port => opts[:port],
  1296. :vhost => opts[:host], :ssl => opts[:ssl],
  1297. :wait => true
  1298. )
  1299. if not site
  1300. raise ArgumentError, "report_web_page was unable to create the associated web site"
  1301. end
  1302. end
  1303. ret = {}
  1304. task = queue(Proc.new {
  1305. page = WebPage.find_or_initialize_by_web_site_id_and_path_and_query(site[:id], path, query)
  1306. page.code = code
  1307. page.body = body
  1308. page.headers = headers
  1309. page.cookie = opts[:cookie] if opts[:cookie]
  1310. page.auth = opts[:auth] if opts[:auth]
  1311. page.mtime = opts[:mtime] if opts[:mtime]
  1312. page.ctype = opts[:ctype] if opts[:ctype]
  1313. page.location = opts[:location] if opts[:location]
  1314. msf_import_timestamps(opts, page)
  1315. page.save!
  1316. ret[:web_page] = page
  1317. })
  1318. if wait
  1319. return nil if task.wait() != :done
  1320. return ret[:web_page]
  1321. end
  1322. return task
  1323. end
  1324. #
  1325. # Report a Web Form to the database. WebForm must be tied to an existing Web Site
  1326. #
  1327. # opts MUST contain
  1328. # :web_site* -- the web site object that this page should be associated with
  1329. # :path -- the virtual host name for this particular web site
  1330. # :query -- the query string that is appended to the path (not valid for GET)
  1331. # :method -- the form method, one of GET, POST, or PATH
  1332. # :params -- an ARRAY of all parameters and values specified in the form
  1333. #
  1334. # If web_site is NOT specified, the following values are mandatory
  1335. # :host -- the ip address of the server hosting the web site
  1336. # :port -- the port number of the associated web site
  1337. # :vhost -- the virtual host for this particular web site
  1338. # :ssl -- whether or not SSL is in use on this port
  1339. #
  1340. #
  1341. # Duplicate records for a given web_site, path, method, and params combination will be overwritten
  1342. #
  1343. def report_web_form(opts)
  1344. return if not active
  1345. wait = opts.delete(:wait)
  1346. wspace = opts.delete(:workspace) || workspace
  1347. path = opts[:path]
  1348. meth = opts[:method].to_s.upcase
  1349. para = opts[:params]
  1350. quer = opts[:query].to_s
  1351. site = nil
  1352. if not (path and meth)
  1353. raise ArgumentError, "report_web_form requires the path and method parameters"
  1354. end
  1355. if not %W{GET POST PATH}.include?(meth)
  1356. raise ArgumentError, "report_web_form requires the method to be one of GET, POST, PATH"
  1357. end
  1358. if opts[:web_site] and opts[:web_site].kind_of?(WebSite)
  1359. site = opts.delete(:web_site)
  1360. else
  1361. site = report_web_site(
  1362. :workspace => wspace,
  1363. :host => opts[:host], :port => opts[:port],
  1364. :vhost => opts[:host], :ssl => opts[:ssl],
  1365. :wait => true
  1366. )
  1367. if not site
  1368. raise ArgumentError, "report_web_form was unable to create the associated web site"
  1369. end
  1370. end
  1371. ret = {}
  1372. task = queue(Proc.new {
  1373. # Since one of our serialized fields is used as a unique parameter, we must do the final
  1374. # comparisons through ruby and not SQL.
  1375. form = nil
  1376. WebForm.find_all_by_web_site_id_and_path_and_method_and_query(site[:id], path, meth, quer).each do |xform|
  1377. if xform.params == para
  1378. form = xform
  1379. break
  1380. end
  1381. end
  1382. if not form
  1383. form = WebForm.new
  1384. form.web_site_id = site[:id]
  1385. form.path = path
  1386. form.method = meth
  1387. form.params = para
  1388. form.query = quer
  1389. end
  1390. msf_import_timestamps(opts, form)
  1391. form.save!
  1392. ret[:web_form] = form
  1393. })
  1394. if wait
  1395. return nil if task.wait() != :done
  1396. return ret[:web_form]
  1397. end
  1398. return task
  1399. end
  1400. #
  1401. # Report a Web Vuln to the database. WebVuln must be tied to an existing Web Site
  1402. #
  1403. # opts MUST contain
  1404. # :web_site* -- the web site object that this page should be associated with
  1405. # :path -- the virtual host name for this particular web site
  1406. # :query -- the query string appended to the path (not valid for GET method flaws)
  1407. # :method -- the form method, one of GET, POST, or PATH
  1408. # :params -- an ARRAY of all parameters and values specified in the form
  1409. # :pname -- the specific field where the vulnerability occurs
  1410. # :proof -- the string showing proof of the vulnerability
  1411. # :risk -- an INTEGER value from 0 to 5 indicating the risk (5 is highest)
  1412. # :name -- the string indicating the type of vulnerability
  1413. #
  1414. # If web_site is NOT specified, the following values are mandatory
  1415. # :host -- the ip address of the server hosting the web site
  1416. # :port -- the port number of the associated web site
  1417. # :vhost -- the virtual host for this particular web site
  1418. # :ssl -- whether or not SSL is in use on this port
  1419. #
  1420. #
  1421. # Duplicate records for a given web_site, path, method, pname, and name combination will be overwritten
  1422. #
  1423. def report_web_vuln(opts)
  1424. return if not active
  1425. wait = opts.delete(:wait)
  1426. wspace = opts.delete(:workspace) || workspace
  1427. path = opts[:path]
  1428. meth = opts[:method]
  1429. para = opts[:params] || []
  1430. quer = opts[:query].to_s
  1431. pname = opts[:pname]
  1432. proof = opts[:proof]
  1433. risk = opts[:risk].to_i
  1434. name = opts[:name].to_s.strip
  1435. blame = opts[:blame].to_s.strip
  1436. desc = opts[:description].to_s.strip
  1437. conf = opts[:confidence].to_i
  1438. cat = opts[:category].to_s.strip
  1439. site = nil
  1440. if not (path and meth and proof and pname)
  1441. raise ArgumentError, "report_web_vuln requires the path, method, proof, risk, name, params, and pname parameters. Received #{opts.inspect}"
  1442. end
  1443. if not %W{GET POST PATH}.include?(meth)
  1444. raise ArgumentError, "report_web_vuln requires the method to be one of GET, POST, PATH. Received '#{meth}'"
  1445. end
  1446. if risk < 0 or risk > 5
  1447. raise ArgumentError, "report_web_vuln requires the risk to be between 0 and 5 (inclusive). Received '#{risk}'"
  1448. end
  1449. if conf < 0 or conf > 100
  1450. raise ArgumentError, "report_web_vuln requires the confidence to be between 1 and 100 (inclusive). Received '#{conf}'"
  1451. end
  1452. if cat.empty?
  1453. raise ArgumentError, "report_web_vuln requires the category to be a valid string"
  1454. end
  1455. if name.empty?
  1456. raise ArgumentError, "report_web_vuln requires the name to be a valid string"
  1457. end
  1458. if opts[:web_site] and opts[:web_site].kind_of?(WebSite)
  1459. site = opts.delete(:web_site)
  1460. else
  1461. site = report_web_site(
  1462. :workspace => wspace,
  1463. :host => opts[:host], :port => opts[:port],
  1464. :vhost => opts[:host], :ssl => opts[:ssl],
  1465. :wait => true
  1466. )
  1467. if not site
  1468. raise ArgumentError, "report_web_form was unable to create the associated web site"
  1469. end
  1470. end
  1471. ret = {}
  1472. task = queue(Proc.new {
  1473. meth = meth.to_s.upcase
  1474. vuln = WebVuln.find_or_initialize_by_web_site_id_and_path_and_method_and_pname_and_category_and_query(site[:id], path, meth, pname, cat, quer)
  1475. vuln.name = name
  1476. vuln.risk = risk
  1477. vuln.params = para
  1478. vuln.proof = proof.to_s
  1479. vuln.category = cat
  1480. vuln.blame = blame
  1481. vuln.description = desc
  1482. vuln.confidence = conf
  1483. msf_import_timestamps(opts, vuln)
  1484. vuln.save!
  1485. ret[:web_vuln] = vuln
  1486. })
  1487. if wait
  1488. return nil if task.wait() != :done
  1489. return ret[:web_vuln]
  1490. end
  1491. return task
  1492. end
  1493. #
  1494. # WMAP
  1495. # Selected host
  1496. #
  1497. def selected_host
  1498. selhost = WmapTarget.find(:first, :conditions => ["selected != 0"] )
  1499. if selhost
  1500. return selhost.host
  1501. else
  1502. return
  1503. end
  1504. end
  1505. #
  1506. # WMAP
  1507. # Selected port
  1508. #
  1509. def selected_port
  1510. WmapTarget.find(:first, :conditions => ["selected != 0"] ).port
  1511. end
  1512. #
  1513. # WMAP
  1514. # Selected ssl
  1515. #
  1516. def selected_ssl
  1517. WmapTarget.find(:first, :conditions => ["selected != 0"] ).ssl
  1518. end
  1519. #
  1520. # WMAP
  1521. # Selected id
  1522. #
  1523. def selected_id
  1524. WmapTarget.find(:first, :conditions => ["selected != 0"] ).object_id
  1525. end
  1526. #
  1527. # WMAP
  1528. # This method iterates the requests table identifiying possible targets
  1529. # This method wiil be remove on second phase of db merging.
  1530. #
  1531. def each_distinct_target(&block)
  1532. request_distinct_targets.each do |target|
  1533. block.call(target)
  1534. end
  1535. end
  1536. #
  1537. # WMAP
  1538. # This method returns a list of all possible targets available in requests
  1539. # This method wiil be remove on second phase of db merging.
  1540. #
  1541. def request_distinct_targets
  1542. WmapRequest.find(:all, :select => 'DISTINCT host,address,port,ssl')
  1543. end
  1544. #
  1545. # WMAP
  1546. # This method iterates the requests table returning a list of all requests of a specific target
  1547. #
  1548. def each_request_target_with_path(&block)
  1549. target_requests('AND wmap_requests.path IS NOT NULL').each do |req|
  1550. block.call(req)
  1551. end
  1552. end
  1553. #
  1554. # WMAP
  1555. # This method iterates the requests table returning a list of all requests of a specific target
  1556. #
  1557. def each_request_target_with_query(&block)
  1558. target_requests('AND wmap_requests.query IS NOT NULL').each do |req|
  1559. block.call(req)
  1560. end
  1561. end
  1562. #
  1563. # WMAP
  1564. # This method iterates the requests table returning a list of all requests of a specific target
  1565. #
  1566. def each_request_target_with_body(&block)
  1567. target_requests('AND wmap_requests.body IS NOT NULL').each do |req|
  1568. block.call(req)
  1569. end
  1570. end
  1571. #
  1572. # WMAP
  1573. # This method iterates the requests table returning a list of all requests of a specific target
  1574. #
  1575. def each_request_target_with_headers(&block)
  1576. target_requests('AND wmap_requests.headers IS NOT NULL').each do |req|
  1577. block.call(req)
  1578. end
  1579. end
  1580. #
  1581. # WMAP
  1582. # This method iterates the requests table returning a list of all requests of a specific target
  1583. #
  1584. def each_request_target(&block)
  1585. target_requests('').each do |req|
  1586. block.call(req)
  1587. end
  1588. end
  1589. #
  1590. # WMAP
  1591. # This method returns a list of all requests from target
  1592. #
  1593. def target_requests(extra_condition)
  1594. WmapRequest.find(:all, :conditions => ["wmap_requests.host = ? AND wmap_requests.port = ? #{extra_condition}",selected_host,selected_port])
  1595. end
  1596. #
  1597. # WMAP
  1598. # This method iterates the requests table calling the supplied block with the
  1599. # request instance of each entry.
  1600. #
  1601. def each_request(&block)
  1602. requests.each do |request|
  1603. block.call(request)
  1604. end
  1605. end
  1606. #
  1607. # WMAP
  1608. # This method allows to query directly the requests table. To be used mainly by modules
  1609. #
  1610. def request_sql(host,port,extra_condition)
  1611. WmapRequest.find(:all, :conditions => ["wmap_requests.host = ? AND wmap_requests.port = ? #{extra_condition}",host,port])
  1612. end
  1613. #
  1614. # WMAP
  1615. # This methods returns a list of all targets in the database
  1616. #
  1617. def requests
  1618. WmapRequest.find(:all)
  1619. end
  1620. #
  1621. # WMAP
  1622. # This method iterates the targets table calling the supplied block with the
  1623. # target instance of each entry.
  1624. #
  1625. def each_target(&block)
  1626. targets.each do |target|
  1627. block.call(target)
  1628. end
  1629. end
  1630. #
  1631. # WMAP
  1632. # This methods returns a list of all targets in the database
  1633. #
  1634. def targets
  1635. WmapTarget.find(:all)
  1636. end
  1637. #
  1638. # WMAP
  1639. # This methods deletes all targets from targets table in the database
  1640. #
  1641. def delete_all_targets
  1642. WmapTarget.delete_all
  1643. end
  1644. #
  1645. # WMAP
  1646. # Find a target matching this id
  1647. #
  1648. def get_target(id)
  1649. target = WmapTarget.find(:first, :conditions => [ "id = ?", id])
  1650. return target
  1651. end
  1652. #
  1653. # WMAP
  1654. # Create a target
  1655. #
  1656. def create_target(host,port,ssl,sel)
  1657. tar = WmapTarget.create(
  1658. :host => host,
  1659. :address => host,
  1660. :port => port,
  1661. :ssl => ssl,
  1662. :selected => sel
  1663. )
  1664. #framework.events.on_db_target(rec)
  1665. end
  1666. #
  1667. # WMAP
  1668. # Create a request (by hand)
  1669. #
  1670. def create_request(host,port,ssl,meth,path,headers,query,body,respcode,resphead,response)
  1671. req = WmapRequest.create(
  1672. :host => host,
  1673. :address => host,
  1674. :port => port,
  1675. :ssl => ssl,
  1676. :meth => meth,
  1677. :path => path,
  1678. :headers => headers,
  1679. :query => query,
  1680. :body => body,
  1681. :respcode => respcode,
  1682. :resphead => resphead,
  1683. :response => response
  1684. )
  1685. #framework.events.on_db_request(rec)
  1686. end
  1687. #
  1688. # WMAP
  1689. # Quick way to query the database (used by wmap_sql)
  1690. #
  1691. def sql_query(sqlquery)
  1692. ActiveRecord::Base.connection.select_all(sqlquery)
  1693. end
  1694. # Returns a REXML::Document from the given data.
  1695. def rexmlify(data)
  1696. if data.kind_of?(REXML::Document)
  1697. return data
  1698. else
  1699. # Make an attempt to recover from a REXML import fail, since
  1700. # it's better than dying outright.
  1701. begin
  1702. return REXML::Document.new(data)
  1703. rescue REXML::ParseException => e
  1704. dlog("REXML error: Badly formatted XML, attempting to recover. Error was: #{e.inspect}")
  1705. return REXML::Document.new(data.gsub(/([\x00-\x08\x0b\x0c\x0e-\x19\x80-\xff])/){ |x| "\\x%.2x" % x.unpack("C*")[0] })
  1706. end
  1707. end
  1708. end
  1709. # Handles timestamps from Metasploit Express imports.
  1710. def msf_import_timestamps(opts,obj)
  1711. obj.created_at = o…

Large files files are truncated, but you can click here to view the full file