Class: HeimdallTools::NiktoMapper

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

Instance Method Summary collapse

Constructor Details

#initialize(nikto_json, _name = nil) ⇒ NiktoMapper

Returns a new instance of NiktoMapper.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/heimdall_tools/nikto_mapper.rb', line 29

def initialize(nikto_json, _name = nil)
  @nikto_json = nikto_json

  begin
    @nikto_nist_mapping = parse_mapper
  rescue StandardError => e
    raise "Invalid Nikto to NIST mapping file: Exception: #{e}"
  end

  # TODO: Support Multi-target scan results
  # Nikto multi-target scans generate invalid format JSONs
  # Possible workaround to use https://stackoverflow.com/a/58209963/1670307

  begin
    @project = JSON.parse(nikto_json)
  rescue StandardError => e
    raise "Invalid Nikto JSON file provided\nNote: nikto_mapper does not support multi-target scan results\n\nException: #{e}"
  end
end

Instance Method Details

#collapse_duplicates(controls) ⇒ Object

Nikto report could have multiple vulnerability entries for multiple findings of same issue type. The meta data is identical across entries method collapse_duplicates return unique controls with applicable findings collapsed into it.



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/heimdall_tools/nikto_mapper.rb', line 96

def collapse_duplicates(controls)
  unique_controls = []

  controls.map { |x| x['id'] }.uniq.each do |id|
    collapsed_results = controls.select { |x| x['id'].eql?(id) }.map { |x| x['results'] }
    unique_control = controls.find { |x| x['id'].eql?(id) }
    unique_control['results'] = collapsed_results.flatten
    unique_controls << unique_control
  end
  unique_controls
end

#desc_tags(data, label) ⇒ Object



89
90
91
# File 'lib/heimdall_tools/nikto_mapper.rb', line 89

def desc_tags(data, label)
  { data: data || NA_STRING, label: label || NA_STRING }
end

#extract_scaninfo(project) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/heimdall_tools/nikto_mapper.rb', line 49

def extract_scaninfo(project)
  info = {}
  begin
    info['policy'] = 'Nikto Website Scanner'
    info['version'] = NA_STRING
    info['projectName'] = "Host: #{project['host']} Port: #{project['port']}"
    info['summary'] = "Banner: #{project['banner']}"

    info
  rescue StandardError => e
    raise "Error extracting project info from nikto JSON file provided Exception: #{e}"
  end
end

#finding(vulnerability) ⇒ Object



63
64
65
66
67
68
69
70
# File 'lib/heimdall_tools/nikto_mapper.rb', line 63

def finding(vulnerability)
  finding = {}
  finding['status'] = 'failed'
  finding['code_desc'] = "URL : #{vulnerability['url']} Method: #{vulnerability['method']}"
  finding['run_time'] = NA_FLOAT
  finding['start_time'] = NA_STRING
  [finding]
end

#impact(severity) ⇒ Object



78
79
80
# File 'lib/heimdall_tools/nikto_mapper.rb', line 78

def impact(severity)
  IMPACT_MAPPING[severity.to_sym]
end

#nist_tag(niktoid) ⇒ Object



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

def nist_tag(niktoid)
  entries = @nikto_nist_mapping.select { |x| niktoid.eql?(x[:niktoid].to_s) && !x[:nistid].nil? }
  tags = entries.map { |x| x[:nistid] }
  tags.empty? ? DEFAULT_NIST_TAG : tags.flatten.uniq
end

#parse_mapperObject



82
83
84
85
86
87
# File 'lib/heimdall_tools/nikto_mapper.rb', line 82

def parse_mapper
  csv_data = CSV.read(NIKTO_NIST_MAPPING_FILE, **{ encoding: 'UTF-8',
                                               headers: true,
                                               header_converters: :symbol })
  csv_data.map(&:to_hash)
end

#to_hdfObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/heimdall_tools/nikto_mapper.rb', line 108

def to_hdf
  controls = []
  @project['vulnerabilities'].each do |vulnerability|
    printf("\rProcessing: %s", $spinner.next)

    item = {}
    item['tags']               = {}
    item['descriptions']       = []
    item['refs']               = NA_ARRAY
    item['source_location']    = NA_HASH
    item['descriptions']       = NA_ARRAY

    item['title']              = vulnerability['msg'].to_s
    item['id']                 = vulnerability['id'].to_s

    # Nikto results JSON does not description fields
    # Duplicating vulnerability msg field
    item['desc']               = vulnerability['msg'].to_s

    # Nitko does not provide finding severity; hard-coding severity to medium
    item['impact']             = impact('medium')
    item['code']               = NA_STRING
    item['results']            = finding(vulnerability)
    item['tags']['nist']       = nist_tag(vulnerability['id'].to_s)
    item['tags']['ösvdb']      = vulnerability['OSVDB']

    controls << item
  end

  controls = collapse_duplicates(controls)
  scaninfo = extract_scaninfo(@project)
  results = HeimdallDataFormat.new(profile_name: scaninfo['policy'],
                                   version: scaninfo['version'],
                                   title: "Nikto Target: #{scaninfo['projectName']}",
                                   summary: "Banner: #{scaninfo['summary']}",
                                   controls: controls,
                                   target_id: scaninfo['projectName'])
  results.to_hdf
end