module Shodanz module API # The Exploits API provides access to several exploit # and vulnerability data sources. At the moment, it # searches across the following: # - Exploit DB # - Metasploit # - Common Vulnerabilities and Exposures (CVE) # # @author Kent 'picat' Gruber class Exploits attr_accessor :key # The path to the REST API endpoint. URL = "https://exploits.shodan.io/api/" # @param key [String] SHODAN API key, defaulted to the *SHODAN_API_KEY* enviroment variable. def initialize(key: ENV['SHODAN_API_KEY']) self.key = key warn "No key has been found or provided!" unless self.key? end # Check if there's an API key. def key? return true if @key; false end # Search across a variety of data sources for exploits and # use facets to get summary information. # == Example # api.search("SQL", port: 443) # api.search(port: 22) # api.search(type: "dos") def search(query = "", facets: {}, page: 1, **params) params[:query] = query params = turn_into_query(params) facets = turn_into_facets(facets) params[:page] = page get("search", params.merge(facets)) end # This method behaves identical to the "/search" method with # the difference that it doesn't return any results. # == Example # api.count(type: "dos") def count(query = "", facets: {}, page: 1, **params) params[:query] = query params = turn_into_query(params) facets = turn_into_facets(params) params[:page] = page get("count", params.merge(facets)) end # Perform a direct GET HTTP request to the REST API. def get(path, **params) resp = Unirest.get "#{URL}#{path}?key=#{@key}", parameters: params raise resp.body["error"] if resp.code != 200 and resp.body.has_key?("error") resp.body end private def turn_into_query(params) filters = params.reject { |key, value| key == :query } filters.each do |key, value| params[:query] << " #{key}:#{value}" end params.select { |key, value| key == :query } end def turn_into_facets(facets) filters = facets.reject { |key, value| key == :facets } facets[:facets] = [] filters.each do |key, value| facets[:facets] << "#{key}:#{value}" end facets[:facets] = facets[:facets].join(",") facets.select { |key, value| key == :facets } end end end end