class HeimdallTools::NiktoMapper

Public Class Methods

new(nikto_json, _name = nil) click to toggle source
# 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

Public Instance Methods

collapse_duplicates(controls) click to toggle source

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.

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# File lib/heimdall_tools/nikto_mapper.rb, line 78
def impact(severity)
  IMPACT_MAPPING[severity.to_sym]
end
nist_tag(niktoid) click to toggle source
# 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_mapper() click to toggle source
# 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_hdf() click to toggle source
# 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