Пример #1
0
    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")
Пример #2
0
 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')
Пример #3
0
 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",
                 })
Пример #4
0
 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()
Пример #5
0
 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
Пример #8
0
 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"
             })
Пример #9
0
    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
Пример #10
0
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()
Пример #12
0
 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()
Пример #13
0
    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)