heimdall_tools 1.3.39 → 1.3.40
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/README.md +18 -0
- data/lib/heimdall_tools.rb +1 -0
- data/lib/heimdall_tools/cli.rb +12 -0
- data/lib/heimdall_tools/help/netsparker_mapper.md +7 -0
- data/lib/heimdall_tools/jfrog_xray_mapper.rb +9 -1
- data/lib/heimdall_tools/netsparker_mapper.rb +167 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a306a3ebf9a2755760b9cc825f1123a62291723d92d215c03d3e9d958d22497
|
|
4
|
+
data.tar.gz: 5e551876a20872c32126a6c96d08e3c6cd6acdf73bc31abf1ba918693764d4e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ed8a026a5fbbd63d3da4ebb4211d8ee8cc371ae29e57f4deb10f9e188491af29b2988e17524aa5ab4c064f62a44349edfa9b626641c89d6a958ff040df39e40
|
|
7
|
+
data.tar.gz: 2874bbd8f062e601ed1fb65b53ec53ee5267d7c17457cef91f936dd28936bac6f35b4387c3d452c301c593cdb13e01ea6d587c1885a88b1a6f025ac3ee38bdaa
|
data/README.md
CHANGED
|
@@ -15,6 +15,7 @@ HeimdallTools supplies several methods to convert output from various tools to "
|
|
|
15
15
|
- **jfrog_xray_mapper** - package vulnerability scanner
|
|
16
16
|
- **dbprotect_mapper** - database vulnerability scanner
|
|
17
17
|
- **aws_config_mapper** - assess, audit, and evaluate AWS resources
|
|
18
|
+
- **netsparker_mapper** - web application security scanner
|
|
18
19
|
|
|
19
20
|
Ruby 2.4 or higher (check using "ruby -v")
|
|
20
21
|
|
|
@@ -234,6 +235,23 @@ FLAGS:
|
|
|
234
235
|
example: heimdall_tools aws_config_mapper -o aws_config_results_hdf.json
|
|
235
236
|
```
|
|
236
237
|
|
|
238
|
+
## netsparker_mapper
|
|
239
|
+
|
|
240
|
+
netsparker_mapper translates an Netsparker XML results file into HDF format JSON to be viewable in Heimdall.
|
|
241
|
+
|
|
242
|
+
The current iteration only works with Netsparker Enterprise Vulnerabilities Scan.
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
USAGE: heimdall_tools netsparker_mapper [OPTIONS] -x <netsparker_results_xml> -o <hdf-scan-results.json>
|
|
246
|
+
|
|
247
|
+
FLAGS:
|
|
248
|
+
-x <netsparker_results_xml> : path to netsparker results XML file.
|
|
249
|
+
-o --output <scan-results> : path to output scan-results json.
|
|
250
|
+
-V --verbose : verbose run [optional].
|
|
251
|
+
|
|
252
|
+
example: heimdall_tools netsparker_mapper -x netsparker_results.xml -o netsparker_hdf.json
|
|
253
|
+
```
|
|
254
|
+
|
|
237
255
|
## version
|
|
238
256
|
|
|
239
257
|
Prints out the gem version
|
data/lib/heimdall_tools.rb
CHANGED
|
@@ -15,4 +15,5 @@ module HeimdallTools
|
|
|
15
15
|
autoload :JfrogXrayMapper, 'heimdall_tools/jfrog_xray_mapper'
|
|
16
16
|
autoload :DBProtectMapper, 'heimdall_tools/dbprotect_mapper'
|
|
17
17
|
autoload :AwsConfigMapper, 'heimdall_tools/aws_config_mapper'
|
|
18
|
+
autoload :NetsparkerMapper, 'heimdall_tools/netsparker_mapper'
|
|
18
19
|
end
|
data/lib/heimdall_tools/cli.rb
CHANGED
|
@@ -122,6 +122,18 @@ module HeimdallTools
|
|
|
122
122
|
puts "\r\HDF Generated:\n"
|
|
123
123
|
puts "#{options[:output]}"
|
|
124
124
|
end
|
|
125
|
+
|
|
126
|
+
desc 'netsparker_mapper', 'netsparker_mapper translates netsparker enterprise results xml to HDF format Json be viewed on Heimdall'
|
|
127
|
+
long_desc Help.text(:netsparker_mapper)
|
|
128
|
+
option :xml, required: true, aliases: '-x'
|
|
129
|
+
option :output, required: true, aliases: '-o'
|
|
130
|
+
option :verbose, type: :boolean, aliases: '-V'
|
|
131
|
+
def netsparker_mapper
|
|
132
|
+
hdf = HeimdallTools::NetsparkerMapper.new(File.read(options[:xml])).to_hdf
|
|
133
|
+
File.write(options[:output], hdf)
|
|
134
|
+
puts "\r\HDF Generated:\n"
|
|
135
|
+
puts "#{options[:output]}"
|
|
136
|
+
end
|
|
125
137
|
|
|
126
138
|
desc 'version', 'prints version'
|
|
127
139
|
def version
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
netsparker_mapper translates an Netsparker XML results file into HDF format json to be viewable in Heimdall
|
|
2
|
+
|
|
3
|
+
The current iteration only works with Netsparker Enterprise Vulnerabilities Scan.
|
|
4
|
+
|
|
5
|
+
Examples:
|
|
6
|
+
|
|
7
|
+
heimdall_tools netsparker_mapper -x netsparker_results.xml -o netsparker_hdf.json
|
|
@@ -57,6 +57,14 @@ module HeimdallTools
|
|
|
57
57
|
[finding]
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
def format_control_desc(vulnerability)
|
|
61
|
+
text = []
|
|
62
|
+
info = vulnerability['component_versions']['more_details']
|
|
63
|
+
text << info['description'].to_s
|
|
64
|
+
text << "cves: #{info['cves'].to_s }" unless info['cves'].nil?
|
|
65
|
+
text.join("<br>")
|
|
66
|
+
end
|
|
67
|
+
|
|
60
68
|
def nist_tag(cweid)
|
|
61
69
|
entries = @cwe_nist_mapping.select { |x| cweid.include?(x[:cweid].to_s) && !x[:nistid].nil? }
|
|
62
70
|
tags = entries.map { |x| x[:nistid] }
|
|
@@ -119,7 +127,7 @@ module HeimdallTools
|
|
|
119
127
|
# If thats a case MD5 hash is used to collapse vulnerability findings of the same type.
|
|
120
128
|
item['id'] = vulnerability['id'].empty? ? OpenSSL::Digest::MD5.digest(vulnerability['summary'].to_s).unpack("H*")[0].to_s : vulnerability['id']
|
|
121
129
|
item['title'] = vulnerability['summary'].to_s
|
|
122
|
-
item['desc'] = vulnerability
|
|
130
|
+
item['desc'] = format_control_desc(vulnerability)
|
|
123
131
|
item['impact'] = impact(vulnerability['severity'].to_s)
|
|
124
132
|
item['code'] = NA_STRING
|
|
125
133
|
item['results'] = finding(vulnerability)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'csv'
|
|
3
|
+
require 'heimdall_tools/hdf'
|
|
4
|
+
require 'utilities/xml_to_hash'
|
|
5
|
+
|
|
6
|
+
RESOURCE_DIR = Pathname.new(__FILE__).join('../../data')
|
|
7
|
+
|
|
8
|
+
CWE_NIST_MAPPING_FILE = File.join(RESOURCE_DIR, 'cwe-nist-mapping.csv')
|
|
9
|
+
OWASP_NIST_MAPPING_FILE = File.join(RESOURCE_DIR, 'owasp-nist-mapping.csv')
|
|
10
|
+
|
|
11
|
+
IMPACT_MAPPING = {
|
|
12
|
+
Critical: 1.0,
|
|
13
|
+
High: 0.7,
|
|
14
|
+
Medium: 0.5,
|
|
15
|
+
Low: 0.3,
|
|
16
|
+
Best_Practice: 0.0,
|
|
17
|
+
Information: 0.0
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
DEFAULT_NIST_TAG = ["SA-11", "RA-5"].freeze
|
|
21
|
+
|
|
22
|
+
# rubocop:disable Metrics/AbcSize
|
|
23
|
+
|
|
24
|
+
module HeimdallTools
|
|
25
|
+
class NetsparkerMapper
|
|
26
|
+
def initialize(xml, name=nil, verbose = false)
|
|
27
|
+
@verbose = verbose
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
@cwe_nist_mapping = parse_mapper(CWE_NIST_MAPPING_FILE)
|
|
31
|
+
@owasp_nist_mapping = parse_mapper(OWASP_NIST_MAPPING_FILE)
|
|
32
|
+
data = xml_to_hash(xml)
|
|
33
|
+
|
|
34
|
+
@vulnerabilities = data['netsparker-enterprise']['vulnerabilities']['vulnerability']
|
|
35
|
+
@scan_info = data['netsparker-enterprise']['target']
|
|
36
|
+
|
|
37
|
+
rescue StandardError => e
|
|
38
|
+
raise "Invalid Netsparker XML file provided Exception: #{e}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_hdf
|
|
43
|
+
controls = []
|
|
44
|
+
@vulnerabilities.each do |vulnerability|
|
|
45
|
+
@item = {}
|
|
46
|
+
@item['id'] = vulnerability['LookupId'].to_s
|
|
47
|
+
@item['title'] = vulnerability['name'].to_s
|
|
48
|
+
@item['desc'] = format_control_desc(vulnerability)
|
|
49
|
+
@item['impact'] = impact(vulnerability['severity'])
|
|
50
|
+
@item['tags'] = {}
|
|
51
|
+
@item['descriptions'] = []
|
|
52
|
+
|
|
53
|
+
@item['descriptions'] << desc_tags(format_check_text(vulnerability), 'check')
|
|
54
|
+
@item['descriptions'] << desc_tags(format_fix_text(vulnerability), 'fix')
|
|
55
|
+
@item['refs'] = NA_ARRAY
|
|
56
|
+
@item['source_location'] = NA_HASH
|
|
57
|
+
@item['tags']['nist'] = nist_tag(vulnerability['classification'])
|
|
58
|
+
@item['code'] = ''
|
|
59
|
+
@item['results'] = finding(vulnerability)
|
|
60
|
+
|
|
61
|
+
controls << @item
|
|
62
|
+
end
|
|
63
|
+
controls = collapse_duplicates(controls)
|
|
64
|
+
results = HeimdallDataFormat.new(profile_name: 'Netsparker Enterprise Scan',
|
|
65
|
+
title: "Netsparker Enterprise Scan ID: #{@scan_info['scan-id']} URL: #{@scan_info['url']}",
|
|
66
|
+
summary: "Netsparker Enterprise Scan",
|
|
67
|
+
target_id: @scan_info['url'],
|
|
68
|
+
controls: controls)
|
|
69
|
+
results.to_hdf
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def parse_html(block)
|
|
75
|
+
block['#cdata-section'].to_s.strip unless block.nil?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def finding(vulnerability)
|
|
79
|
+
finding = {}
|
|
80
|
+
finding['status'] = 'failed'
|
|
81
|
+
finding['code_desc'] = []
|
|
82
|
+
finding['code_desc'] << "http-request : #{parse_html(vulnerability['http-request']['content']) }"
|
|
83
|
+
finding['code_desc'] << "method : #{vulnerability['http-request']['method']}"
|
|
84
|
+
finding['code_desc'] = finding['code_desc'].join("\n")
|
|
85
|
+
|
|
86
|
+
finding['message'] = []
|
|
87
|
+
finding['message'] << "http-response : #{parse_html(vulnerability['http-response']['content']) }"
|
|
88
|
+
finding['message'] << "duration : #{vulnerability['http-response']['duration']}"
|
|
89
|
+
finding['message'] << "status-code : #{vulnerability['http-response']['status-code']}"
|
|
90
|
+
finding['message'] = finding['message'].join("\n")
|
|
91
|
+
finding['run_time'] = NA_FLOAT
|
|
92
|
+
|
|
93
|
+
finding['start_time'] = @scan_info['initiated']
|
|
94
|
+
[finding]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def format_control_desc(vulnerability)
|
|
98
|
+
text = []
|
|
99
|
+
text << "#{parse_html(vulnerability['description'])}" unless vulnerability['description'].nil?
|
|
100
|
+
text << "Exploitation-skills: #{parse_html(vulnerability['exploitation-skills'])}" unless vulnerability['exploitation-skills'].nil?
|
|
101
|
+
text << "Extra-information: #{vulnerability['extra-information']}" unless vulnerability['extra-information'].nil?
|
|
102
|
+
text << "Classification: #{vulnerability['classification']}" unless vulnerability['classification'].nil?
|
|
103
|
+
text << "Impact: #{parse_html(vulnerability['impact'])}" unless vulnerability['impact'].nil?
|
|
104
|
+
text << "FirstSeenDate: #{vulnerability['FirstSeenDate']}" unless vulnerability['FirstSeenDate'].nil?
|
|
105
|
+
text << "LastSeenDate: #{vulnerability['LastSeenDate']}" unless vulnerability['LastSeenDate'].nil?
|
|
106
|
+
text << "Certainty: #{vulnerability['certainty']}" unless vulnerability['certainty'].nil?
|
|
107
|
+
text << "Type: #{vulnerability['type']}" unless vulnerability['type'].nil?
|
|
108
|
+
text << "Confirmed: #{vulnerability['confirmed']}" unless vulnerability['confirmed'].nil?
|
|
109
|
+
text.join("<br>")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def format_check_text(vulnerability)
|
|
113
|
+
text = []
|
|
114
|
+
text << "Exploitation-skills: #{parse_html(vulnerability['exploitation-skills'])}" unless vulnerability['exploitation-skills'].nil?
|
|
115
|
+
text << "Proof-of-concept: #{parse_html(vulnerability['proof-of-concept'])}" unless vulnerability['proof-of-concept'].nil?
|
|
116
|
+
text.join("<br>")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def format_fix_text(vulnerability)
|
|
120
|
+
text = []
|
|
121
|
+
text << "Remedial-actions: #{parse_html(vulnerability['remedial-actions'])}" unless vulnerability['remedial-actions'].nil?
|
|
122
|
+
text << "Remedial-procedure: #{parse_html(vulnerability['remedial-procedure'])}" unless vulnerability['remedial-procedure'].nil?
|
|
123
|
+
text << "Remedy-references: #{parse_html(vulnerability['remedy-references'])}" unless vulnerability['remedy-references'].nil?
|
|
124
|
+
text.join("<br>")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def nist_tag(classification)
|
|
128
|
+
tags = []
|
|
129
|
+
entries = @cwe_nist_mapping.select { |x| classification['cwe'].include?(x[:cweid].to_s) && !x[:nistid].nil? }
|
|
130
|
+
tags << entries.map { |x| x[:nistid] }
|
|
131
|
+
entries = @owasp_nist_mapping.select { |x| classification['owasp'].include?(x[:owaspid].to_s) && !x[:nistid].nil? }
|
|
132
|
+
tags << entries.map { |x| x[:nistid] }
|
|
133
|
+
tags.flatten.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def impact(severity)
|
|
137
|
+
IMPACT_MAPPING[severity.to_sym]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def parse_mapper(mapping_file)
|
|
141
|
+
csv_data = CSV.read(mapping_file, { encoding: 'UTF-8',
|
|
142
|
+
headers: true,
|
|
143
|
+
header_converters: :symbol,
|
|
144
|
+
converters: :all })
|
|
145
|
+
csv_data.map(&:to_hash)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def desc_tags(data, label)
|
|
149
|
+
{ "data": data || NA_STRING, "label": label || NA_STRING }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Netsparker report could have multiple issue entries for multiple findings of same issue type.
|
|
153
|
+
# The meta data is identical across entries
|
|
154
|
+
# method collapse_duplicates return unique controls with applicable findings collapsed into it.
|
|
155
|
+
def collapse_duplicates(controls)
|
|
156
|
+
unique_controls = []
|
|
157
|
+
|
|
158
|
+
controls.map { |x| x['id'] }.uniq.each do |id|
|
|
159
|
+
collapsed_results = controls.select { |x| x['id'].eql?(id) }.map {|x| x['results']}
|
|
160
|
+
unique_control = controls.find { |x| x['id'].eql?(id) }
|
|
161
|
+
unique_control['results'] = collapsed_results.flatten
|
|
162
|
+
unique_controls << unique_control
|
|
163
|
+
end
|
|
164
|
+
unique_controls
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: heimdall_tools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.40
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Thew
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: exe
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2021-03-
|
|
13
|
+
date: 2021-03-16 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: aws-sdk-configservice
|
|
@@ -215,12 +215,14 @@ files:
|
|
|
215
215
|
- lib/heimdall_tools/help/fortify_mapper.md
|
|
216
216
|
- lib/heimdall_tools/help/jfrog_xray_mapper.md
|
|
217
217
|
- lib/heimdall_tools/help/nessus_mapper.md
|
|
218
|
+
- lib/heimdall_tools/help/netsparker_mapper.md
|
|
218
219
|
- lib/heimdall_tools/help/nikto_mapper.md
|
|
219
220
|
- lib/heimdall_tools/help/snyk_mapper.md
|
|
220
221
|
- lib/heimdall_tools/help/sonarqube_mapper.md
|
|
221
222
|
- lib/heimdall_tools/help/zap_mapper.md
|
|
222
223
|
- lib/heimdall_tools/jfrog_xray_mapper.rb
|
|
223
224
|
- lib/heimdall_tools/nessus_mapper.rb
|
|
225
|
+
- lib/heimdall_tools/netsparker_mapper.rb
|
|
224
226
|
- lib/heimdall_tools/nikto_mapper.rb
|
|
225
227
|
- lib/heimdall_tools/snyk_mapper.rb
|
|
226
228
|
- lib/heimdall_tools/sonarqube_mapper.rb
|