def do_generate(self, api_key, logger): ip_address = self.ip try: # Strip the spaces from the parameter value if given if ip_address: ip_address = ip_address.strip() logger.info( "Initiating to fetch context information for ip: {}".format( str(ip_address))) # Opting default timout 60 seconds for the request api_client = GreyNoise(api_key=api_key, timeout=60, integration_name="Splunk") context_info = api_client.ip(ip_address) logger.info( "Successfully retrieved the context information for ip={}". format(str(ip_address))) # Process the API response and send the context information of IP with extractions in the Splunk results = event_generator.make_valid_event('ip', context_info, True) yield results except ValueError: logger.error( "IP address: {} doesn\'t match the valid IP format".format( str(ip_address))) self.write_error("IP address doesn\'t match the valid IP format")
def gnIPCheck(rIP): #https://developer.greynoise.io/docs/using-the-greynoise-community-api api_key = os.getenv('greynoise_key') api_client = GreyNoise(api_key=api_key) utils.rIPRating = [] utils.rIPDomain = [] for ip in rIP: if ipaddress.ip_address(ip).is_private is False: response = api_client.ip(ip) if response['seen'] is False: utils.rIPRating.append('unknown') utils.rIPDomain.append('unknown') elif response['classification'] == 'malicious': utils.rIPRating.append('High') utils.rIPDomain.append( response['metadata']['organization']) elif response['classification'] == 'unknown': utils.rIPRating.append('Medium') utils.rIPDomain.append( response['metadata']['organization']) elif response['classification'] == 'benign': utils.rIPRating.append('Low') utils.rIPDomain.append( response['metadata']['organization']) else: utils.rIPRating.append('error') utils.rIPDomain.append('error') else: utils.rIPRating.append('Private') utils.rIPDomain.append('Local')
def intel(self, type, query, data, conf): if type == "ip": print("[+] Checking GreyNoise...") logging.getLogger("greynoise").setLevel(logging.CRITICAL) if conf["GreyNoise"]["api_type"].lower() == "community": gn = GreyNoise( api_key=conf["GreyNoise"]["key"], integration_name= "Harpoon (https://github.com/Te-k/harpoon)", offering="community", ) res = gn.ip(query) if res["noise"]: data["reports"].append({ "url": "https://viz.greynoise.io/ip/{}".format(query), "title": "Seen by GreyNoise as {}".format(res["name"]), "date": None, "source": "GreyNoise", }) else: gn = GreyNoise( api_key=conf["GreyNoise"]["key"], integration_name= "Harpoon (https://github.com/Te-k/harpoon)", ) res = gn.ip(query) if res["seen"]: data["reports"].append({ "url": "https://viz.greynoise.io/ip/{}".format(query), "title": "Seen by GreyNoise as {}".format(", ".join( res["tags"])), "date": None, "source": "GreyNoise", })
def run(self, conf, args, plugins): logging.getLogger("greynoise").setLevel(logging.CRITICAL) gn = GreyNoise(api_key=conf["GreyNoise"]["key"]) if args.ip: res = gn.ip(args.ip) self.print_results(res, args) elif args.query: res = gn.query(args.query) self.print_results(res, args) else: self.parser.print_help()
def run(self, conf, args, plugins): if conf["GreyNoise"]["key"] == "": print("You need to set your API key with GreyNoise") sys.exit() gn = GreyNoise(api_key=conf["GreyNoise"]["key"]) if args.ip: res = gn.ip(args.ip) self.print_results(res, args) elif args.query: res = gn.query(args.query) self.print_results(res, args) else: self.parser.print_help()
def create_entities(cls, request, response): api_key = request.TransformSettings["GNApiKey"] api_client = GreyNoise( api_key=api_key, integration_name="maltego-community-v1.0.0", offering="community", ) input_ip = response.addEntity("maltego.IPv4Address", request.Value) try: resp = api_client.ip(request.Value) if resp["noise"] or resp["riot"]: if resp["noise"]: response.addEntity("greynoise.noise", "Noise Detected") if resp["riot"]: response.addEntity("greynoise.noise", "Benign Service Detected") response.addEntity("maltego.Alias", resp["name"]) response.addEntity("greynoise.classification", resp["classification"]) response.addEntity("maltego.DateTime", resp["last_seen"]) url = response.addEntity("maltego.URL", resp["link"]) url.addProperty( fieldName="short-title", displayName="GreyNoise color", value=resp["link"], matchingRule="strict", ) url.addProperty( fieldName="url", displayName="GreyNoise color", value=resp["link"], matchingRule="strict", ) else: response.addEntity("greynoise.noise", "No Noise Detected") response.addUIMessage( f"The IP address {request.Value} hasn't been seen by GreyNoise." ) add_display_info( input_ip, resp.get("classification"), resp.get("last_seen"), resp.get("link"), resp.get("name"), ) except Exception as e: response.addUIMessage(e)
class SwMain(GreynoiseBaseClass): def __init__(self, context): super(SwMain, self).__init__(context) self.ip_address = context.inputs["ip_address"] self.api_key = context.asset["api_key"] self.session = GreyNoise( api_key=self.api_key, integration_name="greynoise-community-swimlane-" + PLUGIN_VERSION, offering="community", ) def execute(self): output = [] response = self.session.ip(self.ip_address) output.append(response) return output
def intel(self, type, query, data, conf): if type == "ip": print("[+] Checking GreyNoise...") logging.getLogger("greynoise").setLevel(logging.CRITICAL) gn = GreyNoise(api_key=conf["GreyNoise"]["key"]) res = gn.ip(query) if res["seen"]: data["reports"].append({ "url": "https://viz.greynoise.io/ip/{}".format(query), "title": "Seen by GreyNoise as {}".format(", ".join(res["tags"])), "date": None, "source": "GreyNoise" })
def run(self, params={}): gn_client = GreyNoise( api_server=self.connection.server, api_key=self.connection.api_key, integration_name=self.connection.user_agent, offering="community", ) try: resp = gn_client.ip(params.get(Input.IP_ADDRESS)) if resp["noise"] or resp["riot"]: resp["last_seen"] = pendulum.parse( resp["last_seen"]).to_rfc3339_string() except RequestFailure as e: raise GNRequestFailure(e.args[0], e.args[1]) except ValueError as e: raise GNValueError(e.args[0]) return resp
def lkup_sus_ip_address(susp_addr): """Find RDNS of IP address and return info using GreyNoise API. Args: susp_addr: Suspect IPv4 address. Returns: Domain (if found) & GreyNoise Output (if found). Raises: Error: if susp_addr domain name cannot be found. """ try: rev = dns.reversename.from_address(susp_addr) output = str(dns.resolver.query(rev, 'PTR')[0]) api_client = GreyNoise(api_key="", timeout=15) bring_the_noise = api_client.ip(susp_addr) print("Found domain: {}".format(output)) print('*' * 80) print(bring_the_noise) except dns.resolver.NXDOMAIN as e: print(e)
def run(self): if self.data_type == "ip": api_key = self.get_param("config.key", None) api_type = self.get_param("config.api_type", None) if api_type and api_type.lower() == "community": api_client = GreyNoise( api_key=api_key, timeout=30, integration_name="greynoise-cortex-analyzer-v3.1", offering="community", ) else: api_client = GreyNoise( api_key=api_key, timeout=30, integration_name="greynoise-cortex-analyzer-v3.1", ) try: self.report(api_client.ip(self.get_data())) except Exception as e: self.error("Unable to query GreyNoise API\n{}".format(e)) else: self.notSupported()
def run(self, conf, args, plugins): logging.getLogger("greynoise").setLevel(logging.CRITICAL) if conf["GreyNoise"]["api_type"].lower() == "community": gn = GreyNoise( api_key=conf["GreyNoise"]["key"], integration_name="Harpoon (https://github.com/Te-k/harpoon)", offering="community", ) else: gn = GreyNoise( api_key=conf["GreyNoise"]["key"], integration_name="Harpoon (https://github.com/Te-k/harpoon)", ) if args.ip: res = gn.ip(args.ip) self.print_results(res, args) elif args.query: res = gn.query(args.query) self.print_results(res, args) elif args.list: res = gn.metadata() self.print_results(res, args) else: self.parser.print_help()
def run(self, conf, args, plugins): if "subcommand" in args: if args.subcommand == "info": if not is_ip(unbracket(args.IP)): print("Invalid IP address") sys.exit(1) # FIXME: move code here in a library ip = unbracket(args.IP) try: ipy = IP(ip) except ValueError: print("Invalid IP format, quitting...") return ipinfo = self.ipinfo(ip) print("MaxMind: Located in %s, %s" % (ipinfo["city"], ipinfo["country"])) if ipinfo["asn"] == 0: print("MaxMind: IP not found in the ASN database") else: print("MaxMind: ASN%i, %s" % (ipinfo["asn"], ipinfo["asn_name"])) print("CAIDA Type: %s" % ipinfo["asn_type"]) try: asndb2 = pyasn.pyasn(self.asncidr) res = asndb2.lookup(ip) except OSError: print("Configuration files are not available") print("Please run harpoon update before using harpoon") sys.exit(1) if res[1] is None: print("IP not found in ASN database") else: # Search for name f = open(self.asnname, "r") found = False line = f.readline() name = "" while not found and line != "": s = line.split("|") if s[0] == str(res[0]): name = s[1].strip() found = True line = f.readline() print("ASN %i - %s (range %s)" % (res[0], name, res[1])) if ipinfo["hostname"] != "": print("Hostname: %s" % ipinfo["hostname"]) if ipinfo["specific"] != "": print("Specific: %s" % ipinfo["specific"]) if ipy.iptype() == "PRIVATE": "Private IP" print("") if ipy.version() == 4: print("Censys:\t\thttps://censys.io/ipv4/%s" % ip) print("Shodan:\t\thttps://www.shodan.io/host/%s" % ip) print("IP Info:\thttp://ipinfo.io/%s" % ip) print("BGP HE:\t\thttps://bgp.he.net/ip/%s" % ip) print( "IP Location:\thttps://www.iplocation.net/?query=%s" % ip) elif args.subcommand == "intel": if not is_ip(unbracket(args.IP)): print("Invalid IP address") sys.exit(1) # Start with MISP and OTX to get Intelligence Reports print("###################### %s ###################" % unbracket(args.IP)) passive_dns = [] urls = [] malware = [] files = [] # MISP misp_e = plugins["misp"].test_config(conf) if misp_e: print("[+] Downloading MISP information...") server = ExpandedPyMISP(conf["Misp"]["url"], conf["Misp"]["key"]) misp_results = server.search("attributes", value=unbracket(args.IP)) # Binary Edge be_e = plugins["binaryedge"].test_config(conf) if be_e: try: print("[+] Downloading BinaryEdge information...") be = BinaryEdge(conf["BinaryEdge"]["key"]) # FIXME: this only get the first page res = be.domain_ip(unbracket(args.IP)) for d in res["events"]: passive_dns.append({ "domain": d["domain"], "first": parse(d["updated_at"]).astimezone(pytz.utc), "last": parse(d["updated_at"]).astimezone(pytz.utc), "source": "BinaryEdge", }) except BinaryEdgeException: print( "BinaryEdge request failed, you need a paid subscription" ) # OTX otx_e = plugins["otx"].test_config(conf) if otx_e: print("[+] Downloading OTX information....") otx = OTXv2(conf["AlienVaultOtx"]["key"]) res = otx.get_indicator_details_full( IndicatorTypes.IPv4, unbracket(args.IP)) otx_pulses = res["general"]["pulse_info"]["pulses"] # Get Passive DNS if "passive_dns" in res: for r in res["passive_dns"]["passive_dns"]: passive_dns.append({ "domain": r["hostname"], "first": parse(r["first"]).astimezone(pytz.utc), "last": parse(r["last"]).astimezone(pytz.utc), "source": "OTX", }) if "url_list" in res: for r in res["url_list"]["url_list"]: if "result" in r: urls.append({ "date": parse(r["date"]).astimezone(pytz.utc), "url": r["url"], "ip": r["result"]["urlworker"]["ip"] if "ip" in r["result"]["urlworker"] else "", "source": "OTX", }) else: urls.append({ "date": parse(r["date"]).astimezone(pytz.utc), "url": r["url"], "ip": "", "source": "OTX", }) # RobTex print("[+] Downloading Robtex information....") rob = Robtex() try: res = rob.get_ip_info(unbracket(args.IP)) except RobtexError: print("Error with Robtex") else: for d in ["pas", "pash", "act", "acth"]: if d in res: for a in res[d]: passive_dns.append({ "first": a["date"].astimezone(pytz.utc), "last": a["date"].astimezone(pytz.utc), "domain": a["o"], "source": "Robtex", }) # PT pt_e = plugins["pt"].test_config(conf) if pt_e: out_pt = False print("[+] Downloading Passive Total information....") client = DnsRequest(conf["PassiveTotal"]["username"], conf["PassiveTotal"]["key"]) try: raw_results = client.get_passive_dns( query=unbracket(args.IP)) if "results" in raw_results: for res in raw_results["results"]: passive_dns.append({ "first": parse(res["firstSeen"]).astimezone( pytz.utc), "last": parse(res["lastSeen"]).astimezone( pytz.utc), "domain": res["resolve"], "source": "PT", }) if "message" in raw_results: if "quota_exceeded" in raw_results["message"]: print("Quota exceeded for Passive Total") out_pt = True pt_osint = {} except requests.exceptions.ReadTimeout: print("Timeout on Passive Total requests") if not out_pt: try: client2 = EnrichmentRequest( conf["PassiveTotal"]["username"], conf["PassiveTotal"]["key"], ) # Get OSINT # TODO: add PT projects here pt_osint = client2.get_osint( query=unbracket(args.IP)) # Get malware raw_results = client2.get_malware( query=unbracket(args.IP)) if "results" in raw_results: for r in raw_results["results"]: malware.append({ "hash": r["sample"], "date": parse(r["collectionDate"]), "source": "PT (%s)" % r["source"], }) except requests.exceptions.ReadTimeout: print("Timeout on Passive Total requests") # Urlhaus uh_e = plugins["urlhaus"].test_config(conf) if uh_e: print("[+] Checking urlhaus data...") try: urlhaus = UrlHaus(conf["UrlHaus"]["key"]) res = urlhaus.get_host(unbracket(args.IP)) except UrlHausError: print("Error with the query") else: if "urls" in res: for r in res["urls"]: urls.append({ "date": parse(r["date_added"]).astimezone( pytz.utc), "url": r["url"], "source": "UrlHaus", }) # VT vt_e = plugins["vt"].test_config(conf) if vt_e: if conf["VirusTotal"]["type"] != "public": print("[+] Downloading VT information....") vt = PrivateApi(conf["VirusTotal"]["key"]) res = vt.get_ip_report(unbracket(args.IP)) if "results" in res: if "resolutions" in res["results"]: for r in res["results"]["resolutions"]: passive_dns.append({ "first": parse(r["last_resolved"]).astimezone( pytz.utc), "last": parse(r["last_resolved"]).astimezone( pytz.utc), "domain": r["hostname"], "source": "VT", }) if "undetected_downloaded_samples" in res[ "results"]: for r in res["results"][ "undetected_downloaded_samples"]: files.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) if "undetected_referrer_samples" in res["results"]: for r in res["results"][ "undetected_referrer_samples"]: if "date" in r: files.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) else: # FIXME : should consider data without dates files.append({ "hash": r["sha256"], "date": datetime.datetime(1970, 1, 1), "source": "VT", }) if "detected_downloaded_samples" in res["results"]: for r in res["results"][ "detected_downloaded_samples"]: malware.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) if "detected_referrer_samples" in res["results"]: for r in res["results"][ "detected_referrer_samples"]: if "date" in r: malware.append({ "hash": r["sha256"], "date": parse(r["date"]), "source": "VT", }) else: vt_e = False print("[+] Downloading GreyNoise information....") gn = GreyNoise(conf["GreyNoise"]["key"]) if gn == "": print("Greynoise API key is not set up.") greynoise = gn.ip(unbracket(args.IP)) tg_e = plugins["threatgrid"].test_config(conf) if tg_e: print("[+] Downloading Threat Grid....") try: tg = ThreatGrid(conf["ThreatGrid"]["key"]) res = tg.search_samples(unbracket(args.IP), type="ip") already = [] if "items" in res: for r in res["items"]: if r["sample_sha256"] not in already: d = parse(r["ts"]) d = d.replace(tzinfo=None) malware.append({ "hash": r["sample_sha256"], "date": d, "source": "TG", }) already.append(r["sample_sha256"]) except ThreatGridError as e: print("Error with threat grid: {}".format(e.message)) # ThreatMiner print("[+] Downloading ThreatMiner....") tm = ThreatMiner() response = tm.get_report(unbracket(args.IP)) if response["status_code"] == "200": tmm = response["results"] else: tmm = [] if response["status_code"] != "404": print("Request to ThreatMiner failed: {}".format( response["status_message"])) response = tm.get_related_samples(unbracket(args.IP)) if response["status_code"] == "200": for r in response["results"]: malware.append({ "hash": r, "date": None, "source": "ThreatMiner" }) print("----------------- Intelligence Report") ctor = CommandTor() tor_list = ctor.get_list() if tor_list: if unbracket(args.IP) in tor_list: print("{} is a Tor Exit node".format(unbracket( args.IP))) else: print("Impossible to reach the Tor Exit Node list") if otx_e: if len(otx_pulses): print("OTX:") for p in otx_pulses: print("- %s (%s - %s)" % ( p["name"], p["created"][:10], "https://otx.alienvault.com/pulse/" + p["id"], )) else: print("OTX: Not found in any pulse") if misp_e: if len(misp_results["Attribute"]) > 0: print("MISP:") for event in misp_results["Attribute"]: print("- {} - {}".format(event["Event"]["id"], event["Event"]["info"])) if len(greynoise) > 0: print("GreyNoise: IP identified as") for key, value in greynoise.items(): print(key, "->", value) else: print("GreyNoise: Not found") if pt_e: if "results" in pt_osint: if len(pt_osint["results"]): if len(pt_osint["results"]) == 1: if "name" in pt_osint["results"][0]: print("PT: %s %s" % ( pt_osint["results"][0]["name"], pt_osint["results"][0]["sourceUrl"], )) else: print("PT: %s" % pt_osint["results"][0]["sourceUrl"]) else: print("PT:") for r in pt_osint["results"]: if "name" in r: print("-%s %s" % (r["name"], r["sourceUrl"])) else: print("-%s" % r["sourceUrl"]) else: print("PT: Nothing found!") else: print("PT: Nothing found!") # ThreatMiner if len(tmm) > 0: print("ThreatMiner:") for r in tmm: print("- {} {} - {}".format(r["year"], r["filename"], r["URL"])) if len(malware) > 0: print("----------------- Malware") for r in malware: print("[%s] %s %s" % ( r["source"], r["hash"], r["date"].strftime("%Y-%m-%d") if r["date"] else "", )) if len(files) > 0: print("----------------- Files") for r in sorted(files, key=lambda x: x["date"]): print("[%s] %s %s" % (r["source"], r["hash"], r["date"].strftime("%Y-%m-%d"))) if len(passive_dns) > 0: print("----------------- Passive DNS") for r in sorted(passive_dns, key=lambda x: x["first"], reverse=True): print("[+] %-40s (%s -> %s)(%s)" % ( r["domain"], r["first"].strftime("%Y-%m-%d"), r["last"].strftime("%Y-%m-%d"), r["source"], )) if len(urls) > 0: print("----------------- Urls") for r in sorted(urls, key=lambda x: x["date"], reverse=True): print("[%s] %s - %s" % (r["source"], r["url"], r["date"].strftime("%Y-%m-%d"))) else: self.parser.print_help() else: self.parser.print_help()
def create_entities(cls, request: MaltegoMsg, response): api_key = request.TransformSettings["GNApiKey"] api_client = GreyNoise( api_key=api_key, integration_name="maltego-community-v1.0.0", offering="community", ) # make a precise copy of the input to avoid creating a new graph entity type_name = "maltego.IPv4Address" extra_props = {} if request.Genealogy: type_name = request.Genealogy[0]["Name"] extra_props = request.Properties input_ip = response.addEntity(type_name, request.Value) for k, v in extra_props.items(): input_ip.addProperty(fieldName=k, value=v, matchingRule="loose") try: resp = api_client.ip(request.Value) if resp["noise"] or resp["riot"]: if resp["noise"]: response.addEntity("greynoise.noise", "Noise Detected") if resp["riot"]: response.addEntity("greynoise.noise", "Benign Service Detected") if resp["name"] != "unknown": response.addEntity("maltego.Organization", resp["name"]) response.addEntity("greynoise.classification", resp["classification"]) # add dynamic properties instead of returning more to the graph input_ip.addProperty( fieldName="gn_url", displayName="GreyNoise URL", value=resp["link"], matchingRule="loose", ) input_ip.addProperty( fieldName="gn_last_seen", displayName="GreyNoise last seen", value=resp["last_seen"], matchingRule="loose", ) else: response.addEntity("greynoise.noise", "No Noise Detected") response.addUIMessage( f"The IP address {request.Value} hasn't been seen by GreyNoise." ) add_display_info( input_ip, resp.get("classification"), resp.get("last_seen"), resp.get("link"), resp.get("name"), ) except Exception as e: response.addUIMessage(e)