#! /usr/bin/env python import sys import json import shodan from harpoon.commands.base import Command from dateutil.parser import parse class CommandShodan(Command): """ # Shodan **Queries information from shodan.io API*** * Get information on an IP : `harpoon shodan ip IP` * Get summary (only ports 22, 80 and 443) of historical data on an ip : `harpoon shodan ip -H -s IP` * Get raw json of historical data : `harpoon shodan ip -H -v IP` * Search in the database: `harpoon shodan search SEARCH` """ name = "shodan" description = "Requests Shodan API" config = {'Shodan': ['key']} def add_arguments(self, parser): subparsers = parser.add_subparsers(help='Subcommand') parser_a = subparsers.add_parser('ip', help='Get information on an IP address') parser_a.add_argument('IP', help='IP to be searched') parser_a.add_argument('--history', '-H', action='store_true', help='Also display historical information') parser_a.add_argument('-v', '--verbose', action='store_true', help="Verbose mode (display raw json)") parser_a.add_argument('-s', '--summary', action='store_true', help="Only display information for ports 22, 80 and 443") parser_a.set_defaults(subcommand='ip') parser_b = subparsers.add_parser('search', help='Search in shodan') parser_b.add_argument('QUERY', help='Query') parser_b.set_defaults(subcommand='search') parser_c = subparsers.add_parser('ssh', help='Write ssh history from Shodan historical data') parser_c.add_argument('IP', help='IP address') parser_c.set_defaults(subcommand='ssh') self.parser = parser def run(self, conf, args, plugins): if 'subcommand' in args: if 'Shodan' not in conf and 'key' not in conf['Shodan']: print('Bad configuration for Shodan, quitting...') sys.exit(1) api = shodan.Shodan(conf['Shodan']['key']) if args.subcommand == 'ip': try: res = api.host(args.IP, history=args.history) except shodan.exception.APIError: print("IP not found in Shodan") else: if args.verbose: print(json.dumps(res, sort_keys=True, indent=4)) else: if args.summary: for d in res['data']: if d['port'] == 22: print("%s - port 22 ssh - %s" % ( d['timestamp'][:19], d['data'].split("\n")[0] ) ) elif d['port'] == 80: print("%s - port 80 http - Server \"%s\"" % ( d['timestamp'][:19], d['http']['server'] ) ) elif d['port'] == 443: if 'cert' in d['ssl']: print("%s - port 443 https - Cert \"%s\" \"%s\" %s - Server \"%s\"" % ( d['timestamp'][:19], d['ssl']['cert']['subject']['CN'], d['ssl']['cert']['issuer']['CN'], d['ssl']['cert']['fingerprint']['sha1'], d['http']['server'] ) ) else: print("%s - port 443 https - Cert Unknown- Server \"%s\"" % ( d['timestamp'][:19], d['http']['server'] ) ) else: for d in res['data']: print(d['timestamp']) print(d['_shodan']['module']) print("%s/%i" % (d['transport'], d['port'])) print(d['data']) if 'html' in d: print(d['html'][:2000]) if 'http' in d: print(json.dumps(d['http'])[:3000]) print('') elif args.subcommand == 'search': res = api.search(args.QUERY) print('%i results' % res['total']) for r in res['matches']: print('[+] %s (%s): port %s/%i -> %s\n' % ( r['ip_str'], r['org'], r['transport'], r['port'], r['data'][:1000] ) ) elif args.subcommand == 'ssh': data = {} try: res = api.host(args.IP, history=True) except shodan.exception.APIError: print("IP not found in Shodan") else: for event in res['data']: if event['_shodan']['module'] == 'ssh': if 'ssh' in event: fingerprint = event['ssh']['fingerprint'] date = parse(event['timestamp']) if fingerprint not in data: data[fingerprint] = { 'first': date, 'last': date, 'fingerprint': fingerprint } else: if data[fingerprint]['first'] > date: data[fingerprint]['first'] = date if data[fingerprint]['last'] < date: data[fingerprint]['last'] = date for val in sorted(data.values(), key=lambda x:x['first']): print('%s - %s -> %s' % ( val['fingerprint'], val['first'].strftime('%Y-%m-%d'), val['last'].strftime('%Y-%m-%d') ) ) else: self.parser.print_help() else: self.parser.print_help()