dradis-acunetix 3.18.0
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 +7 -0
- data/.github/issue_template.md +16 -0
- data/.github/pull_request_template.md +36 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +63 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +23 -0
- data/LICENSE +339 -0
- data/README.md +27 -0
- data/Rakefile +2 -0
- data/dradis-acunetix.gemspec +35 -0
- data/lib/acunetix/report_item.rb +168 -0
- data/lib/acunetix/scan.rb +93 -0
- data/lib/dradis-acunetix.rb +9 -0
- data/lib/dradis/plugins/acunetix.rb +12 -0
- data/lib/dradis/plugins/acunetix/engine.rb +9 -0
- data/lib/dradis/plugins/acunetix/field_processor.rb +25 -0
- data/lib/dradis/plugins/acunetix/gem_version.rb +19 -0
- data/lib/dradis/plugins/acunetix/importer.rb +78 -0
- data/lib/dradis/plugins/acunetix/version.rb +13 -0
- data/lib/tasks/thorfile.rb +20 -0
- data/spec/dradis-acunetix_spec.rb +109 -0
- data/spec/fixtures/files/code-pre.acunetix.xml +1732 -0
- data/spec/fixtures/files/commas-format.acunetix.xml +105 -0
- data/spec/fixtures/files/simple.acunetix.xml +1691 -0
- data/spec/fixtures/files/testphp.vulnweb.com.export.acunetix.xml +23976 -0
- data/spec/models/acunetix/scan_spec.rb +74 -0
- data/spec/spec_helper.rb +10 -0
- data/templates/evidence.fields +7 -0
- data/templates/evidence.sample +12 -0
- data/templates/evidence.template +16 -0
- data/templates/report_item.fields +18 -0
- data/templates/report_item.sample +151 -0
- data/templates/report_item.template +59 -0
- data/templates/scan.fields +12 -0
- data/templates/scan.sample +15 -0
- data/templates/scan.template +16 -0
- metadata +172 -0
data/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Acunetix add-on for Dradis
|
|
2
|
+
|
|
3
|
+
[](http://travis-ci.org/dradis/dradis-acunetix) [](https://codeclimate.com/github/dradis/dradis-acunetix.png)
|
|
4
|
+
|
|
5
|
+
The Acunetix add-on enables users to upload Acunexit XML files to create a structure of nodes/notes that contain the same information about the hosts/ports/services as the original file.
|
|
6
|
+
|
|
7
|
+
The add-on requires [Dradis CE](https://dradisframework.org/) > 3.0, or [Dradis Pro](https://dradisframework.com/pro/).
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## More information
|
|
11
|
+
|
|
12
|
+
See the Dradis Framework's [README.md](https://github.com/dradis/dradisframework/blob/master/README.md)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Contributing
|
|
16
|
+
|
|
17
|
+
See the Dradis Framework's [CONTRIBUTING.md](https://github.com/dradis/dradisframework/blob/master/CONTRIBUTING.md)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## License
|
|
21
|
+
|
|
22
|
+
Dradis Framework and all its components are released under [GNU General Public License version 2.0](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Feature requests and bugs
|
|
26
|
+
|
|
27
|
+
Please use the [Dradis Framework issue tracker](https://github.com/dradis/dradis-ce/issues) for add-on improvements and bug reports.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
|
2
|
+
require 'dradis/plugins/acunetix/version'
|
|
3
|
+
version = Dradis::Plugins::Acunetix::VERSION::STRING
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Describe your gem and declare its dependencies:
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.platform = Gem::Platform::RUBY
|
|
9
|
+
spec.name = 'dradis-acunetix'
|
|
10
|
+
spec.version = version
|
|
11
|
+
spec.summary = 'Acunetix add-on for the Dradis Framework.'
|
|
12
|
+
spec.description = 'This add-on allows you to upload and parse output produced from Acunetix Web Vulnerability Scanner into Dradis.'
|
|
13
|
+
|
|
14
|
+
spec.license = 'GPL-2'
|
|
15
|
+
|
|
16
|
+
spec.authors = ['Daniel Martin']
|
|
17
|
+
spec.email = ['etd@nomejortu.com']
|
|
18
|
+
spec.homepage = 'http://dradisframework.org'
|
|
19
|
+
|
|
20
|
+
spec.files = `git ls-files`.split($\)
|
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
23
|
+
|
|
24
|
+
# By not including Rails as a dependency, we can use the gem with different
|
|
25
|
+
# versions of Rails (a sure recipe for disaster, I'm sure), which is needed
|
|
26
|
+
# until we bump Dradis Pro to 4.1.
|
|
27
|
+
# s.add_dependency 'rails', '~> 4.1.1'
|
|
28
|
+
spec.add_dependency 'dradis-plugins', '~> 3.6'
|
|
29
|
+
spec.add_dependency 'nokogiri', '~> 1.3'
|
|
30
|
+
|
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
|
32
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
33
|
+
spec.add_development_dependency 'rspec-rails'
|
|
34
|
+
spec.add_development_dependency 'combustion', '~> 0.5.2'
|
|
35
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
module Acunetix
|
|
2
|
+
# This class represents each of the /ScanGroup/Scan/ReportItems/ReportItem
|
|
3
|
+
# elements in the Acunetix XML document.
|
|
4
|
+
#
|
|
5
|
+
# It provides a convenient way to access the information scattered all over
|
|
6
|
+
# the XML in attributes and nested tags.
|
|
7
|
+
#
|
|
8
|
+
# Instead of providing separate methods for each supported property we rely
|
|
9
|
+
# on Ruby's #method_missing to do most of the work.
|
|
10
|
+
class ReportItem
|
|
11
|
+
attr_accessor :xml
|
|
12
|
+
|
|
13
|
+
# Accepts an XML node from Nokogiri::XML.
|
|
14
|
+
def initialize(xml_node)
|
|
15
|
+
@xml = xml_node
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# List of supported tags. They can be attributes, simple descendans or
|
|
19
|
+
# collections.
|
|
20
|
+
def supported_tags
|
|
21
|
+
[
|
|
22
|
+
# attributes
|
|
23
|
+
# :color
|
|
24
|
+
|
|
25
|
+
# simple tags
|
|
26
|
+
:name, :module_name, :severity, :type, :impact, :description,
|
|
27
|
+
:detailed_information, :recommendation, :cwe,
|
|
28
|
+
|
|
29
|
+
# tags that correspond to Evidence
|
|
30
|
+
:details, :affects, :parameter, :aop_source_file, :aop_source_line,
|
|
31
|
+
:aop_additional, :is_false_positive,
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# nested tags
|
|
35
|
+
:request, :response,
|
|
36
|
+
:cvss_descriptor, :cvss_score,
|
|
37
|
+
:cvss3_descriptor, :cvss3_score, :cvss3_tempscore, :cvss3_envscore,
|
|
38
|
+
|
|
39
|
+
# multiple tags
|
|
40
|
+
:cve_list, :references
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# This allows external callers (and specs) to check for implemented
|
|
45
|
+
# properties
|
|
46
|
+
def respond_to?(method, include_private=false)
|
|
47
|
+
return true if supported_tags.include?(method.to_sym)
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# This method is invoked by Ruby when a method that is not defined in this
|
|
52
|
+
# instance is called.
|
|
53
|
+
#
|
|
54
|
+
# In our case we inspect the @method@ parameter and try to find the
|
|
55
|
+
# attribute, simple descendent or collection that it maps to in the XML
|
|
56
|
+
# tree.
|
|
57
|
+
def method_missing(method, *args)
|
|
58
|
+
|
|
59
|
+
# We could remove this check and return nil for any non-recognized tag.
|
|
60
|
+
# The problem would be that it would make tricky to debug problems with
|
|
61
|
+
# typos. For instance: <>.potr would return nil instead of raising an
|
|
62
|
+
# exception
|
|
63
|
+
unless supported_tags.include?(method)
|
|
64
|
+
super
|
|
65
|
+
return
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Any fields where a simple .camelcase() won't work we need to translate,
|
|
69
|
+
# this includes acronyms (e.g. :cwe would become 'Cwe') and simple nested
|
|
70
|
+
# tags.
|
|
71
|
+
translations_table = {
|
|
72
|
+
cwe: 'CWE',
|
|
73
|
+
aop_source_file: 'AOPSourceFile',
|
|
74
|
+
aop_source_line: 'AOPSourceLine',
|
|
75
|
+
aop_additional: 'AOPAdditional',
|
|
76
|
+
request: 'TechnicalDetails/Request',
|
|
77
|
+
response: 'TechnicalDetails/Response',
|
|
78
|
+
cvss_descriptor: 'CVSS/Descriptor',
|
|
79
|
+
cvss_score: 'CVSS/Score',
|
|
80
|
+
cvss3_descriptor: 'CVSS3/Descriptor',
|
|
81
|
+
cvss3_score: 'CVSS3/Score',
|
|
82
|
+
cvss3_tempscore: 'CVSS3/TempScore',
|
|
83
|
+
cvss3_envscore: 'CVSS3/EnvScore'
|
|
84
|
+
}
|
|
85
|
+
method_name = translations_table.fetch(method, method.to_s.camelcase)
|
|
86
|
+
# first we try the attributes:
|
|
87
|
+
# return @xml.attributes[method_name].value if @xml.attributes.key?(method_name)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# There is a ./References tag, but we want to short-circuit that one to
|
|
91
|
+
# do custom processing.
|
|
92
|
+
return references_list() if method == :references
|
|
93
|
+
|
|
94
|
+
# then we try the children tags
|
|
95
|
+
tag = xml.at_xpath("./#{method_name}")
|
|
96
|
+
if tag && !tag.text.blank?
|
|
97
|
+
if tags_with_html_content.include?(method)
|
|
98
|
+
return cleanup_html(tag.text)
|
|
99
|
+
elsif tags_with_commas.include?(method)
|
|
100
|
+
return cleanup_decimals(tag.text)
|
|
101
|
+
else
|
|
102
|
+
return tag.text
|
|
103
|
+
end
|
|
104
|
+
else
|
|
105
|
+
'n/a'
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
return 'unimplemented' if method == :cve_list
|
|
109
|
+
|
|
110
|
+
# nothing found
|
|
111
|
+
return nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def cleanup_html(source)
|
|
117
|
+
result = source.dup
|
|
118
|
+
result.gsub!(/"/, '"')
|
|
119
|
+
result.gsub!(/&/, '&')
|
|
120
|
+
result.gsub!(/</, '<')
|
|
121
|
+
result.gsub!(/>/, '>')
|
|
122
|
+
|
|
123
|
+
result.gsub!(/<b>(.*?)<\/b>/) { "*#{$1.strip}*" }
|
|
124
|
+
result.gsub!(/<br\/>/, "\n")
|
|
125
|
+
result.gsub!(/<font.*?>(.*?)<\/font>/m, '\1')
|
|
126
|
+
result.gsub!(/<h2>(.*?)<\/h2>/) { "*#{$1.strip}*" }
|
|
127
|
+
result.gsub!(/<i>(.*?)<\/i>/, '\1')
|
|
128
|
+
result.gsub!(/<p>(.*?)<\/p>/, '\1')
|
|
129
|
+
result.gsub!(/<code><pre.*?>(.*?)<\/pre><\/code>/m){|m| "\n\nbc.. #{$1.strip}\n\np. \n" }
|
|
130
|
+
result.gsub!(/<pre.*?>(.*?)<\/pre>/m){|m| "\n\nbc.. #{$1.strip}\n\np. \n" }
|
|
131
|
+
result.gsub!(/<ul>(.*?)<\/ul>/m){"#{$1.strip}\n"}
|
|
132
|
+
|
|
133
|
+
result.gsub!(/<li>(.*?)<\/li>/){"\n* #{$1.strip}"}
|
|
134
|
+
|
|
135
|
+
result.gsub!(/<strong>(.*?)<\/strong>/) { "*#{$1.strip}*" }
|
|
136
|
+
result.gsub!(/<span.*?>(.*?)<\/span>/m){"#{$1.strip}\n"}
|
|
137
|
+
|
|
138
|
+
result
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def cleanup_decimals(source)
|
|
142
|
+
result = source.dup
|
|
143
|
+
result.gsub!(/([0-9])\,([0-9])/, '\1.\2')
|
|
144
|
+
result
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def references_list
|
|
148
|
+
references = ''
|
|
149
|
+
xml.xpath('./References/Reference').each do |xml_reference|
|
|
150
|
+
references << xml_reference.at_xpath('./Database').text()
|
|
151
|
+
references << "\n"
|
|
152
|
+
references << xml_reference.at_xpath('./URL').text()
|
|
153
|
+
references << "\n\n"
|
|
154
|
+
end
|
|
155
|
+
references
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Some of the values have embedded HTML conent that we need to strip
|
|
159
|
+
def tags_with_html_content
|
|
160
|
+
[:details, :description, :detailed_information, :impact, :recommendation]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def tags_with_commas
|
|
164
|
+
[:cvss3_score, :cvss3_tempscore, :cvss3_envscore]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Acunetix
|
|
2
|
+
# This class represents each of the /ScanGroup/Scan elements in the Acunetix
|
|
3
|
+
# XML document.
|
|
4
|
+
#
|
|
5
|
+
# It provides a convenient way to access the information scattered all over
|
|
6
|
+
# the XML in attributes and nested tags.
|
|
7
|
+
#
|
|
8
|
+
# Instead of providing separate methods for each supported property we rely
|
|
9
|
+
# on Ruby's #method_missing to do most of the work.
|
|
10
|
+
class Scan
|
|
11
|
+
attr_accessor :xml
|
|
12
|
+
# Accepts an XML node from Nokogiri::XML.
|
|
13
|
+
def initialize(xml_node)
|
|
14
|
+
@xml = xml_node
|
|
15
|
+
unless @xml.name == "Scan"
|
|
16
|
+
raise "Invalid XML; root node must be called 'Scan'"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# List of supported tags. They are all descendents of the ./Scan node.
|
|
21
|
+
SUPPORTED_TAGS = [
|
|
22
|
+
# attributes
|
|
23
|
+
|
|
24
|
+
# simple tags
|
|
25
|
+
:name, :short_name, :start_url, :start_time, :finish_time, :scan_time,
|
|
26
|
+
:aborted, :responsive, :banner, :os, :web_server, :technologies, :ip,
|
|
27
|
+
:fqdn, :operating_system, :mac_address, :netbios_name, :scan_start_time,
|
|
28
|
+
:scan_stop_time
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
# This allows external callers (and specs) to check for implemented
|
|
32
|
+
# properties
|
|
33
|
+
def respond_to?(method, include_private=false)
|
|
34
|
+
return true if SUPPORTED_TAGS.include?(method.to_sym)
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# This method is invoked by Ruby when a method that is not defined in this
|
|
39
|
+
# instance is called.
|
|
40
|
+
#
|
|
41
|
+
# In our case we inspect the @method@ parameter and try to find the
|
|
42
|
+
# corresponding <tag/> element inside the ./Scan child.
|
|
43
|
+
def method_missing(method, *args)
|
|
44
|
+
# We could remove this check and return nil for any non-recognized tag.
|
|
45
|
+
# The problem would be that it would make tricky to debug problems with
|
|
46
|
+
# typos. For instance: <>.potr would return nil instead of raising an
|
|
47
|
+
# exception
|
|
48
|
+
super and return unless SUPPORTED_TAGS.include?(method)
|
|
49
|
+
|
|
50
|
+
if tag = xml.at_xpath("./#{tag_name_for_method(method)}")
|
|
51
|
+
tag.text
|
|
52
|
+
else
|
|
53
|
+
nil
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def report_items
|
|
59
|
+
@xml.xpath('./ReportItems/ReportItem')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def service
|
|
64
|
+
"port #{start_url_port}, #{banner}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def start_url_host
|
|
69
|
+
start_uri.host
|
|
70
|
+
end
|
|
71
|
+
alias_method :hostname, :start_url_host
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def start_url_port
|
|
75
|
+
start_uri.port
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def start_uri
|
|
81
|
+
@start_uri ||= URI::parse(start_url)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def tag_name_for_method(method)
|
|
85
|
+
# Any fields where a simple .camelcase() won't work we need to translate,
|
|
86
|
+
# this includes acronyms (e.g. :scan_url would become 'ScanUrl').
|
|
87
|
+
{
|
|
88
|
+
start_url: 'StartURL'
|
|
89
|
+
}[method] || method.to_s.camelcase
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Dradis
|
|
2
|
+
module Plugins
|
|
3
|
+
module Acunetix
|
|
4
|
+
end
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'dradis/plugins/acunetix/engine'
|
|
9
|
+
require 'dradis/plugins/acunetix/field_processor'
|
|
10
|
+
require 'dradis/plugins/acunetix/importer'
|
|
11
|
+
require 'dradis/plugins/acunetix/version'
|
|
12
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Dradis::Plugins::Acunetix
|
|
2
|
+
# This processor defers to ::Acunetix::Scan for the scan template and to
|
|
3
|
+
# ::Acunetix::ReportItem for the report_item and evidence templates.
|
|
4
|
+
class FieldProcessor < Dradis::Plugins::Upload::FieldProcessor
|
|
5
|
+
|
|
6
|
+
def post_initialize(args={})
|
|
7
|
+
if data.name == "Scan"
|
|
8
|
+
@acunetix_object = ::Acunetix::Scan.new(data)
|
|
9
|
+
else
|
|
10
|
+
@acunetix_object = ::Acunetix::ReportItem.new(data)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def value(args={})
|
|
15
|
+
field = args[:field]
|
|
16
|
+
|
|
17
|
+
# fields in the template are of the form <foo>.<field>, where <foo>
|
|
18
|
+
# is common across all fields for a given template (and meaningless).
|
|
19
|
+
_, name = field.split('.')
|
|
20
|
+
|
|
21
|
+
@acunetix_object.try(name) || 'n/a'
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Dradis
|
|
2
|
+
module Plugins
|
|
3
|
+
module Acunetix
|
|
4
|
+
# Returns the version of the currently loaded Acunetix as a <tt>Gem::Version</tt>
|
|
5
|
+
def self.gem_version
|
|
6
|
+
Gem::Version.new VERSION::STRING
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module VERSION
|
|
10
|
+
MAJOR = 3
|
|
11
|
+
MINOR = 18
|
|
12
|
+
TINY = 0
|
|
13
|
+
PRE = nil
|
|
14
|
+
|
|
15
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Dradis::Plugins::Acunetix
|
|
2
|
+
class Importer < Dradis::Plugins::Upload::Importer
|
|
3
|
+
|
|
4
|
+
# The framework will call this function if the user selects this plugin from
|
|
5
|
+
# the dropdown list and uploads a file.
|
|
6
|
+
# @returns true if the operation was successful, false otherwise
|
|
7
|
+
def import(params={})
|
|
8
|
+
file_content = File.read( params.fetch(:file) )
|
|
9
|
+
|
|
10
|
+
logger.info{'Parsing Acunetix output file...'}
|
|
11
|
+
@doc = Nokogiri::XML( file_content )
|
|
12
|
+
logger.info{'Done.'}
|
|
13
|
+
|
|
14
|
+
if @doc.xpath('/ScanGroup/Scan').empty?
|
|
15
|
+
error = "No scan results were detected in the uploaded file (/ScanGroup/Scan). Ensure you uploaded an Acunetix XML report."
|
|
16
|
+
logger.fatal{ error }
|
|
17
|
+
content_service.create_note text: error
|
|
18
|
+
return false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
@doc.xpath('/ScanGroup/Scan').each do |xml_scan|
|
|
22
|
+
process_scan(xml_scan)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return true
|
|
26
|
+
end # /import
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
attr_accessor :scan_node
|
|
31
|
+
|
|
32
|
+
def process_scan(xml_scan)
|
|
33
|
+
url = xml_scan.at_xpath('./StartURL').text()
|
|
34
|
+
start_url = URI::parse(url).host || url # urls wo/ protocol returned nil
|
|
35
|
+
|
|
36
|
+
self.scan_node = content_service.create_node(label: start_url, type: :host)
|
|
37
|
+
logger.info{ "\tScan start URL: #{start_url}" }
|
|
38
|
+
|
|
39
|
+
# Define Node properties
|
|
40
|
+
if scan_node.respond_to?(:properties)
|
|
41
|
+
scan_node.set_property(:short_name, xml_scan.at_xpath('./ShortName').text() )
|
|
42
|
+
scan_node.set_property(:start_url, start_url)
|
|
43
|
+
scan_node.set_property(:start_time, xml_scan.at_xpath('./StartTime').text() )
|
|
44
|
+
scan_node.set_property(:finish_time, xml_scan.at_xpath('./FinishTime').text() )
|
|
45
|
+
scan_node.set_property(:scan_time, xml_scan.at_xpath('./ScanTime').text() )
|
|
46
|
+
scan_node.set_property(:aborted, xml_scan.at_xpath('./Aborted').text() )
|
|
47
|
+
scan_node.set_property(:responsive, xml_scan.at_xpath('./Responsive').text() )
|
|
48
|
+
scan_node.set_property(:banner, xml_scan.at_xpath('./Banner').text() )
|
|
49
|
+
scan_node.set_property(:os, xml_scan.at_xpath('./Os').text() )
|
|
50
|
+
scan_node.set_property(:web_server, xml_scan.at_xpath('./WebServer').text() )
|
|
51
|
+
scan_node.set_property(:technologies, xml_scan.at_xpath('./Technologies').text() )
|
|
52
|
+
scan_node.save
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
scan_note = template_service.process_template(template: 'scan', data: xml_scan)
|
|
56
|
+
content_service.create_note text: scan_note, node: scan_node
|
|
57
|
+
|
|
58
|
+
xml_scan.xpath('./ReportItems/ReportItem').each do |xml_report_item|
|
|
59
|
+
process_report_item(xml_report_item)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def process_report_item(xml_report_item)
|
|
64
|
+
plugin_id = "%s/%s" % [
|
|
65
|
+
xml_report_item.at_xpath('./ModuleName').text(),
|
|
66
|
+
xml_report_item.at_xpath('./Name').text()
|
|
67
|
+
]
|
|
68
|
+
logger.info{ "\t\t => Creating new issue (plugin_id: #{plugin_id})" }
|
|
69
|
+
|
|
70
|
+
issue_text = template_service.process_template(template: 'report_item', data: xml_report_item)
|
|
71
|
+
issue = content_service.create_issue(text: issue_text, id: plugin_id)
|
|
72
|
+
|
|
73
|
+
logger.info{ "\t\t => Creating new evidence" }
|
|
74
|
+
evidence_content = template_service.process_template(template: 'evidence', data: xml_report_item)
|
|
75
|
+
content_service.create_evidence(issue: issue, node: scan_node, content: evidence_content)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|