recog 0.01

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.
Files changed (75) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +42 -0
  5. data/LICENSE +23 -0
  6. data/README.md +63 -0
  7. data/bin/recog_export.rb +81 -0
  8. data/bin/recog_match.rb +51 -0
  9. data/bin/recog_verify.rb +45 -0
  10. data/features/match.feature +16 -0
  11. data/features/support/env.rb +5 -0
  12. data/features/verify.feature +31 -0
  13. data/features/xml/banners.xml +2 -0
  14. data/features/xml/failing_banners_fingerprints.xml +20 -0
  15. data/features/xml/matching_banners_fingerprints.xml +22 -0
  16. data/features/xml/no_tests.xml +53 -0
  17. data/features/xml/successful_tests.xml +33 -0
  18. data/features/xml/tests_with_failures.xml +10 -0
  19. data/features/xml/tests_with_warnings.xml +10 -0
  20. data/lib/recog.rb +3 -0
  21. data/lib/recog/db.rb +38 -0
  22. data/lib/recog/db_manager.rb +27 -0
  23. data/lib/recog/fingerprint.rb +60 -0
  24. data/lib/recog/formatter.rb +51 -0
  25. data/lib/recog/match_reporter.rb +77 -0
  26. data/lib/recog/matcher.rb +60 -0
  27. data/lib/recog/matcher_factory.rb +14 -0
  28. data/lib/recog/nizer.rb +263 -0
  29. data/lib/recog/verifier.rb +46 -0
  30. data/lib/recog/verifier_factory.rb +13 -0
  31. data/lib/recog/verify_reporter.rb +85 -0
  32. data/lib/recog/version.rb +3 -0
  33. data/recog.gemspec +34 -0
  34. data/spec/data/best_os_match_1.yml +17 -0
  35. data/spec/data/best_os_match_2.yml +17 -0
  36. data/spec/data/best_service_match_1.yml +17 -0
  37. data/spec/data/smb_native_os.txt +31 -0
  38. data/spec/data/test_fingerprints.xml +24 -0
  39. data/spec/lib/db_spec.rb +89 -0
  40. data/spec/lib/formatter_spec.rb +69 -0
  41. data/spec/lib/match_reporter_spec.rb +90 -0
  42. data/spec/lib/nizer_spec.rb +124 -0
  43. data/spec/lib/verify_reporter_spec.rb +112 -0
  44. data/xml/apache_os.xml +295 -0
  45. data/xml/architecture.xml +45 -0
  46. data/xml/ftp_banners.xml +808 -0
  47. data/xml/h323_callresp.xml +701 -0
  48. data/xml/hp_pjl_id.xml +435 -0
  49. data/xml/http_cookies.xml +379 -0
  50. data/xml/http_servers.xml +3326 -0
  51. data/xml/http_wwwauth.xml +412 -0
  52. data/xml/imap_banners.xml +267 -0
  53. data/xml/nntp_banners.xml +51 -0
  54. data/xml/ntp_banners.xml +538 -0
  55. data/xml/pop_banners.xml +452 -0
  56. data/xml/rsh_resp.xml +90 -0
  57. data/xml/sip_banners.xml +14 -0
  58. data/xml/smb_native_os.xml +385 -0
  59. data/xml/smtp_banners.xml +1738 -0
  60. data/xml/smtp_debug.xml +45 -0
  61. data/xml/smtp_ehlo.xml +53 -0
  62. data/xml/smtp_expn.xml +95 -0
  63. data/xml/smtp_help.xml +212 -0
  64. data/xml/smtp_mailfrom.xml +24 -0
  65. data/xml/smtp_noop.xml +45 -0
  66. data/xml/smtp_quit.xml +31 -0
  67. data/xml/smtp_rcptto.xml +33 -0
  68. data/xml/smtp_rset.xml +23 -0
  69. data/xml/smtp_turn.xml +23 -0
  70. data/xml/smtp_vrfy.xml +109 -0
  71. data/xml/snmp_sysdescr.xml +8008 -0
  72. data/xml/snmp_sysobjid.xml +284 -0
  73. data/xml/ssh_banners.xml +790 -0
  74. data/xml/upnp_banners.xml +590 -0
  75. metadata +190 -0
@@ -0,0 +1,33 @@
1
+ <?xml version="1.0"?>
2
+ <fingerprints>
3
+ <fingerprint pattern="^Cisco-SIPGateway/IOS-([\d\.x]+)$">
4
+ <description>Cisco SIPGateway</description>
5
+ <example>Cisco-SIPGateway/IOS-12.x</example>
6
+ <param pos="0" name="os.vendor" value="Cisco"/>
7
+ <param pos="0" name="os.product" value="IOS"/>
8
+ <param pos="1" name="os.version"/>
9
+ </fingerprint>
10
+ <fingerprint pattern="^Microsoft Exchange Server 2007 IMAP4 service ready$">
11
+ <!-- Microsoft Exchange Server 2007 IMAP4 service ready
12
+ -->
13
+ <description>Microsoft Exchange Server 2007</description>
14
+ <param pos="0" name="service.vendor" value="Microsoft"/>
15
+ <param pos="0" name="service.family" value="Exchange Server"/>
16
+ <param pos="0" name="service.product" value="Exchange 2007 Server"/>
17
+ <param pos="0" name="os.vendor" value="Microsoft"/>
18
+ <param pos="0" name="os.device" value="General"/>
19
+ <param pos="0" name="os.family" value="Windows"/>
20
+ <param pos="0" name="os.product" value="Windows"/>
21
+ </fingerprint>
22
+ <fingerprint pattern="^The Microsoft Exchange IMAP4 service is ready\.?$">
23
+ <example>The Microsoft Exchange IMAP4 service is ready.</example>
24
+ <description>Microsoft Exchange Server</description>
25
+ <param pos="0" name="service.vendor" value="Microsoft"/>
26
+ <param pos="0" name="service.family" value="Exchange Server"/>
27
+ <param pos="0" name="service.product" value="Exchange Server"/>
28
+ <param pos="0" name="os.vendor" value="Microsoft"/>
29
+ <param pos="0" name="os.device" value="General"/>
30
+ <param pos="0" name="os.family" value="Windows"/>
31
+ <param pos="0" name="os.product" value="Windows"/>
32
+ </fingerprint>
33
+ </fingerprints>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <fingerprints>
3
+ <fingerprint pattern="^foo$">
4
+ <description>foo test</description>
5
+ <example>bar</example>
6
+ </fingerprint>
7
+ <fingerprint pattern="^This matches$">
8
+ <example>This almost matches</example>
9
+ </fingerprint>
10
+ </fingerprints>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <fingerprints>
3
+ <fingerprint pattern="^-{10} Welcome to Pure-FTPd (.*)-{10}$">
4
+ <example>---------- Welcome to Pure-FTPd ----------</example>
5
+ <description>Pure-FTPd</description>
6
+ <param pos="1" name="pureftpd.config"/>
7
+ <param pos="0" name="service.family" value="Pure-FTPd"/>
8
+ <param pos="0" name="service.product" value="Pure-FTPd"/>
9
+ </fingerprint>
10
+ </fingerprints>
@@ -0,0 +1,3 @@
1
+ require 'recog/version'
2
+ require 'recog/db_manager'
3
+ require 'recog/nizer'
@@ -0,0 +1,38 @@
1
+ module Recog
2
+ class DB
3
+ require 'nokogiri'
4
+ require 'recog/fingerprint'
5
+
6
+ attr_accessor :path, :fingerprints, :match_key
7
+
8
+ def initialize(path)
9
+ self.path = path
10
+ parse_fingerprints
11
+ end
12
+
13
+ def parse_fingerprints
14
+ self.fingerprints = []
15
+ xml = nil
16
+
17
+ File.open(self.path, "rb") do |fd|
18
+ xml = Nokogiri::XML( fd.read(fd.stat.size))
19
+ end
20
+
21
+ xml.xpath("/fingerprints").each do |fbase|
22
+ if fbase['matches']
23
+ self.match_key = fbase['matches'].to_s
24
+ end
25
+ end
26
+
27
+ unless self.match_key
28
+ self.match_key = File.basename(self.path).sub(/\.xml$/, '')
29
+ end
30
+
31
+ xml.xpath("/fingerprints/fingerprint").each do |fprint|
32
+ fingerprints << Fingerprint.new(fprint)
33
+ end
34
+
35
+ xml = nil
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,27 @@
1
+ module Recog
2
+ class DBManager
3
+ require 'nokogiri'
4
+ require 'recog/db'
5
+
6
+ attr_accessor :path, :databases
7
+
8
+ DefaultDatabasePath = File.expand_path( File.join( File.dirname(__FILE__), "..", "..", "xml") )
9
+
10
+ def initialize(path = DefaultDatabasePath)
11
+ self.path = path
12
+ reload
13
+ end
14
+
15
+ def load_databases
16
+ Dir[self.path + "/*.xml"].each do |dbxml|
17
+ self.databases << DB.new(dbxml)
18
+ end
19
+ end
20
+
21
+ def reload
22
+ self.databases = []
23
+ load_databases
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,60 @@
1
+ module Recog
2
+ class Fingerprint
3
+ attr_reader :name, :regex, :params, :tests
4
+
5
+ def initialize(xml)
6
+ @name = description(xml)
7
+ @regex = create_regexp(xml)
8
+ @params = parse_params(xml)
9
+ @tests = examples(xml)
10
+ end
11
+
12
+ private
13
+
14
+ def description(xml)
15
+ element = xml.xpath('description')
16
+ element.empty? ? '' : element.first.content
17
+ end
18
+
19
+ def create_regexp(xml)
20
+ pattern = xml['pattern']
21
+ flags = xml['flags'].to_s.split(',')
22
+ RegexpFactory.build(pattern, flags)
23
+ end
24
+
25
+ def parse_params(xml)
26
+ {}.tap do |h|
27
+ xml.xpath('param').each do |e|
28
+ name = e['name']
29
+ pos = e['pos'].to_i
30
+ value = e['value'].to_s
31
+ h[name] = [pos, value]
32
+ end
33
+ end
34
+ end
35
+
36
+ def examples(xml)
37
+ xml.xpath('example').collect(&:content)
38
+ end
39
+
40
+ module RegexpFactory
41
+ def self.build(pattern, flags)
42
+ options = build_options(flags)
43
+ Regexp.new(pattern, options)
44
+ end
45
+
46
+ def self.build_options(flags)
47
+ rflags = Regexp::NOENCODING
48
+ flags.each do |flag|
49
+ case flag
50
+ when 'REG_DOT_NEWLINE', 'REG_LINE_ANY_CRLF'
51
+ rflags |= Regexp::MULTILINE
52
+ when 'REG_ICASE'
53
+ rflags |= Regexp::IGNORECASE
54
+ end
55
+ end
56
+ rflags
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,51 @@
1
+ module Recog
2
+ class Formatter
3
+ COLORS = {
4
+ :red => 31,
5
+ :yellow => 33,
6
+ :green => 32,
7
+ :white => 15
8
+ }
9
+
10
+ attr_reader :options, :output
11
+
12
+ def initialize(options, output)
13
+ @options = options
14
+ @output = output || StringIO.new
15
+ end
16
+
17
+ def status_message(text)
18
+ output.puts color(text, :white)
19
+ end
20
+
21
+ def success_message(text)
22
+ output.puts color(text, :green)
23
+ end
24
+
25
+ def warning_message(text)
26
+ output.puts color(text, :yellow)
27
+ end
28
+
29
+ def failure_message(text)
30
+ output.puts color(text, :red)
31
+ end
32
+
33
+ private
34
+
35
+ def color_enabled?
36
+ options.color
37
+ end
38
+
39
+ def color(text, color_code)
40
+ color_enabled? ? colorize(text, color_code) : text
41
+ end
42
+
43
+ def colorize(text, color_code)
44
+ "\e[#{color_code_for(color_code)}m#{text}\e[0m"
45
+ end
46
+
47
+ def color_code_for(code)
48
+ COLORS.fetch(code) { COLORS.fetch(:white) }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,77 @@
1
+ module Recog
2
+ class MatchReporter
3
+ attr_reader :formatter
4
+ attr_reader :line_count, :match_count, :fail_count
5
+
6
+ def initialize(options, formatter)
7
+ @options = options
8
+ @formatter = formatter
9
+ reset_counts
10
+ end
11
+
12
+ def report
13
+ reset_counts
14
+ yield self
15
+ summarize
16
+ end
17
+
18
+ def stop?
19
+ return false unless @options.fail_fast
20
+ @fail_count >= @options.stop_after
21
+ end
22
+
23
+ def increment_line_count
24
+ @line_count += 1
25
+ end
26
+
27
+ def match(text)
28
+ @match_count += 1
29
+ formatter.success_message(text)
30
+ end
31
+
32
+ def failure(text)
33
+ @fail_count += 1
34
+ formatter.failure_message(text)
35
+ end
36
+
37
+ def print_summary
38
+ colorize_summary(summary_line)
39
+ end
40
+
41
+ private
42
+
43
+ def reset_counts
44
+ @line_count = @match_count = @fail_count = 0
45
+ end
46
+
47
+ def detail?
48
+ @options.detail
49
+ end
50
+
51
+ def summarize
52
+ if detail?
53
+ print_lines_processed
54
+ print_summary
55
+ end
56
+ end
57
+
58
+ def print_lines_processed
59
+ formatter.status_message("\nProcessed #{line_count} lines")
60
+ end
61
+
62
+ def summary_line
63
+ summary = "SUMMARY: "
64
+ summary << "#{match_count} matches"
65
+ summary << " and #{fail_count} failures"
66
+ summary
67
+ end
68
+
69
+ def colorize_summary(summary)
70
+ if @fail_count > 0
71
+ formatter.failure_message(summary)
72
+ else
73
+ formatter.success_message(summary)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,60 @@
1
+ module Recog
2
+ class Matcher
3
+ attr_reader :fingerprints, :reporter
4
+
5
+ def initialize(fingerprints, reporter)
6
+ @fingerprints = fingerprints
7
+ @reporter = reporter
8
+ end
9
+
10
+ def match_banners(banners_file)
11
+ reporter.report do
12
+
13
+ fd = $stdin
14
+ file_source = false
15
+
16
+ if banners_file and banners_file != "-"
17
+ fd = File.open(banners_file, "rb")
18
+ file_source = true
19
+ end
20
+
21
+ fd.each_line do |line|
22
+ reporter.increment_line_count
23
+
24
+ line = line.to_s.unpack("C*").pack("C*").strip.gsub(/\\[rn]/, '')
25
+ found = nil
26
+ fingerprints.each do |fp|
27
+ m = line.match(fp.regex)
28
+ if m
29
+ found = [fp, m]
30
+ break
31
+ end
32
+ end
33
+
34
+ if found
35
+ info = { }
36
+ fp, m = found
37
+ fp.params.each_pair do |k,v|
38
+ if v[0] == 0
39
+ info[k] = v[1]
40
+ else
41
+ info[k] = m[ v[0] ]
42
+ end
43
+ end
44
+ info['data'] = line
45
+ reporter.match "MATCH: #{info.inspect}"
46
+ else
47
+ reporter.failure "FAIL: #{line}"
48
+ end
49
+
50
+ if reporter.stop?
51
+ break
52
+ end
53
+ end
54
+
55
+ fd.close if file_source
56
+
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,14 @@
1
+
2
+ require 'recog/matcher'
3
+ require 'recog/formatter'
4
+ require 'recog/match_reporter'
5
+
6
+ module Recog
7
+ module MatcherFactory
8
+ def self.build(options)
9
+ formatter = Formatter.new(options, $stdout)
10
+ reporter = MatchReporter.new(options, formatter)
11
+ Matcher.new(options.fingerprints, reporter)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,263 @@
1
+ module Recog
2
+ class Nizer
3
+
4
+ # Default certainty ratings where none are specified in the fingerprint itself
5
+ DEFAULT_OS_CERTAINTY = 0.85 # Most frequent weights are 0.9, 1.0, and 0.5
6
+ DEFAULT_SERVICE_CERTAINTY = 0.85 # Most frequent weight is 0.85
7
+
8
+ # Non-weighted host attributes that can be extracted from fingerprint matches
9
+ HOST_ATTRIBUTES = %W{
10
+ host.domain
11
+ host.id
12
+ host.ip
13
+ host.mac
14
+ host.name
15
+ host.time
16
+ hw.device
17
+ hw.family
18
+ hw.product
19
+ hw.vendor
20
+ }
21
+
22
+ @@db_manager = nil
23
+
24
+ #
25
+ # Locate a database that corresponds with the match_key and attempt to
26
+ # find a matching fingerprinting, stopping a the first hit. Returns
27
+ # nil when no matching database or fingerprint is found.
28
+ #
29
+ def self.match(match_key, match_string)
30
+ match_string = match_string.to_s.unpack("C*").pack("C*")
31
+ @@db_manager ||= Recog::DBManager.new
32
+ @@db_manager.databases.each do |db|
33
+ next unless db.match_key == match_key
34
+ db.fingerprints.each do |fprint|
35
+ m = fprint.regex.match(match_string)
36
+ next unless m
37
+ result = { 'matched' => fprint.name }
38
+ fprint.params.each_pair do |k,v|
39
+ if v[0] == 0
40
+ result[k] = v[1]
41
+ else
42
+ result[k] = m[ v[0] ]
43
+ end
44
+ end
45
+ return result
46
+ end
47
+ end
48
+ nil
49
+ end
50
+
51
+ #
52
+ # Consider an array of match outputs, choose the best result, taking into
53
+ # account the granularity of OS vs Version vs SP vs Language. Only consider
54
+ # fields relevant to the host (OS, name, mac address, etc).
55
+ #
56
+ def self.best_os_match(matches)
57
+
58
+ # The result hash we return to the caller
59
+ result = {}
60
+
61
+ # Certain attributes should be evaluated separately
62
+ host_attrs = {}
63
+
64
+ # Bucket matches into matched OS product names
65
+ os_products = {}
66
+
67
+ matches.each do |m|
68
+ # Count how many times each host attribute value is asserted
69
+ (HOST_ATTRIBUTES & m.keys).each do |ha|
70
+ host_attrs[ha] ||= {}
71
+ host_attrs[ha][m[ha]] ||= 0
72
+ host_attrs[ha][m[ha]] += 1
73
+ end
74
+
75
+ next unless m.has_key?('os.product')
76
+
77
+ # Group matches by OS product and normalize certainty
78
+ cm = m.dup
79
+ cm['os.certainty'] = ( m['os.certainty'] || DEFAULT_OS_CERTAINTY ).to_f
80
+ os_products[ cm['os.product'] ] ||= []
81
+ os_products[ cm['os.product'] ] << cm
82
+ end
83
+
84
+ #
85
+ # Select the best host attribute value by highest frequency
86
+ #
87
+ host_attrs.keys.each do |hk|
88
+ ranked_attr = host_attrs[hk].keys.sort do |a,b|
89
+ host_attrs[hk][b] <=> host_attrs[hk][a]
90
+ end
91
+ result[hk] = ranked_attr.first
92
+ end
93
+
94
+ # Unable to guess the OS without OS matches
95
+ unless os_products.keys.length > 0
96
+ return result
97
+ end
98
+
99
+ #
100
+ # Select the best operating system name by combined certainty of all
101
+ # matches within an os.product group. Multiple weak matches can
102
+ # outweigh a single strong match by design.
103
+ #
104
+ ranked_os = os_products.keys.sort do |a,b|
105
+ os_products[b].map{ |r| r['os.certainty'] }.inject(:+) <=>
106
+ os_products[a].map{ |r| r['os.certainty'] }.inject(:+)
107
+ end
108
+
109
+ # Within the best match group, try to fill in missing attributes
110
+ os_name = ranked_os.first
111
+
112
+ # Find the best match within the winning group
113
+ ranked_os_matches = os_products[os_name].sort do |a,b|
114
+ b['os.certainty'] <=> a['os.certainty']
115
+ end
116
+
117
+ # Fill in missing result values in descending order of best match
118
+ ranked_os_matches.each do |rm|
119
+ rm.each_pair do |k,v|
120
+ result[k] ||= v
121
+ end
122
+ end
123
+
124
+ result
125
+ end
126
+
127
+ #
128
+ # Consider an array of match outputs, choose the best result, taking into
129
+ # account the granularity of service. Only consider fields relevant to the
130
+ # service.
131
+ #
132
+ def self.best_service_match(matches)
133
+
134
+ # The result hash we return to the caller
135
+ result = {}
136
+
137
+ # Bucket matches into matched service product names
138
+ service_products = {}
139
+
140
+ matches.select{ |m| m.has_key?('service.product') }.each do |m|
141
+ # Group matches by product and normalize certainty
142
+ cm = m.dup
143
+ cm['service.certainty'] = ( m['service.certainty'] || DEFAULT_SERVICE_CERTAINTY ).to_f
144
+ service_products[ cm['service.product'] ] ||= []
145
+ service_products[ cm['service.product'] ] << cm
146
+ end
147
+
148
+ # Unable to guess the service without service matches
149
+ unless service_products.keys.length > 0
150
+ return result
151
+ end
152
+
153
+ #
154
+ # Select the best service name by combined certainty of all matches
155
+ # within an service.product group. Multiple weak matches can
156
+ # outweigh a single strong match by design.
157
+ #
158
+ ranked_service = service_products.keys.sort do |a,b|
159
+ service_products[b].map{ |r| r['service.certainty'] }.inject(:+) <=>
160
+ service_products[a].map{ |r| r['service.certainty'] }.inject(:+)
161
+ end
162
+
163
+ # Within the best match group, try to fill in missing attributes
164
+ service_name = ranked_service.first
165
+
166
+ # Find the best match within the winning group
167
+ ranked_service_matches = service_products[service_name].sort do |a,b|
168
+ b['service.certainty'] <=> a['service.certainty']
169
+ end
170
+
171
+ # Fill in missing service values in descending order of best match
172
+ ranked_service_matches.each do |rm|
173
+ rm.keys.select{ |k| k.index('service.') == 0 }.each do |k|
174
+ result[k] ||= rm[k]
175
+ end
176
+ end
177
+
178
+ result
179
+ end
180
+
181
+ end
182
+ end
183
+
184
+ =begin
185
+
186
+ Current key names:
187
+
188
+ apache.info
189
+ apache.variant
190
+ apache.variant.version
191
+ cookie
192
+ host.domain
193
+ host.id
194
+ host.ip
195
+ host.mac
196
+ host.name
197
+ host.time
198
+ hw.device
199
+ hw.family
200
+ hw.product
201
+ hw.vendor
202
+ imail.eval
203
+ jetty.info
204
+ junction.cookie
205
+ junction.name
206
+ linux.kernel.version
207
+ loadbalancer.poolname
208
+ mdaemon.unregistered
209
+ mercur.os.info
210
+ metainfo.version
211
+ metainfo.version.version
212
+ ms.nttp.version
213
+ notes.build.version
214
+ notes.intl
215
+ ntmail.id
216
+ openssh.comment
217
+ openssh.cvepatch
218
+ os.arch
219
+ os.build
220
+ os.certainty
221
+ os.device
222
+ os.edition
223
+ os.family
224
+ os.product
225
+ os.vendor
226
+ os.version
227
+ os.version.version
228
+ os.version.version.version
229
+ postfix.os.info
230
+ postoffice.build
231
+ postoffice.id
232
+ proftpd.server.name
233
+ pureftpd.config
234
+ qpopper.version
235
+ sendmail.config.version
236
+ sendmail.hpux.phne.version
237
+ sendmail.vendor.version
238
+ service.certainty
239
+ service.component.family
240
+ service.component.product
241
+ service.component.vendor
242
+ service.component.version
243
+ service.family
244
+ service.product
245
+ service.vendor
246
+ service.version
247
+ service.version.version
248
+ service.version.version.version
249
+ service.version.version.version.version
250
+ service.version.version.version.version.version
251
+ siemens.model
252
+ snmp.fpmib.oid.1
253
+ snmp.fpmib.oid.2
254
+ system.time
255
+ system.time.format
256
+ system.time.micros
257
+ system.time.millis
258
+ thttpd.mx-patch
259
+ timeout
260
+ tomcat.info
261
+ zmailer.ident
262
+
263
+ =end