dradis-qualys 4.0.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -53
  3. data/CHANGELOG.template +12 -0
  4. data/dradis-qualys.gemspec +1 -1
  5. data/lib/dradis/plugins/qualys/asset/importer.rb +112 -0
  6. data/lib/dradis/plugins/qualys/engine.rb +13 -0
  7. data/lib/dradis/plugins/qualys/field_processor.rb +23 -3
  8. data/lib/dradis/plugins/qualys/gem_version.rb +1 -1
  9. data/lib/dradis/plugins/qualys/vuln/importer.rb +103 -0
  10. data/lib/dradis/plugins/qualys/was/importer.rb +109 -0
  11. data/lib/dradis/plugins/qualys.rb +4 -1
  12. data/lib/dradis-qualys.rb +4 -0
  13. data/lib/qualys/asset/evidence.rb +74 -0
  14. data/lib/qualys/asset/vulnerability.rb +87 -0
  15. data/lib/qualys/element.rb +32 -25
  16. data/lib/qualys/was/qid.rb +85 -0
  17. data/lib/qualys/was/vulnerability.rb +68 -0
  18. data/lib/tasks/thorfile.rb +15 -1
  19. data/spec/fixtures/files/simple_asset.xml +126 -0
  20. data/spec/fixtures/files/simple_was.xml +134 -0
  21. data/spec/qualys/asset/importer_spec.rb +41 -0
  22. data/spec/qualys/{importer_spec.rb → vuln/importer_spec.rb} +10 -53
  23. data/spec/qualys/was/importer_spec.rb +41 -0
  24. data/spec/spec_helper.rb +3 -0
  25. data/spec/support/spec_macros.rb +46 -0
  26. data/templates/asset-evidence.fields +9 -0
  27. data/templates/asset-evidence.sample +14 -0
  28. data/templates/asset-evidence.template +11 -0
  29. data/templates/asset-issue.fields +14 -0
  30. data/templates/asset-issue.sample +21 -0
  31. data/templates/asset-issue.template +22 -0
  32. data/templates/element.fields +1 -0
  33. data/templates/element.template +4 -0
  34. data/templates/was-evidence.fields +6 -0
  35. data/templates/was-evidence.sample +44 -0
  36. data/templates/was-evidence.template +11 -0
  37. data/templates/was-issue.fields +16 -0
  38. data/templates/was-issue.sample +24 -0
  39. data/templates/was-issue.template +28 -0
  40. metadata +36 -7
  41. data/lib/dradis/plugins/qualys/importer.rb +0 -88
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cfe14be5c9945751d3c77fcfff264b5a78c9ed73088e6279ed2f15548b6e0a8b
4
- data.tar.gz: bbb630a25f91486e55a07105f15826cc84e3aa8f8ce68b56c565218d7a974dea
3
+ metadata.gz: 179f7a4d51e6e9514362058cfe23587808351d96fff29ff3638c1f3020f2bcc3
4
+ data.tar.gz: e0ff0cb6075b177f802fa74f3ba0d396fb8c8ebbecf07fd390860788e2e1e506
5
5
  SHA512:
6
- metadata.gz: b24bba307807b3b6e3fc4284d770b5526bdec667815fbc9c36a2a2dd1497653342c3fb1cc5c8f9cf71efa208d73784d826a1979b0ee8df63730118904fd9d9e9
7
- data.tar.gz: a701e7d3ffa1fb57080a6311f7f692715d19ea36af0bc19da3d5897e15909e119d93f6d7bd084fa89c7cffbb77a384c20c0276c92f69cca599b74ff0bc0be3d8
6
+ metadata.gz: f06c828d8f2209711734decbafa5f2dcb0e3b1f0df3bb9b1fc86b24bcb0634c8a0892d3be4b78d3a87bfd64431cc1091f8dd9b2de1ccfb12ff4ea958a28abaac
7
+ data.tar.gz: e595872f8ad27155e0a5916eed09f043a30e19122402ded9dbdd4ff1367857da4d67bee5c336967406e78e771cca89230b9a263f8a0c8de48bd3ae4fc6116e89
data/CHANGELOG.md CHANGED
@@ -1,73 +1,67 @@
1
- ## Dradis Framework 4.0.0 (July, 2021) ##
1
+ v4.3.0 (April 2022)
2
+ - Adds Qualys Asset Scanner (ASSET) support
3
+ - Bugs fixes:
4
+ - Fixes WAS CVSS3 mapping and not importing fields to the issue
2
5
 
3
- * No changes.
6
+ v4.2.0 (February 2022)
7
+ - Adds 'element.qualys_collection' as issue field
8
+ - Adds Qualys Web Application Scanner (WAS) support
4
9
 
5
- ## Dradis Framework 3.22 (April, 2021) ##
10
+ v4.1.0 (November 2021)
11
+ - Add <dd>, <dt> support
12
+ - Remove orphaned <b> tags
6
13
 
7
- * No changes.
14
+ v4.0.0 (July 2021)
15
+ - No changes
8
16
 
9
- ## Dradis Framework 3.21 (February, 2021) ##
17
+ v3.22.0 (April 2021)
18
+ - No changes
10
19
 
11
- * No changes.
20
+ v3.21.0 (February 2021)
21
+ - No changes
12
22
 
13
- ## Dradis Framework 3.20 (December, 2020) ##
23
+ v3.20.0 (December 2020)
24
+ - No changes
14
25
 
15
- * No changes.
26
+ v3.19.0 (September 2020)
27
+ - No changes
16
28
 
17
- ## Dradis Framework 3.19 (September, 2020) ##
29
+ v3.18.0 (July 2020)
30
+ - No changes
18
31
 
19
- * No changes.
32
+ v3.17.0 (May 2020)
33
+ - No changes
20
34
 
21
- ## Dradis Framework 3.18 (July, 2020) ##
35
+ v3.16.0 (February 2020)
36
+ - No changes
22
37
 
23
- * No changes.
38
+ v3.15.0 (November 2019)
39
+ - No changes
24
40
 
25
- ## Dradis Framework 3.17 (May, 2020) ##
41
+ v3.14.0 (August 2019)
42
+ - No changes
26
43
 
27
- * No changes.
44
+ v3.13.0 (June 2019)
45
+ - No changes
28
46
 
29
- ## Dradis Framework 3.16 (February, 2020) ##
47
+ v3.12.0 (March 2019)
48
+ - No changes
30
49
 
31
- * No changes.
50
+ v3.11.0 (November 2018)
51
+ - No changes
32
52
 
33
- ## Dradis Framework 3.15 (November, 2019) ##
53
+ v3.10.0 (August 2018)
54
+ - No changes
34
55
 
35
- * No changes.
56
+ v3.9.0 (January 2018)
57
+ - Add `os`, `hostname`, and `ip` as Node properties instead of a `Basic host info` Note
36
58
 
37
- ## Dradis Framework 3.14 (August, 2019) ##
59
+ v3.8.0 (September 2017)
60
+ - No changes
38
61
 
39
- * No changes.
62
+ v3.7.0 (July 2017)
63
+ - Better HTML entity translation (thanks @leesoh)
64
+ - Import INFOS, SERVICES, etc as Issues #7 (thanks @rachkor)
40
65
 
41
- ## Dradis Framework 3.13 (June, 2019) ##
42
-
43
- * No changes.
44
-
45
- ## Dradis Framework 3.12 (March, 2019) ##
46
-
47
- * No changes.
48
-
49
- ## Dradis Framework 3.11 (November, 2018) ##
50
-
51
- * No changes.
52
-
53
- ## Dradis Framework 3.10 (August, 2018) ##
54
-
55
- * No changes.
56
-
57
- ## Dradis Framework 3.9 (January, 2018) ##
58
-
59
- * Add `os`, `hostname`, and `ip` as Node properties
60
- instead of a `Basic host info` Note (v3.8.1)
61
-
62
- ## Dradis Framework 3.8 (September, 2017) ##
63
-
64
- * No changes.
65
-
66
- ## Dradis Framework 3.7 (July, 2017) ##
67
-
68
- * Better HTML entity translation (thanks @leesoh).
69
- * Import INFOS, SERVICES, etc as Issues #7 (thanks @rachkor).
70
-
71
- ## Dradis Framework 3.6 (March, 2017) ##
72
-
73
- * No changes.
66
+ v3.6.0 (March 2017)
67
+ - No changes
@@ -0,0 +1,12 @@
1
+ [v#.#.#] ([month] [YYYY])
2
+ - [future tense verb] [feature]
3
+ - Upgraded gems:
4
+ - [gem]
5
+ - Bugs fixes:
6
+ - [future tense verb] [bug fix]
7
+ - Bug tracker items:
8
+ - [item]
9
+ - Security Fixes:
10
+ - High: (Authenticated|Unauthenticated) (admin|author|contributor) [vulnerability description]
11
+ - Medium: (Authenticated|Unauthenticated) (admin|author|contributor) [vulnerability description]
12
+ - Low: (Authenticated|Unauthenticated) (admin|author|contributor) [vulnerability description]
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  # versions of Rails (a sure recipe for disaster, I'm sure), which is needed
25
25
  # until we bump Dradis Pro to 4.1.
26
26
  # s.add_dependency 'rails', '~> 4.1.1'
27
- spec.add_dependency 'dradis-plugins', '~> 4.0.0'
27
+ spec.add_dependency 'dradis-plugins', '~> 4.0'
28
28
  spec.add_dependency 'nokogiri', '~> 1.3'
29
29
 
30
30
  spec.add_development_dependency 'bundler', '~> 1.6'
@@ -0,0 +1,112 @@
1
+ module Dradis::Plugins::Qualys
2
+ module Asset
3
+ ROOT_PATH_NAME = 'ASSET_DATA_REPORT'.freeze
4
+
5
+ def self.meta
6
+ package = Dradis::Plugins::Qualys
7
+
8
+ {
9
+ name: package::Engine::plugin_name,
10
+ description: 'Upload Qualys Asset results (.xml)',
11
+ version: package.version
12
+ }
13
+ end
14
+
15
+ class Importer < Dradis::Plugins::Upload::Importer
16
+ def initialize(args={})
17
+ args[:plugin] = Dradis::Plugins::Qualys
18
+ super(args)
19
+
20
+ @issue_lookup = {}
21
+ end
22
+
23
+ # The framework will call this function if the user selects this plugin from
24
+ # the dropdown list and uploads a file.
25
+ # @returns true if the operation was successful, false otherwise
26
+ def import(params={})
27
+ file_content = File.read( params[:file] )
28
+
29
+ logger.info { 'Parsing Qualys ASSET XML output file...' }
30
+ doc = Nokogiri::XML(file_content)
31
+ logger.info { 'Done.' }
32
+
33
+ if doc.root.name != ROOT_PATH_NAME
34
+ error = 'No scan results were detected in the uploaded file. Ensure you uploaded a Qualys ASSET XML file.'
35
+ logger.fatal { error }
36
+ content_service.create_note text: error
37
+ return false
38
+ end
39
+
40
+ doc.xpath('ASSET_DATA_REPORT/GLOSSARY/VULN_DETAILS_LIST/VULN_DETAILS').each do |xml_issue|
41
+ process_issue(xml_issue)
42
+ end
43
+
44
+ doc.xpath('ASSET_DATA_REPORT/HOST_LIST/HOST').each do |xml_node|
45
+ process_node(xml_node)
46
+ end
47
+
48
+ true
49
+ end
50
+
51
+ private
52
+
53
+ attr_accessor :issue_lookup
54
+
55
+ def process_node(xml_node)
56
+ logger.info { 'Creating node...' }
57
+
58
+ # Create host node
59
+ host_node = content_service.create_node(
60
+ label: xml_node.at_xpath('IP').text,
61
+ type: :host
62
+ )
63
+
64
+ %w[dns host_id operating_system qg_hostid tracking_method].each do |key|
65
+ prop = xml_node.at_xpath(key.upcase)
66
+ host_node.set_property(key.to_sym, prop.text) if prop
67
+ end
68
+
69
+ tags = xml_node.at_xpath('ASSET_TAGS/ASSET_TAG')
70
+ if tags
71
+ tags.each do |tag|
72
+ host_node.set_property(:asset_tags, tag.text)
73
+ end
74
+ end
75
+
76
+ host_node.save
77
+
78
+ xml_node.xpath('./VULN_INFO_LIST/VULN_INFO').each do |xml_evidence|
79
+ process_evidence(xml_evidence, host_node)
80
+ end
81
+ end
82
+
83
+ def process_issue(xml_vuln)
84
+ qid = xml_vuln.at_xpath('QID').text
85
+ logger.info { "\t => Creating new issue (plugin_id: #{ qid })" }
86
+ issue_text = template_service.process_template(template: 'asset-issue', data: xml_vuln)
87
+ issue = content_service.create_issue(text: issue_text, id: qid)
88
+
89
+ issue_lookup[qid.to_i] = issue
90
+ end
91
+
92
+ def process_evidence(xml_evidence, node)
93
+ qid = xml_evidence.at_xpath('./QID').text
94
+
95
+ issue = issue_lookup[qid.to_i]
96
+ if issue
97
+ issue_id = issue.respond_to?(:id) ? issue.id : issue.to_issue.id
98
+
99
+ logger.info { "\t => Creating new evidence (plugin_id: #{qid})" }
100
+ logger.info { "\t\t => Issue: #{issue.title} (plugin_id: #{issue_id})" }
101
+ logger.info { "\t\t => Node: #{node.label} (#{node.id})" }
102
+ else
103
+ logger.info { "\t => Couldn't find QID for issue with ID=#{qid}" }
104
+ return
105
+ end
106
+
107
+ evidence_content = template_service.process_template(template: 'asset-evidence', data: xml_evidence)
108
+ content_service.create_evidence(issue: issue, node: node, content: evidence_content)
109
+ end
110
+ end
111
+ end
112
+ end
@@ -5,5 +5,18 @@ module Dradis::Plugins::Qualys
5
5
  include ::Dradis::Plugins::Base
6
6
  description 'Processes Qualys output'
7
7
  provides :upload
8
+
9
+ # Because this plugin provides two export modules, we have to overwrite
10
+ # the default .uploaders() method.
11
+ #
12
+ # See:
13
+ # Dradis::Plugins::Upload::Base in dradis-plugins
14
+ def self.uploaders
15
+ [
16
+ Dradis::Plugins::Qualys::Asset,
17
+ Dradis::Plugins::Qualys::Vuln,
18
+ Dradis::Plugins::Qualys::WAS
19
+ ]
20
+ end
8
21
  end
9
22
  end
@@ -4,8 +4,19 @@ module Dradis
4
4
  class FieldProcessor < Dradis::Plugins::Upload::FieldProcessor
5
5
 
6
6
  def post_initialize(args={})
7
- @cat_object = data
8
- @qualys_object = ::Qualys::Element.new(data.elements.first)
7
+ case data.name
8
+ when 'CAT'
9
+ @cat_object = data
10
+ @qualys_object = ::Qualys::Element.new(data.elements.first)
11
+ when 'QID'
12
+ @qualys_object = ::Qualys::WAS::QID.new(data)
13
+ when 'VULNERABILITY'
14
+ @qualys_object = ::Qualys::WAS::Vulnerability.new(data)
15
+ when 'VULN_DETAILS'
16
+ @qualys_object = ::Qualys::Asset::Vulnerability.new(data)
17
+ when 'VULN_INFO'
18
+ @qualys_object = ::Qualys::Asset::Evidence.new(data)
19
+ end
9
20
  end
10
21
 
11
22
  def value(args={})
@@ -13,8 +24,14 @@ module Dradis
13
24
 
14
25
  # Fields in the template are of the form <foo>.<field>, where <foo>
15
26
  # is common across all fields for a given template (and meaningless).
16
- _, name = field.split('.')
27
+ # However we can use it to identify the type of scan we're processing.
28
+ type, name = field.split('.')
29
+
30
+ %{element evidence}.include?(type) ? value_network(name) : value_was(name)
31
+ end
17
32
 
33
+ private
34
+ def value_network(name)
18
35
  if %w{cat_fqdn cat_misc cat_port cat_protocol cat_value}.include?(name)
19
36
  attribute = name[4..-1]
20
37
  @cat_object[attribute] || 'n/a'
@@ -36,6 +53,9 @@ module Dradis
36
53
  end
37
54
  end
38
55
 
56
+ def value_was(name)
57
+ @qualys_object.try(name) || 'n/a'
58
+ end
39
59
  end
40
60
  end
41
61
  end
@@ -8,7 +8,7 @@ module Dradis
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 4
11
- MINOR = 0
11
+ MINOR = 3
12
12
  TINY = 0
13
13
  PRE = nil
14
14
 
@@ -0,0 +1,103 @@
1
+ module Dradis::Plugins::Qualys
2
+ module Vuln
3
+ def self.meta
4
+ package = Dradis::Plugins::Qualys
5
+
6
+ {
7
+ name: package::Engine::plugin_name,
8
+ description: 'Upload Qualys Vulnerability Management results (.xml)',
9
+ version: package.version
10
+ }
11
+ end
12
+
13
+ class Importer < Dradis::Plugins::Upload::Importer
14
+ attr_accessor :host_node
15
+
16
+ def initialize(args={})
17
+ args[:plugin] = Dradis::Plugins::Qualys
18
+ super(args)
19
+ end
20
+
21
+ # The framework will call this function if the user selects this plugin from
22
+ # the dropdown list and uploads a file.
23
+ # @returns true if the operation was successful, false otherwise
24
+ def import(params={})
25
+ file_content = File.read( params[:file] )
26
+
27
+ logger.info{'Parsing Qualys output file...'}
28
+ @doc = Nokogiri::XML( file_content )
29
+ logger.info{'Done.'}
30
+
31
+ if @doc.root.name != 'SCAN'
32
+ error = "No scan results were detected in the uploaded file. Ensure you uploaded a Qualys XML file."
33
+ logger.fatal{ error }
34
+ content_service.create_note text: error
35
+ return false
36
+ end
37
+
38
+ @doc.xpath('SCAN/IP').each do |xml_host|
39
+ process_ip(xml_host)
40
+ end
41
+
42
+ return true
43
+ end
44
+
45
+ private
46
+
47
+ def process_ip(xml_host)
48
+ host_ip = xml_host['value']
49
+ logger.info{ "Host: %s" % host_ip }
50
+
51
+ self.host_node = content_service.create_node(label: host_ip, type: :host)
52
+
53
+ host_node.set_property(:ip, host_ip)
54
+ host_node.set_property(:hostname, xml_host['name'])
55
+ if (xml_os = xml_host.xpath('OS')) && xml_os.any?
56
+ host_node.set_property(:os, xml_os.text)
57
+ end
58
+ host_node.save
59
+
60
+ # We treat INFOS, SERVICES, PRACTICES, and VULNS the same way
61
+ # All of these are imported into Dradis as Issues
62
+ ['INFOS', 'SERVICES', 'PRACTICES', 'VULNS'].each do |collection|
63
+ xml_host.xpath(collection).each do |xml_collection|
64
+ process_collection(collection, xml_collection)
65
+ end
66
+ end
67
+ end
68
+
69
+ def process_collection(collection, xml_collection)
70
+ xml_cats = xml_collection.xpath('CAT')
71
+
72
+ xml_cats.each do |xml_cat|
73
+ logger.info{ "\t#{ collection } - #{ xml_cat['value'] }" }
74
+
75
+ empty_dup_xml_cat = xml_cat.dup
76
+ empty_dup_xml_cat.children.remove
77
+
78
+ # For each INFOS/CAT/INFO, SERVICES/CAT/SERVICE, VULNS/CAT/VULN, etc.
79
+ xml_cat.xpath(collection.chop).each do |xml_element|
80
+ dup_xml_cat = empty_dup_xml_cat.dup
81
+ dup_xml_cat.add_child(xml_element.dup)
82
+ cat_number = xml_element[:number]
83
+
84
+ process_vuln(cat_number, dup_xml_cat)
85
+
86
+ end
87
+ end
88
+ end
89
+
90
+ # Takes a <CAT> element containing a single <VULN> element and processes an
91
+ # Issue and Evidence template out of it.
92
+ def process_vuln(vuln_number, xml_cat)
93
+ logger.info{ "\t\t => Creating new issue (plugin_id: #{ vuln_number })" }
94
+ issue_text = template_service.process_template(template: 'element', data: xml_cat)
95
+ issue = content_service.create_issue(text: issue_text, id: vuln_number)
96
+
97
+ logger.info{ "\t\t => Creating new evidence" }
98
+ evidence_content = template_service.process_template(template: 'evidence', data: xml_cat)
99
+ content_service.create_evidence(issue: issue, node: self.host_node, content: evidence_content)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,109 @@
1
+ module Dradis::Plugins::Qualys
2
+
3
+ # This module knows how to parse Qualys Web Application Scanner format.
4
+ module WAS
5
+ def self.meta
6
+ package = Dradis::Plugins::Qualys
7
+
8
+ {
9
+ name: package::Engine::plugin_name,
10
+ description: 'Upload Qualys WAS results (.xml)',
11
+ version: package.version
12
+ }
13
+ end
14
+
15
+ class Importer < Dradis::Plugins::Upload::Importer
16
+ def initialize(args={})
17
+ args[:plugin] = Dradis::Plugins::Qualys
18
+ super(args)
19
+
20
+ @issue_lookup = {}
21
+ end
22
+
23
+ def import(params={})
24
+ file_content = File.read(params[:file])
25
+
26
+ logger.info { 'Parsing Qualys WAS XML output file...'}
27
+ doc = Nokogiri::XML(file_content)
28
+ logger.info { 'Done.' }
29
+
30
+ if doc.root.name != 'WAS_SCAN_REPORT'
31
+ error = 'Document doesn\'t seem to be in the Qualys WAS XML format.'
32
+ logger.fatal { error }
33
+ content_service.create_note text: error
34
+ return false
35
+ end
36
+
37
+ logger.info { 'Global Summary information'}
38
+
39
+ xml_global_summary = doc.at_xpath('WAS_SCAN_REPORT/SUMMARY/GLOBAL_SUMMARY')
40
+ logger.info { 'Security Risk: ' + xml_global_summary.at_xpath('./SECURITY_RISK').text }
41
+ logger.info { 'Vulnerabilities found: ' + xml_global_summary.at_xpath('./VULNERABILITY').text }
42
+
43
+ xml_webapp = doc.at_xpath('WAS_SCAN_REPORT/APPENDIX/WEBAPP')
44
+ process_webapp(xml_webapp)
45
+
46
+ doc.xpath('WAS_SCAN_REPORT/GLOSSARY/QID_LIST/QID').each do |xml_qid|
47
+ process_issue(xml_qid)
48
+ end
49
+
50
+ doc.xpath('WAS_SCAN_REPORT/RESULTS/VULNERABILITY_LIST/VULNERABILITY').each do |xml_vulnerability|
51
+ process_evidence(xml_vulnerability)
52
+ end
53
+
54
+ true
55
+ end
56
+
57
+ private
58
+ attr_accessor :webapp_node, :issue_lookup
59
+
60
+ def process_evidence(xml_vulnerability)
61
+ id = xml_vulnerability.at_xpath('./ID').text
62
+
63
+ issue = issue_lookup[xml_vulnerability.at_xpath('./QID').text.to_i]
64
+ if issue
65
+ issue_id = issue.respond_to?(:id) ? issue.id : issue.to_issue.id
66
+
67
+ logger.info{ "\t => Creating new evidence (plugin_id: #{id})" }
68
+ logger.info{ "\t\t => Issue: #{issue.title} (plugin_id: #{issue_id})" }
69
+ logger.info{ "\t\t => Node: #{webapp_node.label} (#{webapp_node.id})" }
70
+ else
71
+ logger.info{ "\t => Couldn't find QID for evidence with ID=#{id}" }
72
+ return
73
+ end
74
+
75
+ evidence_content = template_service.process_template(template: 'was-evidence', data: xml_vulnerability)
76
+ content_service.create_evidence(issue: issue, node: webapp_node, content: evidence_content)
77
+ end
78
+
79
+ def process_issue(xml_qid)
80
+ qid = xml_qid.at_xpath('QID').text
81
+ logger.info{ "\t => Creating new issue (plugin_id: #{ qid })" }
82
+ issue_text = template_service.process_template(template: 'was-issue', data: xml_qid)
83
+ issue = content_service.create_issue(text: issue_text, id: qid)
84
+
85
+ issue_lookup[qid.to_i] = issue
86
+ end
87
+
88
+ def process_webapp(xml_webapp)
89
+ id = xml_webapp.at_xpath('./ID').text
90
+ name = xml_webapp.at_xpath('./NAME').text
91
+ url = xml_webapp.at_xpath('./URL').text
92
+ scope = xml_webapp.at_xpath('./SCOPE').text
93
+
94
+ uri = URI(url)
95
+ @webapp_node = content_service.create_node(label: uri.host, type: :host)
96
+
97
+ webapp_node.set_property('qualys.webapp.id', id)
98
+ webapp_node.set_property('qualys.webapp.name', name)
99
+ webapp_node.set_property('qualys.webapp.url', url)
100
+ webapp_node.set_property('qualys.webapp.scope', scope)
101
+ webapp_node.save!
102
+
103
+ logger.info { 'Webapp name: ' + name }
104
+ logger.info { 'Webapp URL: ' + url }
105
+ logger.info { 'Webapp scope: ' + scope }
106
+ end
107
+ end
108
+ end
109
+ end
@@ -7,5 +7,8 @@ end
7
7
 
8
8
  require 'dradis/plugins/qualys/engine'
9
9
  require 'dradis/plugins/qualys/field_processor'
10
- require 'dradis/plugins/qualys/importer'
11
10
  require 'dradis/plugins/qualys/version'
11
+
12
+ require 'dradis/plugins/qualys/asset/importer'
13
+ require 'dradis/plugins/qualys/vuln/importer'
14
+ require 'dradis/plugins/qualys/was/importer'
data/lib/dradis-qualys.rb CHANGED
@@ -6,3 +6,7 @@ require 'dradis/plugins/qualys'
6
6
 
7
7
  # Load supporting Qualys classes
8
8
  require 'qualys/element'
9
+ require 'qualys/asset/evidence'
10
+ require 'qualys/asset/vulnerability'
11
+ require 'qualys/was/qid'
12
+ require 'qualys/was/vulnerability'
@@ -0,0 +1,74 @@
1
+ module Qualys::Asset
2
+ # This class represents each of the ASSET_DATA_REPORT/GLOSSARY/VULN_INFO_LIST/
3
+ # VULN_INFO elements in the Qualys Asset 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 Evidence
11
+ # Accepts an XML node from Nokogiri::XML.
12
+ def initialize(xml_node)
13
+ @xml = xml_node
14
+ end
15
+
16
+ # List of supported tags. They can be attributes, simple descendans or
17
+ # collections (e.g. <references/>, <tags/>)
18
+ def supported_tags
19
+ [
20
+ # simple tags
21
+ :first_round, :last_round, :result, :ssl, :times_found,
22
+ :type, :vuln_status,
23
+
24
+ :cvss_base, :cvss3_final
25
+ ]
26
+ end
27
+
28
+ # This allows external callers (and specs) to check for implemented
29
+ # properties
30
+ def respond_to?(method, include_private=false)
31
+ return true if supported_tags.include?(method.to_sym)
32
+ super
33
+ end
34
+
35
+ # This method is invoked by Ruby when a method that is not defined in this
36
+ # instance is called.
37
+ #
38
+ # In our case we inspect the @method@ parameter and try to find the
39
+ # attribute, simple descendent or collection that it maps to in the XML
40
+ # tree.
41
+ def method_missing(method, *args)
42
+ # We could remove this check and return nil for any non-recognized tag.
43
+ # The problem would be that it would make tricky to debug problems with
44
+ # typos. For instance: <>.potr would return nil instead of raising an
45
+ # exception
46
+ unless supported_tags.include?(method)
47
+ super
48
+ return
49
+ end
50
+
51
+ process_field_value(method.to_s)
52
+ end
53
+
54
+ def process_field_value(method)
55
+ tag = @xml.at_xpath("./#{method.upcase}")
56
+
57
+ if tag && !tag.text.blank?
58
+ if tags_with_html_content.include?(method)
59
+ Qualys.cleanup_html(tag.text)
60
+ else
61
+ tag.text
62
+ end
63
+ else
64
+ 'n/a'
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def tags_with_html_content
71
+ %w[result]
72
+ end
73
+ end
74
+ end