heimdall_tools 1.3.42 → 1.3.47
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -2
- data/lib/data/scoutsuite-nist-mapping.csv +140 -0
- data/lib/heimdall_tools.rb +2 -0
- data/lib/heimdall_tools/aws_config_mapper.rb +24 -9
- 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 +7 -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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c1758366de13bb1966a1ffeccbab60c7b1c2d91c221d5ee604dd2d4f1c96dcb
|
4
|
+
data.tar.gz: 2ba1491cb04b569b216c966724b9b8e4f06430a3dc7913ce8bf5e0611ed6896a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38d66cf5d8653a1a859b7254b9b2ba05518ce5c750b73fb6e638b24fca08ea574aaf1e89bbf560f98fa5cdd7d56d49ca5dedf23b20845d56dd9ecb8c41210ce1
|
7
|
+
data.tar.gz: b9db7f5c78640e37795493f36e2b119e4c15d5184d3b830e57bf92ad41709a0fa8345946e249afef7f1adb0ba02a89183c756ce8e81eeafb5cd766232518b197
|
data/README.md
CHANGED
@@ -9,13 +9,30 @@ 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
|
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
|
21
|
+
|
22
|
+
## Want to recommend a mapper for another tool? Please use these steps:
|
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
|
24
|
+
2. Provide a sample output, preferably the most detailed the tool can provide, and also preferably in a machine-readable format, such as xml, json, or csv - whichever is natively available. If it is sensitive we'll work that in #3. (If it's an API only, we'll also just talk about it in #3)
|
25
|
+
3. Let's arrange a time to take a close look at the data it provides to get an idea of all it has to offer. We'll suggest an initial mapping of the HDF core elements. (see https://saf.mitre.org/#/normalize)
|
26
|
+
4. Note: if the tool doesn't provide a NIST SP 800-53 reference, we've worked on mappings to other references such as CWE or OWASP Top 10:
|
27
|
+
https://github.com/mitre/heimdall_tools/tree/master/lib/data
|
28
|
+
https://github.com/mitre/heimdall_tools/blob/master/lib/data/cwe-nist-mapping.csv
|
29
|
+
https://github.com/mitre/heimdall_tools/blob/master/lib/data/owasp-nist-mapping.csv
|
30
|
+
5. If the tool doesn't provide something for #4, or another core element such as impact, we'll help you identify a custom mapping approach.
|
31
|
+
6. We'll help you decide how to preserve any other information (non-core elements) the tool provides to ensure that all of the original tool's intent comes through for the user when the data is viewed in Heimdall.
|
32
|
+
7. Finally, We'll provide final peer review and support merging your pull request.
|
33
|
+
We appreciate your contributions, but we're here to help!
|
34
|
+
|
35
|
+
## How to Install Heimdall Tools:
|
19
36
|
|
20
37
|
Ruby 2.4 or higher (check using "ruby -v")
|
21
38
|
|
@@ -136,7 +153,8 @@ example: heimdall_tools burpsuite_mapper -x burpsuite_results.xml -o scan_result
|
|
136
153
|
|
137
154
|
## nessus_mapper
|
138
155
|
|
139
|
-
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.
|
140
158
|
|
141
159
|
Note: A separate HDF JSON file is generated for each host reported in the Nessus Report.
|
142
160
|
|
@@ -185,6 +203,22 @@ FLAGS:
|
|
185
203
|
example: heimdall_tools nikto_mapper -j nikto_results.json -o nikto_results.json
|
186
204
|
```
|
187
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
|
+
|
188
222
|
## jfrog_xray_mapper
|
189
223
|
|
190
224
|
jfrog_xray_mapper translates an JFrog Xray results JSON file into HDF format JSON to be viewable in Heimdall
|
@@ -252,6 +286,21 @@ FLAGS:
|
|
252
286
|
example: heimdall_tools netsparker_mapper -x netsparker_results.xml -o netsparker_hdf.json
|
253
287
|
```
|
254
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
|
+
|
255
304
|
## version
|
256
305
|
|
257
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
|
data/lib/heimdall_tools.rb
CHANGED
@@ -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
|
@@ -18,8 +18,7 @@ INSUFFICIENT_DATA_MSG = 'Not enough data has been collectd to determine complian
|
|
18
18
|
#
|
19
19
|
module HeimdallTools
|
20
20
|
class AwsConfigMapper
|
21
|
-
def initialize(custom_mapping, endpoint = nil
|
22
|
-
@verbose = verbose
|
21
|
+
def initialize(custom_mapping, endpoint = nil)
|
23
22
|
@default_mapping = get_rule_mapping(AWS_CONFIG_MAPPING_FILE)
|
24
23
|
@custom_mapping = custom_mapping.nil? ? {} : get_rule_mapping(custom_mapping)
|
25
24
|
if endpoint.nil?
|
@@ -38,8 +37,8 @@ module HeimdallTools
|
|
38
37
|
def to_hdf
|
39
38
|
controls = @issues.map do |issue|
|
40
39
|
@item = {}
|
41
|
-
@item['id'] = issue[:
|
42
|
-
@item['title'] = issue[:config_rule_name]
|
40
|
+
@item['id'] = issue[:config_rule_id]
|
41
|
+
@item['title'] = "#{get_account_id(issue[:config_rule_arn])} - #{issue[:config_rule_name]}"
|
43
42
|
@item['desc'] = issue[:description]
|
44
43
|
@item['impact'] = 0.5
|
45
44
|
@item['tags'] = hdf_tags(issue)
|
@@ -55,18 +54,33 @@ module HeimdallTools
|
|
55
54
|
@item
|
56
55
|
end
|
57
56
|
end
|
57
|
+
|
58
58
|
results = HeimdallDataFormat.new(
|
59
59
|
profile_name: 'AWS Config',
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
67
67
|
|
68
68
|
private
|
69
69
|
|
70
|
+
##
|
71
|
+
# Gets the account ID from a config rule ARN
|
72
|
+
#
|
73
|
+
# https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html
|
74
|
+
# https://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html
|
75
|
+
#
|
76
|
+
# Params:
|
77
|
+
# - arn: The ARN of the config rule
|
78
|
+
#
|
79
|
+
# Returns: The account ID portion of the ARN
|
80
|
+
def get_account_id(arn)
|
81
|
+
/:(\d{12}):config-rule/.match(arn)&.captures&.first || 'no-account-id'
|
82
|
+
end
|
83
|
+
|
70
84
|
##
|
71
85
|
# Read in a config rule -> 800-53 control mapping CSV.
|
72
86
|
#
|
@@ -263,7 +277,8 @@ module HeimdallTools
|
|
263
277
|
# If no input parameters, then provide an empty JSON array to the JSON
|
264
278
|
# parser because passing nil to JSON.parse throws an exception.
|
265
279
|
params = (JSON.parse(config_rule[:input_parameters] || '[]').map { |key, value| "#{key}: #{value}" }).join('<br/>')
|
266
|
-
check_text = config_rule[:config_rule_arn] || ''
|
280
|
+
check_text = "ARN: #{config_rule[:config_rule_arn] || 'N/A'}"
|
281
|
+
check_text += "<br/>Source Identifier: #{config_rule.dig(:source, :source_identifier) || 'N/A'}"
|
267
282
|
check_text += "<br/>#{params}" unless params.empty?
|
268
283
|
check_text
|
269
284
|
end
|
@@ -20,9 +20,8 @@ DEFAULT_NIST_TAG = %w{SA-11 RA-5 Rev_4}.freeze
|
|
20
20
|
|
21
21
|
module HeimdallTools
|
22
22
|
class BurpSuiteMapper
|
23
|
-
def initialize(burps_xml, _name = nil
|
23
|
+
def initialize(burps_xml, _name = nil)
|
24
24
|
@burps_xml = burps_xml
|
25
|
-
@verbose = verbose
|
26
25
|
|
27
26
|
begin
|
28
27
|
@cwe_nist_mapping = parse_mapper
|
data/lib/heimdall_tools/cli.rb
CHANGED
@@ -6,7 +6,6 @@ module HeimdallTools
|
|
6
6
|
long_desc Help.text(:fortify_mapper)
|
7
7
|
option :fvdl, required: true, aliases: '-f'
|
8
8
|
option :output, required: true, aliases: '-o'
|
9
|
-
option :verbose, type: :boolean, aliases: '-V'
|
10
9
|
def fortify_mapper
|
11
10
|
hdf = HeimdallTools::FortifyMapper.new(File.read(options[:fvdl])).to_hdf
|
12
11
|
File.write(options[:output], hdf)
|
@@ -17,7 +16,6 @@ module HeimdallTools
|
|
17
16
|
option :json, required: true, aliases: '-j'
|
18
17
|
option :name, required: true, aliases: '-n'
|
19
18
|
option :output, required: true, aliases: '-o'
|
20
|
-
option :verbose, type: :boolean, aliases: '-V'
|
21
19
|
def zap_mapper
|
22
20
|
hdf = HeimdallTools::ZapMapper.new(File.read(options[:json]), options[:name]).to_hdf
|
23
21
|
File.write(options[:output], hdf)
|
@@ -29,7 +27,6 @@ module HeimdallTools
|
|
29
27
|
option :api_url, required: true, aliases: '-u'
|
30
28
|
option :auth, type: :string, required: false
|
31
29
|
option :output, required: true, aliases: '-o'
|
32
|
-
option :verbose, type: :boolean, aliases: '-V'
|
33
30
|
def sonarqube_mapper
|
34
31
|
hdf = HeimdallTools::SonarQubeMapper.new(options[:name], options[:api_url], options[:auth]).to_hdf
|
35
32
|
File.write(options[:output], hdf)
|
@@ -39,7 +36,6 @@ module HeimdallTools
|
|
39
36
|
long_desc Help.text(:burpsuite_mapper)
|
40
37
|
option :xml, required: true, aliases: '-x'
|
41
38
|
option :output, required: true, aliases: '-o'
|
42
|
-
option :verbose, type: :boolean, aliases: '-V'
|
43
39
|
def burpsuite_mapper
|
44
40
|
hdf = HeimdallTools::BurpSuiteMapper.new(File.read(options[:xml])).to_hdf
|
45
41
|
File.write(options[:output], hdf)
|
@@ -49,7 +45,6 @@ module HeimdallTools
|
|
49
45
|
long_desc Help.text(:nessus_mapper)
|
50
46
|
option :xml, required: true, aliases: '-x'
|
51
47
|
option :output_prefix, required: true, aliases: '-o'
|
52
|
-
option :verbose, type: :boolean, aliases: '-V'
|
53
48
|
def nessus_mapper
|
54
49
|
hdfs = HeimdallTools::NessusMapper.new(File.read(options[:xml])).to_hdf
|
55
50
|
|
@@ -64,7 +59,6 @@ module HeimdallTools
|
|
64
59
|
long_desc Help.text(:snyk_mapper)
|
65
60
|
option :json, required: true, aliases: '-j'
|
66
61
|
option :output_prefix, required: true, aliases: '-o'
|
67
|
-
option :verbose, type: :boolean, aliases: '-V'
|
68
62
|
def snyk_mapper
|
69
63
|
hdfs = HeimdallTools::SnykMapper.new(File.read(options[:json]), options[:name]).to_hdf
|
70
64
|
puts "\r\HDF Generated:\n"
|
@@ -78,7 +72,6 @@ module HeimdallTools
|
|
78
72
|
long_desc Help.text(:nikto_mapper)
|
79
73
|
option :json, required: true, aliases: '-j'
|
80
74
|
option :output, required: true, aliases: '-o'
|
81
|
-
option :verbose, type: :boolean, aliases: '-V'
|
82
75
|
def nikto_mapper
|
83
76
|
hdf = HeimdallTools::NiktoMapper.new(File.read(options[:json])).to_hdf
|
84
77
|
File.write(options[:output], hdf)
|
@@ -90,7 +83,6 @@ module HeimdallTools
|
|
90
83
|
long_desc Help.text(:jfrog_xray_mapper)
|
91
84
|
option :json, required: true, aliases: '-j'
|
92
85
|
option :output, required: true, aliases: '-o'
|
93
|
-
option :verbose, type: :boolean, aliases: '-V'
|
94
86
|
def jfrog_xray_mapper
|
95
87
|
hdf = HeimdallTools::JfrogXrayMapper.new(File.read(options[:json])).to_hdf
|
96
88
|
File.write(options[:output], hdf)
|
@@ -102,7 +94,6 @@ module HeimdallTools
|
|
102
94
|
long_desc Help.text(:dbprotect_mapper)
|
103
95
|
option :xml, required: true, aliases: '-x'
|
104
96
|
option :output, required: true, aliases: '-o'
|
105
|
-
option :verbose, type: :boolean, aliases: '-V'
|
106
97
|
def dbprotect_mapper
|
107
98
|
hdf = HeimdallTools::DBProtectMapper.new(File.read(options[:xml])).to_hdf
|
108
99
|
File.write(options[:output], hdf)
|
@@ -114,7 +105,6 @@ module HeimdallTools
|
|
114
105
|
long_desc Help.text(:aws_config_mapper)
|
115
106
|
# option :custom_mapping, required: false, aliases: '-m'
|
116
107
|
option :output, required: true, aliases: '-o'
|
117
|
-
option :verbose, type: :boolean, aliases: '-V'
|
118
108
|
def aws_config_mapper
|
119
109
|
hdf = HeimdallTools::AwsConfigMapper.new(options[:custom_mapping]).to_hdf
|
120
110
|
File.write(options[:output], hdf)
|
@@ -126,7 +116,6 @@ module HeimdallTools
|
|
126
116
|
long_desc Help.text(:netsparker_mapper)
|
127
117
|
option :xml, required: true, aliases: '-x'
|
128
118
|
option :output, required: true, aliases: '-o'
|
129
|
-
option :verbose, type: :boolean, aliases: '-V'
|
130
119
|
def netsparker_mapper
|
131
120
|
hdf = HeimdallTools::NetsparkerMapper.new(File.read(options[:xml])).to_hdf
|
132
121
|
File.write(options[:output], hdf)
|
@@ -134,6 +123,29 @@ module HeimdallTools
|
|
134
123
|
puts options[:output].to_s
|
135
124
|
end
|
136
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
|
+
|
137
149
|
desc 'version', 'prints version'
|
138
150
|
def version
|
139
151
|
puts VERSION
|
@@ -12,15 +12,11 @@ IMPACT_MAPPING = {
|
|
12
12
|
|
13
13
|
module HeimdallTools
|
14
14
|
class DBProtectMapper
|
15
|
-
def initialize(xml, _name = nil
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@entries = compile_findings(dataset['dataset'])
|
21
|
-
rescue StandardError => e
|
22
|
-
raise "Invalid DBProtect XML file provided Exception: #{e};\nNote that XML must be of kind `Check Results Details`."
|
23
|
-
end
|
15
|
+
def initialize(xml, _name = nil)
|
16
|
+
dataset = xml_to_hash(xml)
|
17
|
+
@entries = compile_findings(dataset['dataset'])
|
18
|
+
rescue StandardError => e
|
19
|
+
raise "Invalid DBProtect XML file provided Exception: #{e};\nNote that XML must be of kind `Check Results Details`."
|
24
20
|
end
|
25
21
|
|
26
22
|
def to_hdf
|
@@ -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>
|
@@ -39,9 +39,8 @@ end
|
|
39
39
|
|
40
40
|
module HeimdallTools
|
41
41
|
class NessusMapper
|
42
|
-
def initialize(nessus_xml
|
42
|
+
def initialize(nessus_xml)
|
43
43
|
@nessus_xml = nessus_xml
|
44
|
-
@verbose = verbose
|
45
44
|
read_cci_xml
|
46
45
|
begin
|
47
46
|
@cwe_nist_mapping = parse_mapper
|
@@ -72,7 +71,8 @@ module HeimdallTools
|
|
72
71
|
info = {}
|
73
72
|
|
74
73
|
info['policyName'] = policy['policyName']
|
75
|
-
|
74
|
+
scanner_version = policy['Preferences']['ServerPreferences']['preference'].select { |x| x['name'].eql? 'sc_version' }
|
75
|
+
info['version'] = scanner_version.empty? ? NA_STRING : scanner_version.first['value']
|
76
76
|
info
|
77
77
|
rescue StandardError => e
|
78
78
|
raise "Invalid Nessus XML file provided Exception: #{e}"
|
@@ -221,8 +221,12 @@ module HeimdallTools
|
|
221
221
|
end
|
222
222
|
if item['compliance-reference']
|
223
223
|
@item['tags']['nist'] = cci_nist_tag(parse_refs(item['compliance-reference'], 'CCI'))
|
224
|
+
@item['tags']['cci'] = parse_refs(item['compliance-reference'], 'CCI')
|
225
|
+
@item['tags']['rid'] = parse_refs(item['compliance-reference'], 'Rule-ID').join(',')
|
226
|
+
@item['tags']['stig_id'] = parse_refs(item['compliance-reference'], 'STIG-ID').join(',')
|
224
227
|
else
|
225
228
|
@item['tags']['nist'] = plugin_nist_tag(item['pluginFamily'], item['pluginID'])
|
229
|
+
@item['tags']['rid'] = item['pluginID'].to_s
|
226
230
|
end
|
227
231
|
if item['compliance-solution']
|
228
232
|
@item['descriptions'] << desc_tags(item['compliance-solution'], 'check')
|
@@ -21,19 +21,15 @@ DEFAULT_NIST_TAG = %w{SA-11 RA-5}.freeze
|
|
21
21
|
|
22
22
|
module HeimdallTools
|
23
23
|
class NetsparkerMapper
|
24
|
-
def initialize(xml, _name = nil
|
25
|
-
@
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@scan_info = data['netsparker-enterprise']['target']
|
34
|
-
rescue StandardError => e
|
35
|
-
raise "Invalid Netsparker XML file provided Exception: #{e}"
|
36
|
-
end
|
24
|
+
def initialize(xml, _name = nil)
|
25
|
+
@cwe_nist_mapping = parse_mapper(CWE_NIST_MAPPING_FILE)
|
26
|
+
@owasp_nist_mapping = parse_mapper(OWASP_NIST_MAPPING_FILE)
|
27
|
+
data = xml_to_hash(xml)
|
28
|
+
|
29
|
+
@vulnerabilities = data['netsparker-enterprise']['vulnerabilities']['vulnerability']
|
30
|
+
@scan_info = data['netsparker-enterprise']['target']
|
31
|
+
rescue StandardError => e
|
32
|
+
raise "Invalid Netsparker XML file provided Exception: #{e}"
|
37
33
|
end
|
38
34
|
|
39
35
|
def to_hdf
|
@@ -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,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.47
|
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-06-08 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
|