heimdall_tools 1.3.45 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87936a7488cf8da17690bb3c35d5138a2e9442d8d4c48b307307f4d44423b987
4
- data.tar.gz: 28f172cc25391e697910bb1b2b79fea29c82956cbca953f1e7978080b4e1d646
3
+ metadata.gz: 24ad070383569e79ac08bbc0cae7a049a0f48cbc971d6d897ee2b5aa0989affe
4
+ data.tar.gz: 993a995384452cf8457b3545e3aaddae4b6f6165453f139b9c33b35e3357ed82
5
5
  SHA512:
6
- metadata.gz: bf394cd989527e58e45755881a01ad5d91761201f0a054e5a92a69ae3ac9b943569ef400298d31afee4514b72f3f7b77212b8bcc189107e355c45e1c2758e41d
7
- data.tar.gz: 54c1a3447b631b28c024f0bc77559834464bccc518463a2fee0313d7b19f6252db9d624058eda3118423178f736e080ccffa5601b2cc7ec2daa98332a90d1e8f
6
+ metadata.gz: 65e3d1c2566de4d114f75a0de1659cc895b65045718300559179d86f33d2b9dd9110ee8b106944d1ef764ca89efb5a40bd67891534c095e7b1c37dd709f9c4a9
7
+ data.tar.gz: 2841a54f0abca5d37f4051800f29a90a410bf9599addbfe538d603dae9f725e0c99229c6129fadaee0401cc65a8d5abbbd54ea76d9996d317c4bf1199c4a483a
data/README.md CHANGED
@@ -9,13 +9,15 @@ HeimdallTools supplies several methods to convert output from various tools to "
9
9
  - **fortify_mapper** - commercial static code analysis tool
10
10
  - **zap_mapper** - OWASP ZAP - open-source dynamic code analysis tool
11
11
  - **burpsuite_mapper** - commercial dynamic analysis tool
12
- - **nessus_mapper** - commercial vulnerability scanner
12
+ - **nessus_mapper** - commercial security scanner (supports compliance and vulnerability scans from Tenable.sc and Tenable.io)
13
13
  - **snyk_mapper** - commercial package vulnerability scanner
14
14
  - **nikto_mapper** - open-source web server scanner
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
18
  - **netsparker_mapper** - web application security scanner
19
+ - **sarif_mapper** - static analysis results interchange format
20
+ - **scoutsuite_mapper** - multi-cloud security auditing tool
19
21
 
20
22
  ## Want to recommend a mapper for another tool? Please use these steps:
21
23
  1. Create an [issue](https://github.com/mitre/heimdall_tools/issues/new), and email saf@groups.mitre.org citing the issue link so we can help
@@ -151,7 +153,8 @@ example: heimdall_tools burpsuite_mapper -x burpsuite_results.xml -o scan_result
151
153
 
152
154
  ## nessus_mapper
153
155
 
154
- nessus_mapper translates a Nessus-exported XML results file into HDF format json to be viewable in Heimdall
156
+ nessus_mapper translates a Nessus-exported XML results file into HDF format json to be viewable in Heimdall.
157
+ Supports compliance and vulnerability scans from Tenable.sc and Tenable.io.
155
158
 
156
159
  Note: A separate HDF JSON file is generated for each host reported in the Nessus Report.
157
160
 
@@ -200,6 +203,22 @@ FLAGS:
200
203
  example: heimdall_tools nikto_mapper -j nikto_results.json -o nikto_results.json
201
204
  ```
202
205
 
206
+ ## scoutsuite_mapper
207
+
208
+ scoutsuite_mapper translates Scout Suite results from Javascript to HDF-formatted JSON so as to be viewable on Heimdall
209
+
210
+ Note: Currently this mapper only supports AWS.
211
+
212
+ ```
213
+ USAGE: heimdall_tools scoutsuite_mapper -i <scoutsuite-results-js> -o <hdf-scan-results-json>
214
+
215
+ FLAGS:
216
+ -i --input -j --javascript <scoutsuite-results-js> : path to Scout Suite results Javascript file.
217
+ -o --output <hdf-scan-results-json> : path to output scan-results json.
218
+
219
+ example: heimdall_tools scoutsuite_mapper -i scoutsuite_results.js -o scoutsuite_hdf.json
220
+ ```
221
+
203
222
  ## jfrog_xray_mapper
204
223
 
205
224
  jfrog_xray_mapper translates an JFrog Xray results JSON file into HDF format JSON to be viewable in Heimdall
@@ -267,6 +286,21 @@ FLAGS:
267
286
  example: heimdall_tools netsparker_mapper -x netsparker_results.xml -o netsparker_hdf.json
268
287
  ```
269
288
 
289
+ ## sarif_mapper
290
+
291
+ sarif_mapper translates a SARIF JSON file into HDF format JSON to be viewable in Heimdall
292
+
293
+ ```
294
+ USAGE: heimdall_tools sarif_mapper [OPTIONS] -j <sarif-results-json> -o <hdf-scan-results.json>
295
+
296
+ FLAGS:
297
+ -j <sarif_results_json> : path to SARIF results JSON file.
298
+ -o --output_prefix <prefix> : path to output scan-results json.
299
+ -V --verbose : verbose run [optional].
300
+
301
+ example: heimdall_tools sarif_mapper -j sarif_results.json -o sarif_results_hdf.json
302
+ ```
303
+
270
304
  ## version
271
305
 
272
306
  Prints out the gem version
@@ -0,0 +1,140 @@
1
+ rule,nistid
2
+ acm-certificate-with-close-expiration-date,SC-12
3
+ acm-certificate-with-transparency-logging-disabled,SC-12
4
+ cloudformation-stack-with-role,AC-6
5
+ cloudtrail-duplicated-global-services-logging,AU-6
6
+ cloudtrail-no-cloudwatch-integration,AU-12|SI-4(2)
7
+ cloudtrail-no-data-logging,AU-12
8
+ cloudtrail-no-encryption-with-kms,AU-6
9
+ cloudtrail-no-global-services-logging,AU-12
10
+ cloudtrail-no-log-file-validation,AU-6
11
+ cloudtrail-no-logging,AU-12
12
+ cloudtrail-not-configured,AU-12
13
+ cloudwatch-alarm-without-actions,AU-12
14
+ config-recorder-not-configured,CM-8|CM-8(2)|CM-8(6)
15
+ ec2-ami-public,AC-3
16
+ ec2-default-security-group-in-use,AC-3(3)
17
+ ec2-default-security-group-with-rules,AC-3(3)
18
+ ec2-ebs-snapshot-not-encrypted,SC-28
19
+ ec2-ebs-snapshot-public,AC-3
20
+ ec2-ebs-volume-not-encrypted,SC-28
21
+ ec2-instance-in-security-group,CM-7(1)
22
+ ec2-instance-type,CM-2
23
+ ec2-instance-types,CM-2
24
+ ec2-instance-with-public-ip,AC-3
25
+ ec2-instance-with-user-data-secrets,AC-3
26
+ ec2-security-group-opens-all-ports,CM-7(1)
27
+ ec2-security-group-opens-all-ports-to-all,CM-7(1)
28
+ ec2-security-group-opens-all-ports-to-self,CM-7(1)
29
+ ec2-security-group-opens-icmp-to-all,CM-7(1)
30
+ ec2-security-group-opens-known-port-to-all,CM-7(1)
31
+ ec2-security-group-opens-plaintext-port,CM-7(1)
32
+ ec2-security-group-opens-port-range,CM-7(1)
33
+ ec2-security-group-opens-port-to-all,CM-7(1)
34
+ ec2-security-group-whitelists-aws,CM-7(1)
35
+ ec2-security-group-whitelists-aws-ip-from-banned-region,CM-7(1)
36
+ ec2-security-group-whitelists-non-elastic-ips,CM-7(1)
37
+ ec2-security-group-whitelists-unknown-aws,CM-7(1)
38
+ ec2-security-group-whitelists-unknown-cidrs,CM-7(1)
39
+ ec2-unused-security-group,CM-7(1)
40
+ elb-listener-allowing-cleartext,SC-8
41
+ elb-no-access-logs,AU-12
42
+ elb-older-ssl-policy,SC-8
43
+ elbv2-http-request-smuggling,SC-8
44
+ elbv2-listener-allowing-cleartext,SC-8
45
+ elbv2-no-access-logs,AU-12
46
+ elbv2-no-deletion-protection,SI-7
47
+ elbv2-older-ssl-policy,SC-8
48
+ iam-assume-role-lacks-external-id-and-mfa,AC-17
49
+ iam-assume-role-no-mfa,AC-6
50
+ iam-assume-role-policy-allows-all,AC-6
51
+ iam-ec2-role-without-instances,AC-6
52
+ iam-group-with-inline-policies,AC-6
53
+ iam-group-with-no-users,AC-6
54
+ iam-human-user-with-policies,AC-6
55
+ iam-inline-policy-allows-non-sts-action,AC-6
56
+ iam-inline-policy-allows-NotActions,AC-6
57
+ iam-inline-policy-for-role,AC-6
58
+ iam-managed-policy-allows-full-privileges,AC-6
59
+ iam-managed-policy-allows-non-sts-action,AC-6
60
+ iam-managed-policy-allows-NotActions,AC-6
61
+ iam-managed-policy-for-role,AC-6
62
+ iam-managed-policy-no-attachments,AC-6
63
+ iam-no-support-role,IR-7
64
+ iam-password-policy-expiration-threshold,AC-2
65
+ iam-password-policy-minimum-length,AC-2
66
+ iam-password-policy-no-expiration,AC-2
67
+ iam-password-policy-no-lowercase-required,AC-2
68
+ iam-password-policy-no-number-required,AC-2
69
+ iam-password-policy-no-symbol-required,AC-2
70
+ iam-password-policy-no-uppercase-required,AC-2
71
+ iam-password-policy-reuse-enabled,IA-5(1)
72
+ iam-role-with-inline-policies,AC-6
73
+ iam-root-account-no-hardware-mfa,IA-2(1)
74
+ iam-root-account-no-mfa,IA-2(1)
75
+ iam-root-account-used-recently,AC-6(9)
76
+ iam-root-account-with-active-certs,AC-6(9)
77
+ iam-root-account-with-active-keys,AC-6(9)
78
+ iam-service-user-with-password,AC-2
79
+ iam-unused-credentials-not-disabled,AC-2
80
+ iam-user-no-key-rotation,AC-2
81
+ iam-user-not-in-category-group,AC-2
82
+ iam-user-not-in-common-group,AC-2
83
+ iam-user-unused-access-key-initial-setup,AC-2
84
+ iam-user-with-multiple-access-keys,IA-2
85
+ iam-user-without-mfa,IA-2(1)
86
+ iam-user-with-password-and-key,IA-2
87
+ iam-user-with-policies,AC-2
88
+ kms-cmk-rotation-disabled,SC-12
89
+ logs-no-alarm-aws-configuration-changes,CM-8|CM-8(2)|CM-8(6)
90
+ logs-no-alarm-cloudtrail-configuration-changes,AU-6
91
+ logs-no-alarm-cmk-deletion,AC-2
92
+ logs-no-alarm-console-authentication-failures,AC-2
93
+ logs-no-alarm-iam-policy-changes,AC-2
94
+ logs-no-alarm-nacl-changes,CM-6(2)
95
+ logs-no-alarm-network-gateways-changes,AU-12|CM-6(2)
96
+ logs-no-alarm-root-usage,AU-2
97
+ logs-no-alarm-route-table-changes,AU-12|CM-6(2)
98
+ logs-no-alarm-s3-policy-changes,AC-6|AU-12
99
+ logs-no-alarm-security-group-changes,AC-2(4)
100
+ logs-no-alarm-signin-without-mfa,AC-2
101
+ logs-no-alarm-unauthorized-api-calls,AU-6|SI-4(2)
102
+ logs-no-alarm-vpc-changes,CM-6(1)
103
+ rds-instance-backup-disabled,CP-9
104
+ rds-instance-ca-certificate-deprecated,SC-12
105
+ rds-instance-no-minor-upgrade,SI-2
106
+ rds-instance-short-backup-retention-period,CP-9
107
+ rds-instance-single-az,CP-7
108
+ rds-instance-storage-not-encrypted,SC-28
109
+ rds-postgres-instance-with-invalid-certificate,SC-12
110
+ rds-security-group-allows-all,CM-7(1)
111
+ rds-snapshot-public,SC-28
112
+ redshift-cluster-database-not-encrypted,SC-28
113
+ redshift-cluster-no-version-upgrade,SI-2
114
+ redshift-cluster-publicly-accessible,AC-3
115
+ redshift-parameter-group-logging-disabled,AU-12
116
+ redshift-parameter-group-ssl-not-required,SC-8
117
+ redshift-security-group-whitelists-all,CM-7(1)
118
+ route53-domain-no-autorenew,SC-2
119
+ route53-domain-no-transferlock,SC-2
120
+ route53-domain-transferlock-not-authorized,SC-2
121
+ s3-bucket-allowing-cleartext,SC-28
122
+ s3-bucket-no-default-encryption,SC-28
123
+ s3-bucket-no-logging,AU-2|AU-12
124
+ s3-bucket-no-mfa-delete,SI-7
125
+ s3-bucket-no-versioning,SI-7
126
+ s3-bucket-world-acl,AC-3(3)
127
+ s3-bucket-world-policy-arg,AC-3(3)
128
+ s3-bucket-world-policy-star,AC-3(3)
129
+ ses-identity-dkim-not-enabled,SC-23
130
+ ses-identity-dkim-not-verified,SC-23
131
+ ses-identity-world-policy,AC-6
132
+ sns-topic-world-policy,AC-6
133
+ sqs-queue-world-policy,AC-6
134
+ vpc-custom-network-acls-allow-all,SC-7
135
+ vpc-default-network-acls-allow-all,SC-7
136
+ vpc-network-acl-not-used,SC-7
137
+ vpc-routing-tables-with-peering,AC-3(3)
138
+ vpc-subnet-with-bad-acls,SC-7
139
+ vpc-subnet-with-default-acls,SC-7
140
+ vpc-subnet-without-flow-log,AU-12
@@ -16,4 +16,6 @@ module HeimdallTools
16
16
  autoload :DBProtectMapper, 'heimdall_tools/dbprotect_mapper'
17
17
  autoload :AwsConfigMapper, 'heimdall_tools/aws_config_mapper'
18
18
  autoload :NetsparkerMapper, 'heimdall_tools/netsparker_mapper'
19
+ autoload :SarifMapper, 'heimdall_tools/sarif_mapper'
20
+ autoload :ScoutSuiteMapper, 'heimdall_tools/scoutsuite_mapper'
19
21
  end
@@ -57,10 +57,10 @@ module HeimdallTools
57
57
 
58
58
  results = HeimdallDataFormat.new(
59
59
  profile_name: 'AWS Config',
60
- title: 'AWS Config',
61
- summary: 'AWS Config',
62
- controls: controls,
63
- statistics: { aws_config_sdk_version: Aws::ConfigService::GEM_VERSION },
60
+ title: 'AWS Config',
61
+ summary: 'AWS Config',
62
+ controls: controls,
63
+ statistics: { aws_config_sdk_version: Aws::ConfigService::GEM_VERSION },
64
64
  )
65
65
  results.to_hdf
66
66
  end
@@ -123,6 +123,29 @@ module HeimdallTools
123
123
  puts options[:output].to_s
124
124
  end
125
125
 
126
+ desc 'sarif_mapper', 'sarif_mapper translates a SARIF JSON file into HDF format JSON to be viewable in Heimdall'
127
+ long_desc Help.text(:sarif_mapper)
128
+ option :json, required: true, aliases: '-j'
129
+ option :output, required: true, aliases: '-o'
130
+ option :verbose, type: :boolean, aliases: '-V'
131
+ def sarif_mapper
132
+ hdf = HeimdallTools::SarifMapper.new(File.read(options[:json])).to_hdf
133
+ File.write(options[:output], hdf)
134
+ puts "\r\HDF Generated:\n"
135
+ puts options[:output].to_s
136
+ end
137
+
138
+ desc 'scoutsuite_mapper', 'scoutsuite_mapper translates Scout Suite results from Javascript to HDF-formatted JSON so as to be viewable on Heimdall'
139
+ long_desc Help.text(:scoutsuite_mapper)
140
+ option :javascript, required: true, banner: 'SCOUTSUITE-RESULTS-JS', aliases: ['-i', '--input', '-j']
141
+ option :output, required: true, banner: 'HDF-SCAN-RESULTS-JSON', aliases: '-o'
142
+ def scoutsuite_mapper
143
+ hdf = HeimdallTools::ScoutSuiteMapper.new(File.read(options[:javascript])).to_hdf
144
+ File.write(options[:output], hdf)
145
+ puts "\rHDF Generated:\n"
146
+ puts options[:output].to_s
147
+ end
148
+
126
149
  desc 'version', 'prints version'
127
150
  def version
128
151
  puts VERSION
@@ -0,0 +1,12 @@
1
+ sarif_mapper translates a SARIF JSON file into HDF format JSON to be viewable in Heimdall
2
+
3
+ SARIF level to HDF impact Mapping:
4
+ SARIF level error -> HDF impact 0.7
5
+ SARIF level warning -> HDF impact 0.5
6
+ SARIF level note -> HDF impact 0.3
7
+ SARIF level none -> HDF impact 0.1
8
+ SARIF level not provided -> HDF impact 0.1 as default
9
+
10
+ Examples:
11
+
12
+ heimdall_tools sarif_mapper [OPTIONS] -j <sarif-results-json> -o <hdf-scan-results.json>
@@ -0,0 +1,7 @@
1
+ scoutsuite_mapper translates Scout Suite results from Javascript to HDF-formatted JSON so as to be viewable on Heimdall
2
+
3
+ Note: Currently this mapper only supports AWS.
4
+
5
+ Examples:
6
+
7
+ heimdall_tools scoutsuite_mapper -i <scoutsuite-results-js> -o <hdf-scan-results-json>
@@ -0,0 +1,198 @@
1
+ require 'json'
2
+ require 'csv'
3
+ require 'heimdall_tools/hdf'
4
+
5
+ RESOURCE_DIR = Pathname.new(__FILE__).join('../../data')
6
+
7
+ CWE_NIST_MAPPING_FILE = File.join(RESOURCE_DIR, 'cwe-nist-mapping.csv')
8
+
9
+ IMPACT_MAPPING = {
10
+ error: 0.7,
11
+ warning: 0.5,
12
+ note: 0.3,
13
+ none: 0.0
14
+ }.freeze
15
+
16
+ DEFAULT_NIST_TAG = %w{SA-11 RA-5}.freeze
17
+
18
+ # Loading spinner sign
19
+ $spinner = Enumerator.new do |e|
20
+ loop do
21
+ e.yield '|'
22
+ e.yield '/'
23
+ e.yield '-'
24
+ e.yield '\\'
25
+ end
26
+ end
27
+
28
+ module HeimdallTools
29
+ class SarifMapper
30
+ def initialize(sarif_json, _name = nil, verbose = false)
31
+ @sarif_json = sarif_json
32
+ @verbose = verbose
33
+ begin
34
+ @cwe_nist_mapping = parse_mapper
35
+ @sarif_log = JSON.parse(@sarif_json)
36
+ rescue StandardError => e
37
+ raise "Invalid SARIF JSON file provided\n\nException: #{e}"
38
+ end
39
+ end
40
+
41
+ def extract_scaninfo(sarif_log)
42
+ info = {}
43
+ begin
44
+ info['policy'] = 'SARIF'
45
+ info['version'] = sarif_log['version']
46
+ info['projectName'] = 'Static Analysis Results Interchange Format'
47
+ info['summary'] = NA_STRING
48
+ info
49
+ rescue StandardError => e
50
+ raise "Error extracting project info from SARIF JSON file provided Exception: #{e}"
51
+ end
52
+ end
53
+
54
+ def finding(result)
55
+ finding = {}
56
+ finding['status'] = 'failed'
57
+ finding['code_desc'] = ''
58
+ if get_location(result)['uri']
59
+ finding['code_desc'] += " URL : #{get_location(result)['uri']}"
60
+ end
61
+ if get_location(result)['start_line']
62
+ finding['code_desc'] += " LINE : #{get_location(result)['start_line']}"
63
+ end
64
+ if get_location(result)['start_column']
65
+ finding['code_desc'] += " COLUMN : #{get_location(result)['start_column']}"
66
+ end
67
+ finding['code_desc'].strip!
68
+ finding['run_time'] = NA_FLOAT
69
+ finding['start_time'] = NA_STRING
70
+ finding
71
+ end
72
+
73
+ def add_nist_tag_from_cwe(cweid, taxonomy_name, tags_node)
74
+ entries = @cwe_nist_mapping.select { |x| cweid.include?(x[:cweid].to_s) && !x[:nistid].nil? }
75
+ tags = entries.map { |x| x[:nistid] }
76
+ result_tags = tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
77
+ if result_tags.count.positive?
78
+ if !tags_node
79
+ tags_node = {}
80
+ end
81
+ if !tags_node.key?(taxonomy_name)
82
+ tags_node[taxonomy_name] = []
83
+ end
84
+ result_tags.each do |t|
85
+ tags_node[taxonomy_name] |= [t]
86
+ end
87
+ end
88
+ tags_node
89
+ end
90
+
91
+ def get_location(result)
92
+ location_info = {}
93
+ location_info['uri'] = result.dig('locations', 0, 'physicalLocation', 'artifactLocation', 'uri')
94
+ location_info['start_line'] = result.dig('locations', 0, 'physicalLocation', 'region', 'startLine')
95
+ location_info['start_column'] = result.dig('locations', 0, 'physicalLocation', 'region', 'startColumn')
96
+ location_info
97
+ end
98
+
99
+ def get_rule_info(run, result, rule_id)
100
+ finding = {}
101
+ driver = run.dig('tool', 'driver')
102
+ finding['driver_name'] = driver['name']
103
+ finding['driver_version'] = driver['version']
104
+ rules = driver['rules']
105
+ if rules
106
+ rule = rules.find { |x| x['id'].eql?(rule_id) }
107
+ if rule
108
+ finding['rule_name'] = rule&.[]('name')
109
+ finding['rule_short_description'] = rule&.[]('shortDescription')&.[]('text')
110
+ finding['rule_tags'] = get_tags(rule)
111
+ finding['rule_name'] = rule&.[]('messageStrings')&.[]('default')&.[]('text') unless finding['rule_name']
112
+ end
113
+ end
114
+ finding['rule_name'] = result&.[]('message')&.[]('text') unless finding['rule_name']
115
+ finding
116
+ end
117
+
118
+ def get_tags(rule)
119
+ result = {}
120
+ Array(rule&.[]('relationships')).each do |relationship|
121
+ taxonomy_name = relationship['target']['toolComponent']['name'].downcase
122
+ taxonomy_id = relationship['target']['id']
123
+ if !result.key?(taxonomy_name)
124
+ result[taxonomy_name] = []
125
+ end
126
+ result[taxonomy_name] |= [taxonomy_id]
127
+ end
128
+ result
129
+ end
130
+
131
+ def parse_identifiers(rule_tags, ref)
132
+ # Extracting id number from reference style CWE-297
133
+ rule_tags[ref.downcase].map { |e| e.downcase.split("#{ref.downcase}-")[1] }
134
+ rescue StandardError
135
+ []
136
+ end
137
+
138
+ def impact(severity)
139
+ severity_mapping = IMPACT_MAPPING[severity.to_sym]
140
+ severity_mapping.nil? ? 0.1 : severity_mapping
141
+ end
142
+
143
+ def parse_mapper
144
+ csv_data = CSV.read(CWE_NIST_MAPPING_FILE, **{ encoding: 'UTF-8',
145
+ headers: true,
146
+ header_converters: :symbol,
147
+ converters: :all })
148
+ csv_data.map(&:to_hash)
149
+ end
150
+
151
+ def desc_tags(data, label)
152
+ { data: data || NA_STRING, label: label || NA_STRING }
153
+ end
154
+
155
+ def process_item(run, result, controls)
156
+ printf("\rProcessing: %s", $spinner.next)
157
+ control = controls.find { |x| x['id'].eql?(result['ruleId']) }
158
+
159
+ if control
160
+ control['results'] << finding(result)
161
+ else
162
+ rule_info = get_rule_info(run, result, result['ruleId'])
163
+ item = {}
164
+ item['tags'] = rule_info['rule_tags']
165
+ item['descriptions'] = []
166
+ item['refs'] = NA_ARRAY
167
+ item['source_location'] = { ref: get_location(result)['uri'], line: get_location(result)['start_line'] }
168
+ item['descriptions'] = NA_ARRAY
169
+ item['title'] = rule_info['rule_name'].to_s
170
+ item['id'] = result['ruleId'].to_s
171
+ item['desc'] = rule_info['rule_short_description'].to_s
172
+ item['impact'] = impact(result['level'].to_s)
173
+ item['code'] = NA_STRING
174
+ item['results'] = [finding(result)]
175
+ item['tags'] = add_nist_tag_from_cwe(parse_identifiers(rule_info['rule_tags'], 'CWE'), 'nist', item['tags'])
176
+ controls << item
177
+ end
178
+ end
179
+
180
+ def to_hdf
181
+ controls = []
182
+ @sarif_log['runs'].each do |run|
183
+ run['results'].each do |result|
184
+ process_item(run, result, controls)
185
+ end
186
+ end
187
+
188
+ scaninfo = extract_scaninfo(@sarif_log)
189
+ results = HeimdallDataFormat.new(profile_name: scaninfo['policy'],
190
+ version: scaninfo['version'],
191
+ title: scaninfo['projectName'],
192
+ summary: scaninfo['summary'],
193
+ controls: controls,
194
+ target_id: scaninfo['projectName'])
195
+ results.to_hdf
196
+ end
197
+ end
198
+ end
@@ -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,8 +8,6 @@ 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
13
  def initialize(zap_json, name)
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.45
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-05-01 00:00:00.000000000 Z
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
@@ -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