metasploit_data_models 0.16.4-java → 0.16.5-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,20 +3,98 @@
3
3
  class EnforceAddressUniquenessInWorkspaceInHosts < ActiveRecord::Migration
4
4
  TABLE_NAME = :hosts
5
5
 
6
+ # maps Table -> Association Column for models that "belong to" a Host
7
+ HOST_ASSOCIATION_MAP = {
8
+ 'clients' => 'host_id',
9
+ 'events' => 'host_id',
10
+ 'exploit_attempts' => 'host_id',
11
+ 'exploited_hosts' => 'host_id',
12
+ 'host_details' => 'host_id',
13
+ 'hosts_tags' => 'host_id',
14
+ 'loots' => 'host_id',
15
+ 'notes' => 'host_id',
16
+ 'sessions' => 'host_id',
17
+ 'services' => 'host_id',
18
+ 'vulns' => 'host_id'
19
+ }
20
+
21
+ # Historically there a few scenarios where a user could end up with Hosts
22
+ # in the same workspace with the same IP. Primarily, if you run a Nexpose Scan
23
+ # and a Discover scan simultaneously, AR does not know about these separate
24
+ # transactions, so the Hosts will be valid when added and the user will end up
25
+ # (when transaction completes) with two hosts with the same IP in the same workspace.
26
+ #
27
+ # Since we are adding a DB uniq constraint here, this migration could fail if the user
28
+ # has hit aforementioned scenarios. So we try to "merge" any hosts with the same
29
+ # address in the same workspace before adding the DB constraint, to prevent the
30
+ # migration from simply failing.
31
+ #
32
+ # Note: We can't rely on AR directly here (or in any migration), since we have no
33
+ # idea what version of the code the user has checked out. So we fall back to SQL :(
34
+ def find_and_merge_duplicate_hosts!
35
+ # find all duplicate addresses within the same workspace currently in the db
36
+ dupe_addresses_and_workspaces = ActiveRecord::Base.connection.execute(%Q{
37
+ SELECT workspace_id, address, count_addr
38
+ FROM (
39
+ SELECT workspace_id, address, COUNT(address) AS count_addr
40
+ FROM hosts
41
+ GROUP BY address, workspace_id
42
+ ) X
43
+ WHERE count_addr > 1
44
+ })
45
+
46
+ if dupe_addresses_and_workspaces.present? and
47
+ not dupe_addresses_and_workspaces.num_tuples.zero?
48
+ puts "Duplicate hosts in workspace found. Merging host references."
49
+ # iterate through the duped IPs
50
+ dupe_addresses_and_workspaces.each do |result|
51
+ # so its come to this
52
+ address = ActiveRecord::Base.connection.quote(result['address'])
53
+ workspace_id = result['workspace_id'].to_i
54
+ # look up the duplicate Host table entries to find all IDs of the duped Hosts
55
+ hosts = ActiveRecord::Base.connection.execute(%Q|
56
+ SELECT id
57
+ FROM hosts
58
+ WHERE address=#{address} AND workspace_id=#{workspace_id}
59
+ ORDER BY id DESC
60
+ |)
61
+ # grab and quote the ID for each result row
62
+ hosts = hosts.map { |h| h["id"].to_i }
63
+ # grab every Host entry besides the first one
64
+ first_host_id = hosts.first
65
+ dupe_host_ids = hosts[1..-1]
66
+ # update associations to these duplicate Hosts
67
+ HOST_ASSOCIATION_MAP.each do |table, column|
68
+ ActiveRecord::Base.connection.execute(%Q|
69
+ UPDATE #{table} SET #{column}=#{first_host_id}
70
+ WHERE #{column} IN (#{dupe_host_ids.join(',')})
71
+ |)
72
+ end
73
+ # destroy the duplicate host rows
74
+ ActiveRecord::Base.connection.execute(%Q|
75
+ DELETE FROM hosts WHERE id IN (#{dupe_host_ids.join(',')})
76
+ |)
77
+ end
78
+
79
+ # At this point all duped hosts in the same workspace should be merged.
80
+ # You could end up with duplicate services, but hey its better than just
81
+ # dropping all data about the old Host.
82
+ end
83
+ end
84
+
6
85
  # Restores old index on address
7
86
  def down
8
87
  change_table TABLE_NAME do |t|
9
88
  t.remove_index [:workspace_id, :address]
10
-
11
89
  t.index :address
12
90
  end
13
91
  end
14
92
 
15
93
  # Make index on address scope to workspace_id and be unique
16
94
  def up
95
+ find_and_merge_duplicate_hosts!
17
96
  change_table TABLE_NAME do |t|
18
97
  t.remove_index :address
19
-
20
98
  t.index [:workspace_id, :address], :unique => true
21
99
  end
22
100
  end
@@ -4,5 +4,5 @@ module MetasploitDataModels
4
4
  # metasploit-framework/data/sql/migrate to db/migrate in this project, not all models have specs that verify the
5
5
  # migrations (with have_db_column and have_db_index) and certain models may not be shared between metasploit-framework
6
6
  # and pro, so models may be removed in the future. Because of the unstable API the version should remain below 1.0.0
7
- VERSION = '0.16.4'
7
+ VERSION = '0.16.5'
8
8
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: metasploit_data_models
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.16.4
5
+ version: 0.16.5
6
6
  platform: java
7
7
  authors:
8
8
  - Samuel Huckins
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-07-05 00:00:00.000000000 Z
15
+ date: 2013-07-16 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rake