theHarvester/discovery/shodan/api.py
laramies 09babc0285 2.5
Fixed Google searches, and introduced Requests library
2014-12-16 23:25:12 +00:00

244 lines
7.4 KiB
Python

try:
from json import dumps, loads
except:
from simplejson import dumps, loads
from urllib2 import urlopen
from urllib import urlencode
__all__ = ['WebAPI']
class WebAPIError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
class WebAPI:
"""Wrapper around the SHODAN webservices API"""
class DatalossDb:
def __init__(self, parent):
self.parent = parent
def search(self, **kwargs):
"""Search the Dataloss DB archive.
Arguments:
name -- Name of the affected company/ organisation
arrest -- whether the incident resulted in an arrest
breaches -- the type of breach that occurred (Hack, MissingLaptop etc.)
country -- country where the incident took place
ext -- whether an external, third party was affected
ext_names -- the name of the third party company that was affected
lawsuit -- whether the incident resulted in a lawsuit
records -- the number of records that were lost/ stolen
recovered -- whether the affected items were recovered
sub_types -- the sub-categorization of the affected company/ organization
source -- whether the incident occurred from inside or outside the organization
stocks -- stock symbol of the affected company
types -- the basic type of organization (government, business, educational)
uid -- unique ID for the incident
Returns:
A dictionary with 2 main items: matches (list) and total (int).
"""
return self.parent._request('datalossdb/search', dict(**kwargs))
class Exploits:
def __init__(self, parent):
self.parent = parent
def search(self, query, sources=[],
cve=None, osvdb=None, msb=None, bid=None):
"""Search the entire Shodan Exploits archive using the same query syntax
as the website.
Arguments:
query -- exploit search query; same syntax as website
Optional arguments:
sources -- metasploit, cve, osvdb, exploitdb, or packetstorm
cve -- CVE identifier (ex. 2010-0432)
osvdb -- OSVDB identifier (ex. 11666)
msb -- Microsoft Security Bulletin ID (ex. MS05-030)
bid -- Bugtraq identifier (ex. 13951)
"""
if sources:
query += ' source:' + ','.join(sources)
if cve:
query += ' cve:%s' % (str(cve).strip())
if osvdb:
query += ' osvdb:%s' % (str(osvdb).strip())
if msb:
query += ' msb:%s' % (str(msb).strip())
if bid:
query += ' bid:%s' % (str(bid).strip())
return self.parent._request('search_exploits', {'q': query})
class ExploitDb:
def __init__(self, parent):
self.parent = parent
def download(self, id):
"""Download the exploit code from the ExploitDB archive.
Arguments:
id -- ID of the ExploitDB entry
Returns:
A dictionary with the following fields:
filename -- Name of the file
content-type -- Mimetype
data -- Contents of the file
"""
return self.parent._request('exploitdb/download', {'id': id})
def search(self, query, **kwargs):
"""Search the ExploitDB archive.
Arguments:
query -- Search terms
Optional arguments:
author -- Name of the exploit submitter
platform -- Target platform (e.g. windows, linux, hardware etc.)
port -- Service port number
type -- Any, dos, local, papers, remote, shellcode and webapps
Returns:
A dictionary with 2 main items: matches (list) and total (int).
Each item in 'matches' is a dictionary with the following elements:
id
author
date
description
platform
port
type
"""
return (
self.parent._request(
'exploitdb/search', dict(q=query, **kwargs))
)
class Msf:
def __init__(self, parent):
self.parent = parent
def download(self, id):
"""Download a metasploit module given the fullname (id) of it.
Arguments:
id -- fullname of the module (ex. auxiliary/admin/backupexec/dump)
Returns:
A dictionary with the following fields:
filename -- Name of the file
content-type -- Mimetype
data -- File content
"""
return self.parent._request('msf/download', {'id': id})
def search(self, query, **kwargs):
"""Search for a Metasploit module.
"""
return self.parent._request('msf/search', dict(q=query, **kwargs))
def __init__(self, key):
"""Initializes the API object.
Arguments:
key -- your API key
"""
self.api_key = key
self.base_url = 'http://www.shodanhq.com/api/'
self.dataloss = self.DatalossDb(self)
self.exploits = self.Exploits(self)
self.exploitdb = self.ExploitDb(self)
self.msf = self.Msf(self)
def _request(self, function, params):
"""General-purpose function to create web requests to SHODAN.
Arguments:
function -- name of the function you want to execute
params -- dictionary of parameters for the function
Returns
A JSON string containing the function's results.
"""
# Add the API key parameter automatically
params['key'] = self.api_key
# Send the request
data = urlopen(
self.base_url +
function +
'?' +
urlencode(
params)).read(
)
# Parse the text into JSON
data = loads(data)
# Raise an exception if an error occurred
if data.get('error', None):
raise WebAPIError(data['error'])
# Return the data
return data
def fingerprint(self, banner):
"""Determine the software based on the banner.
Arguments:
banner - HTTP banner
Returns:
A list of software that matched the given banner.
"""
return self._request('fingerprint', {'banner': banner})
def host(self, ip):
"""Get all available information on an IP.
Arguments:
ip -- IP of the computer
Returns:
All available information SHODAN has on the given IP,
subject to API key restrictions.
"""
return self._request('host', {'ip': ip})
def search(self, query):
"""Search the SHODAN database.
Arguments:
query -- search query; identical syntax to the website
Returns:
A dictionary with 3 main items: matches, countries and total.
Visit the website for more detailed information.
"""
return self._request('search', {'q': query})