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.

[View source]

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.

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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