heimdall_tools 1.3.27 → 1.3.32

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.
@@ -46,6 +46,7 @@
46
46
  170, Improper Null Termination,SI-10,4,Information Input Validation
47
47
  176, Improper Handling of Unicode Encoding,,4,
48
48
  185, Incorrect Regular Expression,,4,
49
+ 189, Numeric Errors,SA-11,4,Developer Security Testing and Evaluation
49
50
  190, Integer Overflow or Wraparound,SI-10,4,Information Input Validation
50
51
  195, Signed to Unsigned Conversion Error,,4,
51
52
  200, Information Exposure,SC-8,4,Transmission Confidentiality and Integrity
@@ -79,6 +80,7 @@
79
80
  305, Authentication Bypass by Primary Weakness,IA-8,4,Identification and Authentication (Non-Organizational Users)
80
81
  306, Missing Authentication for Critical Function,AC-3,4,Access Enforcement
81
82
  307, Improper Restriction of Excessive Authentication Attempts,AC-7,4,Unsuccessful Logon Attempts
83
+ 310, Cryptographic Issues,SC-13,4,Cryptographic Protection
82
84
  311, Missing Encryption of Sensitive Data,SC-8,4,Transmission Confidentiality and Integrity
83
85
  321, Use of Hard-coded Cryptographic Key,SC-12,4,Cryptographic Key Establishment and Management
84
86
  325, Missing Required Cryptographic Step,SC-13,4,Cryptographic Protection
@@ -113,15 +115,16 @@
113
115
  401, Improper Release of Memory Before Removing Last Reference,,4,
114
116
  404, Improper Resource Shutdown or Release,,4,
115
117
  415, Double Free,,4,
116
- 416, Use after Free,,4,
118
+ 416, Use after Free,SC-4,4,Information in Shared Resources
117
119
  434, Unrestricted Upload of File with Dangerous Type,AC-6,4,Least Privilege: Privilege Levels for Code Execution
120
+ 444, Inconsistent Interpretation of HTTP Requests ('HTTP Request Smuggling'),SI-10,4,Information Input Validation
118
121
  457, Use of Uninitialized Variable,,4,
119
122
  466, Return of Pointer Value Outside of Expected Range,,4,
120
123
  470, Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection'),SI-10,4,Information Input Validation
121
124
  471, Modification of Assumed-Immutable DATA (MAID),AC-3,4,Access Enforcement
122
125
  474, Use of Function with Inconsistent Implementations,,4,
123
126
  475, Undefined Behavior for Input to API,,4,
124
- 476, NULL Pointer Dereference,,4,
127
+ 476, NULL Pointer Dereference,SI-10,4,Information Input Validation
125
128
  477, Use of Obsolete Functions,,4,
126
129
  478, Missing Default Case in Switch Statement,,4,
127
130
  492, Use of Inner Class Containing Sensitive Data,AC-3,4,Access Enforcement
@@ -130,6 +133,7 @@
130
133
  495, Private Array-Typed Field Returned From A Public Method,AC-3,4,Access Enforcement
131
134
  497, Exposure of System Data to an Unauthorized Control Sphere,SI-11,4,Error Handling
132
135
  501, Trust Boundary Violation,SI-10,4,Information Input Validation
136
+ 502, Deserialization of Untrusted Data,SI-10,4,Information Input Validation
133
137
  521, Weak Password Requirements,IA-5,4,Authenticator Management : -1 Password-based Authentication
134
138
  522, Insufficiently Protected Credentials,SC-8,4,Transmission Confidentiality and Integrity
135
139
  539, Information Exposure Through Persistent Cookies,SC-23,4,Session Authenticity
@@ -159,7 +163,7 @@
159
163
  601, URL Redirection to Untrusted Site ('Open Redirect'),SI-10,4,Information Input Validation
160
164
  607, Public Static Final Field References Mutable Object,,4,
161
165
  609, Double-Checked Locking,,4,
162
- 611, Improper Restriction of XML External Entity Reference ('XXE'),,4,
166
+ 611, Improper Restriction of XML External Entity Reference ('XXE'),SI-10,4,Information Input Validation
163
167
  613, Insufficient Session Expiration,AC-12,4,Session Termination
164
168
  614, Sensitive Cookie in HTTPS Session Without 'Secure' Attribute,SC-8,4,Transmission Confidentiality and Integrity
165
169
  615, Information Exposure Through Comments,AC-3,4,Access Enforcement : -5 Security-Relevant Information
@@ -192,4 +196,4 @@
192
196
  863, Incorrect Authorization,AC-3,4,Access Enforcement
193
197
  915, Improperly Controlled Modification of Dynamically-Determined Object Attributes,SI-10,4,Information Input Validation
194
198
  916, Use of Password Hash With Insufficient Computational Effort,SC-13,4,Cryptographic Protection
195
- 918, Server-Side Request Forgery (SSRF),SI-10,4,Information Input Validation
199
+ 918, Server-Side Request Forgery (SSRF),SI-10,4,Information Input Validation
@@ -10,4 +10,5 @@ module HeimdallTools
10
10
  autoload :SonarQubeMapper, 'heimdall_tools/sonarqube_mapper'
11
11
  autoload :BurpSuiteMapper, 'heimdall_tools/burpsuite_mapper'
12
12
  autoload :NessusMapper, 'heimdall_tools/nessus_mapper'
13
+ autoload :SnykMapper, 'heimdall_tools/snyk_mapper'
13
14
  end
@@ -53,13 +53,28 @@ module HeimdallTools
53
53
  def nessus_mapper
54
54
  hdfs = HeimdallTools::NessusMapper.new(File.read(options[:xml])).to_hdf
55
55
 
56
+ puts "\nHDF Generated:"
56
57
  hdfs.keys.each do | host |
57
58
  File.write("#{options[:output_prefix]}-#{host}.json", hdfs[host])
58
- puts "HDF Generated: #{options[:output_prefix]}-#{host}.json"
59
+ puts "#{options[:output_prefix]}-#{host}.json"
59
60
  end
60
61
 
61
62
  end
62
63
 
64
+ desc 'snyk_mapper', 'snyk_mapper translates Synk results Json to HDF format Json be viewed on Heimdall'
65
+ long_desc Help.text(:fortify_mapper)
66
+ option :json, required: true, aliases: '-j'
67
+ option :output_prefix, required: true, aliases: '-o'
68
+ option :verbose, type: :boolean, aliases: '-V'
69
+ def snyk_mapper
70
+ hdfs = HeimdallTools::SnykMapper.new(File.read(options[:json]), options[:name]).to_hdf
71
+ puts "\r\HDF Generated:\n"
72
+ hdfs.keys.each do | host |
73
+ File.write("#{options[:output_prefix]}-#{host}.json", hdfs[host])
74
+ puts "#{options[:output_prefix]}-#{host}.json"
75
+ end
76
+ end
77
+
63
78
  desc 'version', 'prints version'
64
79
  def version
65
80
  puts VERSION
@@ -0,0 +1,7 @@
1
+ snyk_mapper translates an Snyk results JSON file into HDF format json to be viewable in Heimdall
2
+
3
+ A separate HDF JSON is generated for each project reported in the Snyk Report.
4
+
5
+ Examples:
6
+
7
+ heimdall_tools snyk_mapper -j snyk_results.json -o output-file-prefix
@@ -2,10 +2,12 @@ require 'json'
2
2
  require 'csv'
3
3
  require 'heimdall_tools/hdf'
4
4
  require 'utilities/xml_to_hash'
5
+ require 'nokogiri'
5
6
 
6
7
  RESOURCE_DIR = Pathname.new(__FILE__).join('../../data')
7
8
 
8
9
  NESSUS_PLUGINS_NIST_MAPPING_FILE = File.join(RESOURCE_DIR, 'nessus-plugins-nist-mapping.csv')
10
+ U_CCI_LIST = File.join(RESOURCE_DIR, 'U_CCI_List.xml')
9
11
 
10
12
  IMPACT_MAPPING = {
11
13
  Info: 0.0,
@@ -17,20 +19,33 @@ IMPACT_MAPPING = {
17
19
 
18
20
  DEFAULT_NIST_TAG = ["unmapped"].freeze
19
21
 
22
+ # Nessus results file 800-53 refs does not contain Nist rev version. Using this default
23
+ # version in that case
24
+ DEFAULT_NIST_REV = 'Rev_4'.freeze
25
+
20
26
  NA_PLUGIN_OUTPUT = "This Nessus Plugin does not provide output message.".freeze
21
27
 
22
28
  # rubocop:disable Metrics/AbcSize
23
29
 
30
+ # Loading spinner sign
31
+ $spinner = Enumerator.new do |e|
32
+ loop do
33
+ e.yield '|'
34
+ e.yield '/'
35
+ e.yield '-'
36
+ e.yield '\\'
37
+ end
38
+ end
39
+
24
40
  module HeimdallTools
25
41
  class NessusMapper
26
42
  def initialize(nessus_xml, verbose = false)
27
43
  @nessus_xml = nessus_xml
28
44
  @verbose = verbose
29
-
45
+ read_cci_xml
30
46
  begin
31
47
  @cwe_nist_mapping = parse_mapper
32
48
  @data = xml_to_hash(nessus_xml)
33
-
34
49
  @reports = extract_report
35
50
  @scaninfo = extract_scaninfo
36
51
  rescue StandardError => e
@@ -51,6 +66,10 @@ module HeimdallTools
51
66
  end
52
67
  end
53
68
 
69
+ def parse_refs(refs, key)
70
+ refs.split(',').map { |x| x.split('|')[1] if x.include?(key) }.compact
71
+ end
72
+
54
73
  def extract_scaninfo
55
74
  begin
56
75
  policy = @data['NessusClientData_v2']['Policy']
@@ -82,28 +101,60 @@ module HeimdallTools
82
101
 
83
102
  def finding(issue, timestamp)
84
103
  finding = {}
85
- finding['status'] = 'failed'
86
- finding['code_desc'] = issue['plugin_output'] || NA_PLUGIN_OUTPUT
104
+ # if compliance-result field, this is a policy compliance result entry
105
+ # nessus policy compliance result provides a pass/fail data
106
+ # For non policy compliance results are defaulted to failed
107
+ if issue['compliance-result']
108
+ finding['status'] = issue['compliance-result'].eql?('PASSED') ? 'passed' : 'failed'
109
+ else
110
+ finding['status'] = 'failed'
111
+ end
112
+
113
+ if issue['description']
114
+ finding['code_desc'] = issue['description'].to_s || NA_PLUGIN_OUTPUT
115
+ else
116
+ finding['code_desc'] = issue['plugin_output'] || NA_PLUGIN_OUTPUT
117
+ end
87
118
  finding['run_time'] = NA_FLOAT
88
119
  finding['start_time'] = timestamp
89
120
  [finding]
90
121
  end
91
122
 
92
- def nist_tag(pluginfamily, pluginid)
123
+ def read_cci_xml
124
+ @cci_xml = Nokogiri::XML(File.open(U_CCI_LIST))
125
+ @cci_xml.remove_namespaces!
126
+ rescue StandardError => e
127
+ puts "Exception: #{e.message}"
128
+ end
129
+
130
+ def cci_nist_tag(cci_refs)
131
+ nist_tags = []
132
+ cci_refs.each do | cci_ref |
133
+ item_node = @cci_xml.xpath("//cci_list/cci_items/cci_item[@id='#{cci_ref}']")[0] unless @cci_xml.nil?
134
+ unless item_node.nil?
135
+ nist_ref = item_node.xpath('./references/reference[not(@version <= preceding-sibling::reference/@version) and not(@version <=following-sibling::reference/@version)]/@index').text
136
+ end
137
+ nist_tags << nist_ref
138
+ end
139
+ nist_tags
140
+ end
141
+
142
+ def plugin_nist_tag(pluginfamily, pluginid)
93
143
  entries = @cwe_nist_mapping.select { |x| (x[:pluginfamily].eql?(pluginfamily) && (x[:pluginid].eql?('*') || x[:pluginid].eql?(pluginid.to_i)) ) }
94
144
  tags = entries.map { |x| [x[:nistid].split('|'), "Rev_#{x[:rev]}"] }
95
145
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
96
146
  end
97
147
 
98
148
  def impact(severity)
149
+ # Map CAT levels and Plugin severity to HDF impact levels
99
150
  case severity
100
151
  when "0"
101
152
  IMPACT_MAPPING[:Info]
102
- when "1"
153
+ when "1","III"
103
154
  IMPACT_MAPPING[:Low]
104
- when "2"
155
+ when "2","II"
105
156
  IMPACT_MAPPING[:Medium]
106
- when "3"
157
+ when "3","I"
107
158
  IMPACT_MAPPING[:High]
108
159
  when "4"
109
160
  IMPACT_MAPPING[:Critical]
@@ -142,21 +193,48 @@ module HeimdallTools
142
193
  def to_hdf
143
194
  host_results = {}
144
195
  @reports.each do | report|
145
- # Under current version of the converter `Policy Compliance` items are ignored
146
- report_items = report['ReportItem'].select {|x| !x['pluginFamily'].eql? 'Policy Compliance'}
147
-
148
196
  controls = []
149
- report_items.each do | item |
197
+ report['ReportItem'].each do | item |
198
+ printf("\rProcessing: %s", $spinner.next)
150
199
  @item = {}
151
- @item['id'] = item['pluginID'].to_s
152
- @item['title'] = item['pluginName'].to_s
153
- @item['desc'] = format_desc(item).to_s
154
- @item['impact'] = impact(item['severity'])
155
200
  @item['tags'] = {}
156
201
  @item['descriptions'] = []
157
202
  @item['refs'] = NA_ARRAY
158
203
  @item['source_location'] = NA_HASH
159
- @item['tags']['nist'] = nist_tag(item['pluginFamily'],item['pluginID'])
204
+
205
+ # Nessus results field set are different for 'Policy Compliance' plug-in family vs other plug-in families
206
+ # Following if conditions capture compliance* if it exists else it will default to plugin* fields
207
+ # Current version covers STIG based 'Policy Compliance' results
208
+ # TODO Cover cases for 'Policy Compliance' results based on CIS
209
+ if item['compliance-reference']
210
+ @item['id'] = parse_refs(item['compliance-reference'],'Vuln-ID').join.to_s
211
+ else
212
+ @item['id'] = item['pluginID'].to_s
213
+ end
214
+ if item['compliance-check-name']
215
+ @item['title'] = item['compliance-check-name'].to_s
216
+ else
217
+ @item['title'] = item['pluginName'].to_s
218
+ end
219
+ if item['compliance-info']
220
+ @item['desc'] = item['compliance-info'].to_s
221
+ else
222
+ @item['desc'] = format_desc(item).to_s
223
+ end
224
+ if item['compliance-reference']
225
+ @item['impact'] = impact(parse_refs(item['compliance-reference'],'CAT').join.to_s)
226
+ else
227
+ @item['impact'] = impact(item['severity'])
228
+ end
229
+ if item['compliance-reference']
230
+ @item['tags']['nist'] = cci_nist_tag(parse_refs(item['compliance-reference'],'CCI'))
231
+ else
232
+ @item['tags']['nist'] = plugin_nist_tag(item['pluginFamily'],item['pluginID'])
233
+ end
234
+ if item['compliance-solution']
235
+ @item['descriptions'] << desc_tags(item['compliance-solution'], 'check')
236
+ end
237
+
160
238
  @item['code'] = ''
161
239
  @item['results'] = finding(item, extract_timestamp(report))
162
240
  controls << @item
@@ -0,0 +1,161 @@
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
+
10
+ IMPACT_MAPPING = {
11
+ high: 0.7,
12
+ medium: 0.5,
13
+ low: 0.3,
14
+ }.freeze
15
+
16
+ SNYK_VERSION_REGEX = 'v(\d+.)(\d+.)(\d+)'.freeze
17
+
18
+ DEFAULT_NIST_TAG = ["SA-11", "RA-5"].freeze
19
+
20
+ # Loading spinner sign
21
+ $spinner = Enumerator.new do |e|
22
+ loop do
23
+ e.yield '|'
24
+ e.yield '/'
25
+ e.yield '-'
26
+ e.yield '\\'
27
+ end
28
+ end
29
+
30
+ module HeimdallTools
31
+ class SnykMapper
32
+ def initialize(synk_json, name=nil, verbose = false)
33
+ @synk_json = synk_json
34
+ @verbose = verbose
35
+
36
+ begin
37
+ @cwe_nist_mapping = parse_mapper
38
+ @projects = JSON.parse(synk_json)
39
+
40
+ # Cover single and multi-project scan use cases.
41
+ unless @projects.kind_of?(Array)
42
+ @projects = [ @projects ]
43
+ end
44
+
45
+ rescue StandardError => e
46
+ raise "Invalid Snyk JSON file provided Exception: #{e}"
47
+ end
48
+ end
49
+
50
+ def extract_scaninfo(project)
51
+ info = {}
52
+ begin
53
+ info['policy'] = project['policy']
54
+ reg = Regexp.new(SNYK_VERSION_REGEX, Regexp::IGNORECASE)
55
+ info['version'] = info['policy'].scan(reg).join
56
+ info['projectName'] = project['projectName']
57
+ info['summary'] = project['summary']
58
+
59
+ info
60
+ rescue StandardError => e
61
+ raise "Error extracting project info from Synk JSON file provided Exception: #{e}"
62
+ end
63
+ end
64
+
65
+ def finding(vulnerability)
66
+ finding = {}
67
+ finding['status'] = 'failed'
68
+ finding['code_desc'] = "From : [ #{vulnerability['from'].join(" , ").to_s } ]"
69
+ finding['run_time'] = NA_FLOAT
70
+
71
+ # Snyk results does not profile scan timestamp; using current time to satisfy HDF format
72
+ finding['start_time'] = NA_STRING
73
+ [finding]
74
+ end
75
+
76
+ def nist_tag(cweid)
77
+ entries = @cwe_nist_mapping.select { |x| cweid.include? x[:cweid].to_s }
78
+ tags = entries.map { |x| x[:nistid] }
79
+ tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
80
+ end
81
+
82
+ def parse_identifiers(vulnerability, ref)
83
+ # Extracting id number from reference style CWE-297
84
+ vulnerability['identifiers'][ref].map { |e| e.split("#{ref}-")[1] }
85
+ rescue
86
+ return []
87
+ end
88
+
89
+ def impact(severity)
90
+ IMPACT_MAPPING[severity.to_sym]
91
+ end
92
+
93
+ def parse_mapper
94
+ csv_data = CSV.read(CWE_NIST_MAPPING_FILE, **{ encoding: 'UTF-8',
95
+ headers: true,
96
+ header_converters: :symbol,
97
+ converters: :all })
98
+ csv_data.map(&:to_hash)
99
+ end
100
+
101
+ def desc_tags(data, label)
102
+ { "data": data || NA_STRING, "label": label || NA_STRING }
103
+ end
104
+
105
+ # Snyk report could have multiple vulnerability entries for multiple findings of same issue type.
106
+ # The meta data is identical across entries
107
+ # method collapse_duplicates return unique controls with applicable findings collapsed into it.
108
+ def collapse_duplicates(controls)
109
+ unique_controls = []
110
+
111
+ controls.map { |x| x['id'] }.uniq.each do |id|
112
+ collapsed_results = controls.select { |x| x['id'].eql?(id) }.map {|x| x['results']}
113
+ unique_control = controls.find { |x| x['id'].eql?(id) }
114
+ unique_control['results'] = collapsed_results.flatten
115
+ unique_controls << unique_control
116
+ end
117
+ unique_controls
118
+ end
119
+
120
+
121
+ def to_hdf
122
+ project_results = {}
123
+ @projects.each do | project |
124
+ controls = []
125
+ project['vulnerabilities'].each do | vulnerability |
126
+ printf("\rProcessing: %s", $spinner.next)
127
+
128
+ item = {}
129
+ item['tags'] = {}
130
+ item['descriptions'] = []
131
+ item['refs'] = NA_ARRAY
132
+ item['source_location'] = NA_HASH
133
+ item['descriptions'] = NA_ARRAY
134
+
135
+ item['title'] = vulnerability['title'].to_s
136
+ item['id'] = vulnerability['id'].to_s
137
+ item['desc'] = vulnerability['description'].to_s
138
+ item['impact'] = impact(vulnerability['severity'])
139
+ item['code'] = ''
140
+ item['results'] = finding(vulnerability)
141
+ item['tags']['nist'] = nist_tag( parse_identifiers( vulnerability, 'CWE') )
142
+ item['tags']['cweid'] = parse_identifiers( vulnerability, 'CWE')
143
+ item['tags']['cveid'] = parse_identifiers( vulnerability, 'CVE')
144
+ item['tags']['ghsaid'] = parse_identifiers( vulnerability, 'GHSA')
145
+
146
+ controls << item
147
+ end
148
+ controls = collapse_duplicates(controls)
149
+ scaninfo = extract_scaninfo(project)
150
+ results = HeimdallDataFormat.new(profile_name: scaninfo['policy'],
151
+ version: scaninfo['version'],
152
+ title: "Snyk Project: #{scaninfo['projectName']}",
153
+ summary: "Snyk Summary: #{scaninfo['summary']}",
154
+ controls: controls,
155
+ target_id: scaninfo['projectName'])
156
+ project_results[scaninfo['projectName']] = results.to_hdf
157
+ end
158
+ project_results
159
+ end
160
+ end
161
+ 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.27
4
+ version: 1.3.32
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: 2020-05-22 00:00:00.000000000 Z
13
+ date: 2020-07-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: nokogiri
@@ -203,14 +203,13 @@ executables:
203
203
  extensions: []
204
204
  extra_rdoc_files: []
205
205
  files:
206
- - CHANGELOG.md
207
206
  - Guardfile
208
207
  - LICENSE.md
209
208
  - README.md
210
209
  - Rakefile
211
210
  - exe/heimdall_tools
211
+ - lib/data/U_CCI_List.xml
212
212
  - lib/data/cwe-nist-mapping.csv
213
- - lib/data/gitkeep
214
213
  - lib/data/nessus-plugins-nist-mapping.csv
215
214
  - lib/data/owasp-nist-mapping.csv
216
215
  - lib/heimdall_tools.rb
@@ -223,9 +222,11 @@ files:
223
222
  - lib/heimdall_tools/help/burpsuite_mapper.md
224
223
  - lib/heimdall_tools/help/fortify_mapper.md
225
224
  - lib/heimdall_tools/help/nessus_mapper.md
225
+ - lib/heimdall_tools/help/snyk_mapper.md
226
226
  - lib/heimdall_tools/help/sonarqube_mapper.md
227
227
  - lib/heimdall_tools/help/zap_mapper.md
228
228
  - lib/heimdall_tools/nessus_mapper.rb
229
+ - lib/heimdall_tools/snyk_mapper.rb
229
230
  - lib/heimdall_tools/sonarqube_mapper.rb
230
231
  - lib/heimdall_tools/version.rb
231
232
  - lib/heimdall_tools/zap_mapper.rb