Class: HeimdallTools::FortifyMapper

Inherits:
Object
  • Object
show all
Defined in:
lib/heimdall_tools/fortify_mapper.rb

Instance Method Summary collapse

Constructor Details

#initialize(fvdl) ⇒ FortifyMapper

Returns a new instance of FortifyMapper.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/heimdall_tools/fortify_mapper.rb', line 10

def initialize(fvdl)
  @fvdl = fvdl

  begin
    data = xml_to_hash(fvdl)
    @timestamp = data['FVDL']['CreatedTS']
    @vulns = data['FVDL']['Vulnerabilities']['Vulnerability']
    @snippets = data['FVDL']['Snippets']['Snippet']
    @rules = data['FVDL']['Description']
    @uuid = data['FVDL']['UUID']
    @fortify_version = data['FVDL']['EngineData']['EngineVersion']
  rescue StandardError => e
    raise "Invalid Fortify FVDL file provided Exception: #{e}"
  end
end

Instance Method Details

#impact(classid) ⇒ Object



73
74
75
76
# File 'lib/heimdall_tools/fortify_mapper.rb', line 73

def impact(classid)
  vuln = @vulns.detect { |x| x['ClassInfo']['ClassID'].eql?(classid) }
  vuln['ClassInfo']['DefaultSeverity'].to_f / 5
end

#nist_tag(rule) ⇒ Object



66
67
68
69
70
71
# File 'lib/heimdall_tools/fortify_mapper.rb', line 66

def nist_tag(rule)
  references = rule['References']['Reference']
  references = [references] unless references.is_a?(Array)
  tag = references.detect { |x| x['Author'].eql?(NIST_REFERENCE_NAME) }
  tag.nil? ? DEFAULT_NIST_TAG : tag['Title'].match(/[a-zA-Z][a-zA-Z]-\d{1,2}/)
end

#primaries(classid) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/heimdall_tools/fortify_mapper.rb', line 36

def primaries(classid)
  matched_vulns = @vulns.select { |x| x['ClassInfo']['ClassID'].eql?(classid) }
  findings = []
  matched_vulns.each do |vuln|
    traces = vuln['AnalysisInfo']['Unified']['Trace']
    traces = [traces] unless traces.is_a?(Array)
    traces.each do |trace|
      entries = trace['Primary']['Entry']
      entries = [entries] unless entries.is_a?(Array)
      # This is just regular array access, it is just written in a manner that allows us
      # to use Ruby's safe navigation operator. We rely on
      # entry['Node']['SourceLocation']['snippet'] to exist on all of our entries, so if any
      # of those are empty we reject that element.
      entries = entries.reject { |x| x&.[]('Node')&.[]('SourceLocation')&.[]('snippet').nil? }
      entries.each do |entry|
        findings << process_entry(entry)
      end
    end
  end
  findings.uniq
end

#process_entry(entry) ⇒ Object



26
27
28
29
30
31
32
33
34
# File 'lib/heimdall_tools/fortify_mapper.rb', line 26

def process_entry(entry)
  snippetid = entry['Node']['SourceLocation']['snippet']
  finding = {}
  finding['status'] = 'failed'
  finding['code_desc'] = snippet(snippetid)
  finding['run_time'] = NA_FLOAT
  finding['start_time'] = [@timestamp['date'], @timestamp['time']].join(' ')
  finding
end

#snippet(snippetid) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/heimdall_tools/fortify_mapper.rb', line 58

def snippet(snippetid)
  snippet = @snippets.select { |x| x['id'].eql?(snippetid) }.first
  "\nPath: #{snippet['File']}\n" \
    "StartLine: #{snippet['StartLine']}, " \
    "EndLine: #{snippet['EndLine']}\n" \
    "Code:\n#{snippet['Text']['#cdata-section'].strip}" \
end

#to_hdfObject



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/heimdall_tools/fortify_mapper.rb', line 78

def to_hdf
  controls = []
  @rules.each do |rule|
    @item = {}
    @item['id']              = rule['classID']
    @item['desc']            = rule['Explanation']
    @item['title']           = rule['Abstract']
    @item['impact']          = impact(rule['classID'])
    @item['descriptions']    = NA_ARRAY
    @item['refs']            = NA_ARRAY
    @item['source_location'] = NA_HASH
    @item['code']            = NA_TAG
    @item['results']         = []
    @item['results']         = primaries(@item['id'])
    @item['tags']            = {}
    @item['tags']['nist']    = [nist_tag(rule).to_s, 'Rev_4']
    controls << @item
  end
  results = HeimdallDataFormat.new(profile_name: 'Fortify Static Analyzer Scan',
                                   version: @fortify_version,
                                   title: 'Fortify Static Analyzer Scan',
                                   summary: "Fortify Static Analyzer Scan of UUID: #{@uuid}",
                                   controls: controls)
  results.to_hdf
end