Lucene search
K

SSL Labs API Client

🗓️ 27 Mar 2015 11:34:11Reported by Denis Kolegov <[email protected]>, Francois ChagnonType 
metasploit
 metasploit
🔗 www.rapid7.com👁 108 Views

SSL Labs API client for Metasploit framework to perform SSL security assessment, requests SSL labs API for info, analysis, endpoint data and status codes

Related
Code
ReporterTitlePublishedViews
Family
IBM Security Bulletins
Security Bulletin: IBM Sterling Connect:Enterprise for UNIX affected by the following OpenSSL vulnerability (CVE-2014-0224).
18 Dec 201901:14
ibm
IBM Security Bulletins
Security Bulletin: Tivoli Common Reporting iFixes for multiple Security Vulnerabilities (CVE-2014-3566,CVE-2014-6145,CVE-2014-1568,CVE-2014-4263,CVE-2014-3513,CVE-2014-3567,CVE-2014-3568,CVE-2014-0107,CVE-2014-0075,CVE-2014-0096,CVE-2014-0099,CVE-2014-011
17 Jun 201814:55
ibm
IBM Security Bulletins
Security Bulletin: Security vulnerabilities have been identified in IBM WebSphere MQ (CVE-2014-0224, CVE-2014-3470), Websphere Message Broker and IBM Integration Bus (CVE-2014-0224) shipped with Predictive Maintenance and Quality
15 Jun 201822:33
ibm
IBM Security Bulletins
Security Bulletins for IBM Tealeaf Customer Experience offerings
16 Jun 201819:35
ibm
IBM Security Bulletins
IBM Security Network Protection / IBM QRadar Network Security / XGS Technote Index
31 Jan 202100:10
ibm
IBM Security Bulletins
Security Bulletin: IBM Systems Director is affected by vulnerabilities in OpenSSL (CVE-2014-0224, CVE-2013-0169 and CVE-2014-3470)
31 Jan 201901:25
ibm
IBM Security Bulletins
Security Bulletins - IBM Planning Analytics, Cognos TM1 and Cognos Insight
18 Jul 201817:37
ibm
IBM Security Bulletins
Security Bulletin: Rational ClearCase is affected by OpenSSL vulnerabilities (CVE-2014-0224, CVE-2014-3470, CVE-2015-0292)
10 Jul 201808:34
ibm
IBM Security Bulletins
Security Bulletin:Security vulnerability has been identified in Rational Application Developer shipped with Rational Software Architect for Websphere (CVE-2014-0224, CVE-2014-0221, CVE-2014-0195, CVE-2014-0198, CVE-2010-5298, CVE-2014-3470)
17 Jun 201804:55
ibm
IBM Security Bulletins
Security Bulletin: IBM System x Integrated Management Module (IMM) is affected by the following OpenSSL vulnerabilities: CVE-2014-0224, CVE-2014-0076
31 Jan 201901:25
ibm
Rows per page
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'active_support/inflector'
require 'json'
require 'active_support/core_ext/hash'

class MetasploitModule < Msf::Auxiliary
  class InvocationError < StandardError; end
  class RequestRateTooHigh < StandardError; end
  class InternalError < StandardError; end
  class ServiceNotAvailable < StandardError; end
  class ServiceOverloaded < StandardError; end

  class Api
    attr_reader :max_assessments, :current_assessments

    def initialize
      @max_assessments = 0
      @current_assessments = 0
    end

    def request(name, params = {})
      api_host = "api.ssllabs.com"
      api_port = "443"
      api_path = "/api/v2/"
      user_agent = "Msf_ssllabs_scan"

      name = name.to_s.camelize(:lower)
      uri = api_path + name
      cli = Rex::Proto::Http::Client.new(api_host, api_port, {}, true, 'TLS')
      cli.connect
      req = cli.request_cgi({
          'uri' => uri,
          'agent' => user_agent,
          'method' => 'GET',
          'vars_get' => params
      })
      res = cli.send_recv(req)
      cli.close

      if res && res.code.to_i == 200
        @max_assessments = res.headers['X-Max-Assessments']
        @current_assessments = res.headers['X-Current-Assessments']
        r = JSON.load(res.body)
        fail InvocationError, "API returned: #{r['errors']}" if r.key?('errors')
        return r
      end

      case res.code.to_i
      when 400
        fail InvocationError
      when 429
        fail RequestRateTooHigh
      when 500
        fail InternalError
      when 503
        fail ServiceNotAvailable
      when 529
        fail ServiceOverloaded
      else
        fail StandardError, "HTTP error code #{r.code}", caller
      end
    end

    def report_unused_attrs(type, unused_attrs)
      unused_attrs.each do | attr |
        # $stderr.puts "#{type} request returned unknown parameter #{attr}"
      end
    end

    def info
      obj, unused_attrs = Info.load request(:info)
      report_unused_attrs('info', unused_attrs)
      obj
    end

    def analyse(params = {})
      obj, unused_attrs = Host.load request(:analyze, params)
      report_unused_attrs('analyze', unused_attrs)
      obj
    end

    def get_endpoint_data(params = {})
      obj, unused_attrs = Endpoint.load request(:get_endpoint_data, params)
      report_unused_attrs('get_endpoint_data', unused_attrs)
      obj
    end

    def get_status_codes
      obj, unused_attrs = StatusCodes.load request(:get_status_codes)
      report_unused_attrs('get_status_codes', unused_attrs)
      obj
    end
  end

  class ApiObject

    class << self;
      attr_accessor :all_attributes
      attr_accessor :fields
      attr_accessor :lists
      attr_accessor :refs
    end

    def self.inherited(base)
      base.all_attributes = []
      base.fields = []
      base.lists = {}
      base.refs = {}
    end

    def self.to_api_name(name)
      name.to_s.gsub(/\?$/, '').camelize(:lower)
    end

    def self.to_attr_name(name)
      name.to_s.gsub(/\?$/, '').underscore
    end

    def self.field_methods(name)
      is_bool = name.to_s.end_with?('?')
      attr_name = to_attr_name(name)
      api_name = to_api_name(name)
      class_eval <<-EOF, __FILE__, __LINE__
        def #{attr_name}#{'?' if is_bool}
          @#{api_name}
        end
        def #{attr_name}=(value)
          @#{api_name} = value
        end
      EOF
    end

    def self.has_fields(*names)
      names.each do |name|
        @all_attributes << to_api_name(name)
        @fields << to_api_name(name)
        field_methods(name)
      end
    end

    def self.has_objects_list(name, klass)
      @all_attributes << to_api_name(name)
      @lists[to_api_name(name)] = klass
      field_methods(name)
    end

    def self.has_object_ref(name, klass)
      @all_attributes << to_api_name(name)
      @refs[to_api_name(name)] = klass
      field_methods(name)
    end

    def self.load(attributes = {})
      obj = self.new
      unused_attrs = []
      attributes.each do |name, value|
        if @fields.include?(name)
          obj.instance_variable_set("@#{name}", value)
        elsif @lists.key?(name)
          unless value.nil?
            var = value.map do |v|
              val, ua = @lists[name].load(v)
              unused_attrs.concat ua
              val
            end
            obj.instance_variable_set("@#{name}", var)
          end
        elsif @refs.key?(name)
          unless value.nil?
            val, ua = @refs[name].load(value)
            unused_attrs.concat ua
            obj.instance_variable_set("@#{name}", val)
          end
        else
          unused_attrs << name
        end
      end
      return obj, unused_attrs
    end

    def to_json(opts = {})
      obj = {}
      self.class.all_attributes.each do |api_name|
        v = instance_variable_get("@#{api_name}")
        obj[api_name] = v
      end
      obj.to_json
    end
  end

  class Cert < ApiObject
    has_fields :subject,
               :commonNames,
               :altNames,
               :notBefore,
               :notAfter,
               :issuerSubject,
               :sigAlg,
               :issuerLabel,
               :revocationInfo,
               :crlURIs,
               :ocspURIs,
               :revocationStatus,
               :crlRevocationStatus,
               :ocspRevocationStatus,
               :sgc?,
               :validationType,
               :issues,
               :sct?,
               :mustStaple,
               :sha1Hash,
               :pinSha256

    def valid?
      issues == 0
    end

    def invalid?
      !valid?
    end
  end

  class ChainCert < ApiObject
    has_fields :subject,
               :label,
               :notBefore,
               :notAfter,
               :issuerSubject,
               :issuerLabel,
               :sigAlg,
               :issues,
               :keyAlg,
               :keySize,
               :keyStrength,
               :revocationStatus,
               :crlRevocationStatus,
               :ocspRevocationStatus,
               :raw,
               :sha1Hash,
               :pinSha256

    def valid?
      issues == 0
    end

    def invalid?
      !valid?
    end
  end

  class Chain < ApiObject
    has_objects_list :certs, ChainCert
    has_fields :issues

    def valid?
      issues == 0
    end

    def invalid?
      !valid?
    end
  end

  class Key < ApiObject
    has_fields :size,
               :strength,
               :alg,
               :debianFlaw?,
               :q

    def insecure?
      debian_flaw? || q == 0
    end

    def secure?
      !insecure?
    end
  end

  class Protocol < ApiObject
    has_fields :id,
               :name,
               :version,
               :v2SuitesDisabled?,
               :q

    def insecure?
      q == 0
    end

    def secure?
      !insecure?
    end

  end

  class Info < ApiObject
    has_fields :engineVersion,
               :criteriaVersion,
               :clientMaxAssessments,
               :maxAssessments,
               :currentAssessments,
               :messages,
               :newAssessmentCoolOff
  end

  class SimClient < ApiObject
    has_fields :id,
               :name,
               :platform,
               :version,
               :isReference?
  end

  class Simulation < ApiObject
    has_object_ref :client, SimClient
    has_fields :errorCode,
               :attempts,
               :protocolId,
               :suiteId,
               :kxInfo

    def success?
      error_code == 0
    end

    def error?
      !success?
    end
  end

  class SimDetails < ApiObject
    has_objects_list :results, Simulation
  end

  class StatusCodes < ApiObject
    has_fields :statusDetails

    def [](name)
      status_details[name]
    end
  end

  class Suite < ApiObject
    has_fields :id,
               :name,
               :cipherStrength,
               :dhStrength,
               :dhP,
               :dhG,
               :dhYs,
               :ecdhBits,
               :ecdhStrength,
               :q

    def insecure?
      q == 0
    end

    def secure?
      !insecure?
    end
  end

  class Suites < ApiObject
    has_objects_list :list, Suite
    has_fields :preference?
  end

  class EndpointDetails < ApiObject
    has_fields :hostStartTime
    has_object_ref :key, Key
    has_object_ref :cert, Cert
    has_object_ref :chain, Chain
    has_objects_list :protocols, Protocol
    has_object_ref :suites, Suites
    has_fields :serverSignature,
               :prefixDelegation?,
               :nonPrefixDelegation?,
               :vulnBeast?,
               :renegSupport,
               :stsResponseHeader,
               :stsMaxAge,
               :stsSubdomains?,
               :pkpResponseHeader,
               :sessionResumption,
               :compressionMethods,
               :supportsNpn?,
               :npnProtocols,
               :sessionTickets,
               :ocspStapling?,
               :staplingRevocationStatus,
               :staplingRevocationErrorMessage,
               :sniRequired?,
               :httpStatusCode,
               :httpForwarding,
               :supportsRc4?,
               :forwardSecrecy,
               :rc4WithModern?
    has_object_ref :sims, SimDetails
    has_fields :heartbleed?,
               :heartbeat?,
               :openSslCcs,
               :poodle?,
               :poodleTls,
               :fallbackScsv?,
               :freak?,
               :hasSct,
               :stsStatus,
               :stsPreload,
               :supportsAlpn,
               :rc4Only,
               :protocolIntolerance,
               :miscIntolerance,
               :openSSLLuckyMinus20,
               :logjam,
               :chaCha20Preference,
               :hstsPolicy,
               :hstsPreloads,
               :hpkpPolicy,
               :hpkpRoPolicy,
               :drownHosts,
               :drownErrors,
               :drownVulnerable
  end

  class Endpoint < ApiObject
    has_fields :ipAddress,
               :serverName,
               :statusMessage,
               :statusDetails,
               :statusDetailsMessage,
               :grade,
               :gradeTrustIgnored,
               :hasWarnings?,
               :isExceptional?,
               :progress,
               :duration,
               :eta,
               :delegation
    has_object_ref :details, EndpointDetails
  end

  class Host < ApiObject
    has_fields :host,
               :port,
               :protocol,
               :isPublic?,
               :status,
               :statusMessage,
               :startTime,
               :testTime,
               :engineVersion,
               :criteriaVersion,
               :cacheExpiryTime
    has_objects_list :endpoints, Endpoint
    has_fields :certHostnames
  end

  def initialize(info = {})
    super(update_info(info,
        'Name'          => 'SSL Labs API Client',
        'Description'   => %q{
          This module is a simple client for the SSL Labs APIs, designed for
          SSL/TLS assessment during a penetration test.
        },
        'License'       => MSF_LICENSE,
        'Author'        =>
          [
            'Denis Kolegov <dnkolegov[at]gmail.com>',
            'Francois Chagnon' # ssllab.rb author (https://github.com/Shopify/ssllabs.rb)
           ],
        'DefaultOptions' =>
          {
            'RPORT'      => 443,
            'SSL'        => true,
          }
    ))
    register_options(
      [
        OptString.new('HOSTNAME', [true, 'The target hostname']),
        OptInt.new('DELAY', [true, 'The delay in seconds between  API requests', 5]),
        OptBool.new('USECACHE', [true, 'Use cached results (if available), else force live scan', true]),
        OptBool.new('GRADE', [true, 'Output only the hostname: grade', false]),
        OptBool.new('IGNOREMISMATCH', [true, 'Proceed with assessments even when the server certificate doesn\'t match the assessment hostname', true])
      ])
  end

  def report_good(line)
    print_good line
  end

  def report_warning(line)
    print_warning line
  end

  def report_bad(line)
    print_warning line
  end

  def report_status(line)
    print_status line
  end

  def output_endpoint_data(r)
    ssl_protocols = [
      { id: 771, name: "TLS", version: "1.2", secure: true, active: false },
      { id: 770, name: "TLS", version: "1.1", secure: true, active: false },
      { id: 769, name: "TLS", version: "1.0", secure: true, active: false },
      { id: 768, name: "SSL", version: "3.0", secure: false, active: false },
      { id: 2, name: "SSL", version: "2.0", secure: false, active: false }
    ]

    report_status "-----------------------------------------------------------------"
    report_status "Report for #{r.server_name} (#{r.ip_address})"
    report_status "-----------------------------------------------------------------"

    case r.grade.to_s
    when "A+", "A", "A-"
      report_good "Overall rating: #{r.grade}"
    when "B"
      report_warning "Overall rating: #{r.grade}"
    when "C", "D", "E", "F"
      report_bad "Overall rating: #{r.grade}"
    when "M"
      report_bad "Overall rating: #{r.grade} - Certificate name mismatch"
    when "T"
      report_bad "Overall rating: #{r.grade} - Server's certificate is not trusted"
    end

    report_warning "Grade is #{r.grade_trust_ignored}, if trust issues are ignored)" if r.grade.to_s != r.grade_trust_ignored.to_s

    # Supported protocols
    r.details.protocols.each do |i|
      p = ssl_protocols.detect { |x| x[:id] == i.id }
      p.store(:active, true) if p
    end

    ssl_protocols.each do |proto|
      if proto[:active]
        if proto[:secure]
          report_good "#{proto[:name]} #{proto[:version]} - Yes"
        else
          report_bad "#{proto[:name]} #{proto[:version]} - Yes"
        end
      else
        report_good "#{proto[:name]} #{proto[:version]} - No"
      end
    end

    # Renegotiation
    case
    when r.details.reneg_support == 0
      report_warning "Secure renegotiation is not supported"
    when r.details.reneg_support[0] == 1
      report_bad "Insecure client-initiated renegotiation is supported"
    when r.details.reneg_support[1] == 1
      report_good "Secure renegotiation is supported"
    when r.details.reneg_support[2] == 1
      report_warning "Secure client-initiated renegotiation is supported"
    when r.details.reneg_support[3] == 1
      report_warning "Server requires secure renegotiation support"
    end

    # BEAST
    if r.details.vuln_beast?
      report_bad "BEAST attack - Yes"
    else
      report_good "BEAST attack - No"
    end

    # POODLE (SSLv3)
    if r.details.poodle?
      report_bad "POODLE SSLv3 - Vulnerable"
    else
      report_good "POODLE SSLv3 - Not vulnerable"
    end

    # POODLE TLS
    case r.details.poodle_tls
    when -1
      report_warning "POODLE TLS - Test failed"
    when 0
      report_warning "POODLE TLS - Unknown"
    when 1
      report_good "POODLE TLS - Not vulnerable"
    when 2
      report_bad "POODLE TLS - Vulnerable"
    end

    # Downgrade attack prevention
    if r.details.fallback_scsv?
      report_good "Downgrade attack prevention - Yes, TLS_FALLBACK_SCSV supported"
    else
      report_bad "Downgrade attack prevention - No, TLS_FALLBACK_SCSV not supported"
    end

    # Freak
    if r.details.freak?
      report_bad "Freak - Vulnerable"
    else
      report_good "Freak - Not vulnerable"
    end

    # RC4
    if r.details.supports_rc4?
      report_warning "RC4 - Server supports at least one RC4 suite"
    else
      report_good "RC4 - No"
    end

    # RC4 with modern browsers
    report_warning "RC4 is used with modern clients" if r.details.rc4_with_modern?

    # Heartbeat
    if r.details.heartbeat?
      report_status "Heartbeat (extension) - Yes"
    else
      report_status "Heartbeat (extension) - No"
    end

    # Heartbleed
    if r.details.heartbleed?
      report_bad "Heartbleed (vulnerability) - Yes"
    else
      report_good "Heartbleed (vulnerability) - No"
    end

    # OpenSSL CCS
    case r.details.open_ssl_ccs
    when -1
      report_warning "OpenSSL CCS vulnerability (CVE-2014-0224) - Test failed"
    when 0
      report_warning "OpenSSL CCS vulnerability (CVE-2014-0224) - Unknown"
    when 1
      report_good "OpenSSL CCS vulnerability (CVE-2014-0224) - No"
    when 2
      report_bad "OpenSSL CCS vulnerability (CVE-2014-0224) - Possibly vulnerable, but not exploitable"
    when 3
      report_bad "OpenSSL CCS vulnerability (CVE-2014-0224) - Vulnerable and exploitable"
    end

    # Forward Secrecy
    case
    when r.details.forward_secrecy == 0
      report_bad "Forward Secrecy - No"
    when r.details.forward_secrecy[0] == 1
      report_bad "Forward Secrecy - With some browsers"
    when r.details.forward_secrecy[1] == 1
      report_good "Forward Secrecy - With modern browsers"
    when r.details.forward_secrecy[2] == 1
      report_good "Forward Secrecy - Yes (with most browsers)"
    end

    # HSTS
    if r.details.sts_response_header
      str = "Strict Transport Security (HSTS) - Yes"
      if r.details.sts_max_age && r.details.sts_max_age != -1
        str += ":max-age=#{r.details.sts_max_age}"
      end
      str += ":includeSubdomains" if r.details.sts_subdomains?
      report_good str
    else
      report_bad "Strict Transport Security (HSTS) - No"
    end

    # HPKP
    if r.details.pkp_response_header
      report_good "Public Key Pinning (HPKP) - Yes"
    else
      report_warning "Public Key Pinning (HPKP) - No"
    end

    # Compression
    if r.details.compression_methods == 0
      report_good "Compression - No"
    elsif (r.details.session_tickets & 1) != 0
      report_warning "Compression - Yes (Deflate)"
    end

    # Session Resumption
    case r.details.session_resumption
    when 0
      print_status "Session resumption - No"
    when 1
      report_warning "Session resumption - No (IDs assigned but not accepted)"
    when 2
      print_status "Session resumption - Yes"
    end

    # Session Tickets
    case
    when r.details.session_tickets == 0
      print_status "Session tickets - No"
    when r.details.session_tickets[0] == 1
      print_status "Session tickets - Yes"
    when r.details.session_tickets[1] == 1
      report_good "Session tickets - Implementation is faulty"
    when r.details.session_tickets[2] == 1
      report_warning "Session tickets - Server is intolerant to the extension"
    end

    # OCSP stapling
    if r.details.ocsp_stapling?
      print_status "OCSP Stapling - Yes"
    else
      print_status "OCSP Stapling - No"
    end

    # NPN
    if r.details.supports_npn?
      print_status "Next Protocol Negotiation (NPN) - Yes (#{r.details.npn_protocols})"
    else
      print_status "Next Protocol Negotiation (NPN) - No"
    end

    # SNI
    print_status "SNI Required - Yes" if r.details.sni_required?
  end

  def output_grades_only(r)
    r.endpoints.each do |e|
      if e.status_message == "Ready"
        print_status "Server: #{e.server_name} (#{e.ip_address}) - Grade:#{e.grade}"
      else
        print_status "Server: #{e.server_name} (#{e.ip_address} - Status:#{e.status_message}"
      end
    end
  end

  def output_common_info(r)
    return unless r
    print_status "Host: #{r.host}"

    r.endpoints.each do |e|
      print_status "\t  #{e.ip_address}"
    end
  end

  def output_result(r, grade)
    return unless r
    output_common_info(r)
    if grade
      output_grades_only(r)
    else
      r.endpoints.each do |e|
        if e.status_message == "Ready"
          output_endpoint_data(e)
        else
          print_status "#{e.status_message}"
        end
      end
    end
  end

  def output_testing_details(r)
    return unless r.status == "IN_PROGRESS"

    if r.endpoints.length == 1
      print_status "#{r.host} (#{r.endpoints[0].ip_address}) - Progress #{[r.endpoints[0].progress, 0].max}% (#{r.endpoints[0].status_details_message})"
    elsif r.endpoints.length > 1
      in_progress_srv_num = 0
      ready_srv_num = 0
      pending_srv_num = 0
      r.endpoints.each do |e|
        case e.status_message.to_s
        when "In progress"
          in_progress_srv_num += 1
          print_status "Scanned host: #{e.ip_address} (#{e.server_name})- #{[e.progress, 0].max}% complete (#{e.status_details_message})"
        when "Pending"
          pending_srv_num += 1
        when "Ready"
          ready_srv_num += 1
        end
      end
      progress = ((ready_srv_num.to_f / (pending_srv_num + in_progress_srv_num + ready_srv_num)) * 100.0).round(0)
      print_status "Ready: #{ready_srv_num}, In progress: #{in_progress_srv_num}, Pending: #{pending_srv_num}"
      print_status "#{r.host} - Progress #{progress}%"
    end
  end

  def valid_hostname?(hostname)
    hostname =~ /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/
  end

  def run
    delay = datastore['DELAY']
    hostname = datastore['HOSTNAME']
    unless valid_hostname?(hostname)
      print_status "Invalid hostname"
      return
    end

    usecache = datastore['USECACHE']
    grade = datastore['GRADE']

    # Use cached results
    if usecache
      from_cache = 'on'
      start_new = 'off'
    else
      from_cache = 'off'
      start_new = 'on'
    end

    # Ignore mismatch
    ignore_mismatch = datastore['IGNOREMISMATCH'] ? 'on' : 'off'

    api = Api.new
    info = api.info
    print_status "SSL Labs API info"
    print_status "API version: #{info.engine_version}"
    print_status "Evaluation criteria: #{info.criteria_version}"
    print_status "Running assessments: #{info.current_assessments} (max #{info.max_assessments})"

    if api.current_assessments >= api.max_assessments
      print_status "Too many active assessments"
      return
    end

    if usecache
      r = api.analyse(host: hostname, fromCache: from_cache, ignoreMismatch: ignore_mismatch, all: 'done')
    else
      r = api.analyse(host: hostname, startNew: start_new, ignoreMismatch: ignore_mismatch, all: 'done')
    end

    loop do
      case r.status
      when "DNS"
        print_status "Server: #{r.host} - #{r.status_message}"
      when "IN_PROGRESS"
        output_testing_details(r)
      when "READY"
        output_result(r, grade)
        return
      when "ERROR"
        print_error "#{r.status_message}"
        return
      else
        print_error "Unknown assessment status"
        return
      end
      sleep delay
      r = api.analyse(host: hostname, all: 'done')
    end

    rescue RequestRateTooHigh
      print_error "Request rate is too high, please slow down"
    rescue InternalError
      print_error "Service encountered an error, sleep 5 minutes"
    rescue ServiceNotAvailable
      print_error "Service is not available, sleep 15 minutes"
    rescue ServiceOverloaded
      print_error "Service is overloaded, sleep 30 minutes"
    rescue
      print_error "Invalid parameters"
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

07 Jan 2024 20:02Current
8.2High risk
Vulners AI Score8.2
CVSS 25.8
CVSS 3.17.4
EPSS0.95326
108