dradis-qualys 4.1.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/lib/dradis/plugins/qualys/asset/importer.rb +115 -0
  4. data/lib/dradis/plugins/qualys/engine.rb +13 -0
  5. data/lib/dradis/plugins/qualys/field_processor.rb +23 -3
  6. data/lib/dradis/plugins/qualys/gem_version.rb +1 -1
  7. data/lib/dradis/plugins/qualys/vuln/importer.rb +107 -0
  8. data/lib/dradis/plugins/qualys/was/importer.rb +113 -0
  9. data/lib/dradis/plugins/qualys.rb +4 -1
  10. data/lib/dradis-qualys.rb +4 -0
  11. data/lib/qualys/asset/evidence.rb +74 -0
  12. data/lib/qualys/asset/vulnerability.rb +87 -0
  13. data/lib/qualys/element.rb +31 -29
  14. data/lib/qualys/was/qid.rb +85 -0
  15. data/lib/qualys/was/vulnerability.rb +68 -0
  16. data/lib/tasks/thorfile.rb +15 -1
  17. data/spec/fixtures/files/simple_asset.xml +126 -0
  18. data/spec/fixtures/files/simple_was.xml +134 -0
  19. data/spec/qualys/asset/importer_spec.rb +41 -0
  20. data/spec/qualys/{importer_spec.rb → vuln/importer_spec.rb} +5 -50
  21. data/spec/qualys/was/importer_spec.rb +41 -0
  22. data/spec/spec_helper.rb +3 -0
  23. data/spec/support/spec_macros.rb +46 -0
  24. data/templates/asset-evidence.fields +9 -0
  25. data/templates/asset-evidence.sample +14 -0
  26. data/templates/asset-evidence.template +11 -0
  27. data/templates/asset-issue.fields +14 -0
  28. data/templates/asset-issue.sample +21 -0
  29. data/templates/asset-issue.template +22 -0
  30. data/templates/element.fields +1 -0
  31. data/templates/element.template +4 -0
  32. data/templates/was-evidence.fields +6 -0
  33. data/templates/was-evidence.sample +44 -0
  34. data/templates/was-evidence.template +11 -0
  35. data/templates/was-issue.fields +16 -0
  36. data/templates/was-issue.sample +24 -0
  37. data/templates/was-issue.template +28 -0
  38. metadata +34 -6
  39. data/lib/dradis/plugins/qualys/importer.rb +0 -88
@@ -1,4 +1,27 @@
1
1
  module Qualys
2
+
3
+ def self.cleanup_html(source)
4
+ result = source.dup
5
+ result.gsub!(/"/, '"')
6
+ result.gsub!(/&lt;/, '<')
7
+ result.gsub!(/&gt;/, '>')
8
+
9
+ result.gsub!(/<p>/i, "\n\n")
10
+ result.gsub!(/<br>/i, "\n")
11
+ result.gsub!(/ /, "")
12
+ result.gsub!(/<a href=\"(.*?)\"\s?target=\"_blank\">(.*?)<\/a>/i) { "\"#{$2.strip}\":#{$1.strip}" }
13
+ result.gsub!(/<pre>(.*?)<\/pre>/im) { |m| "\n\nbc.. #{$1.strip}\n\np. \n" }
14
+ result.gsub!(/<b>(.*?)<\/b>/i) { "*#{$1.strip}*" }
15
+ result.gsub!(/<b>|<\/b>/i, "")
16
+ result.gsub!(/<i>(.*?)<\/i>/i) { "_#{$1.strip}_" }
17
+
18
+ result.gsub!(/<dl>|<\/dl>/i, "\n")
19
+ result.gsub!(/<dt>(.*?)<\/dt>/i) { "* #{$1.strip}" }
20
+ result.gsub!(/<dd>(.*?)<\/dd>/i) { "** #{$1.strip}" }
21
+ result
22
+ end
23
+
24
+
2
25
  # This class represents each of the /SCAN/IP/[INFOS|SERVICES|VULNS|PRACTICES]/CAT/[INFO|SERVICE|VULN|PRACTICE]
3
26
  # elements in the Qualys XML document.
4
27
  #
@@ -25,7 +48,10 @@ module Qualys
25
48
  :consequence, :solution, :compliance, :result,
26
49
 
27
50
  # multiple tags
28
- :vendor_reference_list, :cve_id_list, :bugtraq_id_list
51
+ :vendor_reference_list, :cve_id_list, :bugtraq_id_list,
52
+
53
+ # category
54
+ :qualys_collection
29
55
  ]
30
56
  end
31
57
 
@@ -66,10 +92,10 @@ module Qualys
66
92
  return @xml.attributes[method_name].value if @xml.attributes.key?(method_name)
67
93
 
68
94
  # Then we try simple children tags: TITLE, LAST_UPDATE, CVSS_BASE...
69
- tag = @xml.xpath("./#{method_name.upcase}").first
95
+ tag = @xml.at_xpath("./#{method_name.upcase}")
70
96
  if tag && !tag.text.blank?
71
97
  if tags_with_html_content.include?(method)
72
- return cleanup_html(tag.text)
98
+ return Qualys::cleanup_html(tag.text)
73
99
  else
74
100
  return tag.text
75
101
  end
@@ -77,11 +103,8 @@ module Qualys
77
103
  'n/a'
78
104
  end
79
105
 
80
- # Finally the enumerations: vendor_reference_list, cve_id_list, bugtraq_id_list
81
- if method_name == 'references'
82
- # @xml.xpath("./references/reference").collect{|entry| {:source => entry['source'], :text => entry.text} }
83
- elsif method == 'tags'
84
- # @xml.xpath("./tags/tag").collect(&:text)
106
+ if method_name == 'qualys_collection'
107
+ @xml.name
85
108
  else
86
109
  # nothing found, the tag is valid but not present in this ReportItem
87
110
  return nil
@@ -90,27 +113,6 @@ module Qualys
90
113
 
91
114
  private
92
115
 
93
- def cleanup_html(source)
94
- result = source.dup
95
- result.gsub!(/&quot;/, '"')
96
- result.gsub!(/&lt;/, '<')
97
- result.gsub!(/&gt;/, '>')
98
-
99
- result.gsub!(/<p>/i, "\n\n")
100
- result.gsub!(/<br>/i, "\n")
101
- result.gsub!(/ /, "")
102
- result.gsub!(/<a href=\"(.*?)\"\s?target=\"_blank\">(.*?)<\/a>/i) { "\"#{$2.strip}\":#{$1.strip}" }
103
- result.gsub!(/<pre>(.*?)<\/pre>/im) { |m| "\n\nbc.. #{$1.strip}\n\np. \n" }
104
- result.gsub!(/<b>(.*?)<\/b>/i) { "*#{$1.strip}*" }
105
- result.gsub!(/<b>|<\/b>/i, "")
106
- result.gsub!(/<i>(.*?)<\/i>/i) { "_#{$1.strip}_" }
107
-
108
- result.gsub!(/<dl>|<\/dl>/i, "\n")
109
- result.gsub!(/<dt>(.*?)<\/dt>/i) { "* #{$1.strip}" }
110
- result.gsub!(/<dd>(.*?)<\/dd>/i) { "** #{$1.strip}" }
111
- result
112
- end
113
-
114
116
  def tags_with_html_content
115
117
  [:consequence, :diagnosis, :solution]
116
118
  end
@@ -0,0 +1,85 @@
1
+ module Qualys::WAS
2
+ # This class represents each of the WAS_SCAN_REPORT/GLOSSARY/QID_LIST/QID
3
+ # elements in the Qualys WAS 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 QID
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
+ :category, :cwe, :description, :group, :impact, :owasp, :qid,
22
+ :severity, :solution, :title, :wasc,
23
+
24
+ :cvss_base, :cvss_temporal, :cvss3_base, :cvss3_temporal, :cvss3_vector
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 method.starts_with?('cvss3')
58
+ process_cvss3_field(method)
59
+ elsif tag && !tag.text.blank?
60
+ if tags_with_html_content.include?(method)
61
+ Qualys.cleanup_html(tag.text)
62
+ else
63
+ tag.text
64
+ end
65
+ else
66
+ 'n/a'
67
+ end
68
+ end
69
+
70
+ def process_cvss3_field(method)
71
+ translations_table = {
72
+ cvss3_vector: 'CVSS_V3/ATTACK_VECTOR',
73
+ cvss3_base: 'CVSS_V3/BASE',
74
+ cvss3_temporal: 'CVSS_V3/TEMPORAL'
75
+ }
76
+
77
+ @xml.xpath("./#{translations_table[method.to_sym]}").text
78
+ end
79
+
80
+ private
81
+ def tags_with_html_content
82
+ [:description, :impact, :solution]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,68 @@
1
+ module Qualys::WAS
2
+ # This class represents each of the WAS_SCAN_REPORT/RESULTS/VULNERABILITY_LIST/
3
+ # VULNERABILITY elements in the Qualys WAS 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 Vulnerability
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
+ :access_paths, :ajax, :authentication, :ignored, :potential, :url
22
+ ]
23
+ end
24
+
25
+ # This allows external callers (and specs) to check for implemented
26
+ # properties
27
+ def respond_to?(method, include_private=false)
28
+ return true if supported_tags.include?(method.to_sym)
29
+ super
30
+ end
31
+
32
+ # This method is invoked by Ruby when a method that is not defined in this
33
+ # instance is called.
34
+ #
35
+ # In our case we inspect the @method@ parameter and try to find the
36
+ # attribute, simple descendent or collection that it maps to in the XML
37
+ # tree.
38
+ def method_missing(method, *args)
39
+ # We could remove this check and return nil for any non-recognized tag.
40
+ # The problem would be that it would make tricky to debug problems with
41
+ # typos. For instance: <>.potr would return nil instead of raising an
42
+ # exception
43
+ unless supported_tags.include?(method)
44
+ super
45
+ return
46
+ end
47
+
48
+ method_name = method.to_s
49
+
50
+ # Then we try simple children tags: TITLE, LAST_UPDATE, CVSS_BASE...
51
+ tag = @xml.at_xpath("./#{method_name.upcase}")
52
+ if tag && !tag.text.blank?
53
+ if tags_with_html_content.include?(method)
54
+ return Qualys::cleanup_html(tag.text)
55
+ else
56
+ return tag.text
57
+ end
58
+ else
59
+ 'n/a'
60
+ end
61
+ end
62
+
63
+ private
64
+ def tags_with_html_content
65
+ []
66
+ end
67
+ end
68
+ end
@@ -14,8 +14,22 @@ class QualysTasks < Thor
14
14
 
15
15
  detect_and_set_project_scope
16
16
 
17
- importer = Dradis::Plugins::Qualys::Importer.new(task_options)
17
+ importer = Dradis::Plugins::Qualys::Vuln::Importer.new(task_options)
18
18
  importer.import(file: file_path)
19
19
  end
20
20
 
21
+ desc "upload_was FILE", "upload Qualys WAS XML results"
22
+ def upload_was(file_path)
23
+ require 'config/environment'
24
+
25
+ unless File.exists?(file_path)
26
+ $stderr.puts "** the file [#{file_path}] does not exist"
27
+ exit -1
28
+ end
29
+
30
+ detect_and_set_project_scope
31
+
32
+ importer = Dradis::Plugins::Qualys::WAS::Importer.new(task_options)
33
+ importer.import(file: file_path)
34
+ end
21
35
  end
@@ -0,0 +1,126 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+
3
+ <!DOCTYPE ASSET_DATA_REPORT SYSTEM "https://qualysguard.qg3.apps.qualys.com/asset_data_report.dtd">
4
+ <ASSET_DATA_REPORT>
5
+ <HEADER>
6
+ <COMPANY><![CDATA[Security Roots Ltd.]]></COMPANY>
7
+ <USERNAME>dradispro</USERNAME>
8
+ <GENERATION_DATETIME>2021-03-19T18:16:17Z</GENERATION_DATETIME>
9
+ <TEMPLATE><![CDATA[Technical Report]]></TEMPLATE>
10
+ <TARGET>
11
+ <USER_ASSET_GROUPS>
12
+ <ASSET_GROUP_TITLE><![CDATA[ProdManagement]]></ASSET_GROUP_TITLE>
13
+ </USER_ASSET_GROUPS>
14
+ <COMBINED_IP_LIST>
15
+ <RANGE network_id="-100">
16
+ <START>10.0.0.0</START>
17
+ <END>10.0.255.255</END>
18
+ </RANGE>
19
+ <RANGE network_id="-100">
20
+ <START>192.168.0.0</START>
21
+ <END>192.168.255.255</END>
22
+ </RANGE>
23
+ </COMBINED_IP_LIST>
24
+ <ASSET_TAG_LIST>
25
+ <INCLUDED_TAGS scope="any">
26
+ <ASSET_TAG><![CDATA[asset-tag]]></ASSET_TAG>
27
+ </INCLUDED_TAGS>
28
+ </ASSET_TAG_LIST>
29
+ </TARGET>
30
+ <RISK_SCORE_SUMMARY>
31
+ <TOTAL_VULNERABILITIES>479</TOTAL_VULNERABILITIES>
32
+ <AVG_SECURITY_RISK>2.5</AVG_SECURITY_RISK>
33
+ <BUSINESS_RISK>48/100</BUSINESS_RISK>
34
+ </RISK_SCORE_SUMMARY>
35
+ </HEADER>
36
+ <HOST_LIST>
37
+ <HOST>
38
+ <IP network_id="0">10.0.0.1</IP>
39
+ <TRACKING_METHOD>QAGENT</TRACKING_METHOD>
40
+ <ASSET_TAGS>
41
+ <ASSET_TAG><![CDATA[Cloud Agent]]></ASSET_TAG>
42
+ </ASSET_TAGS>
43
+ <HOST_ID>112859328</HOST_ID>
44
+ <DNS><![CDATA[ontlpmutil01]]></DNS>
45
+ <QG_HOSTID><![CDATA[8d7fb998-0512-48c3-bb94-e40ac09ce9d4]]></QG_HOSTID>
46
+ <OPERATING_SYSTEM><![CDATA[Red Hat Enterprise Linux Server 7.9]]></OPERATING_SYSTEM>
47
+ <VULN_INFO_LIST>
48
+ <VULN_INFO>
49
+ <QID id="qid_11">11</QID>
50
+ <TYPE>Vuln</TYPE>
51
+ <SSL>false</SSL>
52
+ <RESULT format="table"><![CDATA[Package Installed Version Required Version
53
+ kernel-debug 3.10.0-957.27.2.el7.x86_64 3.10.0-1160.11.1.el7
54
+ kernel-debug 3.10.0-1160.6.1.el7.x86_64 3.10.0-1160.11.1.el7]]></RESULT>
55
+ <FIRST_FOUND>2020-12-18T13:11:56Z</FIRST_FOUND>
56
+ <LAST_FOUND>2021-03-19T13:05:42Z</LAST_FOUND>
57
+ <TIMES_FOUND>447</TIMES_FOUND>
58
+ <VULN_STATUS>Active</VULN_STATUS>
59
+ <CVSS_FINAL>5.5</CVSS_FINAL>
60
+ <CVSS3_FINAL>6.3</CVSS3_FINAL>
61
+ </VULN_INFO>
62
+ </VULN_INFO_LIST>
63
+ </HOST>
64
+ </HOST_LIST>
65
+ <GLOSSARY>
66
+ <VULN_DETAILS_LIST>
67
+ <VULN_DETAILS id="qid_11">
68
+ <QID id="qid_11">11</QID>
69
+ <TITLE><![CDATA[Hidden RPC Services]]></TITLE>
70
+ <SEVERITY>2</SEVERITY>
71
+ <CATEGORY>RPC</CATEGORY>
72
+ <THREAT><![CDATA[The Portmapper/Rpcbind listens on port 111 and stores an updated list of registered RPC services running on the server (RPC name, version and port number). It acts as a "gateway" for clients wanting to connect to any RPC daemon.
73
+ <P>
74
+ When the portmapper/rpcbind is removed or firewalled, standard RPC client programs fail to obtain the portmapper list. However, by sending carefully crafted packets, it's possible to determine which RPC programs are listening on which port. This technique is known as direct RPC scanning. It's used to bypass portmapper/rpcbind in order to find RPC programs running on a port (TCP or UDP ports). On Linux servers, RPC services are typically listening on privileged ports (below 1024), whereas on Solaris, RPC services are on temporary ports (starting with port 32700).]]></THREAT>
75
+ <IMPACT><![CDATA[Unauthorized users can build a list of RPC services running on the host. If they discover vulnerable RPC services on the host, they then can exploit them.]]></IMPACT>
76
+ <SOLUTION><![CDATA[Firewalling the portmapper port or removing the portmapper service is not sufficient to prevent unauthorized users from accessing the RPC daemons. You should remove all RPC services that are not strictly required on this host.]]></SOLUTION>
77
+ <PCI_FLAG>1</PCI_FLAG>
78
+ <LAST_UPDATE>1999-01-01T08:00:00Z</LAST_UPDATE>
79
+ <CVSS_SCORE>
80
+ <CVSS_BASE source="service">5</CVSS_BASE>
81
+ <CVSS_TEMPORAL>3.6</CVSS_TEMPORAL>
82
+ </CVSS_SCORE>
83
+ <CVSS3_SCORE>
84
+ <CVSS3_BASE>-</CVSS3_BASE>
85
+ <CVSS3_TEMPORAL>-</CVSS3_TEMPORAL>
86
+ </CVSS3_SCORE>
87
+ </VULN_DETAILS>
88
+ </VULN_DETAILS_LIST>
89
+ </GLOSSARY>
90
+ <APPENDICES>
91
+ <NO_RESULTS>
92
+ <IP_LIST>
93
+ <RANGE network_id="-100">
94
+ <START>10.0.0.0</START>
95
+ <END>10.0.0.4</END>
96
+ </RANGE>
97
+ <RANGE network_id="-100">
98
+ <START>192.168.0.0</START>
99
+ <END>192.168.2.4</END>
100
+ </RANGE>
101
+ <RANGE network_id="-100">
102
+ <START>192.168.2.6</START>
103
+ <END>192.168.255.255</END>
104
+ </RANGE>
105
+ </IP_LIST>
106
+ </NO_RESULTS>
107
+ <TEMPLATE_DETAILS>
108
+ <FILTER_SUMMARY>
109
+ Status:New, Active, Re-Opened, Fixed
110
+ Display non-running kernels:
111
+ Off
112
+ Exclude non-running kernels:
113
+ Off
114
+ Exclude non-running services:
115
+ Off
116
+ Exclude QIDs not exploitable due to configuration:
117
+ Off
118
+ Vulnerabilities:
119
+ State:Active
120
+ Included Operating Systems:
121
+ All Operating Systems
122
+ </FILTER_SUMMARY>
123
+ </TEMPLATE_DETAILS>
124
+ </APPENDICES>
125
+ </ASSET_DATA_REPORT>
126
+ <!-- CONFIDENTIAL AND PROPRIETARY INFORMATION. Qualys provides the QualysGuard Service "As Is," without any warranty of any kind. Qualys makes no warranty that the information contained in this report is complete or error-free. Copyright 2021, Qualys, Inc. //-->
@@ -0,0 +1,134 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <WAS_SCAN_REPORT>
3
+ <HEADER>
4
+ <NAME>Scan Report</NAME>
5
+ <DESCRIPTION>Vulnerabilities of all selected scans are consolidated into one report so that you can view their evolution.</DESCRIPTION>
6
+ <GENERATION_DATETIME>10 Nov 2021 10:00AM GMT-0500</GENERATION_DATETIME>
7
+ <COMPANY_INFO>
8
+ <NAME>Sample Company</NAME>
9
+ <ADDRESS>Sample Address</ADDRESS>
10
+ <CITY>Sample City</CITY>
11
+ <STATE>Sample State</STATE>
12
+ <COUNTRY>Sample Country</COUNTRY>
13
+ <ZIP_CODE>00000</ZIP_CODE>
14
+ </COMPANY_INFO>
15
+ <USER_INFO>
16
+ <NAME>Test User</NAME>
17
+ <USERNAME>test_user</USERNAME>
18
+ <ROLE>PC User,VM User</ROLE>
19
+ </USER_INFO>
20
+ </HEADER>
21
+ <FILTERS>
22
+ <FILTER>
23
+ <NAME>REMEDIATION</NAME>
24
+ <VALUE>Include patched findings</VALUE>
25
+ </FILTER>
26
+ <FILTER>
27
+ <NAME>REMEDIATION</NAME>
28
+ <VALUE>Show ignored findings </VALUE>
29
+ </FILTER>
30
+ </FILTERS>
31
+ <TARGET>
32
+ <SCAN>Test Scan</SCAN>
33
+ </TARGET>
34
+ <SUMMARY>
35
+ <GLOBAL_SUMMARY>
36
+ <SECURITY_RISK>High</SECURITY_RISK>
37
+ <VULNERABILITY>31</VULNERABILITY>
38
+ <SENSITIVE_CONTENT>0</SENSITIVE_CONTENT>
39
+ <INFORMATION_GATHERED>30</INFORMATION_GATHERED>
40
+ </GLOBAL_SUMMARY>
41
+ <SUMMARY_STATS>
42
+ <SUMMARY_STAT>
43
+ <SCAN>test Scan</SCAN>
44
+ <DATE>12 Oct 2021</DATE>
45
+ <LEVEL5>5</LEVEL5>
46
+ <LEVEL4>2</LEVEL4>
47
+ <LEVEL3>9</LEVEL3>
48
+ <LEVEL2>2</LEVEL2>
49
+ <LEVEL1>13</LEVEL1>
50
+ <SENSITIVE_CONTENT>0</SENSITIVE_CONTENT>
51
+ <INFORMATION_GATHERED>30</INFORMATION_GATHERED>
52
+ </SUMMARY_STAT>
53
+ </SUMMARY_STATS>
54
+ </SUMMARY>
55
+ <RESULTS>
56
+ <VULNERABILITY_LIST>
57
+ <VULNERABILITY>
58
+ <UNIQUE_ID>test-id</UNIQUE_ID>
59
+ <ID>1</ID>
60
+ <DETECTION_ID>1</DETECTION_ID>
61
+ <QID>6</QID>
62
+ <URL>http://example.com</URL>
63
+ <ACCESS_PATH>
64
+ <URL>http://example.com</URL>
65
+ </ACCESS_PATH>
66
+ <AJAX>false</AJAX>
67
+ <AUTHENTICATION>Not Required</AUTHENTICATION>
68
+ <DETECTION_DATE>21 Aug 2021 10:00PM GMT-0500</DETECTION_DATE>
69
+ <POTENTIAL>false</POTENTIAL>
70
+ <PAYLOADS>
71
+ <PAYLOAD>
72
+ <NUM>1</NUM>
73
+ <PAYLOAD>N/A</PAYLOAD>
74
+ <REQUEST>
75
+ <METHOD>GET</METHOD>
76
+ <URL>http://example.com</URL>
77
+ <HEADERS>
78
+ <HEADER>
79
+ <key>Host</key>
80
+ <value><![CDATA[ example.com ]]></value>
81
+ </HEADER>
82
+ <HEADER>
83
+ <key>User-Agent</key>
84
+ <value>user-agent</value>
85
+ </HEADER>
86
+ <HEADER>
87
+ <key>Accept</key>
88
+ <value><![CDATA[ */*
89
+ </HEADER>
90
+ </HEADERS>
91
+ <BODY></BODY>
92
+ </REQUEST>
93
+ <RESPONSE>
94
+ <CONTENTS base64="true"></CONTENTS>
95
+ </RESPONSE>
96
+ </PAYLOAD>
97
+ </PAYLOADS>
98
+ <IGNORED>false</IGNORED>
99
+ </VULNERABILITY>
100
+ </VULNERABILITY_LIST>
101
+ </RESULTS>
102
+ <GLOSSARY>
103
+ <QID_LIST>
104
+ <QID>
105
+ <QID>6</QID>
106
+ <CATEGORY>Information Gathered</CATEGORY>
107
+ <SEVERITY>1</SEVERITY>
108
+ <TITLE>DNS Host Name</TITLE>
109
+ <GROUP>DIAG</GROUP>
110
+ <DESCRIPTION>The fully qualified domain name of this host, if it was obtained from a DNS server, is displayed in the RESULT section.</DESCRIPTION>
111
+ <IMPACT>N/A</IMPACT>
112
+ <SOLUTION>N/A</SOLUTION>
113
+ <CVSS_BASE>4.3</CVSS_BASE>
114
+ <CVSS_TEMPORAL>3.9</CVSS_TEMPORAL>
115
+ <CVSS_V3>
116
+ <BASE>6.1</BASE>
117
+ <TEMPORAL>5.8</TEMPORAL>
118
+ <ATTACK_VECTOR>Network</ATTACK_VECTOR>
119
+ </CVSS_V3>
120
+ </QID>
121
+ </QID_LIST>
122
+ </GLOSSARY>
123
+ <APPENDIX>
124
+ <WEBAPP>
125
+ <ID>1</ID>
126
+ <NAME>Test</NAME>
127
+ <URL>http://example.com</URL>
128
+ <OWNER>Test User</OWNER>
129
+ <SCOPE>Limit to URL hostname</SCOPE>
130
+ <CUSTOM_ATTRIBUTES/>
131
+ <TAGS/>
132
+ </WEBAPP>
133
+ </APPENDIX>
134
+ </WAS_SCAN_REPORT>
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module Dradis::Plugins
5
+ describe 'Qualys upload plugin' do
6
+ before(:each) do
7
+ # Stub template service
8
+ templates_dir = File.expand_path('../../../../templates', __FILE__)
9
+ expect_any_instance_of(Dradis::Plugins::TemplateService)
10
+ .to receive(:default_templates_dir).and_return(templates_dir)
11
+
12
+ stub_content_service
13
+
14
+ @importer = Dradis::Plugins::Qualys::Asset::Importer.new(
15
+ content_service: @content_service
16
+ )
17
+ end
18
+
19
+ let(:example_xml) { 'spec/fixtures/files/simple_asset.xml' }
20
+ let(:run_import!) { @importer.import(file: example_xml) }
21
+
22
+ it 'creates nodes as needed' do
23
+ expect_to_create_node_with(label: '10.0.2.8')
24
+ run_import!
25
+ end
26
+
27
+ it 'creates issues as needed' do
28
+ expect_to_create_issue_with(text: 'Hidden RPC Services')
29
+ run_import!
30
+ end
31
+
32
+ it 'creates evidence as needed' do
33
+ expect_to_create_evidence_with(
34
+ content: 'http://example.com',
35
+ issue: 'Hidden RPC Services',
36
+ node_label: '10.0.2.8'
37
+ )
38
+ run_import!
39
+ end
40
+ end
41
+ end
@@ -5,37 +5,15 @@ module Dradis::Plugins
5
5
  describe 'Qualys upload plugin' do
6
6
  before(:each) do
7
7
  # Stub template service
8
- templates_dir = File.expand_path('../../../templates', __FILE__)
8
+ templates_dir = File.expand_path('../../../../templates', __FILE__)
9
9
  expect_any_instance_of(Dradis::Plugins::TemplateService)
10
10
  .to receive(:default_templates_dir).and_return(templates_dir)
11
11
 
12
- # Init services
13
- plugin = Dradis::Plugins::Qualys
12
+ stub_content_service
14
13
 
15
- @content_service = Dradis::Plugins::ContentService::Base.new(
16
- logger: Logger.new(STDOUT),
17
- plugin: plugin
18
- )
19
-
20
- @importer = Dradis::Plugins::Qualys::Importer.new(
14
+ @importer = Dradis::Plugins::Qualys::Vuln::Importer.new(
21
15
  content_service: @content_service
22
16
  )
23
-
24
- # Stub dradis-plugins methods
25
- #
26
- # They return their argument hashes as objects mimicking
27
- # Nodes, Issues, etc
28
- allow(@content_service).to receive(:create_node) do |args|
29
- obj = OpenStruct.new(args)
30
- obj.define_singleton_method(:set_property) { |_, __| }
31
- obj
32
- end
33
- allow(@content_service).to receive(:create_issue) do |args|
34
- OpenStruct.new(args)
35
- end
36
- allow(@content_service).to receive(:create_evidence) do |args|
37
- OpenStruct.new(args)
38
- end
39
17
  end
40
18
 
41
19
  let(:example_xml) { 'spec/fixtures/files/simple.xml' }
@@ -84,12 +62,12 @@ module Dradis::Plugins
84
62
  expect_to_create_issue_with(
85
63
  text: "Apache 1.3 HTTP Server Expect Header Cross-Site Scripting"
86
64
  )
87
-
65
+
88
66
  expect_to_create_issue_with(
89
67
  text: "Apache Web Server ETag Header Information Disclosure Weakness",
90
68
  text: "OpenBSD has released a \"patch\":ftp://ftp.openbsd.org/pub/OpenBSD/patches/3.2/common/008_httpd.patch that fixes this vulnerability. After installing the patch, inode numbers returned from the server are encoded using a private hash to avoid the release of sensitive information.\n\n\n\nCustomers"
91
69
  )
92
-
70
+
93
71
  run_import!
94
72
  end
95
73
 
@@ -165,28 +143,5 @@ module Dradis::Plugins
165
143
  @importer.import(file: 'spec/fixtures/files/no_result.xml')
166
144
  end
167
145
  end
168
-
169
-
170
- def expect_to_create_node_with(label:)
171
- expect(@content_service).to receive(:create_node).with(
172
- hash_including label: label
173
- ).once
174
- end
175
-
176
- def expect_to_create_issue_with(text:)
177
- expect(@content_service).to receive(:create_issue) do |args|
178
- expect(args[:text]).to include text
179
- OpenStruct.new(args)
180
- end.once
181
- end
182
-
183
- def expect_to_create_evidence_with(content:, issue:, node_label:)
184
- expect(@content_service).to receive(:create_evidence) do |args|
185
- expect(args[:content]).to include content
186
- expect(args[:issue].text).to include issue
187
- expect(args[:node].label).to eq node_label
188
- end.once
189
- end
190
-
191
146
  end
192
147
  end