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/openvas_document.rb
Views: 11778
1
# -*- coding: binary -*-
2
require "rex/parser/nokogiri_doc_mixin"
3
4
module Rex
5
module Parser
6
7
# If Nokogiri is available, define OpenVas document class.
8
load_nokogiri && class OpenVASDocument < Nokogiri::XML::SAX::Document
9
10
include NokogiriDocMixin
11
12
# ourselves with the @state variable, turning things on when we
13
# get here (and turning things off when we exit in end_element()).
14
def start_element(name=nil,attrs=[])
15
attrs = normalize_attrs(attrs)
16
block = @block
17
@state[:current_tag][name] = true
18
19
unless @text.nil?
20
@state[:text_backup] = @text
21
@text = nil
22
end
23
24
case name
25
when "host"
26
@state[:has_text] = true
27
when 'ref'
28
ref_type = ''
29
ref_id = ''
30
if defined?(attrs) && attrs.kind_of?(Array)
31
attrs.each do |attr|
32
next if !defined?(attr) || !attr.kind_of?(Array) || attr.length != 2
33
if defined?(attr[0]) && defined?(attr[1]) && attr[0] == 'type'
34
ref_type = attr[1]
35
end
36
if defined?(attr[0]) && defined?(attr[1]) && attr[0] == 'id'
37
ref_id = attr[1]
38
end
39
end
40
end
41
if in_tag('result') && in_tag('nvt') && in_tag('refs') &&
42
!ref_type.empty? && !ref_type.empty?
43
case ref_type.upcase
44
when 'CVE'
45
@state[:ref_cve] = [] if @state[:ref_cve].nil?
46
@state[:ref_cve].append(ref_id.strip)
47
when 'URL'
48
@state[:ref_url] = [] if @state[:ref_url].nil?
49
@state[:ref_url].append(ref_id.strip)
50
when 'DFN-CERT'
51
if defined?(@args[:options][:openvas_dfn]) && @args[:options][:openvas_dfn]
52
@state[:ref_dfn] = [] if @state[:ref_dfn].nil?
53
@state[:ref_dfn].append(ref_id.strip)
54
end
55
when 'CERT-BUND'
56
if defined?(@args[:options][:openvas_cert]) && @args[:options][:openvas_cert]
57
@state[:ref_cb] = [] if @state[:ref_cb].nil?
58
@state[:ref_cb].append(ref_id.strip)
59
end
60
end
61
end
62
end
63
end
64
65
# When we exit a tag, this is triggered.
66
def end_element(name=nil)
67
block = @block
68
case name
69
when 'name'
70
if in_tag('result')
71
@state[:has_text] = true
72
@state[:vuln_name] = @text.strip if @text
73
end
74
when 'description'
75
if in_tag('result')
76
@state[:has_text] = true
77
@state[:vuln_desc] = @text.strip if @text
78
end
79
when 'bid'
80
if in_tag('result') && in_tag('nvt')
81
@state[:has_text] = true
82
@state[:bid] = @text.strip if @text
83
end
84
when 'cve'
85
if in_tag('result') && in_tag('nvt')
86
@state[:has_text] = true
87
@state[:cves] = @text.strip if @text
88
end
89
when 'risk_factor'
90
if in_tag('result') && in_tag('nvt')
91
#we do this to clean out the buffer so to speak
92
#if we don't set text to nil now, the text will show up later
93
@state[:has_text] = true
94
end
95
when 'cvss_base'
96
if in_tag('result') && in_tag('nvt')
97
@state[:has_text] = true
98
end
99
when 'subnet'
100
@state[:has_text] = true
101
when 'result'
102
record_vuln
103
when 'threat'
104
@state[:has_text] = true if in_tag('ports') && in_tag('port')
105
when 'host'
106
if in_tag('result')
107
@state[:has_text] = true
108
@state[:host] = @text.strip if @text
109
elsif in_tag('ports') && in_tag('port')
110
@state[:has_text] = true
111
@state[:host] = @text.strip if @text
112
end
113
when 'port'
114
if in_tag('result')
115
@state[:has_text] = true
116
if @text
117
if /^(?<p_num>\d{1,5})\/(?<p_proto>.+)\s\((?<p_name>.+)\)/ =~ @text
118
@state[:name] = p_name.gsub(/iana: /i, '')
119
@state[:port] = p_num
120
@state[:proto] = p_proto
121
elsif @text.index('(')
122
@state[:proto] = @text.split('(')[1].split('/')[1].gsub(/\)/, '')
123
@state[:port] = @text.split('(')[1].split('/')[0].gsub(/\)/, '')
124
elsif @text.index('/')
125
@state[:proto] = @text.split('/')[1].strip
126
@state[:port] = @text.split('/')[0].strip
127
else
128
@state[:proto] = nil
129
@state[:port] = nil
130
end
131
132
if @state[:port] && @state[:port] == 'general'
133
@state[:proto] = nil
134
@state[:port] = nil
135
end
136
end
137
elsif in_tag('ports')
138
if @text
139
if /^(?<p_num>\d{1,5})\/(?<p_proto>.+)\s\((?<p_name>.+)\)/ =~ @text
140
@state[:name] = p_name.gsub(/iana: /i, '')
141
@state[:port] = p_num
142
@state[:proto] = p_proto
143
record_service if p_num
144
elsif @text.index('(')
145
@state[:name] = @text.split(' ')[0]
146
@state[:port] = @text.split('(')[1].split('/')[0]
147
@state[:proto] = @text.split('(')[1].split('/')[1].split(')')[0]
148
record_service unless @state[:name].nil?
149
elsif @text.index('/')
150
@state[:port] = @text.split('/')[0].strip
151
@state[:proto] = @text.split('/')[1].strip
152
record_service unless @state[:port] == 'general'
153
end
154
end
155
end
156
when 'name'
157
return if not in_tag('result')
158
@state[:has_text] = true
159
end
160
161
if @state[:text_backup]
162
@text = @state[:text_backup]
163
@state[:text_backup] = nil
164
else
165
@text = nil
166
end
167
168
@state[:current_tag].delete name
169
end
170
171
def record_vuln
172
if (@state[:cves] and @state[:cves] == "NOCVE") and (@state[:bid] and @state[:bid] == "NOBID")
173
return
174
end
175
176
references = []
177
if @state[:cves] and @state[:cves] != "NOCVE" and !@state[:cves].empty?
178
@state[:cves].split(',').each do |cve|
179
references.append({ :source => "CVE", :value => cve})
180
end
181
end
182
if @state[:bid] and @state[:bid] != "NOBID" and !@state[:bid].empty?
183
@state[:bid].split(',').each do |bid|
184
references.append({ :source => "BID", :value => bid})
185
end
186
end
187
if @state[:ref_cve] && @state[:ref_cve].kind_of?(Array)
188
@state[:ref_cve].each do |cve|
189
references.append({ :source => "CVE", :value => cve.dup}) if !cve.empty?
190
end
191
@state[:ref_cve].clear
192
end
193
if @state[:ref_url] && @state[:ref_url].kind_of?(Array)
194
@state[:ref_url].each do |url|
195
references.append({ :source => "URL", :value => url.dup}) if !url.empty?
196
end
197
@state[:ref_url].clear
198
end
199
if @state[:ref_cb] && @state[:ref_cb].kind_of?(Array)
200
@state[:ref_cb].each do |cb|
201
references.append({ :source => "CB", :value => cb.dup}) if !cb.empty?
202
end
203
@state[:ref_cb].clear
204
end
205
if @state[:ref_dfn] && @state[:ref_dfn].kind_of?(Array)
206
@state[:ref_dfn].each do |dfn|
207
references.append({ :source => "DFN-CERT", :value => dfn.dup}) if !dfn.empty?
208
end
209
@state[:ref_dfn].clear
210
end
211
212
vuln_info = {}
213
vuln_info[:host] = @state[:host]
214
vuln_info[:refs] = normalize_references(references)
215
vuln_info[:name] = @state[:vuln_name]
216
vuln_info[:info] = @state[:vuln_desc]
217
vuln_info[:port] = @state[:port]
218
vuln_info[:proto] = @state[:proto]
219
vuln_info[:workspace] = @args[:workspace]
220
db_report(:vuln, vuln_info)
221
end
222
223
def record_service
224
service_info = {}
225
service_info[:host] = @state[:host]
226
service_info[:name] = @state[:name]
227
service_info[:port] = @state[:port]
228
service_info[:proto] = @state[:proto]
229
service_info[:workspace] = @args[:workspace]
230
231
db_report(:service, service_info)
232
233
host_info = {}
234
host_info[:host] = @state[:host]
235
host_info[:workspace] = @args[:workspace]
236
237
db_report(:host, host_info)
238
end
239
end
240
end
241
end
242
243
244