dradis-netsparker 4.15.0 → 4.16.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7126eb346ac756ae30cfcf04675611e6eba02a6d673de4174385caac0247da70
4
- data.tar.gz: 6688b645ffcd52a2a965e34295ccf2ff1850e17ab4341cbf6e6b5009871cb3a8
3
+ metadata.gz: e17018715e12dec6678428a291684165adf27dc5ac42f071be11bf2a9c5ec9ae
4
+ data.tar.gz: fc2a2e2f197d4d1d4c3a21ffa09def600299986bbf9d0433b286a5282985a353
5
5
  SHA512:
6
- metadata.gz: 3ae43c0bb9014efe1f61a9fe29f0f21c6e44c3fbbad521f233fdf004b1445da908c840fb6f5b6534889386ae0adb50cf947bdb0227339afc41e6df376ff2ac4c
7
- data.tar.gz: d419eda723a86492f8075a21e7105f0ef3a5e38f931840b1a11e4d08fe62bf5d949e1688ffeff94eea9972286b365ee0e4826b07cb52cb22408dbee82be3a12e
6
+ metadata.gz: de430a263b83f423368a6fffdb560678e16b05db0a860710ee7acc6c5f6af9958b18b11ff58fee5d3985f1d964b1ea5043ba29757fdbce359beb3e4cf8cd0ded
7
+ data.tar.gz: 8c664b428f4593f77d10331dc3f12de9063e133647ef0540ee442d3a020fd4b3239ccb94a97745d55ea24ea3274c0fa1c677392b78069eb17056cedef27a66ec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ v4.16.0 (May 2024)
2
+ - Add support for Additional Websites as nodes
3
+ - Parse inline code, not just code blocks
4
+
1
5
  v4.15.0 (December 2024)
2
6
  - No changes
3
7
 
@@ -8,7 +8,7 @@ module Dradis
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 4
11
- MINOR = 15
11
+ MINOR = 16
12
12
  TINY = 0
13
13
  PRE = nil
14
14
 
@@ -7,16 +7,16 @@ module Dradis::Plugins::Netsparker
7
7
  # The framework will call this function if the user selects this plugin from
8
8
  # the dropdown list and uploads a file.
9
9
  # @returns true if the operation was successful, false otherwise
10
- def import(params={})
11
- file_content = File.read( params.fetch(:file) )
10
+ def import(params = {})
11
+ file_content = File.read(params.fetch(:file))
12
12
 
13
- logger.info{'Parsing Netsparker output file...'}
14
- @doc = Nokogiri::XML( file_content )
15
- logger.info{'Done.'}
13
+ logger.info { 'Parsing Netsparker output file...' }
14
+ @doc = Nokogiri::XML(file_content)
15
+ logger.info { 'Done.' }
16
16
 
17
17
  if @doc.xpath('/netsparker').empty?
18
- error = "No scan results were detected in the uploaded file (/netsparker). Ensure you uploaded an Netsparker XML report."
19
- logger.fatal{ error }
18
+ error = 'No scan results were detected in the uploaded file (/netsparker). Ensure you uploaded an Netsparker XML report.'
19
+ logger.fatal { error }
20
20
  content_service.create_note text: error
21
21
  return false
22
22
  end
@@ -34,34 +34,46 @@ module Dradis::Plugins::Netsparker
34
34
  # Create Nodes from the <url> tags
35
35
  host_node_label = xml_host.at_xpath('./url').text
36
36
  host_node_label = URI.parse(host_node_label).host rescue host_node_label
37
- logger.info{ "\t\t => Creating new host: #{host_node_label}" }
37
+ logger.info { "\t\t => Creating new host: #{host_node_label}" }
38
38
  host_node = content_service.create_node(label: host_node_label, type: :host)
39
39
 
40
40
  @doc.xpath('/netsparker/vulnerability').each do |xml_vuln|
41
41
  process_vuln(xml_vuln, host_node)
42
42
  end
43
-
44
43
  end
45
44
 
46
45
  def process_vuln(xml_vuln, host_node)
47
- type = xml_vuln.at_xpath('./type').text()
46
+ type = xml_vuln.at_xpath('./type').text
48
47
 
49
48
  # Create Issues using the Issue template
50
- logger.info{ "\t\t => Creating new Issue: #{type}" }
49
+ logger.info { "\t\t => Creating new Issue: #{type}" }
51
50
 
52
51
  issue_text = mapping_service.apply_mapping(source: 'issue', data: xml_vuln)
53
52
  issue = content_service.create_issue(text: issue_text, id: type)
54
53
 
55
54
  # Create Evidence using the Evidence template
56
55
  # Associate the Evidence with the Node and Issue
57
- logger.info{ "\t\t => Creating new evidence" }
56
+ logger.info { "\t\t => Creating new evidence" }
58
57
  evidence_content = mapping_service.apply_mapping(
59
58
  source: 'evidence', data: xml_vuln
60
59
  )
60
+
61
+ node = get_node(xml_vuln, host_node)
62
+
61
63
  content_service.create_evidence(
62
- issue: issue, node: host_node, content: evidence_content
64
+ issue: issue, node: node, content: evidence_content
63
65
  )
64
66
  end
65
67
 
68
+ def get_node(xml_vuln, host_node)
69
+ url = xml_vuln.at_xpath('./url').text
70
+
71
+ # If the URL is a valid URI and is not the same as the host_node, create a new node
72
+ if url =~ URI::ABS_URI && URI(url).host != host_node.label
73
+ content_service.create_node(label: URI(url).host, type: :host)
74
+ else
75
+ host_node
76
+ end
77
+ end
66
78
  end
67
79
  end
@@ -147,6 +147,7 @@ module Netsparker
147
147
 
148
148
  result.gsub!(/<a .*?href=(?:\"|\')(.*?)(?:\"|\').*?>(?:<i.*?<\/i>)?(.*?)<\/a>/i) { "\"#{$2.strip}\":#{$1.strip}" }
149
149
 
150
+ result.gsub!(/<code>(.*?)<\/code>/) { "@#{$1}@" }
150
151
  result.gsub!(/<code><pre.*?>(.*?)<\/pre><\/code>/m) {|m| "\n\nbc.. #{$1}\n\np. \n" }
151
152
  result.gsub!(/<pre.*?>(.*?)<\/pre>/m) {|m| "\n\nbc.. #{$1}\n\np. \n" }
152
153
  result.gsub!(/<code>(.*?)<\/code>/m) {|m| "\n\nbc.. #{$1}\n\np. \n" }
@@ -0,0 +1,56 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <?xml-stylesheet href="vulnerabilities-list.xsl" type="text/xsl" ?>
3
+
4
+ <netsparker generated="1.2.2017 12:34:45">
5
+ <target>
6
+ <url>https://snorby.org/</url>
7
+ <scantime>1470</scantime>
8
+ </target>
9
+ <vulnerability confirmed="False">
10
+ <url>https://snorby.org/foo</url>
11
+ <type>EmailDisclosure</type>
12
+ <severity>Information</severity>
13
+ <certainty>95</certainty>
14
+
15
+ <rawrequest><rawrequest><![CDATA[REDACTED}]]></rawrequest></rawrequest>
16
+ <rawresponse><rawrequest><![CDATA[REDACTED}]]></rawrequest></rawresponse>
17
+ <extrainformation>
18
+ </extrainformation>
19
+
20
+ <proofs></proofs>
21
+ <classification>
22
+ <OWASP2013></OWASP2013>
23
+ <WASC>13</WASC>
24
+ <CWE>200</CWE>
25
+ <CAPEC>118</CAPEC>
26
+ <PCI31></PCI31>
27
+ <PCI32></PCI32>
28
+ <HIPAA></HIPAA>
29
+ <OWASPPC>C7</OWASPPC>
30
+ </classification>
31
+
32
+ </vulnerability>
33
+ <vulnerability confirmed="False">
34
+ <url>https://example.com</url>
35
+ <type>EmailDisclosure</type>
36
+ <severity>Information</severity>
37
+ <certainty>95</certainty>
38
+
39
+ <rawrequest><rawrequest><![CDATA[REDACTED}]]></rawrequest></rawrequest>
40
+ <rawresponse><rawrequest><![CDATA[REDACTED}]]></rawrequest></rawresponse>
41
+ <extrainformation>
42
+ <info name="Email Address(es)"><![CDATA[info@snorby.org]]></info>
43
+ </extrainformation>
44
+ <proofs></proofs>
45
+ <classification>
46
+ <OWASP2013></OWASP2013>
47
+ <WASC>13</WASC>
48
+ <CWE>200</CWE>
49
+ <CAPEC>118</CAPEC>
50
+ <PCI31></PCI31>
51
+ <PCI32></PCI32>
52
+ <HIPAA></HIPAA>
53
+ <OWASPPC>C7</OWASPPC>
54
+ </classification>
55
+ </vulnerability>
56
+ </netsparker>
@@ -0,0 +1,69 @@
1
+ require 'rails_helper'
2
+ require 'ostruct'
3
+
4
+ require File.expand_path('../../../../dradis-plugins/spec/support/spec_macros.rb', __FILE__)
5
+
6
+ include Dradis::Plugins::SpecMacros
7
+
8
+ module Dradis::Plugins
9
+ describe 'Netsparker upload plugin' do
10
+ before(:each) do
11
+ @fixtures_dir = File.expand_path('../../fixtures/files/', __FILE__)
12
+
13
+ stub_content_service
14
+
15
+ @importer = Dradis::Plugins::Netsparker::Importer.new(
16
+ content_service: @content_service
17
+ )
18
+ end
19
+
20
+ it 'creates the expected Node, Issue, and Evidence from the example file' do
21
+ expect(@content_service).to receive(:create_node).with(hash_including label: 'localhost', type: :host)
22
+
23
+ expect(@content_service).to receive(:create_issue) do |args|
24
+ expect(args[:text]).to include('All sensitive data should be transferred over HTTPS rather than HTTP')
25
+ expect(args[:id]).to eq('PasswordOverHttp')
26
+ OpenStruct.new(args)
27
+ end
28
+
29
+ expect(@content_service).to receive(:create_evidence) do |args|
30
+ expect(args[:content]).to include("#[Request]#\nbc.. GET /login HTTP/1.1")
31
+ expect(args[:issue].id).to eq('PasswordOverHttp')
32
+ expect(args[:node].label).to eq('localhost')
33
+ end
34
+
35
+ @importer.import(file: @fixtures_dir + '/example.xml')
36
+ end
37
+
38
+ it 'creates than one instance of Evidence for a single Issue' do
39
+ expect(@content_service).to receive(:create_node).with(hash_including label: 'snorby.org', type: :host)
40
+
41
+ expect(@content_service).to receive(:create_issue) do |args|
42
+ expect(args[:text]).to include("#[Severity]#\nInformation")
43
+ expect(args[:id]).to eq('EmailDisclosure')
44
+ OpenStruct.new(args)
45
+ end
46
+
47
+ expect(@content_service).to receive(:create_evidence) do |args|
48
+ expect(args[:content]).to include("#[URL]#\nhttps://snorby.org/foo")
49
+ expect(args[:issue].id).to eq('EmailDisclosure')
50
+ expect(args[:node].label).to eq('snorby.org')
51
+ end.once
52
+
53
+ expect(@content_service).to receive(:create_evidence) do |args|
54
+ expect(args[:content]).to include("#[URL]#\nhttps://snorby.org/bar")
55
+ expect(args[:issue].id).to eq('EmailDisclosure')
56
+ expect(args[:node].label).to eq('snorby.org')
57
+ end.once
58
+
59
+ @importer.import(file: @fixtures_dir + '/example-evidence.xml')
60
+ end
61
+
62
+ it 'creates multiple nodes for additional websites' do
63
+ expect(@content_service).to receive(:create_node).with(hash_including label: 'snorby.org', type: :host)
64
+ expect(@content_service).to receive(:create_node).with(hash_including label: 'example.com', type: :host)
65
+
66
+ @importer.import(file: @fixtures_dir + '/multiple-nodes.xml')
67
+ end
68
+ end
69
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dradis-netsparker
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.15.0
4
+ version: 4.16.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: 2024-12-20 00:00:00.000000000 Z
11
+ date: 2025-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dradis-plugins
@@ -122,11 +122,12 @@ files:
122
122
  - lib/dradis/plugins/netsparker/version.rb
123
123
  - lib/netsparker/vulnerability.rb
124
124
  - lib/tasks/thorfile.rb
125
- - spec/dradis-netsparker_spec.rb
126
125
  - spec/fixtures/files/example-evidence.xml
127
126
  - spec/fixtures/files/example.xml
127
+ - spec/fixtures/files/multiple-nodes.xml
128
128
  - spec/fixtures/files/netsparker-localhost-demo.xml
129
129
  - spec/fixtures/files/testsparker.xml
130
+ - spec/netsparker/importer_spec.rb
130
131
  - spec/spec_helper.rb
131
132
  - spec/vulnerability_spec.rb
132
133
  - templates/evidence.sample
@@ -155,10 +156,11 @@ signing_key:
155
156
  specification_version: 4
156
157
  summary: Netsparker add-on for the Dradis Framework.
157
158
  test_files:
158
- - spec/dradis-netsparker_spec.rb
159
159
  - spec/fixtures/files/example-evidence.xml
160
160
  - spec/fixtures/files/example.xml
161
+ - spec/fixtures/files/multiple-nodes.xml
161
162
  - spec/fixtures/files/netsparker-localhost-demo.xml
162
163
  - spec/fixtures/files/testsparker.xml
164
+ - spec/netsparker/importer_spec.rb
163
165
  - spec/spec_helper.rb
164
166
  - spec/vulnerability_spec.rb
@@ -1,85 +0,0 @@
1
- require 'spec_helper'
2
- require 'ostruct'
3
-
4
- module Dradis::Plugins
5
- describe 'Netsparker upload plugin' do
6
- before(:each) do
7
- # Stub template service
8
- templates_dir = File.expand_path('../../templates', __FILE__)
9
- expect_any_instance_of(TemplateService).to \
10
- receive(:default_templates_dir).and_return(templates_dir)
11
-
12
- plugin = Dradis::Plugins::Netsparker
13
-
14
- @content_service = Dradis::Plugins::ContentService::Base.new(
15
- logger: Logger.new(STDOUT),
16
- plugin: plugin
17
- )
18
-
19
- @importer = Dradis::Plugins::Netsparker::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
39
- end
40
-
41
- it "creates the expected Node, Issue, and Evidence from the example file" do
42
- expect(@content_service).to receive(:create_node).with(hash_including label: 'localhost', type: :host)
43
-
44
- expect(@content_service).to receive(:create_issue) do |args|
45
- expect(args[:text]).to include("#[Title]#\nPassword over http")
46
- expect(args[:id]).to eq("PasswordOverHttp")
47
- OpenStruct.new(args)
48
- end
49
-
50
- expect(@content_service).to receive(:create_evidence) do |args|
51
- expect(args[:content]).to include("#[Request]#\nbc.. GET /login HTTP/1.1")
52
- expect(args[:issue].id).to eq("PasswordOverHttp")
53
- expect(args[:node].label).to eq("localhost")
54
- end
55
-
56
- @importer.import(file: 'spec/fixtures/files/example.xml')
57
- end
58
-
59
- it "creates than one instance of Evidence for a single Issue" do
60
- expect(@content_service).to receive(:create_node).with(hash_including label: 'snorby.org', type: :host)
61
-
62
- expect(@content_service).to receive(:create_issue) do |args|
63
- expect(args[:text]).to include("#[Title]#\nEmail disclosure")
64
- expect(args[:id]).to eq("EmailDisclosure")
65
- OpenStruct.new(args)
66
- end
67
-
68
- expect(@content_service).to receive(:create_evidence) do |args|
69
- expect(args[:content]).to include("#[URL]#\nhttps://snorby.org/foo")
70
- expect(args[:issue].id).to eq("EmailDisclosure")
71
- expect(args[:node].label).to eq("snorby.org")
72
- end.once
73
-
74
- expect(@content_service).to receive(:create_evidence) do |args|
75
- expect(args[:content]).to include("#[URL]#\nhttps://snorby.org/bar")
76
- expect(args[:issue].id).to eq("EmailDisclosure")
77
- expect(args[:node].label).to eq("snorby.org")
78
- end.once
79
-
80
- @importer.import(file: 'spec/fixtures/files/example-evidence.xml')
81
- end
82
-
83
- end
84
-
85
- end