CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/parser/nexpose_simple_document.rb
Views: 11780
1
# -*- coding: binary -*-
2
require "rex/parser/nokogiri_doc_mixin"
3
4
module Rex
5
module Parser
6
7
# If Nokogiri is available, define Nexpose document class.
8
load_nokogiri && class NexposeSimpleDocument < Nokogiri::XML::SAX::Document
9
10
include NokogiriDocMixin
11
12
attr_reader :text
13
14
# Triggered every time a new element is encountered. We keep state
15
# ourselves with the @state variable, turning things on when we
16
# get here (and turning things off when we exit in end_element()).
17
def start_element(name=nil,attrs=[])
18
attrs = normalize_attrs(attrs)
19
block = @block
20
@state[:current_tag][name] = true
21
case name
22
when "device"
23
record_device(attrs)
24
when "service"
25
record_service(attrs)
26
when "fingerprint"
27
record_service_fingerprint(attrs)
28
record_host_fingerprint(attrs)
29
when "description"
30
@state[:has_text] = true
31
record_host_fingerprint_data(name,attrs)
32
when "vendor", "family", "product", "version", "architecture"
33
@state[:has_text] = true
34
record_host_fingerprint_data(name,attrs)
35
when "vulnerability"
36
record_service_vuln(attrs)
37
record_host_vuln(attrs)
38
when "id"
39
@state[:has_text] = true
40
record_service_vuln_id(attrs)
41
record_host_vuln_id(attrs)
42
end
43
end
44
45
# When we exit a tag, this is triggered.
46
def end_element(name=nil)
47
block = @block
48
case name
49
when "device" # Wrap it up
50
collect_device_data
51
host_object = report_host &block
52
report_services(host_object)
53
report_host_fingerprint(host_object)
54
report_vulns(host_object)
55
# Reset the state once we close a host
56
@state.delete_if {|k| k != :current_tag}
57
@report_data = {:workspace => @args[:workspace]}
58
when "description"
59
@state[:has_text] = false
60
collect_service_fingerprint_description
61
collect_host_fingerprint_data(name)
62
@text = nil
63
when "vendor", "family", "product", "version", "architecture"
64
@state[:has_text] = false
65
collect_host_fingerprint_data(name)
66
@text = nil
67
when "service"
68
collect_service_data
69
when "id"
70
@state[:has_text] = false
71
collect_service_vuln_id
72
collect_host_vuln_id
73
@text = nil
74
when "vulnerability"
75
collect_service_vuln
76
collect_host_vuln
77
@state[:references] = nil
78
end
79
@state[:current_tag].delete name
80
end
81
82
def report_vulns(host_object)
83
vuln_count = 0
84
block = @block
85
return unless host_object.kind_of? ::Mdm::Host
86
return unless @report_data[:vulns]
87
@report_data[:vulns].each do |vuln|
88
if vuln[:refs]
89
vuln[:refs] << vuln[:name]
90
else
91
vuln[:refs] = [vuln[:name]]
92
end
93
vuln[:refs].uniq!
94
data = {
95
:workspace => host_object.workspace,
96
:host => host_object,
97
:name => vuln[:name],
98
:info => vuln[:info],
99
:refs => vuln[:refs]
100
}
101
if vuln[:port] && vuln[:proto]
102
data[:port] = vuln[:port]
103
data[:proto] = vuln[:proto]
104
end
105
db_report(:vuln,data)
106
end
107
108
end
109
110
def collect_host_vuln_id
111
return unless in_tag("device")
112
return unless in_tag("vulnerability")
113
return if in_tag("service")
114
return unless @state[:host_vuln_id]
115
@state[:references] ||= []
116
ref = normalize_ref( @state[:host_vuln_id]["type"], @text )
117
@state[:references] << ref if ref
118
@state[:host_vuln_id] = nil
119
@text = nil
120
end
121
122
def collect_service_vuln_id
123
return unless in_tag("device")
124
return unless in_tag("vulnerability")
125
return unless in_tag("service")
126
return unless @state[:service_vuln_id]
127
@state[:references] ||= []
128
ref = normalize_ref( @state[:service_vuln_id]["type"], @text )
129
@state[:references] << ref if ref
130
@state[:service_vuln_id] = nil
131
@text = nil
132
end
133
134
def collect_service_vuln
135
return unless in_tag("device")
136
return unless in_tag("vulnerability")
137
return unless in_tag("service")
138
@report_data[:vulns] ||= []
139
return unless actually_vulnerable(@state[:service_vuln])
140
return if @state[:service]["port"].to_i == 0
141
vid = @state[:service_vuln]["id"].to_s.downcase
142
vuln = {
143
:name => "NEXPOSE-#{vid}",
144
:info => vid,
145
:refs => @state[:references],
146
:port => @state[:service]["port"].to_i,
147
:proto => @state[:service]["protocol"]
148
}
149
@report_data[:vulns] << vuln
150
end
151
152
def collect_host_vuln
153
return unless in_tag("vulnerability")
154
return unless in_tag("device")
155
return if in_tag("service")
156
@report_data[:vulns] ||= []
157
return unless actually_vulnerable(@state[:host_vuln])
158
vid = @state[:host_vuln]["id"].to_s.downcase
159
vuln = {
160
:name => "NEXPOSE-#{vid}",
161
:info => vid,
162
:refs => @state[:references]
163
}
164
@report_data[:vulns] << vuln
165
end
166
167
def record_host_vuln_id(attrs)
168
return unless in_tag("device")
169
return if in_tag("service")
170
@state[:host_vuln_id] = attr_hash(attrs)
171
end
172
173
def record_host_vuln(attrs)
174
return unless in_tag("device")
175
return if in_tag("service")
176
@state[:host_vuln] = attr_hash(attrs)
177
end
178
179
def record_service_vuln_id(attrs)
180
return unless in_tag("device")
181
return unless in_tag("service")
182
@state[:service_vuln_id] = attr_hash(attrs)
183
end
184
185
def record_service_vuln(attrs)
186
return unless in_tag("device")
187
return unless in_tag("service")
188
@state[:service_vuln] = attr_hash(attrs)
189
end
190
191
def actually_vulnerable(vuln)
192
vuln_result = vuln["resultCode"]
193
vuln_result =~ /^V[VE]$/
194
end
195
196
def record_device(attrs)
197
attrs.each do |k,v|
198
next unless k == "address"
199
@state[:address] = v
200
end
201
end
202
203
def record_host_fingerprint(attrs)
204
return unless in_tag("device")
205
return if in_tag("service")
206
@state[:host_fingerprint] = attr_hash(attrs)
207
end
208
209
def collect_device_data
210
return unless in_tag("device")
211
@report_data[:host] = @state[:address]
212
@report_data[:state] = Msf::HostState::Alive # always
213
end
214
215
def record_host_fingerprint_data(name, attrs)
216
return unless in_tag("device")
217
return if in_tag("service")
218
return unless in_tag("fingerprint")
219
@state[:host_fingerprint] ||= {}
220
@state[:host_fingerprint].merge! attr_hash(attrs)
221
end
222
223
def collect_host_fingerprint_data(name)
224
return unless in_tag("device")
225
return if in_tag("service")
226
return unless in_tag("fingerprint")
227
return unless @text
228
@report_data[:host_fingerprint] ||= {}
229
@report_data[:host_fingerprint].merge!(@state[:host_fingerprint])
230
@report_data[:host_fingerprint][name] = @text.to_s.strip
231
@text = nil
232
end
233
234
def report_host(&block)
235
if host_is_okay
236
db.emit(:address,@report_data[:host],&block) if block
237
host_object = db_report(:host, @report_data.merge(
238
:workspace => @args[:workspace] ) )
239
if host_object
240
db.report_import_note(host_object.workspace, host_object)
241
end
242
host_object
243
end
244
end
245
246
def report_host_fingerprint(host_object)
247
return unless host_object.kind_of? ::Mdm::Host
248
return unless @report_data[:host_fingerprint].kind_of? Hash
249
@report_data[:host_fingerprint].reject! {|k,v| v.nil? || v.empty?}
250
return if @report_data[:host_fingerprint].empty?
251
note = {
252
:workspace => host_object.workspace,
253
:host => host_object,
254
:type => "host.os.nexpose_fingerprint"
255
}
256
data = {
257
:desc => @report_data[:host_fingerprint]["description"],
258
:vendor => @report_data[:host_fingerprint]["vendor"],
259
:family => @report_data[:host_fingerprint]["family"],
260
:product => @report_data[:host_fingerprint]["product"],
261
:version => @report_data[:host_fingerprint]["version"],
262
:arch => @report_data[:host_fingerprint]["architecture"]
263
}
264
db_report(:note, note.merge(:data => data))
265
end
266
267
def record_service(attrs)
268
return unless in_tag("device")
269
@state[:service] = attr_hash(attrs)
270
end
271
272
def record_service_fingerprint(attrs)
273
return unless in_tag("device")
274
return unless in_tag("service")
275
@state[:service][:fingerprint] = attr_hash(attrs)
276
end
277
278
def collect_service_data
279
return unless in_tag("device")
280
port_hash = {}
281
@report_data[:ports] ||= []
282
@state[:service].each do |k,v|
283
case k
284
when "protocol"
285
port_hash[:proto] = v
286
when "port"
287
port_hash[:port] = v
288
when "name"
289
sname = v.to_s.downcase.split("(")[0].strip
290
if sname == "<unknown>"
291
port_hash[:name] = nil
292
else
293
port_hash[:name] = db.nmap_msf_service_map(sname)
294
end
295
end
296
end
297
if @state[:service_fingerprint]
298
port_hash[:info] = "#{@state[:service_fingerprint]}"
299
end
300
@report_data[:ports] << port_hash.clone
301
@state.delete :service_fingerprint
302
@state.delete :service
303
@report_data[:ports]
304
end
305
306
def collect_service_fingerprint_description
307
return unless in_tag("device")
308
return unless in_tag("service")
309
return unless in_tag("fingerprint")
310
return unless @text
311
@state[:service_fingerprint] = @text.to_s.strip
312
@text = nil
313
end
314
315
def report_services(host_object)
316
return unless host_object.kind_of? ::Mdm::Host
317
return unless @report_data[:ports]
318
return if @report_data[:ports].empty?
319
reported = []
320
@report_data[:ports].each do |svc|
321
reported << db_report(:service, svc.merge(:host => host_object))
322
end
323
reported
324
end
325
326
end
327
328
end
329
end
330
331
332