dradis-nexpose 3.6.0 → 3.7.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
  SHA1:
3
- metadata.gz: 0cdf3e6d6508a016228cb316d7ba3c19b4e7d3f8
4
- data.tar.gz: c4df403c70467bb4ef0b781250ae4c1e22f49bd6
3
+ metadata.gz: 5906571b0939ca05af44ed77f903eca17d542fe8
4
+ data.tar.gz: 4172453a4ed16226603a3d50805f8bfe96b6974d
5
5
  SHA512:
6
- metadata.gz: 5cd20b1775001e1590f1c1917d99df5149ca8fc06c5ba5e6a5f455a4c3d2d7376bcbb502b72c790b307d49d59a2e99296d805e55bd8c967036e1a9aa8837fc0b
7
- data.tar.gz: 67a3b673a71da3de579fcee576d6bbf4fbf6cf5c47ee00d67f22e59ab8c00f2d2574a9b641685e8e1eb6b40cb2abde57b7ef0039d758dcad6eab5f2525da932d
6
+ metadata.gz: 99d93a7c9ea22931e5860e0595b5cc04226212ff283e1ff710ab8a524b00ffde7cacc103934bc896a09637ce7ba28bb3de019fc33c716b17abc621f12e46e898
7
+ data.tar.gz: 82bd8f4ae1a88e9b2cddfc0a046733b9e1d2f632d09dad925fef45d2f07d0bcdd98fb764a16e446128cf08407981b4a8b06984cd41fc0c1577bc390c1ea97f24
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
- ## Dradis Framework 3.6 (March XX, 2017) ##
1
+ ## Dradis Framework 3.7 (July, 2017) ##
2
+
3
+ * Add full evidence template for exporting evidences.
4
+ * Fix issue resulting in Evidence with null content.
5
+
6
+
7
+ ## Dradis Framework 3.6 (March, 2017) ##
2
8
 
3
9
  * No changes.
@@ -6,21 +6,23 @@ module Dradis::Plugins::Nexpose
6
6
 
7
7
  def post_initialize(args={})
8
8
  if data.kind_of?(Hash) ||
9
- data.kind_of?(Nexpose::Scan) ||
10
9
  data.kind_of?(Nexpose::Node) ||
11
10
  data.kind_of?(Nexpose::Service) ||
11
+ data.kind_of?(Nexpose::Scan) ||
12
12
  data.kind_of?(Nexpose::Vulnerability)
13
13
  @nexpose_object = data
14
14
  else
15
15
  # XML from Plugin Manager
16
- if (data.name == 'scan')
17
- @nexpose_object = Nexpose::Scan.new(data)
18
- elsif (data.name == 'node')
16
+ if (data.name == 'node')
19
17
  # Full - node
20
18
  @nexpose_object = Nexpose::Node.new(data)
21
19
  elsif (data.name == 'service')
22
20
  # Full - service
23
21
  @nexpose_object = Nexpose::Service.new(data)
22
+ elsif (data.name == 'scan')
23
+ @nexpose_object = Nexpose::Scan.new(data)
24
+ elsif (data.name == 'test')
25
+ @nexpose_object = Nexpose::Test.new(data)
24
26
  else
25
27
  if data['added']
26
28
  # Full - vulnerability
@@ -86,4 +88,4 @@ module Dradis::Plugins::Nexpose
86
88
  rows.join("\n")
87
89
  end
88
90
  end
89
- end
91
+ end
@@ -9,7 +9,6 @@ module Dradis::Plugins::Nexpose::Formats
9
9
 
10
10
  @vuln_list = []
11
11
  evidence = Hash.new { |h, k| h[k] = {} }
12
- hosts = Array.new
13
12
 
14
13
  # First, extract scans
15
14
  scan_node = content_service.create_node(label: 'Nexpose Scan Summary')
@@ -55,8 +54,10 @@ module Dradis::Plugins::Nexpose::Formats
55
54
  xml_vuln.add_child("<hosts/>") unless xml_vuln.last_element_child.name == "hosts"
56
55
 
57
56
  if xml_vuln.xpath("./hosts/host[text()='#{nexpose_node.address}']").empty?
58
- xml_vuln.last_element_child.add_child( "<host>#{nexpose_node.address}</host>")
57
+ xml_vuln.last_element_child.add_child("<host>#{nexpose_node.address}</host>")
59
58
  end
59
+
60
+ evidence[test_id][nexpose_node.address] = node_test
60
61
  end
61
62
 
62
63
  nexpose_node.endpoints.each do |endpoint|
@@ -100,10 +101,10 @@ module Dradis::Plugins::Nexpose::Formats
100
101
  xml_vuln.add_child("<hosts/>") unless xml_vuln.last_element_child.name == "hosts"
101
102
 
102
103
  if xml_vuln.xpath("./hosts/host[text()='#{nexpose_node.address}']").empty?
103
- xml_vuln.last_element_child.add_child( "<host>#{nexpose_node.address}</host>")
104
+ xml_vuln.last_element_child.add_child("<host>#{nexpose_node.address}</host>")
104
105
  end
105
106
 
106
- evidence[test_id][nexpose_node.address] = service_test[:content]
107
+ evidence[test_id][nexpose_node.address] = service_test
107
108
  end
108
109
  end
109
110
  end
@@ -119,7 +120,10 @@ module Dradis::Plugins::Nexpose::Formats
119
120
  doc.xpath('//VulnerabilityDefinitions/vulnerability').each do |xml_vulnerability|
120
121
  id = xml_vulnerability['id'].downcase
121
122
  # if @vuln_list.include?(id)
122
- issue_text = template_service.process_template(template: 'full_vulnerability', data: xml_vulnerability)
123
+ issue_text = template_service.process_template(
124
+ template: 'full_vulnerability',
125
+ data: xml_vulnerability
126
+ )
123
127
 
124
128
  # retrieve hosts affected by this issue (injected in step 2)
125
129
  #
@@ -141,7 +145,10 @@ module Dradis::Plugins::Nexpose::Formats
141
145
  # if the node exists, this just returns it
142
146
  host_node = content_service.create_node(label: host_name, type: :host)
143
147
 
144
- evidence_content = evidence[id][host_name]
148
+ evidence_content = template_service.process_template(
149
+ template: 'full_evidence',
150
+ data: evidence[id][host_name]
151
+ )
145
152
  content_service.create_evidence(content: evidence_content, issue: issue, node: host_node)
146
153
  end
147
154
 
@@ -8,7 +8,7 @@ module Dradis
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 3
11
- MINOR = 6
11
+ MINOR = 7
12
12
  TINY = 0
13
13
  PRE = nil
14
14
 
@@ -7,6 +7,7 @@ require 'dradis/plugins/nexpose'
7
7
  # Non-dradis related files
8
8
  require 'nexpose/endpoint'
9
9
  require 'nexpose/node'
10
- require 'nexpose/scan'
11
10
  require 'nexpose/service'
11
+ require 'nexpose/scan'
12
+ require 'nexpose/test'
12
13
  require 'nexpose/vulnerability'
data/lib/nexpose/node.rb CHANGED
@@ -33,16 +33,7 @@ module Nexpose
33
33
  # Convert each ./test/test entry into a simple hash
34
34
  def tests(*args)
35
35
  @xml.xpath('./tests/test').collect do |xml_test|
36
- {
37
- :id => xml_test.attributes['id'],
38
- :status => xml_test.attributes['status'],
39
- # in some cases Nexpose doesn't include text content (e.g. udp-ipid-zero)
40
- :content => if (xml_para = xml_test.xpath('./Paragraph').first)
41
- xml_para.text.split("\n").collect(&:strip).reject{|line| line.empty?}.join("\n")
42
- else
43
- ""
44
- end
45
- }
36
+ Nexpose::Test.new(xml_test)
46
37
  end
47
38
  end
48
39
 
@@ -29,17 +29,8 @@ module Nexpose
29
29
 
30
30
  # Convert each ./test/test entry into a simple hash
31
31
  def tests(*args)
32
- @xml.xpath('./tests/test').collect do |xml_test|
33
- content = if xml_test.at_xpath('./Paragraph')
34
- xml_test.at_xpath('./Paragraph').text.split("\n").collect(&:strip).reject{|line| line.empty?}.join("\n")
35
- else
36
- 'n/a'
37
- end
38
- {
39
- id: xml_test.attributes['id'],
40
- status: xml_test.attributes['status'],
41
- content: content
42
- }
32
+ @xml.xpath('./tests/test').map do |xml_test|
33
+ Nexpose::Test.new(xml_test)
43
34
  end
44
35
  end
45
36
 
@@ -0,0 +1,23 @@
1
+ module Nexpose
2
+ class Test
3
+ def self.new(xml_node)
4
+ content =
5
+ if xml_node.at_xpath('./Paragraph')
6
+ xml_node.
7
+ at_xpath('./Paragraph').
8
+ text.
9
+ split("\n").
10
+ collect(&:strip).
11
+ reject { |line| line.empty? }.join("\n")
12
+ else
13
+ 'n/a'
14
+ end
15
+
16
+ {
17
+ id: xml_node.attributes['id'],
18
+ status: xml_node.attributes['status'],
19
+ content: content
20
+ }
21
+ end
22
+ end
23
+ end
@@ -25,7 +25,10 @@ module Nexpose
25
25
  :description, :solution,
26
26
 
27
27
  # multiple tags
28
- :references, :tags
28
+ :references, :tags,
29
+
30
+ # evidence tag
31
+ :details
29
32
  ]
30
33
  end
31
34
 
@@ -83,13 +86,27 @@ module Nexpose
83
86
 
84
87
  # Finally the enumerations: references, tags
85
88
  if method_name == 'references'
86
- @xml.xpath("./references/reference").collect{|entry| {:source => entry['source'], :text => entry.text} }
89
+ references =
90
+ @xml.xpath("./references/reference").map do |entry|
91
+ {:source => entry['source'], :text => entry.text}
92
+ end
93
+
94
+ return references
87
95
  elsif method == 'tags'
88
- @xml.xpath("./tags/tag").collect(&:text)
89
- else
90
- # nothing found, the tag is valid but not present in this ReportItem
91
- return nil
96
+ return @xml.xpath("./tags/tag").collect(&:text)
97
+ end
98
+
99
+ # Handle evidence creation
100
+ if method_name == 'details'
101
+ vuln_id = @xml.attributes['id'].value
102
+
103
+ return @xml.xpath("//test[@id='#{vuln_id}']/Paragraph").
104
+ text.split("\n").
105
+ collect(&:strip).
106
+ reject{|line| line.empty?}.join("\n")
92
107
  end
108
+
109
+ nil
93
110
  end
94
111
  end
95
112
  end
@@ -7,9 +7,6 @@ class NexposeTasks < Thor
7
7
  def upload(file_path)
8
8
  require 'config/environment'
9
9
 
10
- logger = Logger.new(STDOUT)
11
- logger.level = Logger::DEBUG
12
-
13
10
  unless File.exists?(file_path)
14
11
  $stderr.puts "** the file [#{file_path}] does not exist"
15
12
  exit -1
@@ -17,10 +14,8 @@ class NexposeTasks < Thor
17
14
 
18
15
  detect_and_set_project_scope
19
16
 
20
- importer = Dradis::Plugins::Nexpose::Importer.new(logger: logger)
17
+ importer = Dradis::Plugins::Nexpose::Importer.new(task_options)
21
18
  importer.import(file: file_path)
22
-
23
- logger.close
24
19
  end
25
20
 
26
21
  end
@@ -11,12 +11,13 @@ describe 'Nexpose upload plugin' do
11
11
  # Init services
12
12
  plugin = Dradis::Plugins::Nexpose
13
13
 
14
- @content_service = Dradis::Plugins::ContentService.new(plugin: plugin)
15
- template_service = Dradis::Plugins::TemplateService.new(plugin: plugin)
14
+ @content_service = Dradis::Plugins::ContentService::Base.new(
15
+ logger: Logger.new(STDOUT),
16
+ plugin: plugin
17
+ )
16
18
 
17
19
  @importer = plugin::Importer.new(
18
20
  content_service: @content_service,
19
- template_service: template_service
20
21
  )
21
22
 
22
23
  # Stub dradis-plugins methods
@@ -92,27 +93,23 @@ describe 'Nexpose upload plugin' do
92
93
  end.once
93
94
 
94
95
  expect(@content_service).to receive(:create_node) do |args|
95
- expect(args[:label]).to eq("123/udp (open)")
96
- expect(args[:parent].label).to eq("1.1.1.1")
96
+ expect(args[:label]).to eq("Definitions")
97
97
  OpenStruct.new(args)
98
98
  end.once
99
99
  expect(@content_service).to receive(:create_note) do |args|
100
100
  expect(args[:text]).to include("#[Title]#\nService name: NTP")
101
- expect(args[:node].label).to eq("123/udp (open)")
101
+ expect(args[:node].label).to eq("1.1.1.1")
102
102
  end.once
103
103
 
104
104
  expect(@content_service).to receive(:create_node) do |args|
105
- expect(args[:label]).to eq("161/udp (open)")
106
- expect(args[:parent].label).to eq("1.1.1.1")
105
+ expect(args[:label]).to eq("1.1.1.1")
107
106
  OpenStruct.new(args)
108
107
  end.once
109
108
  expect(@content_service).to receive(:create_note) do |args|
110
109
  expect(args[:text]).to include("#[Title]#\nService name: SNMP")
111
- expect(args[:node].label).to eq("161/udp (open)")
110
+ expect(args[:node].label).to eq("1.1.1.1")
112
111
  end.once
113
112
 
114
- expect(@content_service).to receive(:create_node).with(hash_including label: "Definitions").once
115
-
116
113
  expect(@content_service).to receive(:create_issue) do |args|
117
114
  expect(args[:text]).to include("#[Title]#\nApache HTTPD: error responses can expose cookies (CVE-2012-0053)")
118
115
  expect(args[:id]).to eq("ntp-clock-variables-disclosure")
@@ -125,10 +122,8 @@ describe 'Nexpose upload plugin' do
125
122
  OpenStruct.new(args)
126
123
  end.once
127
124
 
128
- expect(@content_service).to receive(:create_node).with(hash_including label: "1.1.1.1", type: :host).once
129
-
130
125
  expect(@content_service).to receive(:create_evidence) do |args|
131
- expect(args[:content]).to include("n/a")
126
+ expect(args[:content]).to include("#[ID]#\nntp-clock-variables-disclosure\n\n")
132
127
  expect(args[:issue].id).to eq("ntp-clock-variables-disclosure")
133
128
  expect(args[:node].label).to eq("1.1.1.1")
134
129
  end.once
@@ -0,0 +1,3 @@
1
+ evidence.id
2
+ evidence.status
3
+ evidence.content
@@ -0,0 +1,17 @@
1
+ <test id="http-coldfusion-cfide-unprotected" key="/CFIDE/adminapi/base.cfc?wsdl" status="vulnerable-exploited" scan-id="4" vulnerable-since="20141110T165124356" pci-compliance-status="fail">
2
+ <Paragraph>
3
+ <UnorderedList>
4
+ <ListItem>Running HTTP service</ListItem>
5
+ </UnorderedList>
6
+ <Paragraph>
7
+ <ContainerBlockElement>
8
+ <ContainerBlockElement>
9
+ <Paragraph>HTTP GET request to
10
+ <URLLink LinkURL="http://10.0.0.1" LinkTitle="http://10.0.0.1"/>
11
+ </Paragraph>HTTP response code was an expected 200
12
+ <Paragraph preformat="true">2: &lt;?xml version="1.0" encoding="UTF-8"?&gt;
13
+ 2: &lt;wsdl:definitions name="xfdregistry"</Paragraph></ContainerBlockElement>
14
+ </ContainerBlockElement>
15
+ </Paragraph>
16
+ </Paragraph>
17
+ </test>
@@ -0,0 +1,8 @@
1
+ #[ID]#
2
+ %evidence.id%
3
+
4
+ #[Status]#
5
+ %evidence.status%
6
+
7
+ #[Content]#
8
+ %evidence.content%
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dradis-nexpose
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Martin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-06 00:00:00.000000000 Z
11
+ date: 2017-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dradis-plugins
@@ -124,12 +124,16 @@ files:
124
124
  - lib/nexpose/node.rb
125
125
  - lib/nexpose/scan.rb
126
126
  - lib/nexpose/service.rb
127
+ - lib/nexpose/test.rb
127
128
  - lib/nexpose/vulnerability.rb
128
129
  - lib/tasks/thorfile.rb
129
130
  - spec/fixtures/files/full.xml
130
131
  - spec/fixtures/files/simple.xml
131
132
  - spec/nexpose_upload_spec.rb
132
133
  - spec/spec_helper.rb
134
+ - templates/full_evidence.fields
135
+ - templates/full_evidence.sample
136
+ - templates/full_evidence.template
133
137
  - templates/full_node.fields
134
138
  - templates/full_node.sample
135
139
  - templates/full_node.template
@@ -165,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
169
  version: '0'
166
170
  requirements: []
167
171
  rubyforge_project:
168
- rubygems_version: 2.4.5
172
+ rubygems_version: 2.6.8
169
173
  signing_key:
170
174
  specification_version: 4
171
175
  summary: Nexpose add-on for the Dradis Framework.