dradis-qualys 4.0.0 → 4.3.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.
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