heimdall_tools 1.3.41 → 1.3.46
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 +51 -2
- data/lib/data/aws-config-mapping.csv +107 -107
- data/lib/data/scoutsuite-nist-mapping.csv +140 -0
- data/lib/heimdall_tools.rb +2 -0
- data/lib/heimdall_tools/aws_config_mapper.rb +35 -17
- data/lib/heimdall_tools/burpsuite_mapper.rb +1 -2
- data/lib/heimdall_tools/cli.rb +23 -11
- data/lib/heimdall_tools/dbprotect_mapper.rb +5 -9
- data/lib/heimdall_tools/fortify_mapper.rb +1 -2
- data/lib/heimdall_tools/help/sarif_mapper.md +12 -0
- data/lib/heimdall_tools/help/scoutsuite_mapper.md +7 -0
- data/lib/heimdall_tools/jfrog_xray_mapper.rb +1 -2
- data/lib/heimdall_tools/nessus_mapper.rb +3 -3
- data/lib/heimdall_tools/netsparker_mapper.rb +9 -13
- data/lib/heimdall_tools/nikto_mapper.rb +1 -2
- data/lib/heimdall_tools/sarif_mapper.rb +198 -0
- data/lib/heimdall_tools/scoutsuite_mapper.rb +180 -0
- data/lib/heimdall_tools/snyk_mapper.rb +1 -2
- data/lib/heimdall_tools/zap_mapper.rb +1 -4
- metadata +10 -5
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'csv'
|
3
|
+
require 'heimdall_tools/hdf'
|
4
|
+
|
5
|
+
RESOURCE_DIR = Pathname.new(__FILE__).join('../../data')
|
6
|
+
|
7
|
+
SCOUTSUITE_NIST_MAPPING_FILE = File.join(RESOURCE_DIR, 'scoutsuite-nist-mapping.csv')
|
8
|
+
|
9
|
+
IMPACT_MAPPING = {
|
10
|
+
danger: 0.7,
|
11
|
+
warning: 0.5
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
DEFAULT_NIST_TAG = %w{SA-11 RA-5}.freeze
|
15
|
+
|
16
|
+
INSPEC_INPUTS_MAPPING = {
|
17
|
+
string: 'String',
|
18
|
+
numeric: 'Numeric',
|
19
|
+
regexp: 'Regexp',
|
20
|
+
array: 'Array',
|
21
|
+
hash: 'Hash',
|
22
|
+
boolean: 'Boolean',
|
23
|
+
any: 'Any'
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
# Loading spinner sign
|
27
|
+
$spinner = Enumerator.new do |e|
|
28
|
+
loop do
|
29
|
+
e.yield '|'
|
30
|
+
e.yield '/'
|
31
|
+
e.yield '-'
|
32
|
+
e.yield '\\'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module HeimdallTools
|
37
|
+
# currently only tested against an AWS based result, but ScoutSuite supports many other cloud providers such as Azure
|
38
|
+
class ScoutSuiteMapper
|
39
|
+
def initialize(scoutsuite_js)
|
40
|
+
begin
|
41
|
+
@scoutsuite_nist_mapping = parse_mapper
|
42
|
+
rescue StandardError => e
|
43
|
+
raise "Invalid Scout Suite to NIST mapping file:\nException: #{e}"
|
44
|
+
end
|
45
|
+
|
46
|
+
begin
|
47
|
+
@scoutsuite_json = scoutsuite_js.lines[1] # first line is `scoutsuite_results =\n` and second line is json
|
48
|
+
@report = JSON.parse(@scoutsuite_json)
|
49
|
+
rescue StandardError => e
|
50
|
+
raise "Invalid Scout Suite JavaScript file provided:\nException: #{e}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_mapper
|
55
|
+
csv_data = CSV.read(SCOUTSUITE_NIST_MAPPING_FILE, { encoding: 'UTF-8', headers: true, header_converters: :symbol })
|
56
|
+
csv_data.map(&:to_hash)
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_attribute(name, value, required = nil, sensitive = nil, type = nil)
|
60
|
+
{ name: name, options: { value: value, required: required, sensitive: sensitive, type: type }.compact }
|
61
|
+
end
|
62
|
+
|
63
|
+
def extract_scaninfo(report)
|
64
|
+
info = {}
|
65
|
+
begin
|
66
|
+
info['name'] = 'Scout Suite Multi-Cloud Security Auditing Tool'
|
67
|
+
info['version'] = report['last_run']['version']
|
68
|
+
info['title'] = "Scout Suite Report using #{report['last_run']['ruleset_name']} ruleset on #{report['provider_name']} with account #{report['account_id']}"
|
69
|
+
info['target_id'] = "#{report['last_run']['ruleset_name']} ruleset:#{report['provider_name']}:#{report['account_id']}"
|
70
|
+
info['summary'] = report['last_run']['ruleset_about']
|
71
|
+
info['attributes'] = [
|
72
|
+
create_attribute('account_id', report['account_id'], true, false, INSPEC_INPUTS_MAPPING[:string]),
|
73
|
+
create_attribute('environment', report['environment']),
|
74
|
+
create_attribute('ruleset', report['ruleset_name']),
|
75
|
+
# think at least these run_parameters are aws only
|
76
|
+
create_attribute('run_parameters_excluded_regions', report['last_run']['run_parameters']['excluded_regions'].join(', ')),
|
77
|
+
create_attribute('run_parameters_regions', report['last_run']['run_parameters']['regions'].join(', ')),
|
78
|
+
create_attribute('run_parameters_services', report['last_run']['run_parameters']['services'].join(', ')),
|
79
|
+
create_attribute('run_parameters_skipped_services', report['last_run']['run_parameters']['skipped_services'].join(', ')),
|
80
|
+
create_attribute('time', report['last_run']['time']),
|
81
|
+
create_attribute('partition', report['partition']), # think this is aws only
|
82
|
+
create_attribute('provider_code', report['provider_code']),
|
83
|
+
create_attribute('provider_name', report['provider_name']),
|
84
|
+
]
|
85
|
+
|
86
|
+
info
|
87
|
+
rescue StandardError => e
|
88
|
+
raise "Error extracting report info from Scout Suite JS->JSON file:\nException: #{e}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def nist_tag(rule)
|
93
|
+
entries = @scoutsuite_nist_mapping.select { |x| rule.eql?(x[:rule].to_s) && !x[:nistid].nil? }
|
94
|
+
tags = entries.map { |x| x[:nistid].split('|') }
|
95
|
+
tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
|
96
|
+
end
|
97
|
+
|
98
|
+
def impact(severity)
|
99
|
+
IMPACT_MAPPING[severity.to_sym]
|
100
|
+
end
|
101
|
+
|
102
|
+
def desc_tags(data, label)
|
103
|
+
{ data: data || NA_STRING, label: label || NA_STRING }
|
104
|
+
end
|
105
|
+
|
106
|
+
def findings(details)
|
107
|
+
finding = {}
|
108
|
+
if (details['checked_items']).zero?
|
109
|
+
finding['status'] = 'skipped'
|
110
|
+
finding['skip_message'] = 'Skipped because no items were checked'
|
111
|
+
elsif (details['flagged_items']).zero?
|
112
|
+
finding['status'] = 'passed'
|
113
|
+
finding['message'] = "0 flagged items out of #{details['checked_items']} checked items"
|
114
|
+
else # there are checked items and things were flagged
|
115
|
+
finding['status'] = 'failed'
|
116
|
+
finding['message'] = "#{details['flagged_items']} flagged items out of #{details['checked_items']} checked items:\n#{details['items'].join("\n")}"
|
117
|
+
end
|
118
|
+
finding['code_desc'] = details['description']
|
119
|
+
finding['start_time'] = @report['last_run']['time']
|
120
|
+
[finding]
|
121
|
+
end
|
122
|
+
|
123
|
+
def compliance(arr)
|
124
|
+
str = 'Compliant with '
|
125
|
+
arr.map do |val|
|
126
|
+
info = "#{val['name']}, reference #{val['reference']}, version #{val['version']}"
|
127
|
+
str + info
|
128
|
+
end.join("\n")
|
129
|
+
end
|
130
|
+
|
131
|
+
def to_hdf
|
132
|
+
controls = []
|
133
|
+
@report['services'].each_key do |service|
|
134
|
+
@report['services'][service]['findings'].each_key do |finding|
|
135
|
+
printf("\rProcessing: %s", $spinner.next)
|
136
|
+
|
137
|
+
finding_id = finding
|
138
|
+
finding_details = @report['services'][service]['findings'][finding]
|
139
|
+
|
140
|
+
item = {}
|
141
|
+
item['id'] = finding_id
|
142
|
+
item['title'] = finding_details['description']
|
143
|
+
|
144
|
+
item['tags'] = { nist: nist_tag(finding_id) }
|
145
|
+
|
146
|
+
item['impact'] = impact(finding_details['level'])
|
147
|
+
|
148
|
+
item['desc'] = finding_details['rationale']
|
149
|
+
|
150
|
+
item['descriptions'] = []
|
151
|
+
item['descriptions'] << desc_tags(finding_details['remediation'], 'fix') unless finding_details['remediation'].nil?
|
152
|
+
item['descriptions'] << desc_tags(finding_details['service'], 'service')
|
153
|
+
item['descriptions'] << desc_tags(finding_details['path'], 'path')
|
154
|
+
item['descriptions'] << desc_tags(finding_details['id_suffix'], 'id_suffix')
|
155
|
+
|
156
|
+
item['refs'] = []
|
157
|
+
item['refs'] += finding_details['references'].map { |link| { url: link } } unless finding_details['references'].nil? || finding_details['references'].empty?
|
158
|
+
item['refs'] << { ref: compliance(finding_details['compliance']) } unless finding_details['compliance'].nil?
|
159
|
+
|
160
|
+
item['source_location'] = NA_HASH
|
161
|
+
item['code'] = NA_STRING
|
162
|
+
|
163
|
+
item['results'] = findings(finding_details)
|
164
|
+
|
165
|
+
controls << item
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
scaninfo = extract_scaninfo(@report)
|
170
|
+
results = HeimdallDataFormat.new(profile_name: scaninfo['name'],
|
171
|
+
version: scaninfo['version'],
|
172
|
+
title: scaninfo['title'],
|
173
|
+
summary: scaninfo['summary'],
|
174
|
+
controls: controls,
|
175
|
+
target_id: scaninfo['target_id'],
|
176
|
+
attributes: scaninfo['attributes'])
|
177
|
+
results.to_hdf
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -8,13 +8,10 @@ RESOURCE_DIR = Pathname.new(__FILE__).join('../../data')
|
|
8
8
|
CWE_NIST_MAPPING_FILE = File.join(RESOURCE_DIR, 'cwe-nist-mapping.csv')
|
9
9
|
DEFAULT_NIST_TAG = %w{SA-11 RA-5}.freeze
|
10
10
|
|
11
|
-
# rubocop:disable Metrics/AbcSize
|
12
|
-
|
13
11
|
module HeimdallTools
|
14
12
|
class ZapMapper
|
15
|
-
def initialize(zap_json, name
|
13
|
+
def initialize(zap_json, name)
|
16
14
|
@zap_json = zap_json
|
17
|
-
@verbose = verbose
|
18
15
|
|
19
16
|
begin
|
20
17
|
data = JSON.parse(zap_json, symbolize_names: true)
|
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.46
|
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-
|
13
|
+
date: 2021-05-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws-sdk-configservice
|
@@ -88,14 +88,14 @@ dependencies:
|
|
88
88
|
requirements:
|
89
89
|
- - "~>"
|
90
90
|
- !ruby/object:Gem::Version
|
91
|
-
version: 1.
|
91
|
+
version: '1.11'
|
92
92
|
type: :runtime
|
93
93
|
prerelease: false
|
94
94
|
version_requirements: !ruby/object:Gem::Requirement
|
95
95
|
requirements:
|
96
96
|
- - "~>"
|
97
97
|
- !ruby/object:Gem::Version
|
98
|
-
version: 1.
|
98
|
+
version: '1.11'
|
99
99
|
- !ruby/object:Gem::Dependency
|
100
100
|
name: openssl
|
101
101
|
requirement: !ruby/object:Gem::Requirement
|
@@ -214,6 +214,7 @@ files:
|
|
214
214
|
- lib/data/nessus-plugins-nist-mapping.csv
|
215
215
|
- lib/data/nikto-nist-mapping.csv
|
216
216
|
- lib/data/owasp-nist-mapping.csv
|
217
|
+
- lib/data/scoutsuite-nist-mapping.csv
|
217
218
|
- lib/heimdall_tools.rb
|
218
219
|
- lib/heimdall_tools/aws_config_mapper.rb
|
219
220
|
- lib/heimdall_tools/burpsuite_mapper.rb
|
@@ -231,6 +232,8 @@ files:
|
|
231
232
|
- lib/heimdall_tools/help/nessus_mapper.md
|
232
233
|
- lib/heimdall_tools/help/netsparker_mapper.md
|
233
234
|
- lib/heimdall_tools/help/nikto_mapper.md
|
235
|
+
- lib/heimdall_tools/help/sarif_mapper.md
|
236
|
+
- lib/heimdall_tools/help/scoutsuite_mapper.md
|
234
237
|
- lib/heimdall_tools/help/snyk_mapper.md
|
235
238
|
- lib/heimdall_tools/help/sonarqube_mapper.md
|
236
239
|
- lib/heimdall_tools/help/zap_mapper.md
|
@@ -238,6 +241,8 @@ files:
|
|
238
241
|
- lib/heimdall_tools/nessus_mapper.rb
|
239
242
|
- lib/heimdall_tools/netsparker_mapper.rb
|
240
243
|
- lib/heimdall_tools/nikto_mapper.rb
|
244
|
+
- lib/heimdall_tools/sarif_mapper.rb
|
245
|
+
- lib/heimdall_tools/scoutsuite_mapper.rb
|
241
246
|
- lib/heimdall_tools/snyk_mapper.rb
|
242
247
|
- lib/heimdall_tools/sonarqube_mapper.rb
|
243
248
|
- lib/heimdall_tools/version.rb
|
@@ -262,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
262
267
|
- !ruby/object:Gem::Version
|
263
268
|
version: '0'
|
264
269
|
requirements: []
|
265
|
-
rubygems_version: 3.2.
|
270
|
+
rubygems_version: 3.2.15
|
266
271
|
signing_key:
|
267
272
|
specification_version: 4
|
268
273
|
summary: Convert Forify, Openzap and Sonarqube results to HDF
|