From f66d9ad6cc55de1728af3faa494f8afd551a4916 Mon Sep 17 00:00:00 2001 From: IP2Location Date: Wed, 13 Dec 2023 07:26:08 +0800 Subject: [PATCH] Add IP2Location.io plugin. (#200) --- README.md | 2 + harpoon/commands/ip2locationio.py | 102 ++++++++++++++++++++++++++++++ harpoon/data/example.conf | 3 + harpoon/lib/ip2locationio.py | 17 +++++ 4 files changed, 124 insertions(+) create mode 100644 harpoon/commands/ip2locationio.py create mode 100644 harpoon/lib/ip2locationio.py diff --git a/README.md b/README.md index bc6060b..58127a5 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ After configuration the following plugins are available within the `harpoon` com intel Gather information on a domain ip Gather information on an IP address ipinfo Request ipinfo.io information + ip2locationio Request IP2Location.io information koodous Request Koodous API malshare Requests MalShare database misp Get information from a MISP server through the API @@ -125,6 +126,7 @@ You can get information on each command with `harpoon help COMMAND` * [Hybrid Analysis](https://www.hybrid-analysis.com/apikeys/info) * [IBM Xforce Exchange](https://exchange.xforce.ibmcloud.com/settings/api) * [ipinfo.io](https://ipinfo.io/) +* [IP2Location.io](https://www.ip2location.io/) * [Koodous](https://koodous.com/) * [MalShare](https://malshare.com/register.php) * [NumVerify](https://numverify.com/) diff --git a/harpoon/commands/ip2locationio.py b/harpoon/commands/ip2locationio.py new file mode 100644 index 0000000..12673b3 --- /dev/null +++ b/harpoon/commands/ip2locationio.py @@ -0,0 +1,102 @@ +#! /usr/bin/env python +import json +import os +import sys +import time + +from harpoon.commands.base import Command +from harpoon.lib.ip2locationio import IP2Locationio, IP2LocationioError +from harpoon.lib.utils import unbracket + + +class CommandIPInfo(Command): + """ + # IP2Location.io plugin + + **Query IP2Location.io API** + + * Get info on an IP : `harpoon ip2locationio ip IP` + * Get infos on a list of IPs in a file : `harpoon ip2locationio file FILE` + """ + name = "ip2locationio" + description = "Request IP2Location.io information" + config = {'IP2Locationio': ['token']} + + def add_arguments(self, parser): + subparsers = parser.add_subparsers(help='Subcommand') + parser_a = subparsers.add_parser('ip', help='Information on an IP') + parser_a.add_argument('IP', help='IP address') + parser_a.set_defaults(subcommand='ip') + parser_b = subparsers.add_parser('file', help='Information on a list of IPs') + parser_b.add_argument('FILE', help='Filename') + parser_b.add_argument('--delay', '-d', type=int, default=1, help='Delay between two queries in seconds') + parser_b.set_defaults(subcommand='file') + self.parser = parser + + def run(self, args, plugins): + ip2locationio = IP2Locationio(token=self._config_data['IP2Locationio']['token']) + if 'subcommand' in args: + if args.subcommand == 'ip': + try: + infos = ip2locationio.get_infos(unbracket(args.IP)) + except IP2LocationioError: + print("Invalid request") + else: + print(json.dumps(infos, sort_keys=True, indent=4, separators=(',', ': '))) + elif args.subcommand == 'file': + if os.path.isfile(args.FILE): + with open(args.FILE) as f: + data = f.read().split("\n") + print( + "IP;Domain;City;Region;Country;Location;" + + "ISP;ASN;AS Name;" + + "Is Proxy;Proxy Type;Threat Type;Last Seen in") + for d in data: + if d.strip() == '': + continue + ip = unbracket(d.strip()) + try: + infos = ip2locationio.get_infos(ip) + except IP2LocationioError: + print("%s;;;;;;;;;;;;;" % ip) + else: + loc = str(infos['latitude']) + ',' + str(infos['longitude']) + if "proxy" in infos: + print("%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s" % ( + ip, + infos['domain'] if 'domain' in infos else '', + infos['city_name'] if 'city' in infos else '', + infos['region_name'] if 'region' in infos else '', + infos['country_name'] if 'country' in infos else '', + loc, + infos['isp'] if 'isp' in infos else '', + infos['asn'] if 'asn' in infos else '', + infos['as'] if 'as' in infos else '', + infos['is_proxy'] if 'is_proxy' in infos else '', + infos['proxy']['proxy_type'] if 'proxy_type' in infos['proxy'] else '', + infos['proxy']['threat'] if 'threat' in infos['proxy'] else '', + (str(infos['proxy']['last_seen']) + (' days' if infos['proxy']['last_seen'] > 1 else ' day')) if 'last_seen' in infos['proxy'] else '' + ) + ) + else: + print("%s;%s;%s;%s;%s;%s;%s;%s;%s;;;;;" % ( + ip, + infos['domain'] if 'domain' in infos else '', + infos['city_name'], + infos['region_name'], + infos['country_name'], + loc, + infos['isp'] if 'isp' in infos else '', + infos['asn'] if 'asn' in infos else '', + infos['as'] if 'as' in infos else '', + ) + ) + time.sleep(args.delay) + + else: + print("This file does not exist") + sys.exit(1) + else: + self.parser.print_help() + else: + self.parser.print_help() diff --git a/harpoon/data/example.conf b/harpoon/data/example.conf index 9d74cff..4978511 100644 --- a/harpoon/data/example.conf +++ b/harpoon/data/example.conf @@ -91,6 +91,9 @@ key: [IPInfo] token: +[IP2Locationio] +token: + [OpenCage] key: diff --git a/harpoon/lib/ip2locationio.py b/harpoon/lib/ip2locationio.py new file mode 100644 index 0000000..17fbe78 --- /dev/null +++ b/harpoon/lib/ip2locationio.py @@ -0,0 +1,17 @@ +import requests + +class IP2LocationioError(Exception): + def __init__(self, message): + self.message = message + Exception.__init__(self, message) + +class IP2Locationio(object): + def __init__(self, token): + self.token = token + self.base_url = 'https://api.ip2location.io/' + + def get_infos(self, ip): + r = requests.get(self.base_url , params={'key': self.token, 'ip': ip}) + if r.status_code != 200: + raise IP2LocationioError('Invalid HTTP code %i' % r.status_code) + return r.json()