#!/usr/bin/python3 # -*- coding: utf-8 -*- """ This module uses the Shodan library to interact with shodan.io to lookup and search for hostnames and IP addresses. """ import click import shodan import requests from . import helpers class ShodanTools(object): """Class with various tools for interacting with Shodan to search for IP addresses and domains.""" # Set the timeout, in seconds, for the web requests requests_timeout = 10 # The Shodan API endpoint for DNS resolution shodan_dns_resolve_uri = "https://api.shodan.io/dns/resolve?hostnames={}&key={}" def __init__(self): """Everything that should be initiated with a new object goes here.""" try: self.shodan_api_key = helpers.config_section_map("Shodan")["api_key"] self.shodan_api = shodan.Shodan(self.shodan_api_key) except Exception: self.shodan_api = None click.secho("[!] Did not find a Shodan API key.",fg="yellow") def run_shodan_search(self,target): """Collect information Shodan has for target domain name. This uses the Shodan search instead of host lookup and returns the target results dictionary from Shodan. A Shodan API key is required. Parameters: target The domain to search for on Shodan """ if self.shodan_api is None: pass else: try: target_results = self.shodan_api.search(target) return target_results except shodan.APIError as error: pass def run_shodan_resolver(self,target): """Resolve a hosname to an IP address using the Shodan API's DNS endpoint. A Shodan API key is required. Parameters: target The hostname to resolve to an IP address using Shodan """ if not helpers.is_ip(target): try: resolved = requests.get(self.shodan_dns_resolve_uri.format(target,self.shodan_api_key),timeout=self.requests_timeout) target_ip = resolved.json()[target] return target_ip except requests.exceptions.Timeout: click.secho("\n[!] The connection to Shodan timed out!",fg="red") except requests.exceptions.TooManyRedirects: click.secho("\n[!] The connection to Shodan encountered too many redirects!",fg="red") except requests.exceptions.RequestException as error: click.secho("\n[!] The connection to Shodan encountered an error!",fg="red") click.secho("L.. Details: {}".format(error),fg="red") return None else: click.secho("[!] Only a hostname can be resolved to an IP address.",fg="red") def run_shodan_lookup(self,target): """Collect information Shodan has for target IP address. This uses the Shodan host lookup instead of search and returns the target results dictionary from Shodan. A Shodan API key is required. Parameters: target The IP address to use for the Shodan query """ if self.shodan_api is None: pass else: try: target_results = self.shodan_api.host(target) return target_results except shodan.APIError as error: if error == "Invalid IP": click.secho("[*] A domain resolved to {}, which Shodan has flagged as an invalid \ IP address. Review it and check the hostname in the final results. If it is a valid address, the \ domain may resolve to an internal asset or have a CNAME for an internal asset.",fg="yellow") else: pass