metasploit_data_models 0.20.1.pre.recog → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/Gemfile +3 -3
- data/app/models/mdm/host.rb +2 -2
- data/lib/mdm/host/operating_system_normalization.rb +888 -803
- data/lib/metasploit_data_models/version.rb +0 -2
- data/metasploit_data_models.gemspec +0 -4
- data/spec/app/models/mdm/host_spec.rb +127 -333
- data/spec/dummy/db/structure.sql +0 -679
- metadata +174 -20
- data/db/migrate/20140919000000_normalize_existing_hosts.rb +0 -8
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
ZmM0ZmRiYjg4NWVhNWI5NzY1ZDk4Y2JjMTQwMGJiNTVmMmNhODVjZQ==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
MmFmNzA2YTJjYjZkNjI3ZjBlNGNhYzQxOTU4N2MwMzA2MDdiNjUwOA==
|
|
7
7
|
SHA512:
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
ZTlkNjNkMjE0ZmU4ZWRhY2MwZWIyMmE3M2M3YzRhZjg3OTg2MmU1YmY3MmJj
|
|
10
|
+
NWNmNTk4MWM0MzM5ZGRjZTg4OGFiYWMwNTMzOWY0ZGMwNWMwZjgwZjc3ODI3
|
|
11
|
+
NjdkNWExZThkNGE0MzY2ZTkwZGJlYTcxOTlhMjEyZWQ4ODFmNTA=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
ZmE4YzgzZjUwNDM5YjJjMzUwOGYwYjk0NzJhYTNmZDkzNDA1ZjhlOGZjMTBl
|
|
14
|
+
NjJlZDlmZjlmNTNlZDlmOWQ5YTM0MmQ4MzRlZjQyYjVkMGQ5NWIxYzZhMWRm
|
|
15
|
+
ZWJiMDRiNDY2Nzk0MmI2ZmI3ZGJkZmE2ZTk3MTY2M2NiNDJkMjE=
|
data/Gemfile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
source "
|
|
1
|
+
source "http://rubygems.org"
|
|
2
2
|
|
|
3
3
|
# Specify your gem's dependencies in metasploit_data_models.gemspec
|
|
4
4
|
gemspec
|
|
@@ -10,8 +10,6 @@ end
|
|
|
10
10
|
|
|
11
11
|
# used by dummy application
|
|
12
12
|
group :development, :test do
|
|
13
|
-
# Upload coverage reports to coveralls.io
|
|
14
|
-
gem 'coveralls', require: false
|
|
15
13
|
# supplies factories for producing model instance for specs
|
|
16
14
|
# Version 4.1.0 or newer is needed to support generate calls without the 'FactoryGirl.' in factory definitions syntax.
|
|
17
15
|
gem 'factory_girl', '>= 4.1.0'
|
|
@@ -26,6 +24,8 @@ group :development, :test do
|
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
group :test do
|
|
27
|
+
# Upload coverage reports to coveralls.io
|
|
28
|
+
gem 'coveralls', require: false
|
|
29
29
|
# In a full rails project, factory_girl_rails would be in both the :development, and :test group, but since we only
|
|
30
30
|
# want rails in :test, factory_girl_rails must also only be in :test.
|
|
31
31
|
# add matchers from shoulda, such as validates_presence_of, which are useful for testing validations
|
data/app/models/mdm/host.rb
CHANGED
|
@@ -359,7 +359,7 @@ class Mdm::Host < ActiveRecord::Base
|
|
|
359
359
|
# The flavor of {#os_name}.
|
|
360
360
|
#
|
|
361
361
|
# @example Windows XP
|
|
362
|
-
# host.os_name = 'Windows'
|
|
362
|
+
# host.os_name = 'Microsoft Windows'
|
|
363
363
|
# host.os_flavor = 'XP'
|
|
364
364
|
#
|
|
365
365
|
# @return [String]
|
|
@@ -379,7 +379,7 @@ class Mdm::Host < ActiveRecord::Base
|
|
|
379
379
|
# The service pack of the {#os_flavor} of the {#os_name}.
|
|
380
380
|
#
|
|
381
381
|
# @example Windows XP SP2
|
|
382
|
-
# host.os_name = 'Windows'
|
|
382
|
+
# host.os_name = 'Microsoft Windows'
|
|
383
383
|
# host.os_flavor = 'XP'
|
|
384
384
|
# host.os_sp = 'SP2'
|
|
385
385
|
#
|
|
@@ -1,292 +1,705 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Leverage the Recog gem as much as possible for sane fingerprint management
|
|
3
|
-
#
|
|
4
|
-
require 'recog'
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
# Rules for operating system fingerprinting in Metasploit
|
|
8
|
-
#
|
|
9
|
-
# The `os.product` key identifies the common-name of a specific operating system
|
|
10
|
-
# Examples include: Linux, Windows XP, Mac OS X, IOS, AIX, HP-UX, VxWorks
|
|
11
|
-
#
|
|
12
|
-
# The `os.version` key identifies the service pack or version of the operating system
|
|
13
|
-
# Sometimes this means a kernel or firmware version when the distribution or OS
|
|
14
|
-
# version is not available.
|
|
15
|
-
# Examples include: SP2, 10.04, 2.6.47, 10.6.1
|
|
16
|
-
#
|
|
17
|
-
# The `os.vendor` key identifies the manufacturer of the operating system
|
|
18
|
-
# Examples include: Microsoft, Ubuntu, Cisco, HP, IBM, Wind River
|
|
19
|
-
#
|
|
20
|
-
# The `os.family` key identifies the group of the operating system. This is often a
|
|
21
|
-
# duplicate of os.product, unless a more specific product name is available.
|
|
22
|
-
# Examples include: Windows, Linux, IOS, HP-UX, AIX
|
|
23
|
-
#
|
|
24
|
-
# The `os.edition` key identifies the specific variant of the operating system
|
|
25
|
-
# Examples include: Enterprise, Professional, Starter, Evaluation, Home, Datacenter
|
|
26
|
-
#
|
|
27
|
-
# An example breakdown of a common operating system is shown below
|
|
28
|
-
#
|
|
29
|
-
# * Microsoft Windows XP Professional Service Pack 3 English (x86)
|
|
30
|
-
# - os.product = 'Windows XP'
|
|
31
|
-
# - os.edition = 'Professional'
|
|
32
|
-
# - os.vendor = 'Microsoft'
|
|
33
|
-
# - os.version = 'SP3'
|
|
34
|
-
# - os.language = 'English'
|
|
35
|
-
# - os.arch = 'x86'
|
|
36
|
-
#
|
|
37
|
-
# These rules are then mapped to the {Mdm::Host} attributes below:
|
|
38
|
-
#
|
|
39
|
-
# * os_name - Maps to a normalized os.product key
|
|
40
|
-
# * os_flavor - Maps to a normalized os.edition key
|
|
41
|
-
# * os_sp - Maps to a normalized os.version key (soon os_version)
|
|
42
|
-
# * os_lang - Maps to a normalized os.language key
|
|
43
|
-
# * arch - Maps to a normalized os.arch key
|
|
44
|
-
#
|
|
45
|
-
# Additional rules include the following mappings:
|
|
46
|
-
#
|
|
47
|
-
# * name - Maps to the host.name key
|
|
48
|
-
# * mac - Maps to the host.mac key
|
|
49
|
-
#
|
|
50
|
-
# The following keys are not mapped to {Mdm::Host} at this time (but should be):
|
|
51
|
-
#
|
|
52
|
-
# * os.vendor
|
|
53
|
-
#
|
|
54
|
-
# In order to execute these rules, this module is responsible for mapping various
|
|
55
|
-
# fingerprint sources to {Mdm::Host} values. This requires some ugly glue code to
|
|
56
|
-
# account for differences between each supported input (external scanners), the
|
|
57
|
-
# Recog gem and associated databases, and how Metasploit itself likes to handle
|
|
58
|
-
# these values. Getting a mapping wrong is often harmless, but can impact the
|
|
59
|
-
# automatic targetting capabilities of certain exploit modules.
|
|
60
|
-
#
|
|
61
|
-
# In other words, this is a best-effort attempt to rationalize multiple competing
|
|
62
|
-
# sources of information about a host and come up with the values representing a
|
|
63
|
-
# normalized assessment of the system. The use of `Recog` and multiple scanner
|
|
64
|
-
# fingerprints can result in a comprehensive (and confident) identification of the
|
|
65
|
-
# remote operating system and associated services.
|
|
66
|
-
#
|
|
67
|
-
# Historically, there are direct conflicts between certain Metasploit modules,
|
|
68
|
-
# certain scanners, and external fingerprint databases in terms of how a
|
|
69
|
-
# particular OS and patch level is represented. This module attempts to fix what
|
|
70
|
-
# it can and serve as documentation and live workarounds for the rest.
|
|
71
|
-
#
|
|
72
|
-
# Examples of known conflicts that are still in progress:
|
|
73
|
-
#
|
|
74
|
-
# * Metasploit defines an OS constant of 'win'/'windows' as Microsoft Windows
|
|
75
|
-
#
|
|
76
|
-
# - Scanner modules report a mix of 'Microsoft Windows' and 'Windows'
|
|
77
|
-
# - Nearly all exploit modules reference 'Windows <Release> SP<Version>'
|
|
78
|
-
# - Nmap (and other scanners) also prefix the vendor before Windows
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
# * Windows service packs represented as 'Service Pack X' or 'SPX'
|
|
82
|
-
#
|
|
83
|
-
# - The preferred form is to set os.version to 'SPX'
|
|
84
|
-
# - Many external scanners & Recog prefer 'Service Pack X'
|
|
85
|
-
#
|
|
86
|
-
# * Apple Mac OS X, Cisco IOS, IBM AIX, Ubuntu Linux, all reported with vendor prefix
|
|
87
|
-
#
|
|
88
|
-
# - The preferred form is to remove the vendor from os.product
|
|
89
|
-
# - {Mdm::Host} currently has no vendor field, so this information is lost today
|
|
90
|
-
# - Many scanners report leading vendor strings and require normalization
|
|
91
|
-
#
|
|
92
|
-
# * The os_flavor field is used in contradictory ways across Metasploit
|
|
93
|
-
#
|
|
94
|
-
# - The preferred form is to be a 'display only' field
|
|
95
|
-
# - Some Recog fingerprints still append the edition to os.product
|
|
96
|
-
# - Many scanners report the edition as a trailing suffix to os.product
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
# Maintenance:
|
|
102
|
-
#
|
|
103
|
-
# 1. Ensure that the latest Recog gem is present and installed
|
|
104
|
-
# 2. For new operating system releases, update relevant sections
|
|
105
|
-
# a) Windows releases will require updates to a few methods
|
|
106
|
-
# 1) parse_windows_os_str()
|
|
107
|
-
# 2) normalize_nmap_fingerprint()
|
|
108
|
-
# 3) normalize_nexpose_fingerprint()
|
|
109
|
-
# 4) Other scanner normalizers
|
|
110
|
-
# b) Mobile operating systems are minimally recognized
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
# @todo Handle OS icon incompatiblities with new fingerprint names
|
|
114
|
-
# Note that VMWare ESX(i) was special cased before as well, make sure it still works
|
|
115
|
-
# 1) Cisco IOS -> IOS breaks the icon mapping in MSP/MSCE of /cisco/
|
|
116
|
-
# 2) Ubuntu Linux -> Linux breaks the distro selection
|
|
117
|
-
# The real solution is to add os_vendor and take this into account for icons
|
|
118
|
-
#
|
|
119
|
-
# @todo Implement rspec coverage for normalize_os()
|
|
120
|
-
# @todo Implement smb.generic fingerprint database (replace {#parse_windows_os_str}?)
|
|
121
|
-
# @todo Implement Samba version matching for specific distributions and OS versions
|
|
122
|
-
# @todo Implement DD-WRT and various embedded device signatures currently missing
|
|
123
|
-
# @todo Correct inconsistencies in os_name use by removing the vendor string (Microsoft Windows -> Windows)
|
|
124
|
-
# This applies to MSF core and a handful of modules, not to mention some Recog fingerprints.
|
|
125
|
-
# @todo Rename host.os_sp to host.os_version
|
|
126
|
-
# @todo Add host.os_vendor
|
|
127
|
-
# @todo Add host.os_confidence
|
|
128
|
-
# @todo Add host.domain
|
|
129
|
-
#
|
|
130
1
|
module Mdm::Host::OperatingSystemNormalization
|
|
131
|
-
|
|
132
|
-
# Cap nmap certainty at 0.84 until we update it more frequently
|
|
133
|
-
# XXX: Without this, Nmap will beat the default certainty of recog
|
|
134
|
-
# matches and its less-confident guesses will take precedence
|
|
135
|
-
# over service-based fingerprints.
|
|
136
|
-
MAX_NMAP_CERTAINTY = 0.84
|
|
137
|
-
|
|
138
2
|
#
|
|
139
3
|
# Normalize the operating system fingerprints provided by various scanners
|
|
140
|
-
# (nmap, nexpose, retina, nessus,
|
|
4
|
+
# (nmap, nexpose, retina, nessus, etc).
|
|
141
5
|
#
|
|
142
|
-
# These are stored as
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
# The goal is to infer as much as we can about the OS of the device and the
|
|
146
|
-
# various {Mdm::Service services} offered using the Recog gem and some glue
|
|
147
|
-
# logic to determine the best weights. This method can result in changes to
|
|
148
|
-
# the recorded {#os_name}, {#os_flavor}, {#os_sp}, {#os_lang}, {#purpose},
|
|
149
|
-
# {#name}, {#arch}, and the {Mdm::Service service details}.
|
|
6
|
+
# These are stored as notes (instead of directly in the os_* fields)
|
|
7
|
+
# specifically for this purpose.
|
|
150
8
|
#
|
|
151
9
|
def normalize_os
|
|
152
|
-
host
|
|
153
|
-
|
|
10
|
+
host = self
|
|
11
|
+
|
|
12
|
+
wname = {} # os_name == Linux, Windows, Mac OS X, VxWorks
|
|
13
|
+
wtype = {} # purpose == server, client, device
|
|
14
|
+
wflav = {} # os_flavor == Ubuntu, Debian, 2003, 10.5, JetDirect
|
|
15
|
+
wvers = {} # os_sp == 9.10, SP2, 10.5.3, 3.05
|
|
16
|
+
warch = {} # arch == x86, PPC, SPARC, MIPS, ''
|
|
17
|
+
wlang = {} # os_lang == English, ''
|
|
18
|
+
whost = {} # hostname
|
|
154
19
|
|
|
155
20
|
# Note that we're already restricting the query to this host by using
|
|
156
21
|
# host.notes instead of Note, so don't need a host_id in the
|
|
157
22
|
# conditions.
|
|
158
23
|
fingerprintable_notes = self.notes.where("ntype like '%%fingerprint'")
|
|
159
|
-
fingerprintable_notes.each do |
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
24
|
+
fingerprintable_notes.each do |fp|
|
|
25
|
+
next if not validate_fingerprint_data(fp)
|
|
26
|
+
norm = normalize_scanner_fp(fp)
|
|
27
|
+
wvers[norm[:os_sp]] = wvers[norm[:os_sp]].to_i + (100 * norm[:certainty])
|
|
28
|
+
wname[norm[:os_name]] = wname[norm[:os_name]].to_i + (100 * norm[:certainty])
|
|
29
|
+
wflav[norm[:os_flavor]] = wflav[norm[:os_flavor]].to_i + (100 * norm[:certainty])
|
|
30
|
+
warch[norm[:arch]] = warch[norm[:arch]].to_i + (100 * norm[:certainty])
|
|
31
|
+
whost[norm[:name]] = whost[norm[:name]].to_i + (100 * norm[:certainty])
|
|
32
|
+
wtype[norm[:type]] = wtype[norm[:type]].to_i + (100 * norm[:certainty])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Grab service information and assign scores. Some services are
|
|
36
|
+
# more trustworthy than others. If more services agree than not,
|
|
37
|
+
# than that should be considered as well.
|
|
38
|
+
# Each service has a starting number of points. Services that
|
|
39
|
+
# are more difficult to fake are awarded more points. The points
|
|
40
|
+
# represent a running total, not a fixed score.
|
|
41
|
+
# XXX: This needs to be refactored in a big way. Tie-breaking is
|
|
42
|
+
# pretty arbitrary, it would be nice to explicitly believe some
|
|
43
|
+
# services over others, but that means recording which service
|
|
44
|
+
# has an opinion and which doesn't. It would also be nice to
|
|
45
|
+
# identify "impossible" combinations of services and alert that
|
|
46
|
+
# something funny is going on.
|
|
163
47
|
# XXX: This hack solves the memory leak generated by self.services.each {}
|
|
164
48
|
fingerprintable_services = self.services.where("name is not null and name != '' and info is not null and info != ''")
|
|
165
49
|
fingerprintable_services.each do |s|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
50
|
+
points = 0
|
|
51
|
+
case s.name
|
|
52
|
+
when 'smb'
|
|
53
|
+
points = 210
|
|
54
|
+
case s.info
|
|
55
|
+
when /\.el([23456])(\s+|$)/ # Match Samba 3.0.33-0.30.el4 as RHEL4
|
|
56
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
57
|
+
wflav["RHEL" + $1] = wflav["RHEL" + $1].to_i + points
|
|
58
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
59
|
+
when /(ubuntu|debian|fedora|red ?hat|rhel)/i
|
|
60
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
61
|
+
wflav[$1.capitalize] = wflav[$1.capitalize].to_i + points
|
|
62
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
63
|
+
when /^Windows/
|
|
64
|
+
win_sp = nil
|
|
65
|
+
win_flav = nil
|
|
66
|
+
win_lang = nil
|
|
67
|
+
|
|
68
|
+
ninfo = s.info
|
|
69
|
+
ninfo.gsub!('(R)', '')
|
|
70
|
+
ninfo.gsub!('(TM)', '')
|
|
71
|
+
ninfo.gsub!(/\s+/, ' ')
|
|
72
|
+
ninfo.gsub!('No Service Pack', 'Service Pack 0')
|
|
73
|
+
|
|
74
|
+
# Windows (R) Web Server 2008 6001 Service Pack 1 (language: Unknown) (name:PG-WIN2008WEB) (domain:WORKGROUP)
|
|
75
|
+
# Windows XP Service Pack 3 (language: English) (name:EGYPT-B3E55BF3C) (domain:EGYPT-B3E55BF3C)
|
|
76
|
+
# Windows 7 Ultimate (Build 7600) (language: Unknown) (name:WIN7) (domain:WORKGROUP)
|
|
77
|
+
# Windows 2003 No Service Pack (language: Unknown) (name:VMWIN2003) (domain:PWNME)
|
|
78
|
+
|
|
79
|
+
#if ninfo =~ /^Windows ([^\s]+)(.*)(Service Pack |\(Build )([^\(]+)\(/
|
|
80
|
+
if ninfo =~ /^Windows (.*)(Service Pack [^\s]+|\(Build [^\)]+\))/
|
|
81
|
+
win_flav = $1.strip
|
|
82
|
+
win_sp = ($2).strip
|
|
83
|
+
win_sp.gsub!(/with.*/, '')
|
|
84
|
+
win_sp.gsub!('Service Pack', 'SP')
|
|
85
|
+
win_sp.gsub!('Build', 'b')
|
|
86
|
+
win_sp.gsub!(/\s+/, '')
|
|
87
|
+
win_sp.tr!("()", '')
|
|
88
|
+
else
|
|
89
|
+
if ninfo =~ /^Windows ([^\s+]+)([^\(]+)\(/
|
|
90
|
+
win_flav = $2.strip
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if ninfo =~ /name: ([^\)]+)\)/
|
|
96
|
+
hostname = $1.strip
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if ninfo =~ /language: ([^\)]+)\)/
|
|
100
|
+
win_lang = $1.strip
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
win_lang = nil if win_lang =~ /unknown/i
|
|
104
|
+
win_vers = win_sp
|
|
105
|
+
|
|
106
|
+
wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points
|
|
107
|
+
wlang[win_lang] = wlang[win_lang].to_i + points if win_lang
|
|
108
|
+
wflav[win_flav] = wflav[win_flav].to_i + points if win_flav
|
|
109
|
+
wvers[win_vers] = wvers[win_vers].to_i + points if win_vers
|
|
110
|
+
whost[hostname] = whost[hostname].to_i + points if hostname
|
|
111
|
+
|
|
112
|
+
case win_flav
|
|
113
|
+
when /NT|2003|2008/
|
|
114
|
+
win_type = 'server'
|
|
115
|
+
else
|
|
116
|
+
win_type = 'client'
|
|
117
|
+
end
|
|
118
|
+
wtype[win_type] = wtype[win_type].to_i + points
|
|
119
|
+
end
|
|
184
120
|
|
|
185
|
-
|
|
186
|
-
|
|
121
|
+
when 'ssh'
|
|
122
|
+
points = 104
|
|
123
|
+
case s.info
|
|
124
|
+
when /honeypot/i # Never trust this
|
|
125
|
+
nil
|
|
126
|
+
when /ubuntu/i
|
|
127
|
+
# This needs to be above /debian/ becuase the ubuntu banner contains both, e.g.:
|
|
128
|
+
# SSH-2.0-OpenSSH_5.3p1 Debian-3ubuntu6
|
|
129
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
130
|
+
wflav['Ubuntu'] = wflav['Ubuntu'].to_i + points
|
|
131
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
132
|
+
when /debian/i
|
|
133
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
134
|
+
wflav['Debian'] = wflav['Debian'].to_i + points
|
|
135
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
136
|
+
when /FreeBSD/
|
|
137
|
+
wname['FreeBSD'] = wname['FreeBSD'].to_i + points
|
|
138
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
139
|
+
when /sun_ssh/i
|
|
140
|
+
wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points
|
|
141
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
142
|
+
when /vshell|remotelyanywhere|freessh/i
|
|
143
|
+
wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points
|
|
144
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
145
|
+
|
|
146
|
+
when /radware/i
|
|
147
|
+
wname['RadWare'] = wname['RadWare'].to_i + points
|
|
148
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
149
|
+
|
|
150
|
+
when /dropbear/i
|
|
151
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
152
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
153
|
+
|
|
154
|
+
when /netscreen/i
|
|
155
|
+
wname['NetScreen'] = wname['NetScreen'].to_i + points
|
|
156
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
157
|
+
|
|
158
|
+
when /vpn3/
|
|
159
|
+
wname['Cisco VPN 3000'] = wname['Cisco VPN 3000'].to_i + points
|
|
160
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
161
|
+
|
|
162
|
+
when /cisco/i
|
|
163
|
+
wname['Cisco IOS'] = wname['Cisco IOS'].to_i + points
|
|
164
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
165
|
+
|
|
166
|
+
when /mpSSH/
|
|
167
|
+
wname['HP iLO'] = wname['HP iLO'].to_i + points
|
|
168
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
169
|
+
end
|
|
170
|
+
when 'http'
|
|
171
|
+
points = 99
|
|
172
|
+
case s.info
|
|
173
|
+
when /iSeries/
|
|
174
|
+
wname['IBM iSeries'] = wname['IBM iSeries'].to_i + points
|
|
175
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
176
|
+
|
|
177
|
+
when /Mandrake/i
|
|
178
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
179
|
+
wflav['Mandrake'] = wflav['Mandrake'].to_i + points
|
|
180
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
181
|
+
|
|
182
|
+
when /Mandriva/i
|
|
183
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
184
|
+
wflav['Mandrake'] = wflav['Mandrake'].to_i + points
|
|
185
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
186
|
+
|
|
187
|
+
when /Ubuntu/i
|
|
188
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
189
|
+
wflav['Ubuntu'] = wflav['Ubuntu'].to_i + points
|
|
190
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
191
|
+
|
|
192
|
+
when /Debian/i
|
|
193
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
194
|
+
wflav['Debian'] = wflav['Debian'].to_i + points
|
|
195
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
196
|
+
|
|
197
|
+
when /Fedora/i
|
|
198
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
199
|
+
wflav['Fedora'] = wflav['Fedora'].to_i + points
|
|
200
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
201
|
+
|
|
202
|
+
when /CentOS/i
|
|
203
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
204
|
+
wflav['CentOS'] = wflav['CentOS'].to_i + points
|
|
205
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
206
|
+
|
|
207
|
+
when /RHEL/i
|
|
208
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
209
|
+
wflav['RHEL'] = wflav['RHEL'].to_i + points
|
|
210
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
211
|
+
|
|
212
|
+
when /Red.?Hat/i
|
|
213
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
214
|
+
wflav['Red Hat'] = wflav['Red Hat'].to_i + points
|
|
215
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
216
|
+
|
|
217
|
+
when /SuSE/i
|
|
218
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
219
|
+
wflav['SUSE'] = wflav['SUSE'].to_i + points
|
|
220
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
221
|
+
|
|
222
|
+
when /TurboLinux/i
|
|
223
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
224
|
+
wflav['TurboLinux'] = wflav['TurboLinux'].to_i + points
|
|
225
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
226
|
+
|
|
227
|
+
when /Gentoo/i
|
|
228
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
229
|
+
wflav['Gentoo'] = wflav['Gentoo'].to_i + points
|
|
230
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
231
|
+
|
|
232
|
+
when /Conectiva/i
|
|
233
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
234
|
+
wflav['Conectiva'] = wflav['Conectiva'].to_i + points
|
|
235
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
236
|
+
|
|
237
|
+
when /Asianux/i
|
|
238
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
239
|
+
wflav['Asianux'] = wflav['Asianux'].to_i + points
|
|
240
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
241
|
+
|
|
242
|
+
when /Trustix/i
|
|
243
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
244
|
+
wflav['Trustix'] = wflav['Trustix'].to_i + points
|
|
245
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
246
|
+
|
|
247
|
+
when /White Box/
|
|
248
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
249
|
+
wflav['White Box'] = wflav['White Box'].to_i + points
|
|
250
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
251
|
+
|
|
252
|
+
when /UnitedLinux/
|
|
253
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
254
|
+
wflav['UnitedLinux'] = wflav['UnitedLinux'].to_i + points
|
|
255
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
256
|
+
|
|
257
|
+
when /PLD\/Linux/
|
|
258
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
259
|
+
wflav['PLD/Linux'] = wflav['PLD/Linux'].to_i + points
|
|
260
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
261
|
+
|
|
262
|
+
when /Vine\/Linux/
|
|
263
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
264
|
+
wflav['Vine/Linux'] = wflav['Vine/Linux'].to_i + points
|
|
265
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
266
|
+
|
|
267
|
+
when /rPath/
|
|
268
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
269
|
+
wflav['rPath'] = wflav['rPath'].to_i + points
|
|
270
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
271
|
+
|
|
272
|
+
when /StartCom/
|
|
273
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
274
|
+
wflav['StartCom'] = wflav['StartCom'].to_i + points
|
|
275
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
276
|
+
|
|
277
|
+
when /linux/i
|
|
278
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
279
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
280
|
+
|
|
281
|
+
when /PalmOS/
|
|
282
|
+
wname['PalmOS'] = wname['PalmOS'].to_i + points
|
|
283
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
284
|
+
|
|
285
|
+
when /Microsoft[\x20\x2d]IIS\/[234]\.0/
|
|
286
|
+
wname['Microsoft Windows NT 4.0'] = wname['Microsoft Windows NT 4.0'].to_i + points
|
|
287
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
288
|
+
|
|
289
|
+
when /Microsoft[\x20\x2d]IIS\/5\.0/
|
|
290
|
+
wname['Microsoft Windows 2000'] = wname['Microsoft Windows 2000'].to_i + points
|
|
291
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
292
|
+
|
|
293
|
+
when /Microsoft[\x20\x2d]IIS\/5\.1/
|
|
294
|
+
wname['Microsoft Windows XP'] = wname['Microsoft Windows XP'].to_i + points
|
|
295
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
296
|
+
|
|
297
|
+
when /Microsoft[\x20\x2d]IIS\/6\.0/
|
|
298
|
+
wname['Microsoft Windows 2003'] = wname['Microsoft Windows 2003'].to_i + points
|
|
299
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
300
|
+
|
|
301
|
+
when /Microsoft[\x20\x2d]IIS\/7\.0/
|
|
302
|
+
wname['Microsoft Windows 2008'] = wname['Microsoft Windows 2008'].to_i + points
|
|
303
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
304
|
+
|
|
305
|
+
when /Win32/i
|
|
306
|
+
wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points
|
|
307
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
308
|
+
|
|
309
|
+
when /DD\-WRT ([^\s]+) /i
|
|
310
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
311
|
+
wflav['DD-WRT'] = wflav['DD-WRT'].to_i + points
|
|
312
|
+
wvers[$1.strip] = wvers[$1.strip].to_i + points
|
|
313
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
314
|
+
|
|
315
|
+
when /Darwin/
|
|
316
|
+
wname['Apple Mac OS X'] = wname['Apple Mac OS X'].to_i + points
|
|
317
|
+
|
|
318
|
+
when /FreeBSD/i
|
|
319
|
+
wname['FreeBSD'] = wname['FreeBSD'].to_i + points
|
|
320
|
+
|
|
321
|
+
when /OpenBSD/i
|
|
322
|
+
wname['OpenBSD'] = wname['OpenBSD'].to_i + points
|
|
323
|
+
|
|
324
|
+
when /NetBSD/i
|
|
325
|
+
wname['NetBSD'] = wname['NetBSD'].to_i + points
|
|
326
|
+
|
|
327
|
+
when /NetWare/i
|
|
328
|
+
wname['Novell NetWare'] = wname['Novell NetWare'].to_i + points
|
|
329
|
+
|
|
330
|
+
when /OpenVMS/i
|
|
331
|
+
wname['OpenVMS'] = wname['OpenVMS'].to_i + points
|
|
332
|
+
|
|
333
|
+
when /SunOS|Solaris/i
|
|
334
|
+
wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points
|
|
187
335
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
336
|
+
when /HP.?UX/i
|
|
337
|
+
wname['HP-UX'] = wname['HP-UX'].to_i + points
|
|
338
|
+
end
|
|
339
|
+
when 'snmp'
|
|
340
|
+
points = 103
|
|
341
|
+
case s.info
|
|
342
|
+
when /^Sun SNMP Agent/
|
|
343
|
+
wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points
|
|
344
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
345
|
+
|
|
346
|
+
when /^SunOS ([^\s]+) ([^\s]+) /
|
|
347
|
+
# XXX 1/2 XXX what does this comment mean i wonder
|
|
348
|
+
wname['Sun Solaris'] = wname['Sun Solaris'].to_i + points
|
|
349
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
350
|
+
|
|
351
|
+
when /^Linux ([^\s]+) ([^\s]+) /
|
|
352
|
+
whost[$1] = whost[$1].to_i + points
|
|
353
|
+
wname['Linux ' + $2] = wname['Linux ' + $2].to_i + points
|
|
354
|
+
wvers[$2] = wvers[$2].to_i + points
|
|
355
|
+
arch = get_arch_from_string(s.info)
|
|
356
|
+
warch[arch] = warch[arch].to_i + points if arch
|
|
357
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
358
|
+
|
|
359
|
+
when /^Novell NetWare ([^\s]+)/
|
|
360
|
+
wname['Novell NetWare ' + $1] = wname['Novell NetWare ' + $1].to_i + points
|
|
361
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
362
|
+
arch = "x86"
|
|
363
|
+
warch[arch] = warch[arch].to_i + points
|
|
364
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
365
|
+
|
|
366
|
+
when /^Novell UnixWare ([^\s]+)/
|
|
367
|
+
wname['Novell UnixWare ' + $1] = wname['Novell UnixWare ' + $1].to_i + points
|
|
368
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
369
|
+
arch = "x86"
|
|
370
|
+
warch[arch] = warch[arch].to_i + points
|
|
371
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
372
|
+
|
|
373
|
+
when /^HP-UX ([^\s]+) ([^\s]+) /
|
|
374
|
+
# XXX
|
|
375
|
+
wname['HP-UX ' + $2] = wname['HP-UX ' + $2].to_i + points
|
|
376
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
377
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
378
|
+
|
|
379
|
+
when /^IBM PowerPC.*Base Operating System Runtime AIX version: (\d+\.\d+)/
|
|
380
|
+
wname['IBM AIX ' + $1] = wname['IBM AIX ' + $1].to_i + points
|
|
381
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
382
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
383
|
+
|
|
384
|
+
when /^SCO TCP\/IP Runtime Release ([^\s]+)/
|
|
385
|
+
wname['SCO UnixWare ' + $1] = wname['SCO UnixWare ' + $1].to_i + points
|
|
386
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
387
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
388
|
+
|
|
389
|
+
when /.* IRIX version ([^\s]+)/
|
|
390
|
+
wname['SGI IRIX ' + $1] = wname['SGI IRIX ' + $1].to_i + points
|
|
391
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
392
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
393
|
+
|
|
394
|
+
when /^Unisys ([^\s]+) version ([^\s]+) kernel/
|
|
395
|
+
wname['Unisys ' + $2] = wname['Unisys ' + $2].to_i + points
|
|
396
|
+
wvers[$2] = wvers[$2].to_i + points
|
|
397
|
+
whost[$1] = whost[$1].to_i + points
|
|
398
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
399
|
+
|
|
400
|
+
when /.*OpenVMS V([^\s]+) /
|
|
401
|
+
# XXX
|
|
402
|
+
wname['OpenVMS ' + $1] = wname['OpenVMS ' + $1].to_i + points
|
|
403
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
404
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
405
|
+
|
|
406
|
+
when /^Hardware:.*Software: Windows NT Version ([^\s]+) /
|
|
407
|
+
wname['Microsoft Windows NT ' + $1] = wname['Microsoft Windows NT ' + $1].to_i + points
|
|
408
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
409
|
+
|
|
410
|
+
when /^Hardware:.*Software: Windows 2000 Version 5\.0/
|
|
411
|
+
wname['Microsoft Windows 2000'] = wname['Microsoft Windows 2000'].to_i + points
|
|
412
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
413
|
+
|
|
414
|
+
when /^Hardware:.*Software: Windows 2000 Version 5\.1/
|
|
415
|
+
wname['Microsoft Windows XP'] = wname['Microsoft Windows XP'].to_i + points
|
|
416
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
417
|
+
|
|
418
|
+
when /^Hardware:.*Software: Windows Version 5\.2/
|
|
419
|
+
wname['Microsoft Windows 2003'] = wname['Microsoft Windows 2003'].to_i + points
|
|
420
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
421
|
+
|
|
422
|
+
# XXX: TODO 2008, Vista, Windows 7
|
|
423
|
+
|
|
424
|
+
when /^Microsoft Windows CE Version ([^\s]+)+/
|
|
425
|
+
wname['Microsoft Windows CE ' + $1] = wname['Microsoft Windows CE ' + $1].to_i + points
|
|
426
|
+
wtype['client'] = wtype['client'].to_i + points
|
|
427
|
+
|
|
428
|
+
when /^IPSO ([^\s]+) ([^\s]+) /
|
|
429
|
+
whost[$1] = whost[$1].to_i + points
|
|
430
|
+
wname['Nokia IPSO ' + $2] = wname['Nokia IPSO ' + $2].to_i + points
|
|
431
|
+
wvers[$2] = wvers[$2].to_i + points
|
|
432
|
+
arch = get_arch_from_string(s.info)
|
|
433
|
+
warch[arch] = warch[arch].to_s + points if arch
|
|
434
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
435
|
+
|
|
436
|
+
when /^Sun StorEdge/
|
|
437
|
+
wname['Sun StorEdge'] = wname['Sun StorEdge'].to_i + points
|
|
438
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
439
|
+
|
|
440
|
+
when /^HP StorageWorks/
|
|
441
|
+
wname['HP StorageWorks'] = wname['HP StorageWorks'].to_i + points
|
|
442
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
443
|
+
|
|
444
|
+
when /^Network Storage/
|
|
445
|
+
# XXX
|
|
446
|
+
wname['Network Storage Router'] = wname['Network Storage Router'].to_i + points
|
|
447
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
448
|
+
|
|
449
|
+
when /Cisco Internetwork Operating System.*Version ([^\s]+)/
|
|
450
|
+
vers = $1.split(/[,^\s]/)[0]
|
|
451
|
+
wname['Cisco IOS ' + vers] = wname['Cisco IOS ' + vers].to_i + points
|
|
452
|
+
wvers[vers] = wvers[vers].to_i + points
|
|
453
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
454
|
+
|
|
455
|
+
when /Cisco Catalyst.*Version ([^\s]+)/
|
|
456
|
+
vers = $1.split(/[,^\s]/)[0]
|
|
457
|
+
wname['Cisco CatOS ' + vers] = wname['Cisco CatOS ' + vers].to_i + points
|
|
458
|
+
wvers[vers] = wvers[vers].to_i + points
|
|
459
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
460
|
+
|
|
461
|
+
when /Cisco 761.*Version ([^\s]+)/
|
|
462
|
+
vers = $1.split(/[,^\s]/)[0]
|
|
463
|
+
wname['Cisco 761 ' + vers] = wname['Cisco 761 ' + vers].to_i + points
|
|
464
|
+
wvers[vers] = wvers[vers].to_i + points
|
|
465
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
466
|
+
|
|
467
|
+
when /Network Analysis Module.*Version ([^\s]+)/
|
|
468
|
+
vers = $1.split(/[,^\s]/)[0]
|
|
469
|
+
wname['Cisco NAM ' + vers] = wname['Cisco NAM ' + vers].to_i + points
|
|
470
|
+
wvers[vers] = wvers[vers].to_i + points
|
|
471
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
472
|
+
|
|
473
|
+
when /VPN 3000 Concentrator Series Version ([^\s]+)/
|
|
474
|
+
vers = $1.split(/[,^\s]/)[0]
|
|
475
|
+
wname['Cisco VPN 3000 ' + vers] = wname['Cisco VPN 3000 ' + vers].to_i + points
|
|
476
|
+
wvers[vers] = wvers[vers].to_i + points
|
|
477
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
478
|
+
|
|
479
|
+
when /ProCurve.*Switch/
|
|
480
|
+
wname['3Com ProCurve Switch'] = wname['3Com ProCurve Switch'].to_i + points
|
|
481
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
482
|
+
|
|
483
|
+
when /ProCurve.*Access Point/
|
|
484
|
+
wname['3Com Access Point'] = wname['3Com Access Point'].to_i + points
|
|
485
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
486
|
+
|
|
487
|
+
when /3Com.*Access Point/i
|
|
488
|
+
wname['3Com Access Point'] = wname['3Com Access Point'].to_i + points
|
|
489
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
490
|
+
|
|
491
|
+
when /ShoreGear/
|
|
492
|
+
wname['ShoreTel Appliance'] = wname['ShoreTel Appliance'].to_i + points
|
|
493
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
494
|
+
|
|
495
|
+
when /firewall/i
|
|
496
|
+
wname['Unknown Firewall'] = wname['Unknown Firewall'].to_i + points
|
|
497
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
498
|
+
|
|
499
|
+
when /phone/i
|
|
500
|
+
wname['Unknown Phone'] = wname['Unknown Phone'].to_i + points
|
|
501
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
502
|
+
|
|
503
|
+
when /router/i
|
|
504
|
+
wname['Unknown Router'] = wname['Unknown Router'].to_i + points
|
|
505
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
506
|
+
|
|
507
|
+
when /switch/i
|
|
508
|
+
wname['Unknown Switch'] = wname['Unknown Switch'].to_i + points
|
|
509
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
510
|
+
#
|
|
511
|
+
# Printer Signatures
|
|
512
|
+
#
|
|
513
|
+
when /^HP ETHERNET MULTI-ENVIRONMENT/
|
|
514
|
+
wname['HP Printer'] = wname['HP Printer'].to_i + points
|
|
515
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
516
|
+
when /Canon/i
|
|
517
|
+
wname['Canon Printer'] = wname['Canon Printer'].to_i + points
|
|
518
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
519
|
+
when /Epson/i
|
|
520
|
+
wname['Epson Printer'] = wname['Epson Printer'].to_i + points
|
|
521
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
522
|
+
when /ExtendNet/i
|
|
523
|
+
wname['ExtendNet Printer'] = wname['ExtendNet Printer'].to_i + points
|
|
524
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
525
|
+
when /Fiery/i
|
|
526
|
+
wname['Fiery Printer'] = wname['Fiery Printer'].to_i + points
|
|
527
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
528
|
+
when /Konica/i
|
|
529
|
+
wname['Konica Printer'] = wname['Konica Printer'].to_i + points
|
|
530
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
531
|
+
when /Lanier/i
|
|
532
|
+
wname['Lanier Printer'] = wname['Lanier Printer'].to_i + points
|
|
533
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
534
|
+
when /Lantronix/i
|
|
535
|
+
wname['Lantronix Printer'] = wname['Lantronix Printer'].to_i + points
|
|
536
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
537
|
+
when /Lexmark/i
|
|
538
|
+
wname['Lexmark Printer'] = wname['Lexmark Printer'].to_i + points
|
|
539
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
540
|
+
when /Magicolor/i
|
|
541
|
+
wname['Magicolor Printer'] = wname['Magicolor Printer'].to_i + points
|
|
542
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
543
|
+
when /Minolta/i
|
|
544
|
+
wname['Minolta Printer'] = wname['Minolta Printer'].to_i + points
|
|
545
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
546
|
+
when /NetJET/i
|
|
547
|
+
wname['NetJET Printer'] = wname['NetJET Printer'].to_i + points
|
|
548
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
549
|
+
when /OKILAN/i
|
|
550
|
+
wname['OKILAN Printer'] = wname['OKILAN Printer'].to_i + points
|
|
551
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
552
|
+
when /Phaser/i
|
|
553
|
+
wname['Phaser Printer'] = wname['Phaser Printer'].to_i + points
|
|
554
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
555
|
+
when /PocketPro/i
|
|
556
|
+
wname['PocketPro Printer'] = wname['PocketPro Printer'].to_i + points
|
|
557
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
558
|
+
when /Ricoh/i
|
|
559
|
+
wname['Ricoh Printer'] = wname['Ricoh Printer'].to_i + points
|
|
560
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
561
|
+
when /Savin/i
|
|
562
|
+
wname['Savin Printer'] = wname['Savin Printer'].to_i + points
|
|
563
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
564
|
+
when /SHARP AR/i
|
|
565
|
+
wname['SHARP Printer'] = wname['SHARP Printer'].to_i + points
|
|
566
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
567
|
+
when /Star Micronix/i
|
|
568
|
+
wname['Star Micronix Printer'] = wname['Star Micronix Printer'].to_i + points
|
|
569
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
570
|
+
when /Source Tech/i
|
|
571
|
+
wname['Source Tech Printer'] = wname['Source Tech Printer'].to_i + points
|
|
572
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
573
|
+
when /Xerox/i
|
|
574
|
+
wname['Xerox Printer'] = wname['Xerox Printer'].to_i + points
|
|
575
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
576
|
+
when /^Brother/i
|
|
577
|
+
wname['Brother Printer'] = wname['Brother Printer'].to_i + points
|
|
578
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
579
|
+
when /^Axis.*Network Print/i
|
|
580
|
+
wname['Axis Printer'] = wname['Axis Printer'].to_i + points
|
|
581
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
582
|
+
when /^Prestige/i
|
|
583
|
+
wname['Prestige Printer'] = wname['Prestige Printer'].to_i + points
|
|
584
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
585
|
+
when /^ZebraNet/i
|
|
586
|
+
wname['ZebraNet Printer'] = wname['ZebraNet Printer'].to_i + points
|
|
587
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
588
|
+
when /e\-STUDIO/i
|
|
589
|
+
wname['eStudio Printer'] = wname['eStudio Printer'].to_i + points
|
|
590
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
591
|
+
when /^Gestetner/i
|
|
592
|
+
wname['Gestetner Printer'] = wname['Gestetner Printer'].to_i + points
|
|
593
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
594
|
+
when /IBM.*Print/i
|
|
595
|
+
wname['IBM Printer'] = wname['IBM Printer'].to_i + points
|
|
596
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
597
|
+
when /HP (Color|LaserJet|InkJet)/i
|
|
598
|
+
wname['HP Printer'] = wname['HP Printer'].to_i + points
|
|
599
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
600
|
+
when /Dell (Color|Laser|Ink)/i
|
|
601
|
+
wname['Dell Printer'] = wname['Dell Printer'].to_i + points
|
|
602
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
603
|
+
when /Print/i
|
|
604
|
+
wname['Unknown Printer'] = wname['Unknown Printer'].to_i + points
|
|
605
|
+
wtype['printer'] = wtype['printer'].to_i + points
|
|
606
|
+
end # End of s.info for SNMP
|
|
607
|
+
|
|
608
|
+
when 'telnet'
|
|
609
|
+
points = 105
|
|
610
|
+
case s.info
|
|
611
|
+
when /IRIX/
|
|
612
|
+
wname['SGI IRIX'] = wname['SGI IRIX'].to_i + points
|
|
613
|
+
when /AIX/
|
|
614
|
+
wname['IBM AIX'] = wname['IBM AIX'].to_i + points
|
|
615
|
+
when /(FreeBSD|OpenBSD|NetBSD)\/(.*) /
|
|
616
|
+
wname[$1] = wname[$1].to_i + points
|
|
617
|
+
arch = get_arch_from_string($2)
|
|
618
|
+
warch[arch] = warch[arch].to_i + points
|
|
619
|
+
when /Ubuntu (\d+(\.\d+)+)/
|
|
620
|
+
wname['Linux'] = wname['Linux'].to_i + points
|
|
621
|
+
wflav['Ubuntu'] = wflav['Ubuntu'].to_i + points
|
|
622
|
+
wvers[$1] = wvers[$1].to_i + points
|
|
623
|
+
when /User Access Verification/
|
|
624
|
+
wname['Cisco IOS'] = wname['Cisco IOS'].to_i + points
|
|
625
|
+
when /Microsoft/
|
|
626
|
+
wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points
|
|
627
|
+
end # End of s.info for TELNET
|
|
628
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
629
|
+
|
|
630
|
+
when 'smtp'
|
|
631
|
+
points = 103
|
|
632
|
+
case s.info
|
|
633
|
+
when /ESMTP.*SGI\.8/
|
|
634
|
+
wname['SGI IRIX'] = wname['SGI IRIX'].to_i + points
|
|
635
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
636
|
+
end # End of s.info for SMTP
|
|
637
|
+
|
|
638
|
+
when 'https'
|
|
639
|
+
points = 101
|
|
640
|
+
case s.info
|
|
641
|
+
when /(VMware\s(ESXi?)).*\s([\d\.]+)/
|
|
642
|
+
# Very reliable fingerprinting from our own esx_fingerprint module
|
|
643
|
+
wname[$1] = wname[$1].to_i + (points * 5)
|
|
644
|
+
wflav[$3] = wflav[$3].to_i + (points * 5)
|
|
645
|
+
wtype['device'] = wtype['device'].to_i + points
|
|
646
|
+
end # End of s.info for HTTPS
|
|
647
|
+
|
|
648
|
+
when 'netbios'
|
|
649
|
+
points = 201
|
|
650
|
+
case s.info
|
|
651
|
+
when /W2K3/i
|
|
652
|
+
wname['Microsoft Windows 2003'] = wname['Microsoft Windows 2003'].to_i + points
|
|
653
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
654
|
+
when /W2K8/i
|
|
655
|
+
wname['Microsoft Windows 2008'] = wname['Microsoft Windows 2008'].to_i + points
|
|
656
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
657
|
+
end # End of s.info for NETBIOS
|
|
658
|
+
|
|
659
|
+
when 'dns'
|
|
660
|
+
points = 101
|
|
661
|
+
case s.info
|
|
662
|
+
when 'Microsoft DNS'
|
|
663
|
+
wname['Microsoft Windows'] = wname['Microsoft Windows'].to_i + points
|
|
664
|
+
wtype['server'] = wtype['server'].to_i + points
|
|
665
|
+
end # End of s.info for DNS
|
|
666
|
+
end # End of s.name case
|
|
667
|
+
# End of Services
|
|
195
668
|
end
|
|
196
669
|
|
|
197
|
-
# Set some sane defaults if needed
|
|
198
|
-
host.os_name ||= 'Unknown'
|
|
199
|
-
host.purpose ||= 'device'
|
|
200
|
-
|
|
201
|
-
host.save if host.changed?
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def recog_matches_for_service(s)
|
|
205
670
|
#
|
|
206
|
-
#
|
|
207
|
-
# replies and associate these with one or more Recog databases. The mapping
|
|
208
|
-
# of service.name to a specific database only fits into so many places and
|
|
209
|
-
# Mdm currently serves that role.
|
|
671
|
+
# Report the best match here
|
|
210
672
|
#
|
|
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
|
-
if
|
|
236
|
-
|
|
673
|
+
best_match = {}
|
|
674
|
+
best_match[:os_name] = wname.keys.sort{|a,b| wname[b] <=> wname[a]}[0]
|
|
675
|
+
best_match[:purpose] = wtype.keys.sort{|a,b| wtype[b] <=> wtype[a]}[0]
|
|
676
|
+
best_match[:os_flavor] = wflav.keys.sort{|a,b| wflav[b] <=> wflav[a]}[0]
|
|
677
|
+
best_match[:os_sp] = wvers.keys.sort{|a,b| wvers[b] <=> wvers[a]}[0]
|
|
678
|
+
best_match[:arch] = warch.keys.sort{|a,b| warch[b] <=> warch[a]}[0]
|
|
679
|
+
best_match[:name] = whost.keys.sort{|a,b| whost[b] <=> whost[a]}[0]
|
|
680
|
+
best_match[:os_lang] = wlang.keys.sort{|a,b| wlang[b] <=> wlang[a]}[0]
|
|
681
|
+
|
|
682
|
+
best_match[:os_flavor] ||= host[:os_flavor] || ""
|
|
683
|
+
if best_match[:os_name]
|
|
684
|
+
# Handle cases where the flavor contains the base name
|
|
685
|
+
# Don't use gsub!() here because the string was a hash key in a
|
|
686
|
+
# previously life and gets frozen on 1.9.1, see #4128
|
|
687
|
+
best_match[:os_flavor] = best_match[:os_flavor].gsub(best_match[:os_name], '')
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
# If we didn't get anything, use whatever the host already has.
|
|
691
|
+
# Failing that, fallback to "Unknown"
|
|
692
|
+
best_match[:os_name] ||= host[:os_name] || 'Unknown'
|
|
693
|
+
best_match[:purpose] ||= 'device'
|
|
694
|
+
|
|
695
|
+
[:os_name, :purpose, :os_flavor, :os_sp, :arch, :name, :os_lang].each do |host_attr|
|
|
696
|
+
next if host.attribute_locked? host_attr
|
|
697
|
+
if best_match[host_attr]
|
|
698
|
+
host[host_attr] = Rex::Text.ascii_safe_hex(best_match[host_attr])
|
|
237
699
|
end
|
|
238
|
-
res = Recog::Nizer.match(rdb, banner)
|
|
239
|
-
matches << res if res
|
|
240
700
|
end
|
|
241
701
|
|
|
242
|
-
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def recog_matches_for_note(note)
|
|
246
|
-
# Skip notes that are missing the correct structure or have been blacklisted
|
|
247
|
-
return [] if not validate_fingerprint_data(note)
|
|
248
|
-
|
|
249
|
-
#
|
|
250
|
-
# These rules define the relationship between fingerprint note keys
|
|
251
|
-
# and specific Recog databases for detailed matching. Notes that do
|
|
252
|
-
# not match a rule are passed to the generic matcher.
|
|
253
|
-
#
|
|
254
|
-
fingerprint_note_match_keys = {
|
|
255
|
-
'smb.fingerprint' => {
|
|
256
|
-
:native_os => [ 'smb.native_os' ],
|
|
257
|
-
},
|
|
258
|
-
'http.fingerprint' => {
|
|
259
|
-
:header_server => [ 'http_header.server', 'apache_os' ],
|
|
260
|
-
:header_set_cookie => [ 'http_header.cookie' ],
|
|
261
|
-
:header_www_authenticate => [ 'http_header.wwwauth' ],
|
|
262
|
-
# TODO: Candidates for future Recog support
|
|
263
|
-
# :content => 'http_body'
|
|
264
|
-
# :code => 'http_response_code'
|
|
265
|
-
# :message => 'http_response_message'
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
matches = []
|
|
270
|
-
|
|
271
|
-
# Look for a specific Recog database for this type and data key
|
|
272
|
-
if fingerprint_note_match_keys.has_key?( note.ntype )
|
|
273
|
-
fingerprint_note_match_keys[ note.ntype ].each_pair do |k,rdbs|
|
|
274
|
-
if note.data.has_key?(k)
|
|
275
|
-
rdbs.each do |rdb|
|
|
276
|
-
res = Recog::Nizer.match(rdb, note.data[k])
|
|
277
|
-
matches << res if res
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
end
|
|
281
|
-
else
|
|
282
|
-
# Add all generic match results to the overall match array
|
|
283
|
-
normalize_scanner_fp(note).each do |m|
|
|
284
|
-
next unless m
|
|
285
|
-
matches << m
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
matches
|
|
702
|
+
host.save if host.changed?
|
|
290
703
|
end
|
|
291
704
|
|
|
292
705
|
# Determine if the fingerprint data is readable. If not, it nearly always
|
|
@@ -307,514 +720,198 @@ module Mdm::Host::OperatingSystemNormalization
|
|
|
307
720
|
end
|
|
308
721
|
end
|
|
309
722
|
|
|
310
|
-
|
|
311
|
-
# Normalize matches in order to handle inconsistencies between fingerprint
|
|
312
|
-
# sources and our desired usage in Metasploit. This amounts to yet more
|
|
313
|
-
# duct tape, but the situation should improve as the fingerprint sources
|
|
314
|
-
# are updated and enhanced. In the future, this method will no longer
|
|
315
|
-
# be needed (or at least, doing less and less work)
|
|
316
|
-
#
|
|
317
|
-
def normalize_match(m)
|
|
318
|
-
# Normalize os.version strings containing 'Service Pack X' to just 'SPX'
|
|
319
|
-
if m['os.version'] and m['os.version'].index('Service Pack ') == 0
|
|
320
|
-
m['os.version'] = m['os.version'].gsub(/Service Pack /, 'SP')
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
if m['os.product']
|
|
723
|
+
protected
|
|
324
724
|
|
|
325
|
-
# Normalize Apple Mac OS X to just Mac OS X
|
|
326
|
-
if m['os.product'] =~ /^Apple Mac/
|
|
327
|
-
m['os.product'] = m['os.product'].gsub(/Apple Mac/, 'Mac')
|
|
328
|
-
m['os.vendor'] ||= 'Apple'
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
# Normalize Sun Solaris/Sun SunOS to just Solaris/SunOS
|
|
332
|
-
if m['os.product'] =~ /^Sun (Solaris|SunOS)/
|
|
333
|
-
m['os.product'] = m['os.product'].gsub(/^Sun /, '')
|
|
334
|
-
m['os.vendor'] ||= 'Oracle'
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
# Normalize Microsoft Windows to just Windows to catch any stragglers
|
|
338
|
-
if m['os.product'] =~ /^Microsoft Windows/
|
|
339
|
-
m['os.product'] = m['os.product'].gsub(/Microsoft Windows/, 'Windows')
|
|
340
|
-
m['os.vendor'] ||= 'Microsoft'
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
# Normalize Windows Server to just Windows to match Metasploit target names
|
|
344
|
-
if m['os.product'] =~ /^Windows Server/
|
|
345
|
-
m['os.product'] = m['os.product'].gsub(/Windows Server/, 'Windows')
|
|
346
|
-
end
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
m
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
#
|
|
353
|
-
# Recog assumes that the protocol version of the SSH banner has been removed
|
|
354
725
|
#
|
|
355
|
-
|
|
356
|
-
if banner =~ /^SSH-\d+\.\d+-(.*)/
|
|
357
|
-
$1
|
|
358
|
-
else
|
|
359
|
-
banner
|
|
360
|
-
end
|
|
361
|
-
end
|
|
362
|
-
|
|
726
|
+
# Convert a host.os.*_fingerprint Note into a hash containing the standard os_* fields
|
|
363
727
|
#
|
|
364
|
-
#
|
|
365
|
-
#
|
|
366
|
-
#
|
|
367
|
-
# values where possible, and use the most confident values we have.
|
|
728
|
+
# Also includes a :certainty which is a float from 0 - 1.00 indicating the
|
|
729
|
+
# scanner's confidence in its fingerprint. If the particular scanner does
|
|
730
|
+
# not provide such information, defaults to 0.80.
|
|
368
731
|
#
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if ! host.attribute_locked?(:purpose)
|
|
390
|
-
host.purpose = guess_purpose_from_match(match)
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
#
|
|
394
|
-
# Map match fields from Recog fingerprint style to Metasploit style
|
|
395
|
-
#
|
|
396
|
-
|
|
397
|
-
# os.build: Examples: 9001, 2600, 7602
|
|
398
|
-
# os.device: Examples: General, ADSL Modem, Broadband router, Cable Modem, Camera, Copier, CSU/DSU
|
|
399
|
-
# os.edition: Examples: Web, Storage, HPC, MultiPoint, Enterprise, Home, Starter, Professional
|
|
400
|
-
# os.family: Examples: Windows, Linux, Solaris, NetWare, ProCurve, Mac OS X, HP-UX, AIX
|
|
401
|
-
# os.product: Examples: Windows, Linux, Windows Server 2008 R2, Windows XP, Enterprise Linux, NEO Tape Library
|
|
402
|
-
# os.vendor: Examples: Microsoft, HP, IBM, Sun, 3Com, Ricoh, Novell, Ubuntu, Apple, Cisco, Xerox
|
|
403
|
-
# os.version: Examples: SP1, SP2, 6.5 SP3 CPR, 10.04, 8.04, 12.10, 4.0, 6.1, 8.5
|
|
404
|
-
# os.language: Examples: English, Arabic, German
|
|
405
|
-
# linux.kernel.version: Examples: 2.6.32
|
|
406
|
-
|
|
407
|
-
# Metasploit currently ignores os.build, os.device, and os.vendor as separate fields.
|
|
408
|
-
|
|
409
|
-
# Select the OS name from os.name, fall back to os.family
|
|
410
|
-
if ! host.attribute_locked?(:os_name)
|
|
411
|
-
# Try to fill this value from os.product first if it exists
|
|
412
|
-
if match.has_key?('os.product')
|
|
413
|
-
host.os_name = sanitize(match['os.product'])
|
|
414
|
-
else
|
|
415
|
-
# Fall back to os.family otherwise, if available
|
|
416
|
-
if match.has_key?('os.family')
|
|
417
|
-
host.os_name = sanitize(match['os.family'])
|
|
732
|
+
# TODO: This whole normalize scanner procedure needs to be shoved off to its own
|
|
733
|
+
# mixin. It's far too long and convoluted, has a ton of repeated code, and is
|
|
734
|
+
# a massive hassle to update with new fingerprints.
|
|
735
|
+
def normalize_scanner_fp(fp)
|
|
736
|
+
return {} if not validate_fingerprint_data(fp)
|
|
737
|
+
ret = {}
|
|
738
|
+
data = fp.data
|
|
739
|
+
case fp.ntype
|
|
740
|
+
when 'host.os.session_fingerprint'
|
|
741
|
+
# These come from meterpreter sessions' client.sys.config.sysinfo
|
|
742
|
+
case data[:os]
|
|
743
|
+
when /Windows/
|
|
744
|
+
ret.update(parse_windows_os_str(data[:os]))
|
|
745
|
+
when /Linux (\d+\.\d+\.\d+\S*)\s* \((\w*)\)/
|
|
746
|
+
ret[:os_name] = "Linux"
|
|
747
|
+
ret[:name] = data[:name]
|
|
748
|
+
ret[:os_sp] = $1
|
|
749
|
+
ret[:arch] = get_arch_from_string($2)
|
|
750
|
+
else
|
|
751
|
+
ret[:os_name] = data[:os]
|
|
418
752
|
end
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
if match['linux.kernel.version']
|
|
433
|
-
host.os_sp = sanitize(match['linux.kernel.version'])
|
|
753
|
+
ret[:arch] = data[:arch] if data[:arch]
|
|
754
|
+
ret[:name] = data[:name] if data[:name]
|
|
755
|
+
|
|
756
|
+
when 'host.os.nmap_fingerprint', 'host.os.mbsa_fingerprint'
|
|
757
|
+
# :os_vendor=>"Microsoft" :os_family=>"Windows" :os_version=>"2000" :os_accuracy=>"94"
|
|
758
|
+
#
|
|
759
|
+
# :os_match=>"Microsoft Windows Vista SP0 or SP1, Server 2008, or Windows 7 Ultimate (build 7000)"
|
|
760
|
+
# :os_vendor=>"Microsoft" :os_family=>"Windows" :os_version=>"7" :os_accuracy=>"100"
|
|
761
|
+
ret[:certainty] = data[:os_accuracy].to_f / 100.0
|
|
762
|
+
if (data[:os_vendor] == data[:os_family])
|
|
763
|
+
ret[:os_name] = data[:os_family]
|
|
764
|
+
else
|
|
765
|
+
ret[:os_name] = data[:os_vendor] + " " + data[:os_family]
|
|
434
766
|
end
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
'firewall'
|
|
474
|
-
when /linux/
|
|
475
|
-
'server'
|
|
476
|
-
else
|
|
477
|
-
'device'
|
|
478
|
-
end
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
# Ensure that the host attribute is using ascii safe text
|
|
482
|
-
# and escapes any other byte value.
|
|
483
|
-
def sanitize(text)
|
|
484
|
-
Rex::Text.ascii_safe_hex(text)
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
#
|
|
488
|
-
# Normalize data from Meterpreter's client.sys.config.sysinfo()
|
|
489
|
-
#
|
|
490
|
-
def normalize_session_fingerprint(data)
|
|
491
|
-
ret = {}
|
|
492
|
-
case data[:os]
|
|
493
|
-
when /Windows/
|
|
494
|
-
ret.update(parse_windows_os_str(data[:os]))
|
|
495
|
-
# Switch to this code block once the multi-meterpreter code review is complete
|
|
496
|
-
=begin
|
|
497
|
-
|
|
498
|
-
when /^(Windows \w+)\s*\(Build (\d+)(.*)\)/
|
|
499
|
-
ret['os.product'] = $1
|
|
500
|
-
ret['os.build'] = $2
|
|
501
|
-
ret['os.vendor'] = 'Microsoft'
|
|
502
|
-
possible_sp = $3
|
|
503
|
-
if possible_sp =~ /Service Pack (\d+)/
|
|
504
|
-
ret['os.version'] = 'SP' + $1
|
|
767
|
+
ret[:os_flavor] = data[:os_version]
|
|
768
|
+
ret[:name] = data[:hostname] if data[:hostname]
|
|
769
|
+
|
|
770
|
+
when 'host.os.nexpose_fingerprint'
|
|
771
|
+
# :family=>"Windows" :certainty=>"0.85" :vendor=>"Microsoft" :product=>"Windows 7 Ultimate Edition"
|
|
772
|
+
# :family=>"Linux" :certainty=>"0.64" :vendor=>"Linux" :product=>"Linux"
|
|
773
|
+
# :family=>"Linux" :certainty=>"0.80" :vendor=>"Ubuntu" :product=>"Linux"
|
|
774
|
+
# :family=>"IOS" :certainty=>"0.80" :vendor=>"Cisco" :product=>"IOS"
|
|
775
|
+
# :family=>"embedded" :certainty=>"0.61" :vendor=>"Linksys" :product=>"embedded"
|
|
776
|
+
ret[:certainty] = data[:certainty].to_f
|
|
777
|
+
case data[:family]
|
|
778
|
+
when /AIX|ESX|Mac OS X|OpenSolaris|Solaris|IOS|Linux/
|
|
779
|
+
if data[:vendor] == data[:family]
|
|
780
|
+
ret[:os_name] = data[:vendor]
|
|
781
|
+
else
|
|
782
|
+
# family often contains the vendor string, so rip it out to
|
|
783
|
+
# avoid useless duplication
|
|
784
|
+
ret[:os_name] = data[:vendor].to_s + " " + data[:family].to_s.gsub(data[:vendor].to_s, '').strip
|
|
785
|
+
end
|
|
786
|
+
when "Windows"
|
|
787
|
+
ret[:os_name] = "Microsoft Windows"
|
|
788
|
+
if data[:product]
|
|
789
|
+
if data[:product][/2008/] && data[:version].to_i == 7
|
|
790
|
+
ret[:os_flavor] = "Windows 7"
|
|
791
|
+
ret[:type] = "client"
|
|
792
|
+
else
|
|
793
|
+
ret[:os_flavor] = data[:product].gsub("Windows", '').strip
|
|
794
|
+
ret[:os_sp] = data[:version] if data[:version]
|
|
795
|
+
if data[:product]
|
|
796
|
+
ret[:type] = "server" if data[:product][/Server/]
|
|
797
|
+
ret[:type] = "client" if data[:product][/^(XP|ME)$/]
|
|
798
|
+
end
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
when "embedded"
|
|
802
|
+
ret[:os_name] = data[:vendor]
|
|
803
|
+
else
|
|
804
|
+
ret[:os_name] = data[:vendor]
|
|
505
805
|
end
|
|
506
|
-
=
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
#
|
|
520
|
-
# Normalize data from Nmap fingerprints
|
|
521
|
-
#
|
|
522
|
-
def normalize_nmap_fingerprint(data)
|
|
523
|
-
ret = {}
|
|
524
|
-
|
|
525
|
-
# :os_vendor=>"Microsoft" :os_family=>"Windows" :os_version=>"2000" :os_accuracy=>"94"
|
|
526
|
-
ret['os.certainty'] = ( data[:os_accuracy].to_f / 100.0 ).to_s if data[:os_accuracy]
|
|
527
|
-
if (data[:os_vendor] == data[:os_family])
|
|
528
|
-
ret['os.product'] = data[:os_family]
|
|
529
|
-
else
|
|
530
|
-
ret['os.product'] = data[:os_family]
|
|
531
|
-
ret['os.vendor'] = data[:os_vendor]
|
|
532
|
-
end
|
|
533
|
-
|
|
534
|
-
# Nmap places the type of Windows (XP, 7, etc) into the version field
|
|
535
|
-
if ret['os.product'] == 'Windows' and data[:os_version]
|
|
536
|
-
ret['os.product'] = ret['os.product'] + ' ' + data[:os_version].to_s
|
|
537
|
-
else
|
|
538
|
-
ret['os.version'] = data[:os_version]
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
ret['host.name'] = data[:hostname] if data[:hostname]
|
|
542
|
-
|
|
543
|
-
if ret['os.certainty']
|
|
544
|
-
ret['os.certainty'] = [ ret['os.certainty'].to_f, MAX_NMAP_CERTAINTY ].min.to_s
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
[ ret ]
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
#
|
|
551
|
-
# Normalize data from MBSA fingerprints
|
|
552
|
-
#
|
|
553
|
-
def normalize_mbsa_fingerprint(data)
|
|
554
|
-
ret = {}
|
|
555
|
-
# :os_match=>"Microsoft Windows Vista SP0 or SP1, Server 2008, or Windows 7 Ultimate (build 7000)"
|
|
556
|
-
# :os_vendor=>"Microsoft" :os_family=>"Windows" :os_version=>"7" :os_accuracy=>"100"
|
|
557
|
-
ret['os.certainty'] = ( data[:os_accuracy].to_f / 100.0 ).to_s if data[:os_accuracy]
|
|
558
|
-
ret['os.family'] = data[:os_family] if data[:os_family]
|
|
559
|
-
ret['os.vendor'] = data[:os_vendor] if data[:os_vendor]
|
|
560
|
-
|
|
561
|
-
if data[:os_family] and data[:os_version]
|
|
562
|
-
ret['os.product'] = data[:os_family] + " " + data[:os_version]
|
|
563
|
-
end
|
|
564
|
-
|
|
565
|
-
ret['host.name'] = data[:hostname] if data[:hostname]
|
|
566
|
-
|
|
567
|
-
[ ret ]
|
|
568
|
-
end
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
#
|
|
572
|
-
# Normalize data from Nexpose fingerprints
|
|
573
|
-
#
|
|
574
|
-
def normalize_nexpose_fingerprint(data)
|
|
575
|
-
ret = {}
|
|
576
|
-
# :family=>"Windows" :certainty=>"0.85" :vendor=>"Microsoft" :product=>"Windows 7 Ultimate Edition"
|
|
577
|
-
# :family=>"Windows" :certainty=>"0.67" :vendor=>"Microsoft" :arch=>"x86" :product=>'Windows 7' :version=>'SP1'
|
|
578
|
-
# :family=>"Linux" :certainty=>"0.64" :vendor=>"Linux" :product=>"Linux"
|
|
579
|
-
# :family=>"Linux" :certainty=>"0.80" :vendor=>"Ubuntu" :product=>"Linux"
|
|
580
|
-
# :family=>"IOS" :certainty=>"0.80" :vendor=>"Cisco" :product=>"IOS"
|
|
581
|
-
# :family=>"embedded" :certainty=>"0.61" :vendor=>"Linksys" :product=>"embedded"
|
|
582
|
-
|
|
583
|
-
ret['os.certainty'] = data[:certainty] if data[:certainty]
|
|
584
|
-
ret['os.family'] = data[:family] if data[:family]
|
|
585
|
-
ret['os.vendor'] = data[:vendor] if data[:vendor]
|
|
586
|
-
|
|
587
|
-
case data[:product]
|
|
588
|
-
when /^Windows/
|
|
589
|
-
|
|
590
|
-
# TODO: Verify Windows CE and Windows 8 RT fingerprints
|
|
591
|
-
# Translate the version into the representation we want
|
|
592
|
-
|
|
593
|
-
case data[:version].to_s
|
|
594
|
-
|
|
595
|
-
# These variants are normalized to just 'Windows <Version>'
|
|
596
|
-
when "NT", "2000", "95", "ME", "XP", "Vista", "7", "8", "8.1"
|
|
597
|
-
ret['os.product'] = "Windows #{data[:version]}"
|
|
598
|
-
|
|
599
|
-
# Service pack in the version field should be recognized
|
|
600
|
-
when /^SP\d+/, /^Service Pack \d+/
|
|
601
|
-
ret['os.product'] = data[:product]
|
|
602
|
-
ret['os.version'] = data[:version]
|
|
603
|
-
|
|
604
|
-
# No version means the version is part of the product already
|
|
605
|
-
when nil, ''
|
|
606
|
-
# Trim any 'Server' suffix and use as it is
|
|
607
|
-
ret['os.product'] = data[:product].sub(/ Server$/, '')
|
|
608
|
-
|
|
609
|
-
# Otherwise, we assume a Server version of Windows
|
|
610
|
-
else
|
|
611
|
-
ret['os.product'] = "Windows Server #{data[:version]}"
|
|
612
|
-
end
|
|
613
|
-
|
|
614
|
-
# Extract the edition string if it is present
|
|
615
|
-
if data[:product] =~ /(XP|Vista|\d+(?:\.\d+)) (\w+|\w+ \w+|\w+ \w+ \w+) Edition/
|
|
616
|
-
ret['os.edition'] = $2
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
when nil, 'embedded'
|
|
620
|
-
# Use the family or vendor name when the product is empty or 'embedded'
|
|
621
|
-
ret['os.product'] = data[:family] unless data[:family] == 'embedded'
|
|
622
|
-
ret['os.product'] ||= data[:vendor]
|
|
623
|
-
ret['os.version'] = data[:version] if data[:version]
|
|
624
|
-
else
|
|
625
|
-
# Default to using the product name reported by Nexpose
|
|
626
|
-
ret['os.product'] = data[:product] if data[:product]
|
|
627
|
-
end
|
|
628
|
-
|
|
629
|
-
ret['os.arch'] = get_arch_from_string(data[:arch]) if data[:arch]
|
|
630
|
-
ret['os.arch'] ||= get_arch_from_string(data[:desc]) if data[:desc]
|
|
631
|
-
|
|
632
|
-
[ ret ]
|
|
633
|
-
end
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
#
|
|
637
|
-
# Normalize data from Retina fingerprints
|
|
638
|
-
#
|
|
639
|
-
def normalize_retina_fingerprint(data)
|
|
640
|
-
ret = {}
|
|
641
|
-
# :os=>"Windows Server 2003 (X64), Service Pack 2"
|
|
642
|
-
case data[:os]
|
|
643
|
-
when /Windows/
|
|
644
|
-
ret.update(parse_windows_os_str(data[:os]))
|
|
645
|
-
else
|
|
646
|
-
# No idea what this looks like if it isn't windows. Just store
|
|
647
|
-
# the whole thing and hope for the best.
|
|
648
|
-
# TODO: Add examples of non-Windows results
|
|
649
|
-
ret['os.product'] = data[:os] if data[:os]
|
|
650
|
-
end
|
|
651
|
-
[ ret ]
|
|
652
|
-
end
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
#
|
|
656
|
-
# Normalize data from Nessus fingerprints
|
|
657
|
-
#
|
|
658
|
-
def normalize_nessus_fingerprint(data)
|
|
659
|
-
ret = {}
|
|
660
|
-
# :os=>"Microsoft Windows 2000 Advanced Server (English)"
|
|
661
|
-
# :os=>"Microsoft Windows 2000\nMicrosoft Windows XP"
|
|
662
|
-
# :os=>"Linux Kernel 2.6"
|
|
663
|
-
# :os=>"Sun Solaris 8"
|
|
664
|
-
# :os=>"IRIX 6.5"
|
|
665
|
-
|
|
666
|
-
# Nessus sometimes jams multiple OS names together with a newline.
|
|
667
|
-
oses = data[:os].split(/\n/)
|
|
668
|
-
if oses.length > 1
|
|
669
|
-
# Multiple fingerprints means Nessus wasn't really sure, reduce
|
|
670
|
-
# the certainty accordingly
|
|
671
|
-
ret['os.certainty'] = 0.5
|
|
672
|
-
else
|
|
673
|
-
ret['os.certainty'] = 0.8
|
|
674
|
-
end
|
|
675
|
-
|
|
676
|
-
# Since there is no confidence associated with them, the best we
|
|
677
|
-
# can do is just take the first one.
|
|
678
|
-
case oses.first
|
|
679
|
-
when /^(Microsoft |)Windows/
|
|
680
|
-
ret.update(parse_windows_os_str(data[:os]))
|
|
681
|
-
|
|
682
|
-
when /(2\.[46]\.\d+[-a-zA-Z0-9]+)/
|
|
683
|
-
# Look for older Linux kernel versions
|
|
684
|
-
ret['os.product'] = "Linux"
|
|
685
|
-
ret['os.version'] = $1
|
|
686
|
-
|
|
687
|
-
when /^Linux Kernel ([\d\.]+)(.*)/
|
|
688
|
-
# Look for strings like "Linux Kernel 2.6 on Ubuntu 9.10 (karmic)"
|
|
689
|
-
# Ex: Linux Kernel 2.2 on Red Hat Linux release 6.2 (Zoot)
|
|
690
|
-
# Ex: Linux Kernel 2.6 on Ubuntu Linux 8.04 (hardy)
|
|
691
|
-
ret['os.product'] = "Linux"
|
|
692
|
-
ret['os.version'] = $1
|
|
693
|
-
|
|
694
|
-
vendor = $2.to_s
|
|
695
|
-
|
|
696
|
-
# Try to snag the vendor name as well
|
|
697
|
-
if vendor =~ /on (\w+|\w+ \w+|\w+ \w+ \w+) (Linux|\d)/
|
|
698
|
-
ret['os.vendor'] = $1
|
|
806
|
+
ret[:arch] = get_arch_from_string(data[:arch]) if data[:arch]
|
|
807
|
+
ret[:arch] ||= get_arch_from_string(data[:desc]) if data[:desc]
|
|
808
|
+
|
|
809
|
+
when 'host.os.retina_fingerprint'
|
|
810
|
+
# :os=>"Windows Server 2003 (X64), Service Pack 2"
|
|
811
|
+
case data[:os]
|
|
812
|
+
when /Windows/
|
|
813
|
+
ret.update(parse_windows_os_str(data[:os]))
|
|
814
|
+
else
|
|
815
|
+
# No idea what this looks like if it isn't windows. Just store
|
|
816
|
+
# the whole thing and hope for the best. XXX: Ghetto. =/
|
|
817
|
+
ret[:os_name] = data[:os]
|
|
699
818
|
end
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
#
|
|
703
|
-
#
|
|
704
|
-
#
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
#
|
|
717
|
-
# Normalize data from Qualys fingerprints
|
|
718
|
-
#
|
|
719
|
-
def normalize_qualys_fingerprint(data)
|
|
720
|
-
ret = {}
|
|
721
|
-
# :os=>"Microsoft Windows 2000"
|
|
722
|
-
# :os=>"Windows 2003"
|
|
723
|
-
# :os=>"Microsoft Windows XP Professional SP3"
|
|
724
|
-
# :os=>"Ubuntu Linux"
|
|
725
|
-
# :os=>"Cisco IOS 12.0(3)T3"
|
|
726
|
-
# :os=>"Red-Hat Linux 6.0"
|
|
727
|
-
case data[:os]
|
|
728
|
-
when /Windows/
|
|
729
|
-
ret.update(parse_windows_os_str(data[:os]))
|
|
730
|
-
|
|
731
|
-
when /^(Cisco) (IOS) (\d+[^\s]+)/
|
|
732
|
-
ret['os.product'] = $2
|
|
733
|
-
ret['os.vendor'] = $1
|
|
734
|
-
ret['os.version'] = $3
|
|
735
|
-
|
|
736
|
-
when /^([^\s]+) (Linux)(.*)/
|
|
737
|
-
ret['os.product'] = $2
|
|
738
|
-
ret['os.vendor'] = $1
|
|
739
|
-
|
|
740
|
-
ver = $3.to_s.strip.split(/\s+/).first
|
|
741
|
-
if ver =~ /^\d+\./
|
|
742
|
-
ret['os.version'] = ver
|
|
819
|
+
when 'host.os.nessus_fingerprint'
|
|
820
|
+
# :os=>"Microsoft Windows 2000 Advanced Server (English)"
|
|
821
|
+
# :os=>"Microsoft Windows 2000\nMicrosoft Windows XP"
|
|
822
|
+
# :os=>"Linux Kernel 2.6"
|
|
823
|
+
# :os=>"Sun Solaris 8"
|
|
824
|
+
# :os=>"IRIX 6.5"
|
|
825
|
+
|
|
826
|
+
# Nessus sometimes jams multiple OS names together with a newline.
|
|
827
|
+
oses = data[:os].split(/\n/)
|
|
828
|
+
if oses.length > 1
|
|
829
|
+
# Multiple fingerprints means Nessus wasn't really sure, reduce
|
|
830
|
+
# the certainty accordingly
|
|
831
|
+
ret[:certainty] = 0.5
|
|
832
|
+
else
|
|
833
|
+
ret[:certainty] = 0.8
|
|
743
834
|
end
|
|
744
835
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
ret['os.arch'] = get_arch_from_string($3)
|
|
768
|
-
else
|
|
769
|
-
ret['os.product'] = data[:os]
|
|
770
|
-
end
|
|
771
|
-
ret['os.arch'] = data[:arch] if data[:arch]
|
|
772
|
-
ret['host.name'] = data[:name] if data[:name]
|
|
773
|
-
[ ret ]
|
|
774
|
-
end
|
|
775
|
-
|
|
776
|
-
#
|
|
777
|
-
# Normalize data from generic fingerprints
|
|
778
|
-
#
|
|
779
|
-
def normalize_generic_fingerprint(data)
|
|
780
|
-
ret = {}
|
|
781
|
-
ret['os.product'] = data[:os_name] || data[:os] || data[:os_fingerprint] || "Unknown"
|
|
782
|
-
ret['os.arch'] = data[:os_arch] if data[:os_arch]
|
|
783
|
-
ret['os.certainty'] = data[:os_certainty] || 0.5
|
|
784
|
-
[ ret ]
|
|
785
|
-
end
|
|
786
|
-
|
|
787
|
-
#
|
|
788
|
-
# Convert a host.os.*_fingerprint Note into a hash containing 'os.*' and 'host.*' fields
|
|
789
|
-
#
|
|
790
|
-
# Also includes a os.certainty which is a float from 0 - 1.00 indicating the
|
|
791
|
-
# scanner's confidence in its fingerprint. If the particular scanner does
|
|
792
|
-
# not provide such information, default to 0.80.
|
|
793
|
-
#
|
|
794
|
-
def normalize_scanner_fp(fp)
|
|
795
|
-
hits = []
|
|
796
|
-
|
|
797
|
-
return hits if not validate_fingerprint_data(fp)
|
|
836
|
+
# Since there is no confidence associated with them, the best we
|
|
837
|
+
# can do is just take the first one.
|
|
838
|
+
case oses.first
|
|
839
|
+
when /Windows/
|
|
840
|
+
ret.update(parse_windows_os_str(data[:os]))
|
|
841
|
+
|
|
842
|
+
when /(2\.[46]\.\d+[-a-zA-Z0-9]+)/
|
|
843
|
+
# Linux kernel version
|
|
844
|
+
ret[:os_name] = "Linux"
|
|
845
|
+
ret[:os_sp] = $1
|
|
846
|
+
when /(.*)?((\d+\.)+\d+)$/
|
|
847
|
+
# Then we don't necessarily know what the os is, but this
|
|
848
|
+
# fingerprint has some version information at the end, pull it
|
|
849
|
+
# off.
|
|
850
|
+
# When Nessus doesn't know what kind of linux it has, it gives an os like
|
|
851
|
+
# "Linux Kernel 2.6"
|
|
852
|
+
# The "Kernel" string is useless, so cut it off.
|
|
853
|
+
ret[:os_name] = $1.gsub("Kernel", '').strip
|
|
854
|
+
ret[:os_sp] = $2
|
|
855
|
+
else
|
|
856
|
+
ret[:os_name] = oses.first
|
|
857
|
+
end
|
|
798
858
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
859
|
+
ret[:name] = data[:hname]
|
|
860
|
+
when 'host.os.qualys_fingerprint'
|
|
861
|
+
# :os=>"Microsoft Windows 2000"
|
|
862
|
+
# :os=>"Windows 2003"
|
|
863
|
+
# :os=>"Microsoft Windows XP Professional SP3"
|
|
864
|
+
# :os=>"Ubuntu Linux"
|
|
865
|
+
# :os=>"Cisco IOS 12.0(3)T3"
|
|
866
|
+
case data[:os]
|
|
867
|
+
when /Windows/
|
|
868
|
+
ret.update(parse_windows_os_str(data[:os]))
|
|
869
|
+
else
|
|
870
|
+
parts = data[:os].split(/\s+/, 3)
|
|
871
|
+
ret[:os_name] = "<unknown>"
|
|
872
|
+
ret[:os_name] = parts[0] if parts[0]
|
|
873
|
+
ret[:os_name] << " " + parts[1] if parts[1]
|
|
874
|
+
ret[:os_sp] = parts[2] if parts[2]
|
|
875
|
+
end
|
|
876
|
+
# XXX: We should really be using smb_version's stored fingerprints
|
|
877
|
+
# instead of parsing the service info manually. Disable for now so we
|
|
878
|
+
# don't count smb twice.
|
|
879
|
+
#when 'smb.fingerprint'
|
|
880
|
+
# # smb_version is kind enough to store everything we need directly
|
|
881
|
+
# ret.merge(fp.data)
|
|
882
|
+
# # If it's windows, this should be a pretty high-confidence
|
|
883
|
+
# # fingerprint. Otherwise, it's samba which doesn't give us much of
|
|
884
|
+
# # anything in most cases.
|
|
885
|
+
# ret[:certainty] = 1.0 if fp.data[:os_name] =~ /Windows/
|
|
886
|
+
when 'host.os.fusionvm_fingerprint'
|
|
887
|
+
case data[:os]
|
|
888
|
+
when /Windows/
|
|
889
|
+
ret.update(parse_windows_os_str(data[:os]))
|
|
890
|
+
when /Linux ([^[:space:]]*) ([^[:space:]]*) .* (\(.*\))/
|
|
891
|
+
ret[:os_name] = "Linux"
|
|
892
|
+
ret[:name] = $1
|
|
893
|
+
ret[:os_sp] = $2
|
|
894
|
+
ret[:arch] = get_arch_from_string($3)
|
|
895
|
+
else
|
|
896
|
+
ret[:os_name] = data[:os]
|
|
897
|
+
end
|
|
898
|
+
ret[:arch] = data[:arch] if data[:arch]
|
|
899
|
+
ret[:name] = data[:name] if data[:name]
|
|
805
900
|
else
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
901
|
+
# If you've fallen through this far, you've hit a generalized
|
|
902
|
+
# pass-through fingerprint parser.
|
|
903
|
+
ret[:os_name] = data[:os_name] || data[:os] || data[:os_fingerprint] || "<unknown>"
|
|
904
|
+
ret[:type] = data[:os_purpose] if data[:os_purpose]
|
|
905
|
+
ret[:arch] = data[:os_arch] if data[:os_arch]
|
|
906
|
+
ret[:certainty] = data[:os_certainty] || 0.5
|
|
907
|
+
end
|
|
908
|
+
ret[:certainty] ||= 0.8
|
|
909
|
+
ret
|
|
811
910
|
end
|
|
812
911
|
|
|
813
912
|
#
|
|
814
913
|
# Take a windows version string and return a hash with fields suitable for
|
|
815
|
-
# Host this object's version fields.
|
|
816
|
-
# external fingerprints and should eventually be replaced by per-source
|
|
817
|
-
# mappings.
|
|
914
|
+
# Host this object's version fields.
|
|
818
915
|
#
|
|
819
916
|
# A few example strings that this will have to parse:
|
|
820
917
|
# sessions
|
|
@@ -836,64 +933,52 @@ module Mdm::Host::OperatingSystemNormalization
|
|
|
836
933
|
def parse_windows_os_str(str)
|
|
837
934
|
ret = {}
|
|
838
935
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
ret[
|
|
936
|
+
ret[:os_name] = "Microsoft Windows"
|
|
937
|
+
arch = get_arch_from_string(str)
|
|
938
|
+
ret[:arch] = arch if arch
|
|
842
939
|
|
|
843
|
-
|
|
940
|
+
if str =~ /(Service Pack|SP) ?(\d+)/
|
|
941
|
+
ret[:os_sp] = "SP#{$2}"
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
# Flavor
|
|
844
945
|
case str
|
|
845
946
|
when /\.NET Server/
|
|
846
|
-
ret[
|
|
847
|
-
when /
|
|
848
|
-
ret[
|
|
849
|
-
when / (NT (?:3\.51|4\.0))/
|
|
850
|
-
ret['os.product'] << ' ' + $1
|
|
851
|
-
when /Windows (95|98|ME|XP|Vista|[\d\.]+)/
|
|
852
|
-
ret['os.product'] << ' ' + $1
|
|
947
|
+
ret[:os_flavor] = "2003"
|
|
948
|
+
when /(XP|2000 Advanced Server|2000|2003|2008|SBS|Vista|7 .* Edition|7)/
|
|
949
|
+
ret[:os_flavor] = $1
|
|
853
950
|
else
|
|
854
951
|
# If we couldn't pull out anything specific for the flavor, just cut
|
|
855
952
|
# off the stuff we know for sure isn't it and hope for the best
|
|
856
|
-
ret[
|
|
857
|
-
|
|
858
|
-
# Make sure the product name doesn't include any non-alphanumeric stuff
|
|
859
|
-
# This fixes cases where the above code leaves 'Windows XX (Build 3333,)...'
|
|
860
|
-
ret['os.product'] = ret['os.product'].split(/[^a-zA-Z0-9 ]/).first.strip
|
|
861
|
-
|
|
862
|
-
end
|
|
863
|
-
|
|
864
|
-
# Take a guess at the architecture
|
|
865
|
-
arch = get_arch_from_string(str)
|
|
866
|
-
ret['os.arch'] = arch if arch
|
|
867
|
-
|
|
868
|
-
# Extract any service pack value in the string
|
|
869
|
-
if str =~ /(Service Pack|SP) ?(\d+)/i
|
|
870
|
-
ret['os.version'] = "SP#{$2}"
|
|
871
|
-
end
|
|
872
|
-
|
|
873
|
-
# Extract any build ID found in the string
|
|
874
|
-
if str =~ /build (\d+)/i
|
|
875
|
-
ret['os.build'] = $1
|
|
953
|
+
ret[:os_flavor] ||= str.gsub(/(Microsoft )?Windows|(Service Pack|SP) ?(\d+)/, '').strip
|
|
876
954
|
end
|
|
877
955
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
ret['os.edition'] = $2
|
|
956
|
+
if str =~ /NT|2003|2008|SBS|Server/
|
|
957
|
+
ret[:type] = 'server'
|
|
881
958
|
else
|
|
882
|
-
|
|
883
|
-
ret['os.edition'] = $1
|
|
884
|
-
end
|
|
959
|
+
ret[:type] = 'client'
|
|
885
960
|
end
|
|
886
961
|
|
|
887
962
|
ret
|
|
888
963
|
end
|
|
889
964
|
|
|
890
|
-
#
|
|
891
|
-
# Return a normalized architecture based on patterns in the input string.
|
|
892
|
-
# This will identify things like sparc, powerpc, x86_x64, and i686
|
|
893
|
-
#
|
|
965
|
+
# A case switch to return a normalized arch based on a given string.
|
|
894
966
|
def get_arch_from_string(str)
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
967
|
+
case str
|
|
968
|
+
when /x64|amd64|x86_64/i
|
|
969
|
+
"x64"
|
|
970
|
+
when /x86|i[3456]86/i
|
|
971
|
+
"x86"
|
|
972
|
+
when /PowerPC|PPC|POWER|ppc/
|
|
973
|
+
"ppc"
|
|
974
|
+
when /SPARC/i
|
|
975
|
+
"sparc"
|
|
976
|
+
when /MIPS/i
|
|
977
|
+
"mips"
|
|
978
|
+
when /ARM/i
|
|
979
|
+
"arm"
|
|
980
|
+
else
|
|
981
|
+
nil
|
|
982
|
+
end
|
|
898
983
|
end
|
|
899
|
-
end
|
|
984
|
+
end
|