dradis-nexpose 4.10.0 → 4.11.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.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +12 -3
- data/CHANGELOG.md +6 -0
- data/README.md +2 -2
- data/lib/dradis/plugins/nexpose/formats/full.rb +39 -38
- data/lib/dradis/plugins/nexpose/gem_version.rb +2 -2
- data/lib/nexpose/endpoint.rb +5 -7
- data/lib/nexpose/node.rb +6 -12
- data/lib/nexpose/service.rb +18 -11
- data/lib/nexpose/test.rb +3 -1
- data/lib/nexpose/vulnerability.rb +3 -2
- data/spec/fixtures/files/full.xml +1 -1
- data/spec/fixtures/files/full_with_duplicate_node.xml +136 -0
- data/spec/nexpose_upload_spec.rb +177 -146
- data/templates/full_evidence.fields +2 -0
- data/templates/full_evidence.sample +1 -1
- data/templates/full_service.fields +1 -1
- data/templates/full_service.sample +1 -1
- data/templates/full_vulnerability.fields +1 -0
- data/templates/full_vulnerability.sample +1 -0
- metadata +9 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fefa5d899cb4a34cead8f685c4bd13efdea29d034ddb7a505ce0e00f23b9b17d
|
|
4
|
+
data.tar.gz: 713ae33f6884e7c75393055f4cf68932a4ec9ef310e722d333b34c83df8b65ba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a07af401d0dbe92e6d488244502eae76d2404482429190b8e7a68117c97e79e850905b0ab71954024137e9144125de3169866ef2749343c9b0d909c7e3027e1
|
|
7
|
+
data.tar.gz: 69b31e47e60b9ee6bbd6771222ea1a8f5940bf9d40c6700e789bee6a546a2b296d087b9a75fc850c32f827c9ac917bd22cbc16ebffed2ed6449f5ac8ca77023b
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
Please review [CONTRIBUTING.md](https://github.com/dradis/dradis-ce/blob/develop/CONTRIBUTING.md) and remove this line.
|
|
2
|
+
|
|
1
3
|
### Summary
|
|
2
4
|
|
|
3
5
|
Provide a general description of the code changes in your pull
|
|
@@ -6,6 +8,11 @@ these bugs have open GitHub issues, be sure to tag them here as well,
|
|
|
6
8
|
to keep the conversation linked together.
|
|
7
9
|
|
|
8
10
|
|
|
11
|
+
### Testing Steps
|
|
12
|
+
|
|
13
|
+
Provide steps to test functionality, described in detail for someone not familiar with this part of the application / code base
|
|
14
|
+
|
|
15
|
+
|
|
9
16
|
### Other Information
|
|
10
17
|
|
|
11
18
|
If there's anything else that's important and relevant to your pull
|
|
@@ -26,11 +33,13 @@ products, we must have the copyright associated with the entire
|
|
|
26
33
|
codebase. Any code you create which is merged must be owned by us.
|
|
27
34
|
That's not us trying to be a jerks, that's just the way it works.
|
|
28
35
|
|
|
29
|
-
Please review the [CONTRIBUTING.md](https://github.com/dradis/dradis-ce/blob/master/CONTRIBUTING.md)
|
|
30
|
-
file for the details.
|
|
31
|
-
|
|
32
36
|
You can delete this section, but the following sentence needs to
|
|
33
37
|
remain in the PR's description:
|
|
34
38
|
|
|
35
39
|
> I assign all rights, including copyright, to any future Dradis
|
|
36
40
|
> work by myself to Security Roots.
|
|
41
|
+
|
|
42
|
+
### Check List
|
|
43
|
+
|
|
44
|
+
- [ ] Added a CHANGELOG entry
|
|
45
|
+
- [ ] Added specs
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
v4.11.0 (January 2024)
|
|
2
|
+
- Add port/protocol to evidences
|
|
3
|
+
- Use the details in <os> as the OS node property
|
|
4
|
+
- Import `vulnerability.risk_score` as a new Issue field
|
|
5
|
+
- Allow multiple evidence with the same test id & node address
|
|
6
|
+
|
|
1
7
|
v4.10.0 (September 2023)
|
|
2
8
|
- Update gemspec links
|
|
3
9
|
|
data/README.md
CHANGED
|
@@ -11,12 +11,12 @@ The add-on requires [Dradis CE](https://dradisframework.org/) > 3.0, or [Dradis
|
|
|
11
11
|
|
|
12
12
|
## More information
|
|
13
13
|
|
|
14
|
-
See the Dradis Framework's [README.md](https://github.com/dradis/
|
|
14
|
+
See the Dradis Framework's [README.md](https://github.com/dradis/dradis-ce/blob/develop/README.md)
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
## Contributing
|
|
18
18
|
|
|
19
|
-
See the Dradis Framework's [CONTRIBUTING.md](https://github.com/dradis/
|
|
19
|
+
See the Dradis Framework's [CONTRIBUTING.md](https://github.com/dradis/dradis-ce/blob/develop/CONTRIBUTING.md)
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
## License
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module Dradis::Plugins::Nexpose::Formats
|
|
2
|
-
|
|
3
2
|
# This module knows how to parse Nexpose Ful XML format.
|
|
4
3
|
module Full
|
|
5
4
|
private
|
|
@@ -12,30 +11,29 @@ module Dradis::Plugins::Nexpose::Formats
|
|
|
12
11
|
|
|
13
12
|
# First, extract scans
|
|
14
13
|
scan_node = content_service.create_node(label: 'Nexpose Scan Summary')
|
|
15
|
-
logger.info{ "\tProcessing scan summary" }
|
|
14
|
+
logger.info { "\tProcessing scan summary" }
|
|
16
15
|
|
|
17
16
|
doc.xpath('//scans/scan').each do |xml_scan|
|
|
18
17
|
note_text = template_service.process_template(template: 'full_scan', data: xml_scan)
|
|
19
18
|
content_service.create_note(node: scan_node, text: note_text)
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
|
|
23
21
|
# Second, we parse the nodes
|
|
24
22
|
doc.xpath('//nodes/node').each do |xml_node|
|
|
25
23
|
nexpose_node = Nexpose::Node.new(xml_node)
|
|
26
24
|
|
|
27
25
|
host_node = content_service.create_node(label: nexpose_node.address, type: :host)
|
|
28
|
-
logger.info{ "\tProcessing host: #{nexpose_node.address}" }
|
|
26
|
+
logger.info { "\tProcessing host: #{nexpose_node.address}" }
|
|
29
27
|
|
|
30
28
|
# add the summary note for this host
|
|
31
29
|
note_text = template_service.process_template(template: 'full_node', data: nexpose_node)
|
|
32
30
|
content_service.create_note(node: host_node, text: note_text)
|
|
33
31
|
|
|
34
32
|
if host_node.respond_to?(:properties)
|
|
35
|
-
logger.info{ "\tAdding host properties to #{nexpose_node.address}"}
|
|
33
|
+
logger.info { "\tAdding host properties to #{nexpose_node.address}" }
|
|
36
34
|
host_node.set_property(:ip, nexpose_node.address)
|
|
37
35
|
host_node.set_property(:hostname, nexpose_node.names)
|
|
38
|
-
host_node.set_property(:os, nexpose_node.
|
|
36
|
+
host_node.set_property(:os, nexpose_node.fingerprints)
|
|
39
37
|
host_node.set_property(:risk_score, nexpose_node.risk_score)
|
|
40
38
|
host_node.save
|
|
41
39
|
end
|
|
@@ -54,21 +52,22 @@ module Dradis::Plugins::Nexpose::Formats
|
|
|
54
52
|
# See:
|
|
55
53
|
# http://stackoverflow.com/questions/1625446/problem-with-upper-case-and-lower-case-xpath-functions-in-selenium-ide/1625859#1625859
|
|
56
54
|
xml_vuln = doc.xpath("//VulnerabilityDefinitions/vulnerability[translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='#{test_id}']").first
|
|
57
|
-
xml_vuln.add_child(
|
|
55
|
+
xml_vuln.add_child('<hosts/>') unless xml_vuln.last_element_child.name == 'hosts'
|
|
58
56
|
|
|
59
57
|
if xml_vuln.xpath("./hosts/host[text()='#{nexpose_node.address}']").empty?
|
|
60
58
|
xml_vuln.last_element_child.add_child("<host>#{nexpose_node.address}</host>")
|
|
61
59
|
end
|
|
62
60
|
|
|
63
|
-
evidence[test_id][nexpose_node.address]
|
|
61
|
+
evidence[test_id][nexpose_node.address] ||= []
|
|
62
|
+
evidence[test_id][nexpose_node.address] << node_test
|
|
64
63
|
end
|
|
65
64
|
|
|
66
65
|
nexpose_node.endpoints.each do |endpoint|
|
|
67
66
|
# endpoint_node = content_service.create_node(label: endpoint.label, parent: host_node)
|
|
68
|
-
logger.info{ "\t\tEndpoint: #{endpoint.label}" }
|
|
67
|
+
logger.info { "\t\tEndpoint: #{endpoint.label}" }
|
|
69
68
|
|
|
70
69
|
if host_node.respond_to?(:properties)
|
|
71
|
-
logger.info{ "\t\tAdding to Services table" }
|
|
70
|
+
logger.info { "\t\tAdding to Services table" }
|
|
72
71
|
host_node.set_service(
|
|
73
72
|
port: endpoint.port.to_i,
|
|
74
73
|
protocol: endpoint.protocol,
|
|
@@ -102,13 +101,14 @@ module Dradis::Plugins::Nexpose::Formats
|
|
|
102
101
|
# http://stackoverflow.com/questions/1625446/problem-with-upper-case-and-lower-case-xpath-functions-in-selenium-ide/1625859#1625859
|
|
103
102
|
#
|
|
104
103
|
xml_vuln = doc.xpath("//VulnerabilityDefinitions/vulnerability[translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='#{test_id}']").first
|
|
105
|
-
xml_vuln.add_child(
|
|
104
|
+
xml_vuln.add_child('<hosts/>') unless xml_vuln.last_element_child.name == 'hosts'
|
|
106
105
|
|
|
107
106
|
if xml_vuln.xpath("./hosts/host[text()='#{nexpose_node.address}']").empty?
|
|
108
107
|
xml_vuln.last_element_child.add_child("<host>#{nexpose_node.address}</host>")
|
|
109
108
|
end
|
|
110
109
|
|
|
111
|
-
evidence[test_id][nexpose_node.address]
|
|
110
|
+
evidence[test_id][nexpose_node.address] ||= []
|
|
111
|
+
evidence[test_id][nexpose_node.address] << service_test
|
|
112
112
|
end
|
|
113
113
|
end
|
|
114
114
|
end
|
|
@@ -118,42 +118,43 @@ module Dradis::Plugins::Nexpose::Formats
|
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
# Third, parse vulnerability definitions
|
|
121
|
-
logger.info{ "\tProcessing issue definitions:" }
|
|
121
|
+
logger.info { "\tProcessing issue definitions:" }
|
|
122
122
|
|
|
123
123
|
doc.xpath('//VulnerabilityDefinitions/vulnerability').each do |xml_vulnerability|
|
|
124
124
|
id = xml_vulnerability['id'].downcase
|
|
125
125
|
# if @vuln_list.include?(id)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
# 3.2 associate with the nodes via Evidence.
|
|
146
|
-
# TODO: there is room for improvement here by providing proper Evidence content
|
|
147
|
-
xml_vulnerability.xpath('./hosts/host').collect(&:text).each do |host_name|
|
|
148
|
-
# if the node exists, this just returns it
|
|
149
|
-
host_node = content_service.create_node(label: host_name, type: :host)
|
|
126
|
+
issue_text = template_service.process_template(
|
|
127
|
+
template: 'full_vulnerability',
|
|
128
|
+
data: xml_vulnerability
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# retrieve hosts affected by this issue (injected in step 2)
|
|
132
|
+
#
|
|
133
|
+
# There is no need for the below as Issues are linked to hosts via the
|
|
134
|
+
# corresponding Evidence instance
|
|
135
|
+
#
|
|
136
|
+
# note_text << "\n\n#[host]#\n"
|
|
137
|
+
# note_text << xml_vulnerability.xpath('./hosts/host').collect(&:text).join("\n")
|
|
138
|
+
# note_text << "\n\n"
|
|
139
|
+
|
|
140
|
+
# 3.1 create the Issue
|
|
141
|
+
issue = content_service.create_issue(text: issue_text, id: id)
|
|
142
|
+
logger.info { "\tIssue: #{issue.fields ? issue.fields['Title'] : id}" }
|
|
150
143
|
|
|
144
|
+
# 3.2 associate with the nodes via Evidence.
|
|
145
|
+
# TODO: there is room for improvement here by providing proper Evidence content
|
|
146
|
+
xml_vulnerability.xpath('./hosts/host').map(&:text).each do |host_name|
|
|
147
|
+
# if the node exists, this just returns it
|
|
148
|
+
host_node = content_service.create_node(label: host_name, type: :host)
|
|
149
|
+
|
|
150
|
+
evidence[id][host_name].each do |evidence|
|
|
151
151
|
evidence_content = template_service.process_template(
|
|
152
152
|
template: 'full_evidence',
|
|
153
|
-
data: evidence
|
|
153
|
+
data: evidence
|
|
154
154
|
)
|
|
155
155
|
content_service.create_evidence(content: evidence_content, issue: issue, node: host_node)
|
|
156
156
|
end
|
|
157
|
+
end
|
|
157
158
|
|
|
158
159
|
# end
|
|
159
160
|
end
|
data/lib/nexpose/endpoint.rb
CHANGED
|
@@ -8,7 +8,6 @@ module Nexpose
|
|
|
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 Endpoint
|
|
11
|
-
|
|
12
11
|
# Accepts an XML node from Nokogiri::XML.
|
|
13
12
|
def initialize(xml_node)
|
|
14
13
|
@xml = xml_node
|
|
@@ -39,13 +38,14 @@ module Nexpose
|
|
|
39
38
|
# Each of the services associated with this endpoint. Returns an array of
|
|
40
39
|
# Nexpose::Service objects
|
|
41
40
|
def services
|
|
42
|
-
@xml.xpath('./services/service').
|
|
41
|
+
@xml.xpath('./services/service').map do |xml_service|
|
|
42
|
+
Service.new(xml_service, endpoint: { port: port, protocol: protocol })
|
|
43
|
+
end
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
|
|
46
46
|
# This allows external callers (and specs) to check for implemented
|
|
47
47
|
# properties
|
|
48
|
-
def respond_to?(method, include_private=false)
|
|
48
|
+
def respond_to?(method, include_private = false)
|
|
49
49
|
return true if supported_tags.include?(method.to_sym)
|
|
50
50
|
super
|
|
51
51
|
end
|
|
@@ -57,7 +57,6 @@ module Nexpose
|
|
|
57
57
|
# attribute, simple descendent or collection that it maps to in the XML
|
|
58
58
|
# tree.
|
|
59
59
|
def method_missing(method, *args)
|
|
60
|
-
|
|
61
60
|
# We could remove this check and return nil for any non-recognized tag.
|
|
62
61
|
# The problem would be that it would make tricky to debug problems with
|
|
63
62
|
# typos. For instance: <>.potr would return nil instead of raising an
|
|
@@ -69,8 +68,7 @@ module Nexpose
|
|
|
69
68
|
|
|
70
69
|
# First we try the attributes. In Ruby we use snake_case, but in XML
|
|
71
70
|
# CamelCase is used for some attributes
|
|
72
|
-
translations_table = {
|
|
73
|
-
}
|
|
71
|
+
translations_table = {}
|
|
74
72
|
|
|
75
73
|
method_name = translations_table.fetch(method, method.to_s)
|
|
76
74
|
return @xml.attributes[method_name].value if @xml.attributes.key?(method_name)
|
data/lib/nexpose/node.rb
CHANGED
|
@@ -43,10 +43,9 @@ module Nexpose
|
|
|
43
43
|
@xml.xpath('./endpoints/endpoint').collect { |xml_endpoint| Endpoint.new(xml_endpoint) }
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
|
|
47
46
|
# This allows external callers (and specs) to check for implemented
|
|
48
47
|
# properties
|
|
49
|
-
def respond_to?(method, include_private=false)
|
|
48
|
+
def respond_to?(method, include_private = false)
|
|
50
49
|
return true if supported_tags.include?(method.to_sym)
|
|
51
50
|
super
|
|
52
51
|
end
|
|
@@ -58,7 +57,6 @@ module Nexpose
|
|
|
58
57
|
# attribute, simple descendent or collection that it maps to in the XML
|
|
59
58
|
# tree.
|
|
60
59
|
def method_missing(method, *args)
|
|
61
|
-
|
|
62
60
|
# We could remove this check and return nil for any non-recognized tag.
|
|
63
61
|
# The problem would be that it would make tricky to debug problems with
|
|
64
62
|
# typos. For instance: <>.potr would return nil instead of raising an
|
|
@@ -84,7 +82,7 @@ module Nexpose
|
|
|
84
82
|
|
|
85
83
|
# Finally the enumerations: names
|
|
86
84
|
if method_name == 'names'
|
|
87
|
-
@xml.xpath(
|
|
85
|
+
@xml.xpath('./names/name').collect(&:text)
|
|
88
86
|
|
|
89
87
|
elsif ['fingerprints', 'software'].include?(method_name)
|
|
90
88
|
|
|
@@ -93,14 +91,10 @@ module Nexpose
|
|
|
93
91
|
'software' => './software/fingerprint'
|
|
94
92
|
}[method_name]
|
|
95
93
|
|
|
96
|
-
@xml.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
[name.sub(/-/,'_').to_sym, xml_attribute.value]
|
|
101
|
-
end
|
|
102
|
-
]
|
|
103
|
-
end
|
|
94
|
+
xml_os = @xml.at_xpath(xpath_selector)
|
|
95
|
+
return '' if xml_os.nil?
|
|
96
|
+
|
|
97
|
+
xml_os.attributes['product'].value
|
|
104
98
|
else
|
|
105
99
|
# nothing found, the tag is valid but not present in this ReportItem
|
|
106
100
|
return nil
|
data/lib/nexpose/service.rb
CHANGED
|
@@ -8,9 +8,15 @@ module Nexpose
|
|
|
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 Service
|
|
11
|
+
attr_accessor :endpoint, :xml
|
|
12
|
+
|
|
11
13
|
# Accepts an XML node from Nokogiri::XML.
|
|
12
|
-
|
|
14
|
+
#
|
|
15
|
+
# endpoint - If the Service is instantiated from the Endpoint class (e.g.
|
|
16
|
+
# from <endpoint><services>...) , it will have access to the parent data.
|
|
17
|
+
def initialize(xml_node, endpoint: nil)
|
|
13
18
|
@xml = xml_node
|
|
19
|
+
@endpoint = endpoint
|
|
14
20
|
end
|
|
15
21
|
|
|
16
22
|
# List of supported tags. They can be attributes, simple descendans or
|
|
@@ -29,15 +35,18 @@ module Nexpose
|
|
|
29
35
|
|
|
30
36
|
# Convert each ./test/test entry into a simple hash
|
|
31
37
|
def tests(*args)
|
|
32
|
-
|
|
38
|
+
xml.xpath('./tests/test').map do |xml_test|
|
|
39
|
+
# Inject evidence with data from the node
|
|
40
|
+
xml_test['port'] = endpoint[:port]
|
|
41
|
+
xml_test['protocol'] = endpoint[:protocol]
|
|
42
|
+
|
|
33
43
|
Nexpose::Test.new(xml_test)
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
46
|
|
|
37
|
-
|
|
38
47
|
# This allows external callers (and specs) to check for implemented
|
|
39
48
|
# properties
|
|
40
|
-
def respond_to?(method, include_private=false)
|
|
49
|
+
def respond_to?(method, include_private = false)
|
|
41
50
|
return true if supported_tags.include?(method.to_sym)
|
|
42
51
|
super
|
|
43
52
|
end
|
|
@@ -49,7 +58,6 @@ module Nexpose
|
|
|
49
58
|
# attribute, simple descendent or collection that it maps to in the XML
|
|
50
59
|
# tree.
|
|
51
60
|
def method_missing(method, *args)
|
|
52
|
-
|
|
53
61
|
# We could remove this check and return nil for any non-recognized tag.
|
|
54
62
|
# The problem would be that it would make tricky to debug problems with
|
|
55
63
|
# typos. For instance: <>.potr would return nil instead of raising an
|
|
@@ -61,11 +69,10 @@ module Nexpose
|
|
|
61
69
|
|
|
62
70
|
# First we try the attributes. In Ruby we use snake_case, but in XML
|
|
63
71
|
# CamelCase is used for some attributes
|
|
64
|
-
translations_table = {
|
|
65
|
-
}
|
|
72
|
+
translations_table = {}
|
|
66
73
|
|
|
67
74
|
method_name = translations_table.fetch(method, method.to_s)
|
|
68
|
-
return
|
|
75
|
+
return xml.attributes[method_name].value if xml.attributes.key?(method_name)
|
|
69
76
|
|
|
70
77
|
# Finally the enumerations: references, tags
|
|
71
78
|
if ['fingerprints', 'configurations'].include?(method_name)
|
|
@@ -74,11 +81,11 @@ module Nexpose
|
|
|
74
81
|
'configurations' => './configuration/config'
|
|
75
82
|
}[method_name]
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
{:
|
|
84
|
+
xml.xpath(xpath_selector).collect do |xml_item|
|
|
85
|
+
{ text: xml_item.text }.merge(
|
|
79
86
|
Hash[
|
|
80
87
|
xml_item.attributes.collect do |name, xml_attribute|
|
|
81
|
-
[name.sub(/-/,'_').to_sym, xml_attribute.value]
|
|
88
|
+
[name.sub(/-/, '_').to_sym, xml_attribute.value]
|
|
82
89
|
end
|
|
83
90
|
]
|
|
84
91
|
)
|
data/lib/nexpose/test.rb
CHANGED
|
@@ -20,8 +20,8 @@ module Nexpose
|
|
|
20
20
|
def supported_tags
|
|
21
21
|
[
|
|
22
22
|
# attributes
|
|
23
|
-
:
|
|
24
|
-
:published, :
|
|
23
|
+
:added, :cvss_score, :cvss_vector, :modified, :nexpose_id, :pci_severity,
|
|
24
|
+
:published, :risk_score, :severity, :title,
|
|
25
25
|
|
|
26
26
|
# simple tags
|
|
27
27
|
:description, :solution,
|
|
@@ -64,6 +64,7 @@ module Nexpose
|
|
|
64
64
|
translations_table = {
|
|
65
65
|
:nexpose_id => 'id',
|
|
66
66
|
:pci_severity => 'pciSeverity',
|
|
67
|
+
:risk_score => 'riskScore',
|
|
67
68
|
:cvss_score => 'cvssScore',
|
|
68
69
|
:cvss_vector =>'cvssVector'
|
|
69
70
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<NexposeReport version="2.0">
|
|
3
|
+
<scans>
|
|
4
|
+
<scan endTime="20141110T175832478" id="4" name="USDA_Internal" startTime="20141110T094538362" status="finished"/>
|
|
5
|
+
</scans>
|
|
6
|
+
<nodes>
|
|
7
|
+
<node address="1.1.1.1" device-id="75" risk-score="0.0" scan-template="Edge Standard" site-importance="Normal" site-name="USDA_Internal" status="alive">
|
|
8
|
+
<names>
|
|
9
|
+
<name>localhost:5000</name>
|
|
10
|
+
</names>
|
|
11
|
+
<fingerprints>
|
|
12
|
+
<os certainty="0.80" family="IOS" product="IOS" vendor="Cisco" arch="x86_64"/>
|
|
13
|
+
</fingerprints>
|
|
14
|
+
<tests/>
|
|
15
|
+
<endpoints>
|
|
16
|
+
<endpoint port="123" protocol="udp" status="open">
|
|
17
|
+
<services>
|
|
18
|
+
<service name="NTP">
|
|
19
|
+
<fingerprints>
|
|
20
|
+
<fingerprint certainty="0.90" family="NTP" product="NTP" vendor="Cisco"/>
|
|
21
|
+
</fingerprints>
|
|
22
|
+
<configuration>
|
|
23
|
+
<config name="ntp.variables">system="cisco", leap=0, stratum=5, rootdelay=88.21,
|
|
24
|
+
|
|
25
|
+
rootdispersion=108.54, peer=24960, refid=135.89.100.96,
|
|
26
|
+
|
|
27
|
+
reftime=0xD80BB6B5.715ACDD8, poll=10, clock=0xD80BB78F.8931F3F6,
|
|
28
|
+
|
|
29
|
+
phase=8.259, freq=-141.24, error=11.32</config>
|
|
30
|
+
</configuration>
|
|
31
|
+
<tests>
|
|
32
|
+
<test id="ntp-clock-variables-disclosure" pci-compliance-status="pass" scan-id="4" status="vulnerable-exploited" vulnerable-since="20141110T161846666">
|
|
33
|
+
<Paragraph>
|
|
34
|
+
<Paragraph>The following NTP variables were found from a readvar request: system="cisco", leap=0, stratum=5, rootdelay=88.21,
|
|
35
|
+
rootdispersion=108.54, peer=24960, refid=135.89.100.96,
|
|
36
|
+
reftime=0xD80BB6B5.715ACDD8, poll=10, clock=0xD80BB78F.8931F3F6,
|
|
37
|
+
phase=8.259, freq=-141.24, error=11.32</Paragraph>
|
|
38
|
+
</Paragraph>
|
|
39
|
+
</test>
|
|
40
|
+
</tests>
|
|
41
|
+
</service>
|
|
42
|
+
</services>
|
|
43
|
+
</endpoint>
|
|
44
|
+
<endpoint port="161" protocol="udp" status="open">
|
|
45
|
+
<services>
|
|
46
|
+
<service name="SNMP">
|
|
47
|
+
<tests/>
|
|
48
|
+
</service>
|
|
49
|
+
</services>
|
|
50
|
+
</endpoint>
|
|
51
|
+
</endpoints>
|
|
52
|
+
</node>
|
|
53
|
+
<node address="1.1.1.1" device-id="75" risk-score="0.0" scan-template="Edge Standard" site-importance="Normal" site-name="USDA_Internal" status="alive">
|
|
54
|
+
<names>
|
|
55
|
+
<name>localhost:6000</name>
|
|
56
|
+
</names>
|
|
57
|
+
<fingerprints>
|
|
58
|
+
<os certainty="0.80" family="IOS" product="IOS" vendor="Cisco" arch="x86_64"/>
|
|
59
|
+
</fingerprints>
|
|
60
|
+
<tests/>
|
|
61
|
+
<endpoints>
|
|
62
|
+
<endpoint port="123" protocol="udp" status="open">
|
|
63
|
+
<services>
|
|
64
|
+
<service name="NTP">
|
|
65
|
+
<fingerprints>
|
|
66
|
+
<fingerprint certainty="0.90" family="NTP" product="NTP" vendor="Cisco"/>
|
|
67
|
+
</fingerprints>
|
|
68
|
+
<configuration>
|
|
69
|
+
<config name="ntp.variables">system="cisco", leap=0, stratum=5, rootdelay=88.21,
|
|
70
|
+
|
|
71
|
+
rootdispersion=108.54, peer=24960, refid=135.89.100.96,
|
|
72
|
+
|
|
73
|
+
reftime=0xD80BB6B5.715ACDD8, poll=10, clock=0xD80BB78F.8931F3F6,
|
|
74
|
+
|
|
75
|
+
phase=8.259, freq=-141.24, error=11.32</config>
|
|
76
|
+
</configuration>
|
|
77
|
+
<tests>
|
|
78
|
+
<test id="ntp-clock-variables-disclosure" pci-compliance-status="pass" scan-id="4" status="vulnerable-exploited" vulnerable-since="20141110T161846666">
|
|
79
|
+
<Paragraph>
|
|
80
|
+
<Paragraph>The following NTP variables were found from a readvar request: system="cisco", leap=0, stratum=5, rootdelay=88.21,
|
|
81
|
+
rootdispersion=108.54, peer=24960, refid=135.89.100.96,
|
|
82
|
+
reftime=0xD80BB6B5.715ACDD8, poll=10, clock=0xD80BB78F.8931F3F6,
|
|
83
|
+
phase=8.259, freq=-141.24, error=11.32</Paragraph>
|
|
84
|
+
</Paragraph>
|
|
85
|
+
</test>
|
|
86
|
+
</tests>
|
|
87
|
+
</service>
|
|
88
|
+
</services>
|
|
89
|
+
</endpoint>
|
|
90
|
+
<endpoint port="161" protocol="udp" status="open">
|
|
91
|
+
<services>
|
|
92
|
+
<service name="SNMP">
|
|
93
|
+
<tests/>
|
|
94
|
+
</service>
|
|
95
|
+
</services>
|
|
96
|
+
</endpoint>
|
|
97
|
+
</endpoints>
|
|
98
|
+
</node>
|
|
99
|
+
</nodes>
|
|
100
|
+
<VulnerabilityDefinitions>
|
|
101
|
+
<vulnerability added="20120412T000000000" cvssScore="4.3" cvssVector="(AV:N/AC:M/Au:N/C:P/I:N/A:N)" id="ntp-clock-variables-disclosure" modified="20131205T000000000" pciSeverity="3" published="20120127T000000000" riskScore="378.27377" severity="4" title="Apache HTTPD: error responses can expose cookies (CVE-2012-0053)">
|
|
102
|
+
<malware/>
|
|
103
|
+
<exploits>
|
|
104
|
+
<exploit id="3479" link="http://www.exploit-db.com/exploits/18442" skillLevel="Expert" title="Apache httpOnly Cookie Disclosure" type="exploitdb"/>
|
|
105
|
+
</exploits>
|
|
106
|
+
<description>
|
|
107
|
+
<ContainerBlockElement>
|
|
108
|
+
<Paragraph>A flaw was found in the default error response for status code 400. This flaw could be used by an attacker to expose "httpOnly" cookies when no custom ErrorDocument is specified.</Paragraph>
|
|
109
|
+
</ContainerBlockElement>
|
|
110
|
+
</description>
|
|
111
|
+
<references>
|
|
112
|
+
<reference source="APPLE">APPLE-SA-2012-09-19-2</reference>
|
|
113
|
+
<reference source="BID">51706</reference>
|
|
114
|
+
<reference source="CVE">CVE-2012-0053</reference>
|
|
115
|
+
<reference source="REDHAT">RHSA-2012:0128</reference>
|
|
116
|
+
<reference source="SECUNIA">48551</reference>
|
|
117
|
+
<reference source="URL">http://httpd.apache.org/security/vulnerabilities_20.html</reference>
|
|
118
|
+
<reference source="URL">http://httpd.apache.org/security/vulnerabilities_22.html</reference>
|
|
119
|
+
</references>
|
|
120
|
+
<tags>
|
|
121
|
+
<tag>Apache</tag>
|
|
122
|
+
<tag>Apache HTTP Server</tag>
|
|
123
|
+
<tag>Web</tag>
|
|
124
|
+
</tags>
|
|
125
|
+
<solution>
|
|
126
|
+
<ContainerBlockElement>
|
|
127
|
+
<Paragraph>Apache HTTPD >= 2.0 and < 2.0.65</Paragraph>
|
|
128
|
+
<Paragraph>Download and apply the upgrade from:
|
|
129
|
+
|
|
130
|
+
<URLLink LinkTitle="http://archive.apache.org/dist/httpd/httpd-2.0.65.tar.gz" LinkURL="http://archive.apache.org/dist/httpd/httpd-2.0.65.tar.gz"/></Paragraph>
|
|
131
|
+
<Paragraph>Many platforms and distributions provide pre-built binary packages for Apache HTTP server. These pre-built packages are usually customized and optimized for a particular distribution, therefore we recommend that you use the packages if they are available for your operating system.</Paragraph>
|
|
132
|
+
</ContainerBlockElement>
|
|
133
|
+
</solution>
|
|
134
|
+
</vulnerability>
|
|
135
|
+
</VulnerabilityDefinitions>
|
|
136
|
+
</NexposeReport>
|
data/spec/nexpose_upload_spec.rb
CHANGED
|
@@ -1,170 +1,201 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'rails_helper'
|
|
2
2
|
require 'ostruct'
|
|
3
3
|
|
|
4
4
|
describe 'Nexpose upload plugin' do
|
|
5
|
-
before
|
|
6
|
-
|
|
7
|
-
templates_dir = File.expand_path('../../templates', __FILE__)
|
|
8
|
-
expect_any_instance_of(Dradis::Plugins::TemplateService)
|
|
9
|
-
.to receive(:default_templates_dir).and_return(templates_dir)
|
|
10
|
-
|
|
11
|
-
# Init services
|
|
12
|
-
plugin = Dradis::Plugins::Nexpose
|
|
13
|
-
|
|
14
|
-
@content_service = Dradis::Plugins::ContentService::Base.new(
|
|
15
|
-
logger: Logger.new(STDOUT),
|
|
16
|
-
plugin: plugin
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
@importer = plugin::Importer.new(
|
|
20
|
-
content_service: @content_service,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
# Stub dradis-plugins methods
|
|
24
|
-
#
|
|
25
|
-
# They return their argument hashes as objects mimicking
|
|
26
|
-
# Nodes, Issues, etc
|
|
27
|
-
allow(@content_service).to receive(:create_node) do |args|
|
|
28
|
-
OpenStruct.new(args)
|
|
29
|
-
end
|
|
30
|
-
allow(@content_service).to receive(:create_note) do |args|
|
|
31
|
-
OpenStruct.new(args)
|
|
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
|
|
5
|
+
before do
|
|
6
|
+
@fixtures_dir = File.expand_path('../fixtures/files/', __FILE__)
|
|
39
7
|
end
|
|
40
8
|
|
|
41
|
-
describe
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
9
|
+
describe 'importer' do
|
|
10
|
+
before(:each) do
|
|
11
|
+
# Stub template service
|
|
12
|
+
templates_dir = File.expand_path('../../templates', __FILE__)
|
|
13
|
+
expect_any_instance_of(Dradis::Plugins::TemplateService)
|
|
14
|
+
.to receive(:default_templates_dir).and_return(templates_dir)
|
|
15
|
+
|
|
16
|
+
# Init services
|
|
17
|
+
plugin = Dradis::Plugins::Nexpose
|
|
18
|
+
|
|
19
|
+
@content_service = Dradis::Plugins::ContentService::Base.new(
|
|
20
|
+
logger: Logger.new(STDOUT),
|
|
21
|
+
plugin: plugin
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
@importer = plugin::Importer.new(
|
|
25
|
+
content_service: @content_service,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# Stub dradis-plugins methods
|
|
29
|
+
#
|
|
30
|
+
# They return their argument hashes as objects mimicking
|
|
31
|
+
# Nodes, Issues, etc
|
|
32
|
+
allow(@content_service).to receive(:create_node) do |args|
|
|
55
33
|
OpenStruct.new(args)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
expect(@content_service).to receive(:create_node) do |args|
|
|
59
|
-
expect(args[:label]).to eq('udp-000')
|
|
60
|
-
expect(args[:parent].label).to eq("1.1.1.1")
|
|
34
|
+
end
|
|
35
|
+
allow(@content_service).to receive(:create_note) do |args|
|
|
61
36
|
OpenStruct.new(args)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
expect(@content_service).to receive(:create_note) do |args|
|
|
65
|
-
expect(args[:text]).to include("#[Id]#\nntpd-crypto")
|
|
66
|
-
expect(args[:text]).to include("#[host]#\n1.1.1.1")
|
|
67
|
-
expect(args[:node].label).to eq("udp-000")
|
|
68
|
-
end.once
|
|
69
|
-
|
|
70
|
-
expect(@content_service).to receive(:create_note) do |args|
|
|
71
|
-
expect(args[:text]).to include("#[Id]#\nntp-clock-radio")
|
|
72
|
-
expect(args[:text]).to include("#[host]#\n1.1.1.1")
|
|
73
|
-
expect(args[:node].label).to eq("udp-000")
|
|
74
|
-
end.once
|
|
75
|
-
|
|
76
|
-
@importer.import(file: 'spec/fixtures/files/simple.xml')
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
describe "Importer: Full" do
|
|
81
|
-
it "creates nodes, issues, notes and an evidences as needed" do
|
|
82
|
-
expect(@content_service).to receive(:create_node).with(hash_including label: "Nexpose Scan Summary").once
|
|
83
|
-
expect(@content_service).to receive(:create_note) do |args|
|
|
84
|
-
expect(args[:text]).to include("#[Title]#\nUSDA_Internal (4)")
|
|
85
|
-
expect(args[:node].label).to eq("Nexpose Scan Summary")
|
|
86
|
-
end.once
|
|
87
|
-
|
|
88
|
-
expect(@content_service).to receive(:create_node).with(
|
|
89
|
-
hash_including label: "1.1.1.1", type: :host
|
|
90
|
-
).twice
|
|
91
|
-
|
|
92
|
-
expect(@content_service).to receive(:create_note) do |args|
|
|
93
|
-
expect(args[:text]).to include("#[Title]#\n1.1.1.1")
|
|
94
|
-
expect(args[:node].label).to eq("1.1.1.1")
|
|
95
|
-
end.once
|
|
96
|
-
|
|
97
|
-
expect(@content_service).to receive(:create_note) do |args|
|
|
98
|
-
expect(args[:text]).to include("#[Title]#\nService name: NTP")
|
|
99
|
-
expect(args[:node].label).to eq("1.1.1.1")
|
|
100
|
-
end.once
|
|
101
|
-
|
|
102
|
-
expect(@content_service).to receive(:create_note) do |args|
|
|
103
|
-
expect(args[:text]).to include("#[Title]#\nService name: SNMP")
|
|
104
|
-
expect(args[:node].label).to eq("1.1.1.1")
|
|
105
|
-
end.once
|
|
106
|
-
|
|
107
|
-
expect(@content_service).to receive(:create_issue) do |args|
|
|
108
|
-
expect(args[:text]).to include("#[Title]#\nApache HTTPD: error responses can expose cookies (CVE-2012-0053)")
|
|
109
|
-
expect(args[:id]).to eq("ntp-clock-variables-disclosure")
|
|
37
|
+
end
|
|
38
|
+
allow(@content_service).to receive(:create_issue) do |args|
|
|
110
39
|
OpenStruct.new(args)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
expect(@content_service).to receive(:create_issue) do |args|
|
|
114
|
-
expect(args[:text]).to include("#[Title]#\nApache HTTPD: ETag Inode Information Leakage (CVE-2003-1418)")
|
|
115
|
-
expect(args[:id]).to eq("ntp-clock-variables-disclosure")
|
|
40
|
+
end
|
|
41
|
+
allow(@content_service).to receive(:create_evidence) do |args|
|
|
116
42
|
OpenStruct.new(args)
|
|
117
|
-
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
118
45
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
expect(
|
|
123
|
-
|
|
46
|
+
describe 'Importer: Simple' do
|
|
47
|
+
it 'creates nodes, issues, notes and an evidences as needed' do
|
|
48
|
+
|
|
49
|
+
expect(@content_service).to receive(:create_node).with(hash_including label: '1.1.1.1', type: :host).once
|
|
50
|
+
|
|
51
|
+
expect(@content_service).to receive(:create_note) do |args|
|
|
52
|
+
expect(args[:text]).to include('Host Description : Linux 2.6.9-89.ELsmp')
|
|
53
|
+
expect(args[:text]).to include('Scanner Fingerprint certainty : 0.80')
|
|
54
|
+
expect(args[:node].label).to eq('1.1.1.1')
|
|
55
|
+
end.once
|
|
56
|
+
|
|
57
|
+
expect(@content_service).to receive(:create_node) do |args|
|
|
58
|
+
expect(args[:label]).to eq('Generic Findings')
|
|
59
|
+
expect(args[:parent].label).to eq('1.1.1.1')
|
|
60
|
+
OpenStruct.new(args)
|
|
61
|
+
end.once
|
|
62
|
+
|
|
63
|
+
expect(@content_service).to receive(:create_node) do |args|
|
|
64
|
+
expect(args[:label]).to eq('udp-000')
|
|
65
|
+
expect(args[:parent].label).to eq('1.1.1.1')
|
|
66
|
+
OpenStruct.new(args)
|
|
67
|
+
end.once
|
|
68
|
+
|
|
69
|
+
expect(@content_service).to receive(:create_note) do |args|
|
|
70
|
+
expect(args[:text]).to include("#[Id]#\nntpd-crypto")
|
|
71
|
+
expect(args[:text]).to include("#[host]#\n1.1.1.1")
|
|
72
|
+
expect(args[:node].label).to eq('udp-000')
|
|
73
|
+
end.once
|
|
74
|
+
|
|
75
|
+
expect(@content_service).to receive(:create_note) do |args|
|
|
76
|
+
expect(args[:text]).to include("#[Id]#\nntp-clock-radio")
|
|
77
|
+
expect(args[:text]).to include("#[host]#\n1.1.1.1")
|
|
78
|
+
expect(args[:node].label).to eq('udp-000')
|
|
79
|
+
end.once
|
|
80
|
+
|
|
81
|
+
@importer.import(file: @fixtures_dir + '/simple.xml')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
124
84
|
|
|
125
|
-
|
|
126
|
-
|
|
85
|
+
describe 'Importer: Full' do
|
|
86
|
+
it 'creates nodes, issues, notes and an evidences as needed' do
|
|
87
|
+
expect(@content_service).to receive(:create_node).with(hash_including label: 'Nexpose Scan Summary').once
|
|
88
|
+
expect(@content_service).to receive(:create_note) do |args|
|
|
89
|
+
expect(args[:text]).to include("#[Title]#\nUSDA_Internal (4)")
|
|
90
|
+
expect(args[:node].label).to eq('Nexpose Scan Summary')
|
|
91
|
+
end.once
|
|
92
|
+
|
|
93
|
+
expect(@content_service).to receive(:create_node) do |args|
|
|
94
|
+
expect(args[:label]).to eq('1.1.1.1')
|
|
95
|
+
expect(args[:type]).to eq(:host)
|
|
96
|
+
create(:node, args.except(:type))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
expect(@content_service).to receive(:create_note) do |args|
|
|
100
|
+
expect(args[:text]).to include("#[Title]#\n1.1.1.1")
|
|
101
|
+
expect(args[:node].label).to eq('1.1.1.1')
|
|
102
|
+
end.once
|
|
103
|
+
|
|
104
|
+
expect(@content_service).to receive(:create_note) do |args|
|
|
105
|
+
expect(args[:text]).to include("#[Title]#\nService name: NTP")
|
|
106
|
+
expect(args[:node].label).to eq('1.1.1.1')
|
|
107
|
+
end.once
|
|
108
|
+
|
|
109
|
+
expect(@content_service).to receive(:create_note) do |args|
|
|
110
|
+
expect(args[:text]).to include("#[Title]#\nService name: SNMP")
|
|
111
|
+
expect(args[:node].label).to eq('1.1.1.1')
|
|
112
|
+
end.once
|
|
113
|
+
|
|
114
|
+
expect(@content_service).to receive(:create_issue) do |args|
|
|
115
|
+
expect(args[:text]).to include("#[Title]#\nApache HTTPD: error responses can expose cookies (CVE-2012-0053)")
|
|
116
|
+
expect(args[:id]).to eq('ntp-clock-variables-disclosure')
|
|
117
|
+
OpenStruct.new(args)
|
|
118
|
+
end.once
|
|
119
|
+
|
|
120
|
+
expect(@content_service).to receive(:create_issue) do |args|
|
|
121
|
+
expect(args[:text]).to include("#[Title]#\nApache HTTPD: ETag Inode Information Leakage (CVE-2003-1418)")
|
|
122
|
+
expect(args[:id]).to eq('ntp-clock-variables-disclosure')
|
|
123
|
+
OpenStruct.new(args)
|
|
124
|
+
end.once
|
|
125
|
+
|
|
126
|
+
expect(@content_service).to receive(:create_evidence) do |args|
|
|
127
|
+
expect(args[:content]).to include("#[ID]#\nntp-clock-variables-disclosure\n\n")
|
|
128
|
+
expect(args[:issue].id).to eq('ntp-clock-variables-disclosure')
|
|
129
|
+
expect(args[:node].label).to eq('1.1.1.1')
|
|
130
|
+
end.once
|
|
131
|
+
|
|
132
|
+
@importer.import(file: @fixtures_dir + '/full.xml')
|
|
133
|
+
|
|
134
|
+
expect(Node.find_by(label: '1.1.1.1').properties[:os]).to eq('IOS')
|
|
135
|
+
end
|
|
127
136
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
137
|
+
it 'wraps ciphers inside ssl issues in code blocks' do
|
|
138
|
+
expect(@content_service).to receive(:create_issue) do |args|
|
|
139
|
+
expect(args[:text]).to include('bc. ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256')
|
|
140
|
+
OpenStruct.new(args)
|
|
141
|
+
end.once
|
|
132
142
|
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
@importer.import(file: @fixtures_dir + '/ssl.xml')
|
|
144
|
+
end
|
|
135
145
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
expect(
|
|
139
|
-
|
|
140
|
-
|
|
146
|
+
# Regression test for github.com/dradis/dradis-nexpose/issues/1
|
|
147
|
+
it 'populates solutions regardless they are wrapped in paragraphs or lists' do
|
|
148
|
+
expect(@content_service).to receive(:create_issue) do |args|
|
|
149
|
+
expect(args[:text]).to include("#[Solution]#\n\nApache HTTPD >= 2.0 and < 2.0.65")
|
|
150
|
+
OpenStruct.new(args)
|
|
151
|
+
end.once
|
|
141
152
|
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
expect(@content_service).to receive(:create_issue) do |args|
|
|
154
|
+
expect(args[:text]).to include("#[Solution]#\n")
|
|
155
|
+
expect(args[:text]).to include('You can remove inode information from the ETag header')
|
|
156
|
+
OpenStruct.new(args)
|
|
157
|
+
end.once
|
|
144
158
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
expect(@content_service).to receive(:create_issue) do |args|
|
|
148
|
-
expect(args[:text]).to include("#[Solution]#\n\nApache HTTPD >= 2.0 and < 2.0.65")
|
|
149
|
-
OpenStruct.new(args)
|
|
150
|
-
end.once
|
|
159
|
+
@importer.import(file: @fixtures_dir + '/full.xml')
|
|
160
|
+
end
|
|
151
161
|
|
|
152
|
-
|
|
153
|
-
expect(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
162
|
+
it 'transforms html entities (< and >)' do
|
|
163
|
+
expect(@content_service).to receive(:create_issue) do |args|
|
|
164
|
+
expect(args[:text]).to include("#[Solution]#\n\nApache HTTPD >= 2.0 and < 2.0.65")
|
|
165
|
+
OpenStruct.new(args)
|
|
166
|
+
end
|
|
157
167
|
|
|
158
|
-
|
|
168
|
+
@importer.import(file: @fixtures_dir + '/full.xml')
|
|
169
|
+
end
|
|
159
170
|
end
|
|
160
171
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
expect(
|
|
164
|
-
|
|
172
|
+
describe 'Importer: Full with duplicate nodes' do
|
|
173
|
+
it 'creates evidence for each instance of the node' do
|
|
174
|
+
expect(@content_service).to receive(:create_node).with(hash_including label: 'Nexpose Scan Summary').once
|
|
175
|
+
expect(@content_service).to receive(:create_node) do |args|
|
|
176
|
+
expect(args[:label]).to eq('1.1.1.1')
|
|
177
|
+
expect(args[:type]).to eq(:host)
|
|
178
|
+
create(:node, args.except(:type))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
expect(@content_service).to receive(:create_evidence) do |args|
|
|
182
|
+
expect(args[:content]).to include("#[ID]#\nntp-clock-variables-disclosure\n\n")
|
|
183
|
+
expect(args[:issue].id).to eq('ntp-clock-variables-disclosure')
|
|
184
|
+
expect(args[:node].label).to eq('1.1.1.1')
|
|
185
|
+
end.twice
|
|
186
|
+
|
|
187
|
+
@importer.import(file: @fixtures_dir + '/full_with_duplicate_node.xml')
|
|
165
188
|
end
|
|
166
|
-
|
|
167
|
-
@importer.import(file: 'spec/fixtures/files/full.xml')
|
|
168
189
|
end
|
|
169
190
|
end
|
|
191
|
+
|
|
192
|
+
it 'parses the fingerprints field' do
|
|
193
|
+
doc = Nokogiri::XML(File.read(@fixtures_dir + '/full.xml'))
|
|
194
|
+
|
|
195
|
+
ts = Dradis::Plugins::TemplateService.new(plugin: Dradis::Plugins::Nexpose)
|
|
196
|
+
ts.set_template(template: 'full_node', content: "#[Fingerprints]#\n%node.fingerprints%\n")
|
|
197
|
+
result = ts.process_template(data: doc.at_xpath('//nodes/node'), template: 'full_node')
|
|
198
|
+
|
|
199
|
+
expect(result).to include('IOS')
|
|
200
|
+
end
|
|
170
201
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
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">
|
|
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" port="123" protocol="udp">
|
|
2
2
|
<Paragraph>
|
|
3
3
|
<UnorderedList>
|
|
4
4
|
<ListItem>Running HTTP service</ListItem>
|
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: 4.
|
|
4
|
+
version: 4.11.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:
|
|
11
|
+
date: 2024-01-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dradis-plugins
|
|
@@ -96,7 +96,7 @@ dependencies:
|
|
|
96
96
|
version: 0.5.2
|
|
97
97
|
description: This add-on allows you to upload and parse output produced from Nexpose
|
|
98
98
|
scanner into Dradis.
|
|
99
|
-
email:
|
|
99
|
+
email:
|
|
100
100
|
executables: []
|
|
101
101
|
extensions: []
|
|
102
102
|
extra_rdoc_files: []
|
|
@@ -130,6 +130,7 @@ files:
|
|
|
130
130
|
- lib/nexpose/vulnerability.rb
|
|
131
131
|
- lib/tasks/thorfile.rb
|
|
132
132
|
- spec/fixtures/files/full.xml
|
|
133
|
+
- spec/fixtures/files/full_with_duplicate_node.xml
|
|
133
134
|
- spec/fixtures/files/simple.xml
|
|
134
135
|
- spec/fixtures/files/ssl.xml
|
|
135
136
|
- spec/nexpose_upload_spec.rb
|
|
@@ -156,7 +157,7 @@ homepage: https://dradis.com/integrations/nexpose.html
|
|
|
156
157
|
licenses:
|
|
157
158
|
- GPL-2
|
|
158
159
|
metadata: {}
|
|
159
|
-
post_install_message:
|
|
160
|
+
post_install_message:
|
|
160
161
|
rdoc_options: []
|
|
161
162
|
require_paths:
|
|
162
163
|
- lib
|
|
@@ -171,12 +172,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
171
172
|
- !ruby/object:Gem::Version
|
|
172
173
|
version: '0'
|
|
173
174
|
requirements: []
|
|
174
|
-
rubygems_version: 3.
|
|
175
|
-
signing_key:
|
|
175
|
+
rubygems_version: 3.3.7
|
|
176
|
+
signing_key:
|
|
176
177
|
specification_version: 4
|
|
177
178
|
summary: Nexpose add-on for the Dradis Framework.
|
|
178
179
|
test_files:
|
|
179
180
|
- spec/fixtures/files/full.xml
|
|
181
|
+
- spec/fixtures/files/full_with_duplicate_node.xml
|
|
180
182
|
- spec/fixtures/files/simple.xml
|
|
181
183
|
- spec/fixtures/files/ssl.xml
|
|
182
184
|
- spec/nexpose_upload_spec.rb
|