dradis-acunetix 3.21.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2bc712213246678b841ed4688437086c3b414272cce89f2146979b9039d3cdb7
4
- data.tar.gz: a8f11a4e761a038e88c39728f2b91daf53274f0c8865cfe4c56f7ec4c4a6a07d
3
+ metadata.gz: 51556b55f942044ecfee72c442aae44020e9285a7b7296c3ad0574b47e40aaad
4
+ data.tar.gz: 2a9502eec3842ead36eb9e5160a1a5c87a5b05a35d589895a210cba2e736e3ff
5
5
  SHA512:
6
- metadata.gz: 70a09b2f5efe78c69a5c752c4831dbfffe6747130191d45e404b208db984ad18eacf566af93c71a16845f9ad2688c72cb339a6b61b0ba33c1c49bce943bc2ba5
7
- data.tar.gz: f435cedb8c3cbc542257b19e7297b239a4653ae1c01dbc4fc29c76c725a75182630db4a31ce91b85e2939e491f9a43c0a39ad9b0b2084e2013d0b5e8aaa6bf44
6
+ metadata.gz: a879fdecfdf4db243a812bdb0d5c4ac7ae45a63b4b274c5f627a5f957d99ce6a07dd74dc7b1d1f0b82fd72c45e901f612c4ffa404dd6e04262a3fa6c20181800
7
+ data.tar.gz: 0e4e6f8c93dda9f65850d0adcd18a87dd49cec9c1e7cc726b253780a7fc4ef905a035ead6aa89f3f4551cf34d352838c39f69373089422ea0960d3fc9d370628
data/CHANGELOG.md CHANGED
@@ -1,78 +1,60 @@
1
- ## Dradis Framework 3.21 (February, 2021) #
1
+ v4.2.0 (February 2022)
2
+ - No changes
2
3
 
3
- * No changes
4
+ v4.1.0 (November 2021)
5
+ - No changes
4
6
 
7
+ v4.0.0 (July 2021)
8
+ - Add support for Acunetix 360
9
+ - Make Request and Response fields available at the Evidence level
5
10
 
6
- ## Dradis Framework 3.20 (December, 2020) #
11
+ v3.22.0 (April 2021)
12
+ - No changes
7
13
 
8
- * No changes
14
+ v3.21.0 (February 2021)
15
+ - No changes
9
16
 
17
+ v3.20.0 (December 2020)
18
+ - No changes
10
19
 
11
- ## Dradis Framework 3.19 (September, 2020) #
20
+ v3.19.0 (September 2020)
21
+ - No changes
12
22
 
13
- * No changes
23
+ v3.18.0 (July 2020)
24
+ - No changes
14
25
 
26
+ v3.17.0 (May 2020)
27
+ - No changes
15
28
 
16
- ## Dradis Framework 3.18 (July, 2020) #
29
+ v3.16.0 (February 2020)
30
+ - No changes
17
31
 
18
- * No changes
32
+ v3.15.0 (November 2019)
33
+ - No changes
19
34
 
35
+ v3.14.0 (August 2019)
36
+ - No changes
20
37
 
21
- ## Dradis Framework 3.17 (May, 2020) #
38
+ v3.13.0 (June 2019)
39
+ - No changes
22
40
 
23
- * No changes
41
+ v3.12.0 (March 2019)
42
+ - Resolves create_node errors that appeared with URLs without "http"
24
43
 
44
+ v3.11.0 (November 2018)
45
+ - No changes
25
46
 
26
- ## Dradis Framework 3.16 (February, 2020) #
47
+ v3.10.0 (August 2018)
48
+ - No changes
27
49
 
28
- * No changes
50
+ v3.9.0 (January 2018)
51
+ - Add Node properties from Scan template fields (v3.8.1)
29
52
 
53
+ v3.8.0 (September 2017)
54
+ - No changes
30
55
 
31
- ## Dradis Framework 3.15 (November, 2019) #
56
+ v3.7.0 (July 2017)
57
+ - Better HTML substitutions (thanks @MrJester)
32
58
 
33
- * No changes
34
-
35
-
36
- ## Dradis Framework 3.14 (August, 2019) #
37
-
38
- * No changes
39
-
40
-
41
- ## Dradis Framework 3.13 (June, 2019) #
42
-
43
- * No changes
44
-
45
-
46
- ## Dradis Framework 3.12 (March, 2019) #
47
-
48
- * Resolves create_node errors that appeared with URLs without "http"
49
-
50
-
51
- ## Dradis Framework 3.11 (November, 2018) #
52
-
53
- * No changes
54
-
55
-
56
- ## Dradis Framework 3.10 (August, 2018) #
57
-
58
- * No changes
59
-
60
-
61
- ## Dradis Framework 3.9 (January, 2018) #
62
-
63
- * Add Node properties from Scan template fields (v3.8.1)
64
-
65
-
66
- ## Dradis Framework 3.8 (September, 2017) ##
67
-
68
- * No changes
69
-
70
-
71
- ## Dradis Framework 3.7 (July, 2017) ##
72
-
73
- * Better HTML substitutions (thanks @MrJester).
74
-
75
-
76
- ## Dradis Framework 3.6 (March, 2017) ##
77
-
78
- * Fix error in how <ul> and <li> tags were being imported.
59
+ v3.6.0 (March 2017)
60
+ - Fix error in how <ul> and <li> tags were being imported
@@ -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]
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  # versions of Rails (a sure recipe for disaster, I'm sure), which is needed
26
26
  # until we bump Dradis Pro to 4.1.
27
27
  # s.add_dependency 'rails', '~> 4.1.1'
28
- spec.add_dependency 'dradis-plugins', '~> 3.6'
28
+ spec.add_dependency 'dradis-plugins', '~> 4.0'
29
29
  spec.add_dependency 'nokogiri', '~> 1.3'
30
30
 
31
31
  spec.add_development_dependency 'bundler', '~> 1.6'
@@ -0,0 +1,77 @@
1
+ module Acunetix
2
+ module Cleanup
3
+ private
4
+
5
+ # Convert HTML in the text to Textile format
6
+ def cleanup_html(source)
7
+ result = source.dup
8
+
9
+ format_table(result)
10
+
11
+ result.gsub!(/&quot;/, '"')
12
+ result.gsub!(/&amp;/, '&')
13
+ result.gsub!(/&lt;/, '<')
14
+ result.gsub!(/&gt;/, '>')
15
+
16
+ result.gsub!(/<b>(.*?)<\/b>/) { "*#{$1.strip}*" }
17
+ result.gsub!(/<br\/>/, "\n")
18
+ result.gsub!(/<div(.*?)>|<\/div>/, '')
19
+ result.gsub!(/<a.*?>(.*?)<\/a>/m, '\1')
20
+ result.gsub!(/<font.*?>(.*?)<\/font>/m, '\1')
21
+ result.gsub!(/<h2>(.*?)<\/h2>/) { "*#{$1.strip}*" }
22
+ result.gsub!(/<i>(.*?)<\/i>/, '\1')
23
+ result.gsub!(/<p.*?>(.*?)<\/p>/) { "p. #{$1.strip}\n" }
24
+ result.gsub!(/<code><pre.*?>(.*?)<\/pre><\/code>/m){|m| "\n\nbc.. #{$1.strip}\n\np. \n" }
25
+ result.gsub!(/<code>(.*?)<\/code>/) { "\n\nbc. #{$1.strip}\n\n" }
26
+ result.gsub!(/<pre.*?>(.*?)<\/pre>/m){|m| "\n\nbc.. #{$1.strip}\n\np. \n" }
27
+
28
+ result.gsub!(/<li.*?>([\s\S]*?)<\/li>/m){"\n* #{$1.strip}"}
29
+ result.gsub!(/<ul>([\s\S]*?)<\/ul>/m){ "#{$1.strip}\n" }
30
+ result.gsub!(/(<ul>)|(<\/ul>|(<ol>)|(<\/ol>))/, "\n")
31
+ result.gsub!(/<li>/, "\n* ")
32
+ result.gsub!(/<\/li>/, "\n")
33
+
34
+ result.gsub!(/<strong>(.*?)<\/strong>/) { "*#{$1.strip}*" }
35
+ result.gsub!(/<span.*?>(.*?)<\/span>/m){"#{$1.strip}\n"}
36
+
37
+ result
38
+ end
39
+
40
+ # Replace periods for commas as decimals
41
+ def cleanup_decimals(source)
42
+ result = source.dup
43
+ result.gsub!(/([0-9])\,([0-9])/, '\1.\2')
44
+ result
45
+ end
46
+
47
+ def format_table(str)
48
+ return unless str.include?('</table>')
49
+
50
+ str.gsub!(/<table.*?>[\s\S]*<\/table>/) do |table|
51
+ rows = ['']
52
+
53
+ table.scan(/<tr>[\s\S]*?<\/tr>/).each do |tr|
54
+ row = '|'
55
+
56
+ tr.scan(/<td.*?>[\s\S]*?<\/td>/).each do |data|
57
+ header = rows.empty? ? '_. ' : ''
58
+ row << "#{header}#{data.gsub(/<td.*?>|<\/td>/, '')}|"
59
+ end
60
+
61
+ rows << row
62
+ end
63
+
64
+ rows.join("\n")
65
+ end
66
+ end
67
+
68
+ # Some of the values have embedded HTML conent that we need to strip
69
+ def tags_with_html_content
70
+ [:details, :description, :detailed_information, :impact, :recommendation]
71
+ end
72
+
73
+ def tags_with_commas
74
+ [:cvss3_score, :cvss3_tempscore, :cvss3_envscore]
75
+ end
76
+ end
77
+ end
@@ -8,6 +8,8 @@ module Acunetix
8
8
  # Instead of providing separate methods for each supported property we rely
9
9
  # on Ruby's #method_missing to do most of the work.
10
10
  class ReportItem
11
+ include Cleanup
12
+
11
13
  attr_accessor :xml
12
14
 
13
15
  # Accepts an XML node from Nokogiri::XML.
@@ -113,37 +115,6 @@ module Acunetix
113
115
 
114
116
  private
115
117
 
116
- def cleanup_html(source)
117
- result = source.dup
118
- result.gsub!(/&quot;/, '"')
119
- result.gsub!(/&amp;/, '&')
120
- result.gsub!(/&lt;/, '<')
121
- result.gsub!(/&gt;/, '>')
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
118
  def references_list
148
119
  references = ''
149
120
  xml.xpath('./References/Reference').each do |xml_reference|
@@ -154,15 +125,5 @@ module Acunetix
154
125
  end
155
126
  references
156
127
  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
128
  end
168
129
  end
@@ -0,0 +1,110 @@
1
+ module Acunetix
2
+ class Vulnerability
3
+ include Cleanup
4
+
5
+ attr_accessor :xml
6
+
7
+ # Accepts an XML node from Nokogiri::XML.
8
+ def initialize(xml_node)
9
+ @xml = xml_node
10
+ end
11
+
12
+ def supported_tags
13
+ [
14
+ # Vulnerability fields
15
+ :capec, :certainty, :confirmed, :cvss31_base, :cvss31_environmental,
16
+ :cvss31_temporal, :cvss31_vector, :cvss_base, :cvss_environmental,
17
+ :cvss_temporal, :cvss_vector, :cwe, :description, :exploitation_skills,
18
+ :external_references, :hipaa, :impact, :iso27001, :name, :owasp,
19
+ :owasppc, :pci32, :remedial_actions, :remedial_procedure,
20
+ :remedy_references, :severity, :state, :type, :url, :wasc,
21
+
22
+ # Evidence fields
23
+ :http_request, :http_request_method,
24
+ :http_response, :http_response_status_code, :http_response_duration
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
+ translations_table = vulnerability_table.merge(evidence_table)
52
+
53
+ method_name = translations_table.fetch(method, method.to_s.dasherize)
54
+
55
+ # then we try the children tags
56
+ tag = xml.at_xpath("./#{method_name}")
57
+ if tag && !tag.text.blank?
58
+ if tags_with_html_content.include?(method)
59
+ return cleanup_html(tag.text)
60
+ else
61
+ return tag.text
62
+ end
63
+ else
64
+ 'n/a'
65
+ end
66
+
67
+ # nothing found
68
+ return nil
69
+ end
70
+
71
+ private
72
+
73
+ # Define a hash to get the actual XPATH operator we will use to
74
+ # find the field value, given a field name.
75
+ def vulnerability_table
76
+ owasp_fields = [
77
+ :owasp, :wasc, :cwe, :capec, :pci32, :hipaa, :owasppc, :iso27001
78
+ ]
79
+ vulnerability_table = {
80
+ cvss_vector: 'cvss/vector',
81
+ cvss_base: 'cvss/score/type[. = "Base"]/following::value',
82
+ cvss_temporal: 'cvss/score/type[. = "Temporal"]/following::value',
83
+ cvss_environmental: 'cvss/score/type[. = "Environmental"]/following::value',
84
+ cvss31_vector: 'cvss31/vector',
85
+ cvss31_base: 'cvss31/score/type[. = "Base"]/following::value',
86
+ cvss31_temporal: 'cvss31/score/type[. = "Temporal"]/following::value',
87
+ cvss31_environmental: 'cvss31/score/type[. = "Environmental"]/following::value',
88
+ }
89
+
90
+ vulnerability_table.merge! Hash[owasp_fields.map { |field| [field, field.to_s] }]
91
+
92
+ # Append the 'classifications' parent to each translated field name
93
+ vulnerability_table.each do |_, value|
94
+ value.replace("classification/#{value}")
95
+ end
96
+
97
+ vulnerability_table
98
+ end
99
+
100
+ def evidence_table
101
+ {
102
+ http_request: 'http-request/content',
103
+ http_request_method: 'http-request/method',
104
+ http_response: 'http-response/content',
105
+ http_response_status_code: 'http-response/status-code',
106
+ http_response_duration: 'http-response/duration'
107
+ }
108
+ end
109
+ end
110
+ end
@@ -4,11 +4,15 @@ module Dradis::Plugins::Acunetix
4
4
  class FieldProcessor < Dradis::Plugins::Upload::FieldProcessor
5
5
 
6
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
7
+ @acunetix_object =
8
+ case data.name
9
+ when 'Scan'
10
+ ::Acunetix::Scan.new(data)
11
+ when 'vulnerability'
12
+ ::Acunetix::Vulnerability.new(data)
13
+ else
14
+ ::Acunetix::ReportItem.new(data)
15
+ end
12
16
  end
13
17
 
14
18
  def value(args={})
@@ -0,0 +1,51 @@
1
+ module Dradis::Plugins::Acunetix::Formats
2
+ module Acunetix360
3
+
4
+ private
5
+
6
+ def process_acunetix360
7
+ process_target_node
8
+ process_acunetix360_vulnerabilities
9
+ end
10
+
11
+ def process_target_node
12
+ target_xml = xml.at_xpath('//acunetix-360/target')
13
+ @scan_node = content_service.create_node(
14
+ label: target_xml.at_xpath('url').text,
15
+ type: :host
16
+ )
17
+
18
+ logger.info { "Creating target node: #{scan_node.label}" }
19
+
20
+ if scan_node.respond_to?(:properties)
21
+ scan_node.set_property(:scan_id, target_xml.at_xpath('scan-id').text)
22
+ scan_node.set_property(:initiated, target_xml.at_xpath('initiated').text)
23
+ scan_node.set_property(:duration, target_xml.at_xpath('duration').text)
24
+ end
25
+ end
26
+
27
+ def process_acunetix360_vulnerabilities
28
+ logger.info { 'Creating issues from Acunetix360 vulnerabilities.' }
29
+
30
+ xml.xpath('//acunetix-360/vulnerabilities/vulnerability').each do |vuln_xml|
31
+ issue_text = template_service.process_template(
32
+ template: 'vulnerability_360',
33
+ data: vuln_xml
34
+ )
35
+
36
+ type = vuln_xml.at_xpath('type').text
37
+
38
+ logger.info { "\t\t => Creating new issue: #{type}" }
39
+ issue = content_service.create_issue(text: issue_text, id: type)
40
+
41
+ evidence_text = template_service.process_template(
42
+ template: 'evidence_360',
43
+ data: vuln_xml
44
+ )
45
+
46
+ logger.info { "\t\t => Creating new evidence" }
47
+ content_service.create_evidence(issue: issue, node: scan_node, content: evidence_text)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,58 @@
1
+ module Dradis::Plugins::Acunetix::Formats
2
+ module Standard
3
+
4
+ private
5
+
6
+ def process_standard
7
+ xml.xpath('/ScanGroup/Scan').each do |xml_scan|
8
+ process_scan(xml_scan)
9
+ end
10
+ end
11
+
12
+ def process_scan(xml_scan)
13
+ url = xml_scan.at_xpath('./StartURL').text()
14
+ start_url = URI::parse(url).host || url # urls wo/ protocol returned nil
15
+
16
+ self.scan_node = content_service.create_node(label: start_url, type: :host)
17
+ logger.info{ "\tScan start URL: #{start_url}" }
18
+
19
+ # Define Node properties
20
+ if scan_node.respond_to?(:properties)
21
+ scan_node.set_property(:short_name, xml_scan.at_xpath('./ShortName').text() )
22
+ scan_node.set_property(:start_url, start_url)
23
+ scan_node.set_property(:start_time, xml_scan.at_xpath('./StartTime').text() )
24
+ scan_node.set_property(:finish_time, xml_scan.at_xpath('./FinishTime').text() )
25
+ scan_node.set_property(:scan_time, xml_scan.at_xpath('./ScanTime').text() )
26
+ scan_node.set_property(:aborted, xml_scan.at_xpath('./Aborted').text() )
27
+ scan_node.set_property(:responsive, xml_scan.at_xpath('./Responsive').text() )
28
+ scan_node.set_property(:banner, xml_scan.at_xpath('./Banner').text() )
29
+ scan_node.set_property(:os, xml_scan.at_xpath('./Os').text() )
30
+ scan_node.set_property(:web_server, xml_scan.at_xpath('./WebServer').text() )
31
+ scan_node.set_property(:technologies, xml_scan.at_xpath('./Technologies').text() )
32
+ scan_node.save
33
+ end
34
+
35
+ scan_note = template_service.process_template(template: 'scan', data: xml_scan)
36
+ content_service.create_note text: scan_note, node: scan_node
37
+
38
+ xml_scan.xpath('./ReportItems/ReportItem').each do |xml_report_item|
39
+ process_report_item(xml_report_item)
40
+ end
41
+ end
42
+
43
+ def process_report_item(xml_report_item)
44
+ plugin_id = "%s/%s" % [
45
+ xml_report_item.at_xpath('./ModuleName').text(),
46
+ xml_report_item.at_xpath('./Name').text()
47
+ ]
48
+ logger.info { "\t\t => Creating new issue (plugin_id: #{plugin_id})" }
49
+
50
+ issue_text = template_service.process_template(template: 'report_item', data: xml_report_item)
51
+ issue = content_service.create_issue(text: issue_text, id: plugin_id)
52
+
53
+ logger.info { "\t\t => Creating new evidence" }
54
+ evidence_content = template_service.process_template(template: 'evidence', data: xml_report_item)
55
+ content_service.create_evidence(issue: issue, node: scan_node, content: evidence_content)
56
+ end
57
+ end
58
+ end
@@ -7,8 +7,8 @@ module Dradis
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 3
11
- MINOR = 21
10
+ MAJOR = 4
11
+ MINOR = 2
12
12
  TINY = 0
13
13
  PRE = nil
14
14
 
@@ -1,5 +1,12 @@
1
+ require 'dradis/plugins/acunetix/formats/standard'
2
+ require 'dradis/plugins/acunetix/formats/acunetix360'
3
+
1
4
  module Dradis::Plugins::Acunetix
2
5
  class Importer < Dradis::Plugins::Upload::Importer
6
+ include Dradis::Plugins::Acunetix::Formats::Standard
7
+ include Dradis::Plugins::Acunetix::Formats::Acunetix360
8
+
9
+ attr_accessor :scan_node, :xml
3
10
 
4
11
  # The framework will call this function if the user selects this plugin from
5
12
  # the dropdown list and uploads a file.
@@ -8,71 +15,25 @@ module Dradis::Plugins::Acunetix
8
15
  file_content = File.read( params.fetch(:file) )
9
16
 
10
17
  logger.info{'Parsing Acunetix output file...'}
11
- @doc = Nokogiri::XML( file_content )
18
+ @xml = Nokogiri::XML( file_content )
12
19
  logger.info{'Done.'}
13
20
 
14
- if @doc.xpath('/ScanGroup/Scan').empty?
21
+ if xml.xpath('/ScanGroup/Scan').present?
22
+ logger.info { 'Standard Acunetix import detected.' }
23
+ process_standard
24
+
25
+ return true
26
+ elsif xml.xpath('//acunetix-360').present?
27
+ logger.info { 'Acunetix360 import detected.' }
28
+ process_acunetix360
29
+
30
+ return true
31
+ else
15
32
  error = "No scan results were detected in the uploaded file (/ScanGroup/Scan). Ensure you uploaded an Acunetix XML report."
16
33
  logger.fatal{ error }
17
34
  content_service.create_note text: error
18
35
  return false
19
36
  end
20
-
21
- @doc.xpath('/ScanGroup/Scan').each do |xml_scan|
22
- process_scan(xml_scan)
23
- end
24
-
25
- return true
26
37
  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
38
  end
78
39
  end
@@ -5,5 +5,7 @@ require 'dradis-plugins'
5
5
  require 'dradis/plugins/acunetix'
6
6
 
7
7
  # load supporting Acunetix classes
8
+ require 'acunetix/concerns/cleanup'
8
9
  require 'acunetix/report_item'
9
- require 'acunetix/scan'
10
+ require 'acunetix/scan'
11
+ require 'acunetix/vulnerability'
@@ -5,3 +5,5 @@ evidence.aop_source_file
5
5
  evidence.aop_source_line
6
6
  evidence.aop_additional
7
7
  evidence.is_false_positive
8
+ evidence.request
9
+ evidence.response
@@ -9,4 +9,24 @@
9
9
  <AOP_SourceLine>0</AOP_SourceLine>
10
10
  <AOP_Additional><![CDATA[]]></AOP_Additional>
11
11
  <IsFalsePositive><![CDATA[False]]></IsFalsePositive>
12
- </ReportItem>
12
+ <TechnicalDetails>
13
+ <Request><![CDATA[GET /hpp/params.php?p=1'%22()%26%25&lt;ScRiPt%20&gt;prompt(951846)&lt;/ScRiPt&gt;&amp;pp=1 HTTP/1.1
14
+ Referer: http://testphp.vulnweb.com:80/
15
+ Host: testphp.vulnweb.com
16
+ Connection: Keep-alive
17
+ Accept-Encoding: gzip,deflate
18
+ User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36
19
+ Accept: */*
20
+
21
+ ]]></Request>
22
+ <Response><![CDATA[HTTP/1.1 200 OK
23
+ Server: nginx/1.4.1
24
+ Date: Tue, 07 Oct 2014 17:30:28 GMT
25
+ Content-Type: text/html
26
+ Connection: keep-alive
27
+ X-Powered-By: PHP/5.3.10-1~lucid+2uwsgi2
28
+ Original-Content-Encoding: gzip
29
+ Content-Length: 40
30
+ ]]></Response>
31
+ </TechnicalDetails>
32
+ </ReportItem>
@@ -0,0 +1,5 @@
1
+ evidence_360.http_request
2
+ evidence_360.http_request_method
3
+ evidence_360.http_response
4
+ evidence_360.http_response_status_code
5
+ evidence_360.http_response_duration
@@ -0,0 +1,114 @@
1
+ <vulnerability>
2
+ <http-request>
3
+ <method>GET</method>
4
+ <parameters>
5
+ <parameter name="param1" type="UrlRewrite" value="&amp;apos;))&amp;#32;WAITFOR&amp;#32;DELAY&amp;#32;&amp;apos;0:0:25&amp;apos;--" vulnerable="vulnerable" />
6
+ </parameters>
7
+ <content><![CDATA[GET /blog/%27))%20WAITFOR%20DELAY%20%270%3a0%3a25%27--/ HTTP/1.1
8
+ Host: aspnet.testsparker.com
9
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
10
+ Accept-Encoding: gzip, deflate
11
+ Accept-Language: en-us,en;q=0.5
12
+ Cache-Control: no-cache
13
+ Cookie: ASP.NET_SessionId=44lomqqluxhcl2e4yxvrmxsq; TestCookie=Hello
14
+ Referer: http://aspnet.testsparker.com/Blogs.aspx
15
+ User-Agent: Mozilla/5.0 (Windows NT 10.0; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
16
+ X-Scanner: Acunetix 360
17
+
18
+ ]]></content>
19
+ </http-request>
20
+ <http-response>
21
+ <status-code>404</status-code>
22
+ <duration>25024.4049</duration>
23
+ <content><![CDATA[HTTP/1.1 404 Not Found
24
+ Server: Microsoft-IIS/8.5
25
+ X-Powered-By: ASP.NET
26
+ X-AspNet-Version: 4.0.30319
27
+ Content-Length: 3084
28
+ Content-Type: text/html; charset=utf-8
29
+ Date: Tue, 16 Jun 2020 13:15:01 GMT
30
+ Cache-Control: private
31
+
32
+
33
+
34
+ <!DOCTYPE html>
35
+
36
+ <html xmlns="http://www.w3.org/1999/xhtml">
37
+ <head><meta http-equiv="content-type" content="text/html; charset=UTF-8" /><meta charset="utf-8" /><title>
38
+ Bitcoin Web Site
39
+ </title><meta name="generator" content="Bootply" /><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /><link href="//maxcdn.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet" /><link href="/statics/style.css" rel="stylesheet" />
40
+ <!--[if lt IE 9]>
41
+ <script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
42
+ <![endif]-->
43
+ </head>
44
+ <body>
45
+ <div id="resetbar">
46
+ This website is automatically reset at every midnight (00:00 - UTC).
47
+ </div>
48
+ <form method="post" action="" id="form1">
49
+ <div class="aspNetHidden">
50
+ <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJLTIzMTExOTgyZGSsxJXO6Juz0H9WnmLaZ/ANH9shOpBmzSi1EHH6egImZA==" />
51
+ </div>
52
+
53
+ <div class="aspNetHidden">
54
+
55
+ <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="5C9CE5AE" />
56
+ </div>
57
+ <div class="navbar navbar-default">
58
+ <div class="container">
59
+
60
+ <a class="navbar-brand">Bitcoin Web Site</a>
61
+ <ul class="nav navbar-nav">
62
+ <li><a href="/Default.aspx">Home</a></li>
63
+ <li><a href="/Blogs.aspx">Blog</a></li>
64
+ <li><a href="/Shop.aspx">Shop</a></li>
65
+ <li><a href="/Converter.aspx">Converter & Pricings</a></li>
66
+ <li><a href="/Request.aspx?r=/statics/download/">Demo</a></li>
67
+ <li><a href="/Help.aspx">Help</a></li>
68
+ <li><a href="/Contact.aspx">Contact</a></li>
69
+ <li><a href="/administrator/Login.aspx">Login</a></li>
70
+ </ul>
71
+
72
+ </div>
73
+ </div>
74
+ <div class="container">
75
+ <div>
76
+ <!-- contentTop -->
77
+
78
+ </div>
79
+ <div class="row">
80
+ <!-- contentCenterMenu -->
81
+
82
+
83
+
84
+ <h1>
85
+ <span id="contentCenterMenu_blogSQLInjection_lblSubject"></span>
86
+ </h1>
87
+ <p>
88
+ <span id="contentCenterMenu_blogSQLInjection_lblDate" style="font-style:italic;"></span>
89
+ </p>
90
+ <p>
91
+ <span id="contentCenterMenu_blogSQLInjection_lblContent"></span>
92
+ </p>
93
+
94
+
95
+ </div>
96
+ <hr />
97
+ </div>
98
+ <!-- /container -->
99
+ <!-- script references -->
100
+ <div id="footer">
101
+ <div class="container">
102
+
103
+
104
+ <p class="muted credit"><a href="/redirect.aspx?site=bitcoin.org" target="_blank" rel="noopener noreferrer">Bitcoin Foundation.</a></p>
105
+ </div>
106
+ </div>
107
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
108
+ <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
109
+ </form>
110
+ </body>
111
+ </html>
112
+ ]]></content>
113
+ </http-response>
114
+ </vulnerability>
@@ -0,0 +1,5 @@
1
+ #[HTTP Request]#
2
+ %evidence_360.http_request%
3
+
4
+ #[HTTP Response]#
5
+ %evidence_360.http_response%
@@ -0,0 +1,30 @@
1
+ vulnerability_360.name
2
+ vulnerability_360.type
3
+ vulnerability_360.url
4
+ vulnerability_360.description
5
+ vulnerability_360.impact
6
+ vulnerability_360.remedial_actions
7
+ vulnerability_360.exploitation_skills
8
+ vulnerability_360.remedial_procedure
9
+ vulnerability_360.remedy_references
10
+ vulnerability_360.external_references
11
+ vulnerability_360.severity
12
+ vulnerability_360.certainty
13
+ vulnerability_360.confirmed
14
+ vulnerability_360.state
15
+ vulnerability_360.owasp
16
+ vulnerability_360.wasc
17
+ vulnerability_360.cwe
18
+ vulnerability_360.capec
19
+ vulnerability_360.pci32
20
+ vulnerability_360.hipaa
21
+ vulnerability_360.owasppc
22
+ vulnerability_360.iso27001
23
+ vulnerability_360.cvss_vector
24
+ vulnerability_360.cvss_base
25
+ vulnerability_360.cvss_temporal
26
+ vulnerability_360.cvss_environmental
27
+ vulnerability_360.cvss31_vector
28
+ vulnerability_360.cvss31_base
29
+ vulnerability_360.cvss31_temporal
30
+ vulnerability_360.cvss31_environmental
@@ -0,0 +1,90 @@
1
+ <vulnerability>
2
+ <LookupId>d202b64e-8451-407c-3680-abdc02f0038f</LookupId>
3
+ <url>http://aspnet.testsparker.com/blog/%27))%20WAITFOR%20DELAY%20%270%3a0%3a25%27--/</url>
4
+ <type>ConfirmedBlindSqlInjection</type>
5
+ <name>Blind SQL Injection</name>
6
+ <severity>Critical</severity>
7
+ <certainty>100</certainty>
8
+ <confirmed>True</confirmed>
9
+ <state>Present</state>
10
+ <FirstSeenDate>6/16/2020 1:41:23 PM +00:00</FirstSeenDate>
11
+ <LastSeenDate>6/16/2020 1:41:23 PM +00:00</LastSeenDate>
12
+ <classification>
13
+ <owasp>A1</owasp>
14
+ <wasc>19</wasc>
15
+ <cwe>89</cwe>
16
+ <capec>66</capec>
17
+ <pci32>6.5.1</pci32>
18
+ <hipaa>164.306(a), 164.308(a)</hipaa>
19
+ <owasppc></owasppc>
20
+ <iso27001>A.14.2.5</iso27001>
21
+
22
+
23
+ <cvss>
24
+ <vector>CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N</vector>
25
+
26
+ <score>
27
+ <type>Base</type>
28
+ <value>8.6</value>
29
+ <severity>High</severity>
30
+ </score>
31
+ <score>
32
+ <type>Temporal</type>
33
+ <value>8.6</value>
34
+ <severity>High</severity>
35
+ </score>
36
+ <score>
37
+ <type>Environmental</type>
38
+ <value>8.6</value>
39
+ <severity>High</severity>
40
+ </score>
41
+
42
+ </cvss>
43
+
44
+
45
+
46
+ <cvss31>
47
+ <vector>CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N</vector>
48
+
49
+ <score>
50
+ <type>Base</type>
51
+ <value>8.6</value>
52
+ <severity>High</severity>
53
+ </score>
54
+ <score>
55
+ <type>Temporal</type>
56
+ <value>8.6</value>
57
+ <severity>High</severity>
58
+ </score>
59
+ <score>
60
+ <type>Environmental</type>
61
+ <value>8.6</value>
62
+ <severity>High</severity>
63
+ </score>
64
+
65
+ </cvss31>
66
+ </classification>
67
+
68
+ <description><![CDATA[<p>Acunetix 360 identified a Blind SQL Injection, which occurs when data input by a user is interpreted as an SQL command rather than as normal data by the backend database.</p>
69
+ <p>This is an extremely common vulnerability and its successful exploitation can have critical implications.</p>
70
+ <p>Acunetix 360 <strong>confirmed</strong> the vulnerability by executing a test SQL query on the backend database. In these tests, SQL injection was not obvious, but the different responses from the page based on the injection test allowed us to identify and confirm the SQL injection.</p>]]></description>
71
+ <impact><![CDATA[<div>Depending on the backend database, the database connection settings, and the operating system, an attacker can mount one or more of the following attacks successfully:
72
+ <ul>
73
+ <li>Reading, updating and deleting arbitrary data or tables from the database</li>
74
+ <li>Executing commands on the underlying operating system</li>
75
+ </ul>
76
+ </div>]]></impact>
77
+ <remedial-actions><![CDATA[<div>
78
+ <ol>
79
+ <li>See the remedy for solution.</li>
80
+ <li>If you are not using a database access layer (DAL), consider using one. This will help you centralize the issue. You can also use ORM (<em>object relational mapping</em>). Most of the ORM systems use only parameterized queries and this can solve the whole SQL injection problem.</li>
81
+ <li>Locate the all dynamically generated SQL queries and convert them to parameterized queries. <em>(If you decide to use a DAL/ORM, change all legacy code to use these new libraries.)</em></li>
82
+ <li>Use your weblogs and application logs to see if there were any previous but undetected attacks to this resource.</li>
83
+ </ol>
84
+ </div>]]></remedial-actions>
85
+ <exploitation-skills><![CDATA[<div>There are numerous freely available tools to exploit SQL injection vulnerabilities. This is a complex area with many dependencies; however, it should be noted that the numerous resources available in this area have raised both attacker awareness of the issues and their ability to discover and leverage them. SQL injection is one of the most common web application vulnerabilities.</div>]]></exploitation-skills>
86
+ <remedial-procedure><![CDATA[<div>A robust method for mitigating the threat of SQL injection-based vulnerabilities is to use parameterized queries (<em>prepared statements</em>). Almost all modern languages provide built-in libraries for this. Wherever possible, do not create dynamic SQL queries or SQL queries with string concatenation.</div>]]></remedial-procedure>
87
+ <remedy-references><![CDATA[<div><ul><li><a target='_blank' href='https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet'><i class='icon-external-link'></i>SQL injection Prevention Cheat Sheet</a></li><li><a target='_blank' href='http://bobby-tables.com'><i class='icon-external-link'></i>A guide to preventing SQL injection</a></li></ul></div>]]></remedy-references>
88
+ <external-references><![CDATA[<div><ul><li><a target='_blank' href='https://www.owasp.org/index.php/Blind_SQL_Injection'><i class='icon-external-link'></i>Blind SQL Injection</a></li><li><a target='_blank' href='https://www.acunetix.com/blog/web-security/sql-injection-cheat-sheet/#BlindSQLInjections'><i class='icon-external-link'></i>SQL Injection Cheat Sheet[#Blind]</a></li><li><a target='_blank' href='https://www.owasp.org/index.php/SQL_injection'><i class='icon-external-link'></i>OWASP SQL injection</a></li><li><a target='_blank' href='https://www.acunetix.com/blog/web-security/sql-injection-vulnerability/'><i class='icon-external-link'></i>SQL Injection Vulnerability</a></li></ul></div>]]></external-references>
89
+ <proof-of-concept></proof-of-concept>
90
+ </vulnerability>
@@ -0,0 +1,74 @@
1
+ #[Title]#
2
+ %vulnerability_360.name%
3
+
4
+ #[Type]#
5
+ %vulnerability_360.type%
6
+
7
+ #[URL]#
8
+ %vulnerability_360.url%
9
+
10
+ #[Severity]#
11
+ %vulnerability_360.severity%
12
+
13
+ #[Description]#
14
+ %vulnerability_360.description%
15
+
16
+ #[Impact]#
17
+ %vulnerability_360.impact%
18
+
19
+ #[Certainty]#
20
+ %vulnerability_360.certainty%
21
+
22
+ #[Confirmed]#
23
+ %vulnerability_360.confirmed%
24
+
25
+ #[State]#
26
+ %vulnerability_360.state%
27
+
28
+ #[OWASP]#
29
+ %vulnerability_360.owasp%
30
+
31
+ #[WASC]#
32
+ %vulnerability_360.wasc%
33
+
34
+ #[CWE]#
35
+ %vulnerability_360.cwe%
36
+
37
+ #[CAPEC]#
38
+ %vulnerability_360.capec%
39
+
40
+ #[PCI32]#
41
+ %vulnerability_360.pci32%
42
+
43
+ #[HIPAA]#
44
+ %vulnerability_360.hipaa%
45
+
46
+ #[OWASPPC]#
47
+ %vulnerability_360.owasppc%
48
+
49
+ #[ISO27001]#
50
+ %vulnerability_360.iso27001%
51
+
52
+ #[CVSSVector]#
53
+ %vulnerability_360.cvss_vector%
54
+
55
+ #[CVSSBase]#
56
+ %vulnerability_360.cvss_base%
57
+
58
+ #[CVSSTemporal]#
59
+ %vulnerability_360.cvss_temporal%
60
+
61
+ #[CVSSEnvironmental]#
62
+ %vulnerability_360.cvss_environmental%
63
+
64
+ #[CVSS3Vector]#
65
+ %vulnerability_360.cvss31_vector%
66
+
67
+ #[CVSS3Base]#
68
+ %vulnerability_360.cvss31_base%
69
+
70
+ #[CVSS3Temporal]#
71
+ %vulnerability_360.cvss31_temporal%
72
+
73
+ #[CVSS3Environmental]#
74
+ %vulnerability_360.cvss31_environmental%
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dradis-acunetix
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.21.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Martin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-12 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dradis-plugins
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.6'
19
+ version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '3.6'
26
+ version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -107,18 +107,23 @@ files:
107
107
  - ".gitignore"
108
108
  - ".rspec"
109
109
  - CHANGELOG.md
110
+ - CHANGELOG.template
110
111
  - CONTRIBUTING.md
111
112
  - Gemfile
112
113
  - LICENSE
113
114
  - README.md
114
115
  - Rakefile
115
116
  - dradis-acunetix.gemspec
117
+ - lib/acunetix/concerns/cleanup.rb
116
118
  - lib/acunetix/report_item.rb
117
119
  - lib/acunetix/scan.rb
120
+ - lib/acunetix/vulnerability.rb
118
121
  - lib/dradis-acunetix.rb
119
122
  - lib/dradis/plugins/acunetix.rb
120
123
  - lib/dradis/plugins/acunetix/engine.rb
121
124
  - lib/dradis/plugins/acunetix/field_processor.rb
125
+ - lib/dradis/plugins/acunetix/formats/acunetix360.rb
126
+ - lib/dradis/plugins/acunetix/formats/standard.rb
122
127
  - lib/dradis/plugins/acunetix/gem_version.rb
123
128
  - lib/dradis/plugins/acunetix/importer.rb
124
129
  - lib/dradis/plugins/acunetix/version.rb
@@ -133,17 +138,23 @@ files:
133
138
  - templates/evidence.fields
134
139
  - templates/evidence.sample
135
140
  - templates/evidence.template
141
+ - templates/evidence_360.fields
142
+ - templates/evidence_360.sample
143
+ - templates/evidence_360.template
136
144
  - templates/report_item.fields
137
145
  - templates/report_item.sample
138
146
  - templates/report_item.template
139
147
  - templates/scan.fields
140
148
  - templates/scan.sample
141
149
  - templates/scan.template
150
+ - templates/vulnerability_360.fields
151
+ - templates/vulnerability_360.sample
152
+ - templates/vulnerability_360.template
142
153
  homepage: http://dradisframework.org
143
154
  licenses:
144
155
  - GPL-2
145
156
  metadata: {}
146
- post_install_message:
157
+ post_install_message:
147
158
  rdoc_options: []
148
159
  require_paths:
149
160
  - lib
@@ -158,8 +169,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
169
  - !ruby/object:Gem::Version
159
170
  version: '0'
160
171
  requirements: []
161
- rubygems_version: 3.2.4
162
- signing_key:
172
+ rubygems_version: 3.1.4
173
+ signing_key:
163
174
  specification_version: 4
164
175
  summary: Acunetix add-on for the Dradis Framework.
165
176
  test_files: