From aef4235ae6a87ee4d4664f0dd33fc4c3d1a0f40d Mon Sep 17 00:00:00 2001 From: Conor <93926445+cmcnally-r7@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:48:11 +0000 Subject: [PATCH] [GreyNoise] 2.0.0 release (#2981) * [GreyNoise] Updates + New Actions + New Trigger (#2916) * update spec * updates * validation fixes * updates * updates * formatting * clean up * add vuln action * add timeline lookup * add similar_lookup * help sum * add trigger * trigger fixes * trigger fixes * linting * updates * updates * unit tests and fixes * fix trigger output * fix trigger * review feedback * update all action outputs * fix typos * update examples * example updates * GreyNoise 2.0.0 fixes (#2982) * Fix SCA, PluginValidator, update unit test imports * Remove forgotten breakpoint * Greynoise unit test fix (#2983) * Fix unit tests * Update SDK * Fix final unit test * Last unit tests fix hopefully * Cloud eenable greynoise (#2986) --------- Co-authored-by: Brad Chiappetta <38439955+bradchiappetta@users.noreply.github.com> --- plugins/greynoise/.CHECKSUM | 36 +- plugins/greynoise/Dockerfile | 20 +- plugins/greynoise/bin/icon_greynoise | 32 +- plugins/greynoise/help.md | 1030 +++++++++++++---- .../icon_greynoise/actions/__init__.py | 21 +- .../actions/community_lookup/__init__.py | 2 +- .../actions/community_lookup/action.py | 31 +- .../actions/community_lookup/schema.py | 16 +- .../actions/context_lookup/__init__.py | 2 +- .../actions/context_lookup/action.py | 40 +- .../actions/context_lookup/schema.py | 143 ++- .../actions/get_tag_details/__init__.py | 2 +- .../actions/get_tag_details/action.py | 33 +- .../actions/get_tag_details/schema.py | 64 +- .../actions/gnql_query/__init__.py | 2 +- .../actions/gnql_query/action.py | 18 +- .../actions/gnql_query/schema.py | 386 +++--- .../actions/quick_lookup/__init__.py | 2 +- .../actions/quick_lookup/action.py | 27 +- .../actions/quick_lookup/schema.py | 27 +- .../actions/riot_lookup/__init__.py | 2 +- .../actions/riot_lookup/action.py | 35 +- .../actions/riot_lookup/schema.py | 31 +- .../actions/similar_lookup/__init__.py | 2 + .../actions/similar_lookup/action.py | 38 + .../actions/similar_lookup/schema.py | 225 ++++ .../actions/timeline_lookup/__init__.py | 2 + .../actions/timeline_lookup/action.py | 38 + .../actions/timeline_lookup/schema.py | 345 ++++++ .../actions/vulnerability_lookup/__init__.py | 2 + .../actions/vulnerability_lookup/action.py | 45 + .../actions/vulnerability_lookup/schema.py | 270 +++++ .../icon_greynoise/connection/__init__.py | 2 +- .../icon_greynoise/connection/connection.py | 14 +- .../icon_greynoise/connection/schema.py | 18 +- .../icon_greynoise/tasks/__init__.py | 2 + .../icon_greynoise/triggers/__init__.py | 5 +- .../monitor_ips_in_greynoise/__init__.py | 2 + .../monitor_ips_in_greynoise/schema.py | 84 ++ .../monitor_ips_in_greynoise/trigger.py | 47 + .../greynoise/icon_greynoise/util/__init__.py | 2 +- plugins/greynoise/icon_greynoise/util/util.py | 24 - plugins/greynoise/plugin.spec.yaml | 901 +++++++++++++- plugins/greynoise/requirements.txt | 4 +- plugins/greynoise/setup.py | 4 +- plugins/greynoise/unit_test/__init__.py | 4 + .../greynoise/unit_test/payloads/__init__.py | 0 .../unit_test/payloads/community_ip.json | 10 + .../unit_test/payloads/context_ip.json | 68 ++ .../unit_test/payloads/cve_details.json | 37 + .../unit_test/payloads/gnql_query.json | 77 ++ .../unit_test/payloads/quick_ip.json | 9 + .../greynoise/unit_test/payloads/riot_ip.json | 11 + .../unit_test/payloads/similar_ip.json | 38 + .../unit_test/payloads/tag_details.json | 22 + .../unit_test/payloads/timeline_ip.json | 58 + .../unit_test/test_community_lookup.py | 31 + .../unit_test/test_context_lookup.py | 60 + .../unit_test/test_get_tag_details.py | 35 + .../greynoise/unit_test/test_gnql_query.py | 67 ++ .../greynoise/unit_test/test_quick_lookup.py | 28 + .../greynoise/unit_test/test_riot_lookup.py | 33 + .../unit_test/test_similar_lookup.py | 52 + .../unit_test/test_timeline_lookup.py | 63 + .../unit_test/test_vulnerability_lookup.py | 58 + plugins/greynoise/unit_test/util.py | 39 + 66 files changed, 4182 insertions(+), 696 deletions(-) mode change 100755 => 100644 plugins/greynoise/help.md create mode 100644 plugins/greynoise/icon_greynoise/actions/similar_lookup/__init__.py create mode 100644 plugins/greynoise/icon_greynoise/actions/similar_lookup/action.py create mode 100644 plugins/greynoise/icon_greynoise/actions/similar_lookup/schema.py create mode 100644 plugins/greynoise/icon_greynoise/actions/timeline_lookup/__init__.py create mode 100644 plugins/greynoise/icon_greynoise/actions/timeline_lookup/action.py create mode 100644 plugins/greynoise/icon_greynoise/actions/timeline_lookup/schema.py create mode 100644 plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/__init__.py create mode 100644 plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/action.py create mode 100755 plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/schema.py create mode 100644 plugins/greynoise/icon_greynoise/tasks/__init__.py create mode 100755 plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/__init__.py create mode 100644 plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/schema.py create mode 100644 plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/trigger.py mode change 100755 => 100644 plugins/greynoise/icon_greynoise/util/__init__.py delete mode 100644 plugins/greynoise/icon_greynoise/util/util.py create mode 100644 plugins/greynoise/unit_test/__init__.py create mode 100644 plugins/greynoise/unit_test/payloads/__init__.py create mode 100644 plugins/greynoise/unit_test/payloads/community_ip.json create mode 100644 plugins/greynoise/unit_test/payloads/context_ip.json create mode 100644 plugins/greynoise/unit_test/payloads/cve_details.json create mode 100644 plugins/greynoise/unit_test/payloads/gnql_query.json create mode 100644 plugins/greynoise/unit_test/payloads/quick_ip.json create mode 100644 plugins/greynoise/unit_test/payloads/riot_ip.json create mode 100644 plugins/greynoise/unit_test/payloads/similar_ip.json create mode 100644 plugins/greynoise/unit_test/payloads/tag_details.json create mode 100644 plugins/greynoise/unit_test/payloads/timeline_ip.json create mode 100644 plugins/greynoise/unit_test/test_community_lookup.py create mode 100644 plugins/greynoise/unit_test/test_context_lookup.py create mode 100644 plugins/greynoise/unit_test/test_get_tag_details.py create mode 100644 plugins/greynoise/unit_test/test_gnql_query.py create mode 100644 plugins/greynoise/unit_test/test_quick_lookup.py create mode 100644 plugins/greynoise/unit_test/test_riot_lookup.py create mode 100644 plugins/greynoise/unit_test/test_similar_lookup.py create mode 100644 plugins/greynoise/unit_test/test_timeline_lookup.py create mode 100644 plugins/greynoise/unit_test/test_vulnerability_lookup.py create mode 100644 plugins/greynoise/unit_test/util.py diff --git a/plugins/greynoise/.CHECKSUM b/plugins/greynoise/.CHECKSUM index cc97a85f3b..111d46ac1e 100644 --- a/plugins/greynoise/.CHECKSUM +++ b/plugins/greynoise/.CHECKSUM @@ -1,35 +1,51 @@ { - "spec": "21e4aba5536e29ebde5b6b0d33c7d1f1", - "manifest": "0fbfe5119cf508fcbf30641105ae188d", - "setup": "71be7f1ce465bc3700098c8ea7a8bb13", + "spec": "663d04017fe9a605df63fd8584a4beb4", + "manifest": "9d3f4a959fda3eb80588c86648597b40", + "setup": "7d0148b4efc7745f17003a77e9e73c55", "schemas": [ { "identifier": "community_lookup/schema.py", - "hash": "c11ee6039e822efc804b17753c6fbbe1" + "hash": "37abd579045b68430ce584170968a270" }, { "identifier": "context_lookup/schema.py", - "hash": "27aed1cfd2a85f49bc317dce7d19aae4" + "hash": "df5822cc975eef45019e516ddb00d1e7" }, { "identifier": "get_tag_details/schema.py", - "hash": "9823f81c29046f34aa441ed58db094fb" + "hash": "805cc2db6612fc9b0ee438bbb58b231c" }, { "identifier": "gnql_query/schema.py", - "hash": "65c08f73e888728d2f812254efd3c15d" + "hash": "4c9874ce15384fdfafab25591d39d900" }, { "identifier": "quick_lookup/schema.py", - "hash": "0e7fc3a38329b5137a280b87982619b8" + "hash": "a0b8045428133eca9d2ac6cc2ffe4a7a" }, { "identifier": "riot_lookup/schema.py", - "hash": "9e8d337328f1cc2c1900d25932e8ffa5" + "hash": "0ee1bf7d6db7ee88dfd7f105bfb50ea6" + }, + { + "identifier": "similar_lookup/schema.py", + "hash": "f8c96c19c59fd30ef806bf36c47bad7b" + }, + { + "identifier": "timeline_lookup/schema.py", + "hash": "71963f3bf33ac17d5a46c2b017f8e9a8" + }, + { + "identifier": "vulnerability_lookup/schema.py", + "hash": "d2e8b45236448f806ce8aa4eadeec367" }, { "identifier": "connection/schema.py", - "hash": "f7e83e2e638bbb1f4a198c8ee93a7e05" + "hash": "f7a3e43e3b17d8e2059b6499b67e7e5a" + }, + { + "identifier": "monitor_ips_in_greynoise/schema.py", + "hash": "bb05b2a9d9ef8add550c7149ddf7c2d2" } ] } \ No newline at end of file diff --git a/plugins/greynoise/Dockerfile b/plugins/greynoise/Dockerfile index f63e5aa532..60397d66f8 100755 --- a/plugins/greynoise/Dockerfile +++ b/plugins/greynoise/Dockerfile @@ -1,26 +1,20 @@ -FROM rapid7/insightconnect-python-3-38-slim-plugin:4 -# Refer to the following documentation for available SDK parent images: https://komand.github.io/python/sdk.html#version +FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:6.2.2 -LABEL organization=rapid7 +LABEL organization=greynoise LABEL sdk=python -# Add any custom package dependencies here -# NOTE: Add pip packages to requirements.txt - -# End package dependencies - -# Add source code WORKDIR /python/src + ADD ./plugin.spec.yaml /plugin.spec.yaml -ADD . /python/src +ADD ./requirements.txt /python/src/requirements.txt -# Install pip dependencies RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; fi -# Install plugin +ADD . /python/src + RUN python setup.py build && python setup.py install # User to run plugin code. The two supported users are: root, nobody USER nobody -ENTRYPOINT ["/usr/local/bin/icon_greynoise"] \ No newline at end of file +ENTRYPOINT ["/usr/local/bin/icon_greynoise"] diff --git a/plugins/greynoise/bin/icon_greynoise b/plugins/greynoise/bin/icon_greynoise index c891f83785..23ddc61fa4 100755 --- a/plugins/greynoise/bin/icon_greynoise +++ b/plugins/greynoise/bin/icon_greynoise @@ -1,12 +1,12 @@ #!/usr/bin/env python -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import os import json from sys import argv Name = "GreyNoise" Vendor = "greynoise" -Version = "1.0.0" +Version = "2.0.0" Description = "GreyNoise helps analysts recognize events not worth their attention. Indicators in GreyNoise are likely associated with opportunistic internet scanning or common business services, not targeted threats. This context helps analysts focus on what matters most" @@ -23,7 +23,7 @@ def main(): monkey.patch_all() import insightconnect_plugin_runtime - from icon_greynoise import connection, actions, triggers + from icon_greynoise import connection, actions, triggers, tasks class ICONGreynoise(insightconnect_plugin_runtime.Plugin): def __init__(self): @@ -34,18 +34,26 @@ def main(): description=Description, connection=connection.Connection() ) - self.add_action(actions.CommunityLookup()) - + self.add_trigger(triggers.MonitorIpsInGreynoise()) + self.add_action(actions.ContextLookup()) - + + self.add_action(actions.RiotLookup()) + + self.add_action(actions.QuickLookup()) + self.add_action(actions.GetTagDetails()) - + self.add_action(actions.GnqlQuery()) - - self.add_action(actions.QuickLookup()) - - self.add_action(actions.RiotLookup()) - + + self.add_action(actions.CommunityLookup()) + + self.add_action(actions.VulnerabilityLookup()) + + self.add_action(actions.TimelineLookup()) + + self.add_action(actions.SimilarLookup()) + """Run plugin""" cli = insightconnect_plugin_runtime.CLI(ICONGreynoise()) diff --git a/plugins/greynoise/help.md b/plugins/greynoise/help.md old mode 100755 new mode 100644 index 4668e9ea03..2dafc6955e --- a/plugins/greynoise/help.md +++ b/plugins/greynoise/help.md @@ -1,35 +1,36 @@ # Description -GreyNoise helps analysts recognize events not worth their attention. Indicators in GreyNoise are likely associated with -opportunistic internet scanning or common business services, not targeted threats. This context helps analysts focus -on what matters most. The GreyNoise Plugin provides users with context on an IP address around the activity -GreyNoise has observed. - -More information can be found at [greynoise.io/tech](https://greynoise.io/tech) +GreyNoise helps analysts recognize events not worth their attention. Indicators in GreyNoise are likely associated with opportunistic internet scanning or common business services, not targeted threats. This context helps analysts focus on what matters most # Key Features * Perform a GreyNoise IP Context Lookup * Perform a GreyNoise IP Quick Lookup -* Perform a GreyNoise IP RIOT (Rule it out) Lookup +* Perform a GreyNoise IP RIOT Lookup * Query for additional Tag details * Perform a GreyNoise Community IP Lookup +* Perform a GreyNoise Vulnerability Lookup +* Perform a GreyNoise IP Timeline Lookup +* Perform a GreyNoise IP Similarity Lookup +* Query a list of IPs on a Trigger # Requirements -* Requires an API Key for the GreyNoise API [GreyNoise Account Details](https://viz.greynoise.io/account) -* A free trial can be created on the [GreyNoise Visualizer](https://viz.greynoise.io/signup) -* For Users with Community API Access only, a Community API key is required, and the only action supported is the Community IP Lookup. Other actions will fail with a 401 for a Community API key. +* A GreyNoise API key + +# Supported Product Versions + +* GreyNoise API v1/2/3 # Documentation ## Setup -The connection configuration accepts the following parameters: +The connection configuration accepts the following parameters: -|Name|Type|Default|Required|Description|Enum|Example| -|----|----|-------|--------|-----------|----|-------| -|credentials|credential_secret_key|None|True|API key from GreyNoise Account|None|abcdefghijklmnopqrstuvwxyz0123456789| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|credentials|credential_secret_key|None|True|API key from GreyNoise Account|None|abcdefghijklmnopqrstuvwxyz0123456789|None|None| Example input: @@ -43,16 +44,17 @@ Example input: ### Actions -#### Context IP Lookup -This action is used to query a routable IPv4 address in the GreyNoise Context API endpoint. +#### Community IP Lookup -##### Input +This action is used to query a routable IPv4 address in the GreyNoise Community API -|Name|Type|Default|Required|Description|Enum|Example| -|----|----|-------|--------|-----------|----|-------| -|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4| +##### Input +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4|None|None| + Example input: ``` @@ -63,112 +65,325 @@ Example input: ##### Output -|Name|Type|Required|Description| -|----|----|--------|-----------| -|actor|string|False|GreyNoise Actor Associated with IP| -|bot|boolean|False|GreyNoise has identified this as a Bot| -|classification|string|False|GreyNoise Classification| -|cve|[]string|False|CVEs associated with GreyNoise Tags| -|first_seen|date|False|First Seen By GreyNoise| -|ip|string|False|Value that was Queried| -|last_seen|string|False|Last Seen By GreyNoise| -|metadata|metadata|False|GreyNoise IP Metadata| -|raw_data|raw_data|False|GreyNoise IP Raw Data| -|seen|boolean|False|Has this IP been Seen by GreyNoise| -|spoofable|boolean|False|IP address may be spoofed| -|tags|[]string|False|GreyNoise Tags Associated with IP| -|viz_url|string|False|Link to GreyNoise Visualizer for IP Details| -|vpn|boolean|False|GreyNoise has identified this as a VPN| -|vpn_service|string|False|Name of VPN Service| +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|classification|string|False|GreyNoise Classification|benign| +|ip|string|False|Value that was Queried|1.2.3.4| +|last_seen|string|False|Last Seen By GreyNoise|2024-01-01| +|link|string|False|Link to GreyNoise Visualizer for IP Details|https://viz.greynoise.io/ip/1.1.1.1| +|message|string|False|GreyNoise Community API Status Message|IP found| +|name|string|False|GreyNoise Actor or Service Name Associated with IP|Acme Inc.| +|noise|boolean|False|Defines if IP is Internet Noise|True| +|riot|boolean|False|Defines if IP is part of GreyNoise RIOT dataset|True| + +Example output: +``` +{ + "classification": "benign", + "ip": "1.2.3.4", + "last_seen": "2024-01-01", + "link": "https://viz.greynoise.io/ip/1.1.1.1", + "message": "IP found", + "name": "Acme Inc.", + "noise": true, + "riot": true +} +``` + +#### Context IP Lookup + +This action is used to query a routable IPv4 address in the GreyNoise Context API endpoint + +##### Input + +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4|None|None| + +Example input: + +``` +{ + "ip_address": "1.2.3.4" +} +``` + +##### Output + +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|actor|string|False|GreyNoise Actor Associated with IP|Acme, Inc| +|bot|boolean|False|GreyNoise has identified this as a Bot|False| +|classification|string|False|GreyNoise Classification|malicious| +|cve|[]string|False|CVEs associated with GreyNoise Tags|["CVE-1111-1111", "CVE-2222-2222"]| +|first_seen|date|False|First Seen By GreyNoise|2024-01-01| +|ip|string|False|Value that was Queried|1.2.3.4| +|last_seen|string|False|Last Seen By GreyNoise|2024-01-01| +|metadata|metadata|False|GreyNoise IP Metadata|{'asn': 'AS12345', 'category': 'isp', 'city': 'Reno', 'country': 'Brazil', 'country_code': 'BZ', 'destination_countries': ['Brazil', 'Spain'], 'destination_country_codes': ['BZ', 'ES'], 'organization': 'Acme Inc.', 'os': 'Windows XP', 'rdns': 'scanner.example.io', 'region': 'Arizona', 'sensor_count': 5, 'sensor_hits': 5, 'source_country': 'Brazil', 'source_country_code': 'BE', 'tor': False}| +|raw_data|raw_data|False|GreyNoise IP Raw Data|{'hassh': [{'fingerprint': 'abcdefg1234567', 'port': 22}], 'ja3': [{'fingerprint': 'abcdefg1234567', 'port': 22}], 'scan': [{'port': 22, 'protocol': 'TCP'}], 'web': {'paths': ['/', '/robots.txt'], 'useragents': ['user-agent']}}| +|seen|boolean|False|Has this IP been Seen by GreyNoise|True| +|spoofable|boolean|False|IP address may be spoofed|False| +|tags|[]string|False|GreyNoise Tags Associated with IP|Tag 1, Tag2| +|viz_url|string|False|Link to GreyNoise Visualizer for IP Details|https://viz.greynoise.io/ip/1.1.1.1| +|vpn|boolean|False|GreyNoise has identified this as a VPN|False| +|vpn_service|string|False|Name of VPN Service|My VPN| + Example output: ``` { - "ip": "190.79.85.166", - "first_seen": "2021-03-27T00:00:00+00:00", - "last_seen": "2021-04-14T00:00:00+00:00", - "seen": true, - "tags": ["Eternalblue"], - "actor": "unknown", - "spoofable": false, - "classification": "malicious", - "cve": ["CVE-2017-0144"], + "actor": "Acme, Inc", "bot": false, - "vpn": false, - "vpn_service": "", + "classification": "malicious", + "cve": [ + "CVE-1111-1111", + "CVE-2222-2222" + ], + "first_seen": "2024-01-01", + "ip": "1.2.3.4", + "last_seen": "2024-01-01", "metadata": { - "asn": "AS8048", - "city": "Caracas", - "country": "Venezuela", - "country_code": "VE", - "organization": "CANTV Servicios, Venezuela", + "asn": "AS12345", "category": "isp", - "tor": false, - "rdns": "190-79-85-166.dyn.dsl.cantv.net", - "os": "Windows 7/8", - "region": "Distrito Federal" - }, + "city": "Reno", + "country": "Brazil", + "country_code": "BZ", + "destination_countries": [ + "Brazil", + "Spain" + ], + "destination_country_codes": [ + "BZ", + "ES" + ], + "organization": "Acme Inc.", + "os": "Windows XP", + "rdns": "scanner.example.io", + "region": "Arizona", + "sensor_count": 5, + "sensor_hits": 5, + "source_country": "Brazil", + "source_country_code": "BE", + "tor": false + }, "raw_data": { - "scan": [{ - "port": 445, - "protocol": "TCP" - }], - "web": {}, - "ja3": [], - "hassh": [] - } + "hassh": [ + { + "fingerprint": "abcdefg1234567", + "port": 22 + } + ], + "ja3": [ + { + "fingerprint": "abcdefg1234567", + "port": 22 + } + ], + "scan": [ + { + "port": 22, + "protocol": "TCP" + } + ], + "web": { + "paths": [ + "/", + "/robots.txt" + ], + "useragents": [ + "user-agent" + ] + } + }, + "seen": true, + "spoofable": false, + "tags": "Tag 1, Tag2", + "viz_url": "https://viz.greynoise.io/ip/1.1.1.1", + "vpn": false, + "vpn_service": "My VPN" } ``` -#### Quick IP Lookup +#### Get Tag Details -This action is used to query a routable IPv4 address in the GreyNoise Quick API endpoint. +This action is used to get Details of a GreyNoise Tag ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -|----|----|-------|--------|-----------|----|-------| -|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4| - +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|tag_name|string|None|True|Tag Name to get additional Details From|None|BingBot|None|None| + Example input: ``` { - "ip_address": "1.2.3.4" + "tag_name": "BingBot" } ``` ##### Output -|Name|Type|Required|Description| -|----|----|--------|-----------| -|code|string|False|Response Code from Quick API endpoint| -|code_message|string|False|Response Code Message from Quick API endpoint| -|ip|string|False|Value that was Queried| -|noise|boolean|False|Defines if IP is Internet Noise| - +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|category|string|False|Tag Category|activity| +|created_at|string|False|The date the tag was added to GreyNoise tag library|2024-01-01| +|cves|[]string|False|CVEs associate with Tag|CVE-2020-1234,CVE-1241-23521| +|description|string|False|Description of the Tag|This is a tag description| +|id|string|False|The unique ID for the tag|aa-bb-cc-dd| +|intention|string|False|Tag Intention|malicious| +|label|string|False|The unique label for the tag|BINGBOT_SCANNER| +|name|string|False|Name of GreyNoise Tag|BingBot| +|recommend_block|boolean|False|GreyNoise Recommends Blocking IPs associated with this Tag|False| +|references|[]string|False|References|https://thisisareference.url| +|related_tags|[]string|False|Tags that are related to this tag|["BingBot Scanner"]| +|slug|string|False|The unique slug for the tag|bingbot-scanner| + Example output: ``` { - "ip": "1.1.1.1", - "noise": false, - "code": "0x00", - "code_message": "IP has never been observed scanning the Internet" + "category": "activity", + "created_at": "2024-01-01", + "cves": "CVE-2020-1234,CVE-1241-23521", + "description": "This is a tag description", + "id": "aa-bb-cc-dd", + "intention": "malicious", + "label": "BINGBOT_SCANNER", + "name": "BingBot", + "recommend_block": false, + "references": "https://thisisareference.url", + "related_tags": [ + "BingBot Scanner" + ], + "slug": "bingbot-scanner" } ``` -#### RIOT IP Lookup +#### GreyNoise Query -This action is used to query a routable IPv4 address in the GreyNoise RIOT API endpoint. +This action is used to perform a GreyNoise GNQL Query ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -|----|----|-------|--------|-----------|----|-------| -|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|query|string|None|True|Query in GreyNoise Query Language (GNQL) Syntax|None|last_seen:1d classification:'malicious' metadata.asn:'AS8452'|None|None| +|size|string|10|False|Max Number of IPs to Return Data For|None|10|None|None| + +Example input: + +``` +{ + "query": "last_seen:1d classification:'malicious' metadata.asn:'AS8452'", + "size": 10 +} +``` + +##### Output + +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|complete|boolean|False|Indicates if all pages of the query have been returned by the API|True| +|count|integer|False|Total count of IPs returned Query|10| +|data|[]data|False|GreyNoise Data Object, Contains IP Object for each IP returned by the query|[{"actor": "Acme, Inc", "bot": False, "classification": "malicious", "cve": ["CVE-1111-1111", "CVE-2222-2222"], "first_seen": "2024-01-01", "ip": "1.2.3.4", "last_seen": "2024-01-01", "metadata": {"asn": "AS12345", "category": "isp", "city": "Reno", "country": "Brazil", "country_code": "BZ", "destination_countries": ["Brazil", "Spain"], "destination_country_codes": ["BZ", "ES"], "organization": "Acme Inc.", "os": "Windows XP", "rdns": "scanner.example.io", "region": "Arizona", "sensor_count": 5, "sensor_hits": 5, "source_country": "Brazil", "source_country_code": "BE", "tor": False}, "raw_data": {"hassh": [{"fingerprint": "abcdefg1234567", "port": 22}], "ja3": [{"fingerprint": "abcdefg1234567", "port": 22}], "scan": [{"port": 22, "protocol": "TCP"}], "web": {"paths": ["/", "/robots.txt"], "useragents": ["user-agent"]}}, "seen": True, "spoofable": False, "tags": "Tag 1, Tag2", "vpn": False, "vpn_service": "My VPN"}]| +|message|string|False|GreyNoise Query Message, indicates if there were issues with the query|ok| +|query|string|False|GreyNoise Query Sent to API|sample query| + +Example output: +``` +{ + "complete": true, + "count": 10, + "data": [ + { + "actor": "Acme, Inc", + "bot": false, + "classification": "malicious", + "cve": [ + "CVE-1111-1111", + "CVE-2222-2222" + ], + "first_seen": "2024-01-01", + "ip": "1.2.3.4", + "last_seen": "2024-01-01", + "metadata": { + "asn": "AS12345", + "category": "isp", + "city": "Reno", + "country": "Brazil", + "country_code": "BZ", + "destination_countries": [ + "Brazil", + "Spain" + ], + "destination_country_codes": [ + "BZ", + "ES" + ], + "organization": "Acme Inc.", + "os": "Windows XP", + "rdns": "scanner.example.io", + "region": "Arizona", + "sensor_count": 5, + "sensor_hits": 5, + "source_country": "Brazil", + "source_country_code": "BE", + "tor": false + }, + "raw_data": { + "hassh": [ + { + "fingerprint": "abcdefg1234567", + "port": 22 + } + ], + "ja3": [ + { + "fingerprint": "abcdefg1234567", + "port": 22 + } + ], + "scan": [ + { + "port": 22, + "protocol": "TCP" + } + ], + "web": { + "paths": [ + "/", + "/robots.txt" + ], + "useragents": [ + "user-agent" + ] + } + }, + "seen": true, + "spoofable": false, + "tags": "Tag 1, Tag2", + "vpn": false, + "vpn_service": "My VPN" + } + ], + "message": "ok", + "query": "sample query" +} +``` + +#### Quick IP Lookup + +This action is used to query a routable IPv4 address in the GreyNoise Quick API endpoint + +##### Input + +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4|None|None| + Example input: ``` @@ -179,90 +394,86 @@ Example input: ##### Output -|Name|Type|Required|Description| -|----|----|--------|-----------| -|category|string|False|RIOT Category IP is part of| -|description|string|False|Description of the IP service| -|explanation|string|False|Explanation for why this is likely benign| -|ip|string|False|Value that was Queried| -|last_updated|date|False|Last time this IP was updated in RIOT dataset| -|name|string|False|Vendor Name IP belongs to| -|reference|string|False|Additional reference information| -|riot|boolean|False|Defines if IP is part of GreyNoise RIOT dataset| -|viz_url|string|False|Link to GreyNoise Visualizer for IP Details| - +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|code|string|False|Response Code from Quick API endpoint|00x0| +|code_message|string|False|Response Code Message from Quick API endpoint|Internet noise found| +|ip|string|False|Value that was Queried|1.2.3.4| +|noise|boolean|False|Defines if IP is Internet Noise|True| +|riot|boolean|False|Defines if IP is a Common Business Service|True| + Example output: ``` { - "ip": "8.8.8.8", - "riot": true, - "category": "public_dns", - "name": "Google Public DNS", - "description": "Google's global domain name system (DNS) resolution service.", - "explanation": "Public DNS services are used as alternatives to ISP's name servers. You may see devices on your - network communicating with Google Public DNS over port 53/TCP or 53/UDP to resolve DNS lookups.", - "last_updated": "2021-04-20T13:55:41Z", - "reference": "https://developers.google.com/speed/public-dns/docs/isp#alternative", - "viz_url": "https://viz.greynoise.io/riot/8.8.8.8"} + "code": "00x0", + "code_message": "Internet noise found", + "ip": "1.2.3.4", + "noise": true, + "riot": true } ``` -#### Get Tag Details +#### RIOT IP Lookup -This action is used to get Details of a GreyNoise Tag. +This action is used to query a routable IPv4 address in the GreyNoise RIOT API endpoint ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -|----|----|-------|--------|-----------|----|-------| -|tag_name|string|None|True|Tag Name to get additional Details From|None|BingBot| - +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4|None|None| + Example input: ``` { - "tag_name": "BingBot" + "ip_address": "1.2.3.4" } ``` ##### Output -|Name|Type|Required|Description| -|----|----|--------|-----------| -|category|string|False|Tag Category| -|cves|[]object|False|CVEs associate with Tag| -|description|string|False|Description of the Tag| -|intention|string|False|Tag Intention| -|name|string|False|Name of GreyNoise Tag| -|recommend_block|boolean|False|GreyNoise Recommends Blocking IPs associated with this Tag| -|references|[]object|False|References| - +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|category|string|False|RIOT Category IP is part of|cdn| +|description|string|False|Description of the IP service|Acme Inc is just an example.| +|explanation|string|False|Explanation for why this is likely a common service|This is an explanation.| +|ip|string|False|Value that was Queried|1.2.3.4| +|last_updated|date|False|Last time this IP was updated in RIOT dataset|2024-01-01| +|name|string|False|Vendor Name IP belongs to|Acme Inc.| +|reference|string|False|Additional reference information|http://one.one.one.one| +|riot|boolean|False|Defines if IP is part of GreyNoise RIOT dataset|True| +|trust_level|string|False|IP Trust Level information|1| +|viz_url|string|False|Link to GreyNoise Visualizer for IP Details|https://viz.greynoise.io/ip/1.1.1.1| + Example output: ``` { - "name": "BingBot", - "category": "search_engine", - "intention": "benign", - "description": "This IP address belongs to Bing, Microsoft's search engine. It is used to crawl web servers around - the Internet and index content for search.", - "references": [], - "recommend_block": false, - "cves": [] + "category": "cdn", + "description": "Acme Inc is just an example.", + "explanation": "This is an explanation.", + "ip": "1.2.3.4", + "last_updated": "2024-01-01", + "name": "Acme Inc.", + "reference": "http://one.one.one.one", + "riot": true, + "trust_level": 1, + "viz_url": "https://viz.greynoise.io/ip/1.1.1.1" } ``` -#### Community IP Lookup +#### IP Similarity Lookup -This action is used to query a routable IPv4 address in the GreyNoise Community API. +This action is used to query a routable IPv4 address in the GreyNoise for similar IPs ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -|----|----|-------|--------|-----------|----|-------| -|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4| - +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4|None|None| + Example input: ``` @@ -273,158 +484,495 @@ Example input: ##### Output -|Name|Type|Required|Description| -|----|----|--------|-----------| -|classification|string|False|GreyNoise Classification| -|ip|string|False|Value that was Queried| -|last_seen|string|False|Last Seen By GreyNoise| -|link|string|False|Link to GreyNoise Visualizer for IP Details| -|message|string|False|GreyNoise Community API Status Message| -|name|string|False|GreyNoise Actor or Service Name Associated with IP| -|noise|boolean|False|Defines if IP is Internet Noise| -|riot|boolean|False|Defines if IP is part of GreyNoise RIOT dataset| - +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|ip|ip_sim|False|IP Similarity Metadata|{'actor': 'Acme Inc.', 'asn': 'AS12345', 'city': 'Seattle', 'classification': 'benign', 'country': 'Brazil', 'country_code': 'BE', 'first_seen': '2020-07-08T17:15:10Z', 'ip': '1.2.3.4', 'last_seen': '2020-07-08T17:15:10Z', 'organization': 'Acme Inc'}| +|similar_ips|[]similar_ip|False|Similar IPs|[{"actor": "Acme Inc", "asn": "AS12345", "city": "New York", "classification": "benign", "country": "Ukraine", "country_code": "UK", "features_matched": ["feature-1", "feature-2"], "first_seen": "2020-07-08T17:15:10Z", "ip": "1.2.3.4", "last_seen": "2020-07-08T17:15:10Z", "organization": "Acme Inc", "score": 0.83}]| +|total|integer|False|Total Number of Similar IPs returned|5| + Example output: ``` { - "classification": "benign", - "ip": "1.1.1.1", - "last_seen": "2021-04-20T00:00:00+00:00", - "link": "https://viz.greynoise.io/riot/1.1.1.1", - "message": "Success", - "name": "Cloudflare Public DNS", - "noise": false, - "riot": true + "ip": { + "actor": "Acme Inc.", + "asn": "AS12345", + "city": "Seattle", + "classification": "benign", + "country": "Brazil", + "country_code": "BE", + "first_seen": "2020-07-08T17:15:10Z", + "ip": "1.2.3.4", + "last_seen": "2020-07-08T17:15:10Z", + "organization": "Acme Inc" + }, + "similar_ips": [ + { + "actor": "Acme Inc", + "asn": "AS12345", + "city": "New York", + "classification": "benign", + "country": "Ukraine", + "country_code": "UK", + "features_matched": [ + "feature-1", + "feature-2" + ], + "first_seen": "2020-07-08T17:15:10Z", + "ip": "1.2.3.4", + "last_seen": "2020-07-08T17:15:10Z", + "organization": "Acme Inc", + "score": 0.83 + } + ], + "total": 5 } ``` -#### GreyNoise Query +#### IP Timeline Lookup -This action is used to perform a GreyNoise GNQL Query. +This action is used to query a routable IPv4 address in the GreyNoise for Scanner Daily Timeline details ##### Input -|Name|Type|Default|Required|Description|Enum|Example| -|----|----|-------|--------|-----------|----|-------| -|query|string|None|True|Query in GreyNoise Query Language (GNQL) Syntax|None|last_seen:1d| -|size|string|10|False|Max Number of IPs to Return Data For|None|10| - +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|ip_address|string|None|True|Routable IPv4 address to query|None|1.2.3.4|None|None| + Example input: ``` { - "query": "last_seen:1d", - "size": "10" + "ip_address": "1.2.3.4" } ``` ##### Output -|Name|Type|Required|Description| -|----|----|--------|-----------| -|complete|boolean|False|GreyNoise Query Completed| -|count|integer|False|Count of IPs In Query| -|data|[]data|False|GreyNoise Query Data| -|message|string|False|GreyNoise Query Message| -|query|string|False|GreyNoise Query Sent to API| - +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|activity|[]timeline_activity|False|IP Timeline Activity Events|[{"asn": "AS12345", "category": "isp", "city": "Seattle", "classification": "benign", "country": "Spain", "country_code": "ES", "destinations": [{"country": "Brazil", "country_code": "BE"}], "hassh_fingerprints": ["asdfa1412", "asasdf2125"], "http_web_paths": ["robots.txt"], "http_user_agents": ["Hello World"], "ja3_fingerprints": ["abasdfas", "abasdfasdf"], "organization": "Acme Inc", "protocols": [{"port": 22, "transport_protocol": "TCP", "app_protocol": "TCP"}], "rdns": "scanner.acme.io", "region": "Arizona", "spoofable": False, "tags": [{"tag_category": "activity", "tag_description": "This is a description of the tag.", "tag_intention": "malicious", "tag_name": "IoT Bot Tag"}], "timestampe": "2020-07-08T17:15:10Z", "tor": False, "vpn": False, "vpn_service": "VPN Name"}]| +|ip|string|False|Value that was Queried|1.2.3.4| +|metadata|timeline_metadata|False|IP Timeline Metadata|{'end_time': '2020-07-08T17:15:10Z', 'ip': '1.2.3.4', 'limit': 5, 'next_cursor': 'asdf142qas3241asdf234sfa', 'start_time': '2020-07-08T17:15:10Z'}| + Example output: ``` { - "complete": false, - "count": 318201, - "data": [ + "activity": [ { - "ip": "117.239.128.2", - "metadata": { - "asn": "AS9829", - "city": "Hyderabad", - "country": "India", - "country_code": "IN", - "organization": "National Internet Backbone", - "category": "isp", - "tor": false, - "rdns": "", - "os": "Windows 7/8", - "region": "Telangana" - }, - "bot": false, - "vpn": false, - "vpn_service": "", + "asn": "AS12345", + "category": "isp", + "city": "Seattle", + "classification": "benign", + "country": "Spain", + "country_code": "ES", + "destinations": [ + { + "country": "Brazil", + "country_code": "BE" + } + ], + "hassh_fingerprints": [ + "asdfa1412", + "asasdf2125" + ], + "http_user_agents": [ + "Hello World" + ], + "http_web_paths": [ + "robots.txt" + ], + "ja3_fingerprints": [ + "abasdfas", + "abasdfasdf" + ], + "organization": "Acme Inc", + "protocols": [ + { + "app_protocol": "TCP", + "port": 22, + "transport_protocol": "TCP" + } + ], + "rdns": "scanner.acme.io", + "region": "Arizona", "spoofable": false, - "raw_data": { - "scan": [ - { - "port": 445, - "protocol": "TCP" - } - ], - "web": {}, - "ja3": [], - "hassh": [] - }, - "first_seen": "2021-04-07", - "last_seen": "2021-04-20", - "rdns": "", - "seen": true, "tags": [ - "Eternalblue", - "SMBv1 Crawler" + { + "tag_category": "activity", + "tag_description": "This is a description of the tag.", + "tag_intention": "malicious", + "tag_name": "IoT Bot Tag" + } ], - "actor": "unknown", - "classification": "malicious", - "cve": [ - "CVE-2017-0144" - ] + "timestampe": "2020-07-08T17:15:10Z", + "tor": false, + "vpn": false, + "vpn_service": "VPN Name" } ], - "message": "ok", - "query": "last_seen:1d" + "ip": "1.2.3.4", + "metadata": { + "end_time": "2020-07-08T17:15:10Z", + "ip": "1.2.3.4", + "limit": 5, + "next_cursor": "asdf142qas3241asdf234sfa", + "start_time": "2020-07-08T17:15:10Z" + } +} +``` + +#### Vulnerability Lookup + +This action is used to check GreyNoise for Vulnerability information + +##### Input + +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|cve_id|string|None|True|A CVE ID to look up in GreyNoise|None|CVE-2020-12345|None|None| + +Example input: + +``` +{ + "cve_id": "CVE-2020-12345" } ``` +##### Output + +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|details|vuln_details|False|GreyNoise Vulnerability Details|{'cve_cvss_score': 9.8, 'product': 'Product Name', 'published_to_nist_nvd': False, 'vendor': 'Acme Inc', 'vulnerability_description': 'This is a product description.', 'vulnerability_name': 'This is a vuln name.'}| +|exploitation_activity|vuln_exploitation_activity|False|GreyNoise Vulnerability Exploitation Activity|{'activity_seen': True, 'benign_ip_count_10d': 5, 'benign_ip_count_1d': 5, 'benign_ip_count_30d': 5, 'threat_ip_count_10d': 5, 'threat_ip_count_1d': 5, 'threat_ip_count_30d': 5}| +|exploitation_details|vuln_exploitation_details|False|GreyNoise Vulnerability Exploitation Details|{'attack_vector': 'NETWORK', 'epss_score': 0.0, 'exploit_found': True, 'exploitation_registered_in_kev': False}| +|exploitation_stats|vuln_exploitation_stats|False|GreyNoise Vulnerability Exploitation Stats|{'number_of_available_exploits': 1, 'number_of_botnets_exploiting_vulnerability': 1, 'number_of_threat_actors_exploiting_vulnerability': 1}| +|id|string|False|Value that was searched|CVE-2020-12345| +|timeline|vuln_timeline|False|GreyNoise Vulnerability Timeline|{'cisa_kev_date_added': '2020-07-08T17:15:10Z', 'cve_last_updated_date': '2020-07-08T17:15:10Z', 'cve_published_date': '2020-07-08T17:15:10Z', 'first_known_published_date': '2020-07-08T17:15:10Z'}| + +Example output: + +``` +{ + "details": { + "cve_cvss_score": 9.8, + "product": "Product Name", + "published_to_nist_nvd": false, + "vendor": "Acme Inc", + "vulnerability_description": "This is a product description.", + "vulnerability_name": "This is a vuln name." + }, + "exploitation_activity": { + "activity_seen": true, + "benign_ip_count_10d": 5, + "benign_ip_count_1d": 5, + "benign_ip_count_30d": 5, + "threat_ip_count_10d": 5, + "threat_ip_count_1d": 5, + "threat_ip_count_30d": 5 + }, + "exploitation_details": { + "attack_vector": "NETWORK", + "epss_score": 0.0, + "exploit_found": true, + "exploitation_registered_in_kev": false + }, + "exploitation_stats": { + "number_of_available_exploits": 1, + "number_of_botnets_exploiting_vulnerability": 1, + "number_of_threat_actors_exploiting_vulnerability": 1 + }, + "id": "CVE-2020-12345", + "timeline": { + "cisa_kev_date_added": "2020-07-08T17:15:10Z", + "cve_last_updated_date": "2020-07-08T17:15:10Z", + "cve_published_date": "2020-07-08T17:15:10Z", + "first_known_published_date": "2020-07-08T17:15:10Z" + } +} +``` ### Triggers -_This plugin does not contain any triggers._ -### Custom Output Types +#### Monitor IP List in GreyNoise -_This plugin does not contain any custom output types._ +This trigger is used to query a list of IPs in GreyNoise based on IP List every interval to identify if any of them are + actively scanning the internet -## Troubleshooting +##### Input -### Response 401 +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|interval|integer|3600|True|How frequently (in seconds) to trigger a greeting|None|3600|None|None| +|ip_list|[]string|None|True|List of IP Addresses or CIDR blocks to check for scanning activity|None|[1.2.3.4,5.2.3.0/24]|None|None| +|lookback_days|integer|1|True|Number of Days to look back for scanning activity. Recommended "1", Max "90"|None|1|None|None| + +Example input: -If the actions are returning a 401, ensure that the API key provided is valid and has an appropriate subscription or -trial associated with it. +``` +{ + "interval": 3600, + "ip_list": "[1.2.3.4,5.2.3.0/24]", + "lookback_days": 1 +} +``` -### Response 429 +##### Output -If the actions are returning a 429, check your daily rate-limit quota, as the API indicates the daily limit has been -reached or exceeded. +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|alert_ip_list|[]string|False|The list of IPs that were found scanning|1.2.3.4,5.2.3.5| + +Example output: -### Community API Keys +``` +{ + "alert_ip_list": "1.2.3.4,5.2.3.5" +} +``` +### Tasks + +*This plugin does not contain any tasks.* + +### Custom Types + +**metadata** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|ASN|string|None|False|ASN|AS12345| +|Category|string|None|False|Category|isp| +|City|string|None|False|City|Reno| +|Country|string|None|False|Country|Brazil| +|Country Code|string|None|False|Country Code|BZ| +|Destination Countries|[]string|None|False|List of countries with GreyNoise sensors that observed this IP|["Brazil", "Spain"]| +|Destination Country Codes|[]string|None|False|List of countries (by code) with GreyNoise sensors that observed this IP|["BZ", "ES"]| +|Organization|string|None|False|Organization|Acme Inc.| +|OS|string|None|False|OS|Windows XP| +|rDNS|string|None|False|rDNS|scanner.example.io| +|Region|string|None|False|Region|Arizona| +|Sensor Count|integer|None|False|Count of Sensors that observed traffic from this IP|5| +|Sensor Hits|integer|None|False|Count of Sensor events observed from this IP|5| +|Source Country|string|None|False|Source country where this IP is located|Brazil| +|Source Country Code|string|None|False|Source country (by code) where this IP is located|BE| +|TOR|boolean|None|False|TOR|False| + +**web** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Web Paths|[]string|None|False|User Agents|["/", "/robots.txt"]| +|User Agents|[]string|None|False|User Agents|["user-agent"]| + +**scan** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Port|integer|None|False|Port|22| +|Protocol|string|None|False|Protocol|TCP| + +**hassh** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Fingerprint|string|None|False|Fingerprint|abcdefg1234567| +|Port|integer|None|False|Port|22| + +**ja3** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Fingerprint|string|None|False|Fingerprint|abcdefg1234567| +|Port|integer|None|False|Port|22| + +**raw_data** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|HASSH|[]hassh|None|False|HASSH|None| +|JA3|[]ja3|None|False|Ja3|None| +|Scan|[]scan|None|False|Scan|None| +|Web|web|None|False|Web|None| + +**data** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|GreyNoise Actor|string|None|False|GreyNoise Actor Associated with IP|Actor Name| +|GreyNoise Bot|boolean|None|False|GreyNoise has identified this as a Bot|False| +|GreyNoise Classification|string|None|False|GreyNoise Classification|benign| +|GreyNoise CVEs|[]string|None|False|CVEs associated with GreyNoise Tags|CVE-1234-12345| +|GreyNoise First Seen|date|None|False|First Seen By GreyNoise|2024-01-01| +|IP Address|string|None|False|IP Address|1.2.4.5| +|GreyNoise Last Seen|string|None|False|Last Seen By GreyNoise|2024-01-01| +|GreyNoise Metadata|metadata|None|False|GreyNoise IP Metadata|{'ASN': 'AS12345', 'Category': 'isp', 'City': 'Reno', 'Country': 'Brazil', 'Country Code': 'BZ', 'Destination Countries': ['Brazil', 'Spain'], 'Destination Country Codes': ['BZ', 'ES'], 'Organization': 'Acme Inc.', 'OS': 'Windows XP', 'rDNS': 'scanner.example.io', 'Region': 'Arizona', 'Sensor Count': 5, 'Sensor Hits': 5, 'Source Country': 'Brazil', 'Source Country Code': 'BE', 'TOR': False}| +|GreyNoise Raw Data|raw_data|None|False|GreyNoise IP Raw Data|{'HASSH': [{'Fingerprint': 'abcdefg1234567', 'Port': 22}], 'JA3': [{'Fingerprint': 'abcdefg1234567', 'Port': 22}], 'Scan': [{'Port': 22, 'Protocol': 'TCP'}], 'Web': {'Web Paths': ['/', '/robots.txt'], 'User Agents': ['user-agent']}}| +|GreyNoise Seen|boolean|None|False|Has this IP been Seen by GreyNoise|False| +|GreyNoise Spoofable|boolean|None|False|IP address may be spoofed|False| +|GreyNoise Tags|[]string|None|False|GreyNoise Tags Associated with IP|["tag1", "tag2"]| +|GreyNoise VPN|boolean|None|False|GreyNoise has identified this as a VPN|False| +|GreyNoise VPN Service|string|None|False|Name of VPN Service|VPN Name| + +**vuln_timeline** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Date Added to CISA KEV|string|None|False|Date Added to CISA KEV|2020-07-08T17:15:10Z| +|Date CVE was Last Updated|string|None|False|Date CVE was Last Updated|2020-07-08T17:15:10Z| +|Date CVE was Published|string|None|False|Date CVE was Published|2020-07-08T17:15:10Z| +|Date of First Published POC|string|None|False|Date of First Published POC|2020-07-08T17:15:10Z| + +**vuln_exploitation_stats** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Number of Available Exploits|integer|None|False|Number of Available Exploits|1| +|Number of Associated Botnets|integer|None|False|Number of Associated Botnets|1| +|Number of Threat Actors Exploiting Vulnerability|integer|None|False|Number of Threat Actors Exploiting Vulnerability|1| + +**vuln_exploitation_details** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Attack Vector|string|None|False|Attack Vector|NETWORK| +|EPSS Score|float|None|False|EPSS Score|0.0| +|Exploit Found|boolean|None|False|Exploit Found|False| +|Exploitation Registered in KEV|boolean|None|False|Exploitation Registered in KEV|False| + +**vuln_exploitation_activity** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|GreyNoise Observed Activity|boolean|None|False|GreyNoise Observed Activity|True| +|Benign IP Count - 10 days|integer|None|False|Benign IP Count - 10 days|5| +|Benign IP Count - 1 day|integer|None|False|Benign IP Count - 1 day|5| +|Benign IP Count - 30 days|integer|None|False|Benign IP Count - 30 days|5| +|Threat IP Count - 10 days|integer|None|False|Threat IP Count - 10 days|5| +|Threat IP Count - 1 day|integer|None|False|Threat IP Count - 1 day|5| +|Threat IP Count - 30 days|integer|None|False|Threat IP Count - 30 days|5| + +**vuln_details** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|CVE CVSS Score|float|None|False|CVE CVSS Score|9.8| +|Product Name|string|None|False|Product Name|Product Name| +|Is CVE Published in NIST NVD|boolean|None|False|Is CVE Published in NIST NVD|False| +|Vendor Name|string|None|False|Vendor Name|Acme Inc| +|Vulnerability Description|string|None|False|Vulnerability Description|This is a product description.| +|Vulnerability Name|string|None|False|Vulnerability Name|This is a vuln name.| + +**timeline_metadata** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Timeline Period End Time|date|None|False|Timeline Period End Time|2020-07-08T17:15:10Z| +|IP Address|string|None|False|IP Queried|1.2.3.4| +|Event Limit|integer|None|False|Max number of events to return|5| +|Cursor Value|string|None|False|Cursor value for additional pages of details|asdf142qas3241asdf234sfa| +|Timeline Period Start Time|date|None|False|Timeline Period Start Time|2020-07-08T17:15:10Z| + +**timeline_activity** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|ASN|string|None|False|ASN|AS12345| +|Category|string|None|False|Category|isp| +|City|string|None|False|City|Seattle| +|GreyNoise Classification|string|None|False|GreyNoise Classification|benign| +|Country|string|None|False|Country|Spain| +|Country Code|string|None|False|Country Code|ES| +|Destinations|[]destinations|None|False|Destinations|None| +|HASSH Fingerprints|[]string|None|False|HASSH Fingerprints|["asdfa1412", "asasdf2125"]| +|HTTP Web Paths|[]string|None|False|HTTP Web Paths|["/", "/robots.txt"]| +|HTTP User Agents|[]string|None|False|HTTP User Agents|["/", "/robots.txt"]| +|JA3 Fingerprints|[]string|None|False|JA3 Fingerprints|["abasdfas", "abasdfasdf"]| +|Organization|string|None|False|Organization|Acme Inc| +|Protocols|[]protocols|None|False|Destinations|None| +|rDNS|string|None|False|rDNS|scanner.acme.io| +|Region|string|None|False|Region|Arizona| +|Spoofable|boolean|None|False|Spoofable|False| +|Tags|[]tags|None|False|Tags|None| +|Event Timestamp|date|None|False|Event Timestamp|2020-07-08T17:15:10Z| +|Tor Exit Node|boolean|None|False|Tor Exit Node|False| +|VPN|boolean|None|False|VPN|False| +|VPN Service|string|None|False|VPN Service|VPN Name| + +**destinations** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Country|string|None|False|Country|Brazil| +|Country Code|string|None|False|Country Code|BE| + +**protocols** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|App Protocol|string|None|False|App Protocol|http| +|Port|integer|None|False|Port|22| +|Transport Protocol|string|None|False|Transport Protocol|TCP| + +**tags** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Tag Category|string|None|False|Tag Category|activity| +|Tag Description|string|None|False|Tag Description|This is a description of the tag.| +|Tag Intention|string|None|False|Tag Intention|malicious| +|Tag Name|string|None|False|Tag Name|IoT Bot Tag| + +**ip_sim** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Actor|string|None|False|Actor|Acme Inc.| +|ASN|string|None|False|ASN|AS12345| +|City|string|None|False|City|Seattle| +|Classification|string|None|False|Classification|benign| +|Country|string|None|False|Country|Brazil| +|Country Code|string|None|False|Country Code|BE| +|First Seen|string|None|False|First Seen|2020-07-08T17:15:10Z| +|IP Address|string|None|False|IP Address|1.2.3.4| +|Last Seen|string|None|False|Last Seen|2020-07-08T17:15:10Z| +|Organization|string|None|False|Organization|Acme Inc| + +**similar_ip** + +|Name|Type|Default|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | :--- | +|Actor|string|None|False|Actor|Acme Inc| +|ASN|string|None|False|ASN|AS12345| +|City|string|None|False|City|New York| +|Classification|string|None|False|Classification|benign| +|Country|string|None|False|Country|Ukraine| +|Country Code|string|None|False|Country Code|UK| +|Features Matched|[]string|None|False|Features Matched|["feature-1", "feature-2"]| +|First Seen|string|None|False|First Seen|2020-07-08T17:15:10Z| +|IP Address|string|None|False|IP Address|1.2.3.4| +|Last Seen|string|None|False|Last Seen|2020-07-08T17:15:10Z| +|Organization|string|None|False|Organization|Acme Inc| +|Similarity Score|float|None|False|Similarity Score|0.83| -For users with Community API Keys or Enterprise Trial Keys that have expired, the Community IP Lookup is the only -action that will continue to function. All other actions will return an 401. This is expected behavior. -### Other Issues +## Troubleshooting -For any other API or plugin related issues, feel free to reach out to [GreyNoise Support](mailto:support@greynoise.io) -or reference the [GreyNoise Developer Documentation](https://developer.greynoise.io) +Ensure that the GreyNoise API key used has appropriate access for the actions being used. # Version History +* 2.0.0 - Upgrade GreyNoise SDK v2.3.0 | Fix Action Outputs | New actions:`vulnerability_lookup`, `timeline_lookup`, `similar_lookup` | New trigger: `greynoise_alert` * 1.0.1 - Fix bug with connection parameters -* 1.0.0 - Initial plugin +* 1.0.0 - Initial plugin. # Links +* [GreyNoise](https://greynoise.io) + ## References -* [GreyNoise](https://greynoise.io) -* [GreyNoise Developer Docs](https://developer.greynoise.io) +* [GreyNoise Documentation](https://docs.greynoise.io) * [GreyNoise Free Trial Signup](https://viz.greynoise.io/signup) -* [GreyNoise Account Info](https://viz.greynoise.io/account) +* [GreyNoise Account Info](https://viz.greynoise.io/account) \ No newline at end of file diff --git a/plugins/greynoise/icon_greynoise/actions/__init__.py b/plugins/greynoise/icon_greynoise/actions/__init__.py index 39469776ab..21519c581a 100755 --- a/plugins/greynoise/icon_greynoise/actions/__init__.py +++ b/plugins/greynoise/icon_greynoise/actions/__init__.py @@ -1,7 +1,20 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT -from .community_lookup.action import CommunityLookup +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT + from .context_lookup.action import ContextLookup + +from .riot_lookup.action import RiotLookup + +from .quick_lookup.action import QuickLookup + from .get_tag_details.action import GetTagDetails + from .gnql_query.action import GnqlQuery -from .quick_lookup.action import QuickLookup -from .riot_lookup.action import RiotLookup + +from .community_lookup.action import CommunityLookup + +from .vulnerability_lookup.action import VulnerabilityLookup + +from .timeline_lookup.action import TimelineLookup + +from .similar_lookup.action import SimilarLookup + diff --git a/plugins/greynoise/icon_greynoise/actions/community_lookup/__init__.py b/plugins/greynoise/icon_greynoise/actions/community_lookup/__init__.py index 0df064eac8..a2c2313d72 100755 --- a/plugins/greynoise/icon_greynoise/actions/community_lookup/__init__.py +++ b/plugins/greynoise/icon_greynoise/actions/community_lookup/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .action import CommunityLookup diff --git a/plugins/greynoise/icon_greynoise/actions/community_lookup/action.py b/plugins/greynoise/icon_greynoise/actions/community_lookup/action.py index 65159dd4ae..b05e83b14d 100755 --- a/plugins/greynoise/icon_greynoise/actions/community_lookup/action.py +++ b/plugins/greynoise/icon_greynoise/actions/community_lookup/action.py @@ -1,10 +1,10 @@ import insightconnect_plugin_runtime -from .schema import CommunityLookupInput, CommunityLookupOutput, Input, Component +from .schema import CommunityLookupInput, CommunityLookupOutput, Input, Output, Component # Custom imports below -from icon_greynoise.util.util import GNRequestFailure, GNValueError -from greynoise import GreyNoise +from insightconnect_plugin_runtime.exceptions import PluginException from greynoise.exceptions import RequestFailure +from greynoise import GreyNoise import pendulum @@ -29,10 +29,25 @@ def run(self, params={}): 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 RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) - except ValueError as e: - raise GNValueError(e.args[0]) + except ValueError as error: + raise PluginException( + cause=f"Input does not appear to be valid: {Input.IP_ADDRESS}. Error Message: {error.args[0]}", + assistance="Please provide a valid public IPv4 address.", + ) - return resp + return { + Output.CLASSIFICATION: resp.get("classification"), + Output.IP: resp.get("ip"), + Output.LAST_SEEN: resp.get("last_seen"), + Output.LINK: resp.get("link"), + Output.MESSAGE: resp.get("message"), + Output.NAME: resp.get("name"), + Output.NOISE: resp.get("noise"), + Output.RIOT: resp.get("riot"), + } diff --git a/plugins/greynoise/icon_greynoise/actions/community_lookup/schema.py b/plugins/greynoise/icon_greynoise/actions/community_lookup/schema.py index 3cf0b4ee6d..096fbc0dcd 100755 --- a/plugins/greynoise/icon_greynoise/actions/community_lookup/schema.py +++ b/plugins/greynoise/icon_greynoise/actions/community_lookup/schema.py @@ -1,4 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import insightconnect_plugin_runtime import json @@ -9,7 +9,7 @@ class Component: class Input: IP_ADDRESS = "ip_address" - + class Output: CLASSIFICATION = "classification" @@ -20,10 +20,10 @@ class Output: NAME = "name" NOISE = "noise" RIOT = "riot" - + class CommunityLookupInput(insightconnect_plugin_runtime.Input): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -37,7 +37,8 @@ class CommunityLookupInput(insightconnect_plugin_runtime.Input): }, "required": [ "ip_address" - ] + ], + "definitions": {} } """) @@ -46,7 +47,7 @@ def __init__(self): class CommunityLookupOutput(insightconnect_plugin_runtime.Output): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -99,7 +100,8 @@ class CommunityLookupOutput(insightconnect_plugin_runtime.Output): "description": "Defines if IP is part of GreyNoise RIOT dataset", "order": 3 } - } + }, + "definitions": {} } """) diff --git a/plugins/greynoise/icon_greynoise/actions/context_lookup/__init__.py b/plugins/greynoise/icon_greynoise/actions/context_lookup/__init__.py index 0b08e5842c..5c355c8551 100755 --- a/plugins/greynoise/icon_greynoise/actions/context_lookup/__init__.py +++ b/plugins/greynoise/icon_greynoise/actions/context_lookup/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .action import ContextLookup diff --git a/plugins/greynoise/icon_greynoise/actions/context_lookup/action.py b/plugins/greynoise/icon_greynoise/actions/context_lookup/action.py index 6122abb5c9..8477feab57 100755 --- a/plugins/greynoise/icon_greynoise/actions/context_lookup/action.py +++ b/plugins/greynoise/icon_greynoise/actions/context_lookup/action.py @@ -1,8 +1,8 @@ import insightconnect_plugin_runtime -from .schema import ContextLookupInput, ContextLookupOutput, Input, Component +from .schema import ContextLookupInput, ContextLookupOutput, Input, Output, Component # Custom imports below -from icon_greynoise.util.util import GNRequestFailure, GNValueError +from insightconnect_plugin_runtime.exceptions import PluginException from greynoise.exceptions import RequestFailure import pendulum @@ -17,16 +17,40 @@ def __init__(self): ) def run(self, params={}): + viz_base_url = "https://viz.greynoise.io/ip/" try: resp = self.connection.gn_client.ip(params.get(Input.IP_ADDRESS)) if resp["seen"]: resp["first_seen"] = pendulum.parse(resp["first_seen"]).to_rfc3339_string() resp["last_seen"] = pendulum.parse(resp["last_seen"]).to_rfc3339_string() - resp["viz_url"] = "https://viz.greynoise.io/ip/" + str(params.get(Input.IP_ADDRESS)) + resp["viz_url"] = viz_base_url + str(resp["ip"]) - except RequestFailure as e: - raise GNRequestFailure(e.args[0], e.args[1]) - except ValueError as e: - raise GNValueError(e.args[0]) + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) - return resp + except ValueError as error: + raise PluginException( + cause=f"Input does not appear to be valid: {Input.IP_ADDRESS}. Error Message: {error.args[0]}", + assistance="Please provide a valid public IPv4 address.", + ) + + return { + Output.ACTOR: resp.get("actor"), + Output.BOT: resp.get("bot"), + Output.CLASSIFICATION: resp.get("classification"), + Output.CVE: resp.get("cve"), + Output.FIRST_SEEN: resp.get("first_seen"), + Output.IP: resp.get("ip"), + Output.LAST_SEEN: resp.get("last_seen"), + Output.METADATA: resp.get("metadata"), + Output.RAW_DATA: resp.get("raw_data"), + Output.SEEN: resp.get("seen"), + Output.SPOOFABLE: resp.get("spoofable"), + Output.TAGS: resp.get("tags"), + Output.VIZ_URL: resp.get("viz_url"), + Output.VPN: resp.get("vpn"), + Output.VPN_SERVICE: resp.get("vpn_service"), + } diff --git a/plugins/greynoise/icon_greynoise/actions/context_lookup/schema.py b/plugins/greynoise/icon_greynoise/actions/context_lookup/schema.py index 1b25541a08..b17d7e5182 100755 --- a/plugins/greynoise/icon_greynoise/actions/context_lookup/schema.py +++ b/plugins/greynoise/icon_greynoise/actions/context_lookup/schema.py @@ -1,4 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import insightconnect_plugin_runtime import json @@ -9,7 +9,7 @@ class Component: class Input: IP_ADDRESS = "ip_address" - + class Output: ACTOR = "actor" @@ -27,10 +27,10 @@ class Output: VIZ_URL = "viz_url" VPN = "vpn" VPN_SERVICE = "vpn_service" - + class ContextLookupInput(insightconnect_plugin_runtime.Input): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -44,7 +44,8 @@ class ContextLookupInput(insightconnect_plugin_runtime.Input): }, "required": [ "ip_address" - ] + ], + "definitions": {} } """) @@ -53,7 +54,7 @@ def __init__(self): class ContextLookupOutput(insightconnect_plugin_runtime.Output): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -87,10 +88,10 @@ class ContextLookupOutput(insightconnect_plugin_runtime.Output): }, "first_seen": { "type": "string", - "title": "GreyNoise First Seen", + "format": "date-time", "displayType": "date", + "title": "GreyNoise First Seen", "description": "First Seen By GreyNoise", - "format": "date-time", "order": 2 }, "ip": { @@ -221,6 +222,48 @@ class ContextLookupOutput(insightconnect_plugin_runtime.Output): "title": "TOR", "description": "TOR", "order": 10 + }, + "sensor_count": { + "type": "integer", + "title": "Sensor Count", + "description": "Count of Sensors that observed traffic from this IP", + "order": 11 + }, + "sensor_hits": { + "type": "integer", + "title": "Sensor Hits", + "description": "Count of Sensor events observed from this IP", + "order": 12 + }, + "destination_countries": { + "type": "array", + "title": "Destination Countries", + "description": "List of countries with GreyNoise sensors that observed this IP", + "items": { + "type": "string" + }, + "order": 13 + }, + "destination_country_codes": { + "type": "array", + "title": "Destination Country Codes", + "description": "List of countries (by code) with GreyNoise sensors that observed this IP", + "items": { + "type": "string" + }, + "order": 14 + }, + "source_country": { + "type": "string", + "title": "Source Country", + "description": "Source country where this IP is located", + "order": 15 + }, + "source_country_code": { + "type": "string", + "title": "Source Country Code", + "description": "Source country (by code) where this IP is located", + "order": 16 } } }, @@ -233,7 +276,7 @@ class ContextLookupOutput(insightconnect_plugin_runtime.Output): "title": "HASSH", "description": "HASSH", "items": { - "type": "object" + "$ref": "#/definitions/hassh" }, "order": 1 }, @@ -242,7 +285,7 @@ class ContextLookupOutput(insightconnect_plugin_runtime.Output): "title": "JA3", "description": "Ja3", "items": { - "type": "object" + "$ref": "#/definitions/ja3" }, "order": 2 }, @@ -256,30 +299,46 @@ class ContextLookupOutput(insightconnect_plugin_runtime.Output): "order": 3 }, "web": { - "type": "object", + "$ref": "#/definitions/web", "title": "Web", "description": "Web", "order": 4 } - }, - "definitions": { - "scan": { - "type": "object", - "title": "scan", - "properties": { - "port": { - "type": "integer", - "title": "Port", - "description": "Port", - "order": 1 - }, - "protocol": { - "type": "string", - "title": "Protocol", - "description": "Protocol", - "order": 2 - } - } + } + }, + "hassh": { + "type": "object", + "title": "hassh", + "properties": { + "port": { + "type": "integer", + "title": "Port", + "description": "Port", + "order": 1 + }, + "fingerprint": { + "type": "string", + "title": "Fingerprint", + "description": "Fingerprint", + "order": 2 + } + } + }, + "ja3": { + "type": "object", + "title": "ja3", + "properties": { + "port": { + "type": "integer", + "title": "Port", + "description": "Port", + "order": 1 + }, + "fingerprint": { + "type": "string", + "title": "Fingerprint", + "description": "Fingerprint", + "order": 2 } } }, @@ -300,6 +359,30 @@ class ContextLookupOutput(insightconnect_plugin_runtime.Output): "order": 2 } } + }, + "web": { + "type": "object", + "title": "web", + "properties": { + "useragents": { + "type": "array", + "title": "User Agents", + "description": "User Agents", + "items": { + "type": "string" + }, + "order": 1 + }, + "paths": { + "type": "array", + "title": "Web Paths", + "description": "User Agents", + "items": { + "type": "string" + }, + "order": 2 + } + } } } } diff --git a/plugins/greynoise/icon_greynoise/actions/get_tag_details/__init__.py b/plugins/greynoise/icon_greynoise/actions/get_tag_details/__init__.py index bb717cf968..acb65b7698 100755 --- a/plugins/greynoise/icon_greynoise/actions/get_tag_details/__init__.py +++ b/plugins/greynoise/icon_greynoise/actions/get_tag_details/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .action import GetTagDetails diff --git a/plugins/greynoise/icon_greynoise/actions/get_tag_details/action.py b/plugins/greynoise/icon_greynoise/actions/get_tag_details/action.py index 891477fb89..e57b06857d 100755 --- a/plugins/greynoise/icon_greynoise/actions/get_tag_details/action.py +++ b/plugins/greynoise/icon_greynoise/actions/get_tag_details/action.py @@ -1,8 +1,8 @@ import insightconnect_plugin_runtime -from .schema import GetTagDetailsInput, GetTagDetailsOutput, Input, Component +from .schema import GetTagDetailsInput, GetTagDetailsOutput, Input, Output, Component # Custom imports below -from icon_greynoise.util.util import GNRequestFailure +from insightconnect_plugin_runtime.exceptions import PluginException from greynoise.exceptions import RequestFailure @@ -23,9 +23,26 @@ def run(self, params={}): for tag in resp["metadata"]: if tag["name"].lower() == tag_name: output = tag - except RequestFailure as e: - raise GNRequestFailure(e.args[0], e.args[1]) - if output: - return output - else: - return {"name": params.get(Input.TAG_NAME), "description": "Tag Not Found"} + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) + + if not output: + output = {"name": params.get(Input.TAG_NAME), "description": "Tag Not Found"} + + return { + Output.CATEGORY: output.get("category"), + Output.CREATED_AT: output.get("created_at"), + Output.CVES: output.get("cves"), + Output.DESCRIPTION: output.get("description"), + Output.ID: output.get("id"), + Output.INTENTION: output.get("intention"), + Output.LABEL: output.get("label"), + Output.NAME: output.get("name"), + Output.RECOMMEND_BLOCK: output.get("recommend_block"), + Output.REFERENCES: output.get("references"), + Output.RELATED_TAGS: output.get("related_tags"), + Output.SLUG: output.get("slug"), + } diff --git a/plugins/greynoise/icon_greynoise/actions/get_tag_details/schema.py b/plugins/greynoise/icon_greynoise/actions/get_tag_details/schema.py index 0c52c331c4..5a7c538ce0 100755 --- a/plugins/greynoise/icon_greynoise/actions/get_tag_details/schema.py +++ b/plugins/greynoise/icon_greynoise/actions/get_tag_details/schema.py @@ -1,4 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import insightconnect_plugin_runtime import json @@ -9,20 +9,25 @@ class Component: class Input: TAG_NAME = "tag_name" - + class Output: CATEGORY = "category" + CREATED_AT = "created_at" CVES = "cves" DESCRIPTION = "description" + ID = "id" INTENTION = "intention" + LABEL = "label" NAME = "name" RECOMMEND_BLOCK = "recommend_block" REFERENCES = "references" - + RELATED_TAGS = "related_tags" + SLUG = "slug" + class GetTagDetailsInput(insightconnect_plugin_runtime.Input): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -36,7 +41,8 @@ class GetTagDetailsInput(insightconnect_plugin_runtime.Input): }, "required": [ "tag_name" - ] + ], + "definitions": {} } """) @@ -45,7 +51,7 @@ def __init__(self): class GetTagDetailsOutput(insightconnect_plugin_runtime.Output): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -56,12 +62,18 @@ class GetTagDetailsOutput(insightconnect_plugin_runtime.Output): "description": "Tag Category", "order": 2 }, + "created_at": { + "type": "string", + "title": "Tag Created At", + "description": "The date the tag was added to GreyNoise tag library", + "order": 8 + }, "cves": { "type": "array", - "title": "CVEs", + "title": "Tag Associated CVEs", "description": "CVEs associate with Tag", "items": { - "type": "object" + "type": "string" }, "order": 7 }, @@ -71,12 +83,24 @@ class GetTagDetailsOutput(insightconnect_plugin_runtime.Output): "description": "Description of the Tag", "order": 4 }, + "id": { + "type": "string", + "title": "Tag ID", + "description": "The unique ID for the tag", + "order": 9 + }, "intention": { "type": "string", "title": "Tag Intention", "description": "Tag Intention", "order": 3 }, + "label": { + "type": "string", + "title": "Tag Label", + "description": "The unique label for the tag", + "order": 10 + }, "name": { "type": "string", "title": "Tag Name", @@ -85,20 +109,36 @@ class GetTagDetailsOutput(insightconnect_plugin_runtime.Output): }, "recommend_block": { "type": "boolean", - "title": "Recommend Block", + "title": "Tag Recommend Block", "description": "GreyNoise Recommends Blocking IPs associated with this Tag", "order": 6 }, "references": { "type": "array", - "title": "References", + "title": "Tag References", "description": "References", "items": { - "type": "object" + "type": "string" }, "order": 5 + }, + "related_tags": { + "type": "array", + "title": "Tag Related Tags", + "description": "Tags that are related to this tag", + "items": { + "type": "string" + }, + "order": 12 + }, + "slug": { + "type": "string", + "title": "Tag Slug", + "description": "The unique slug for the tag", + "order": 11 } - } + }, + "definitions": {} } """) diff --git a/plugins/greynoise/icon_greynoise/actions/gnql_query/__init__.py b/plugins/greynoise/icon_greynoise/actions/gnql_query/__init__.py index 942401319d..b66c4fab58 100755 --- a/plugins/greynoise/icon_greynoise/actions/gnql_query/__init__.py +++ b/plugins/greynoise/icon_greynoise/actions/gnql_query/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .action import GnqlQuery diff --git a/plugins/greynoise/icon_greynoise/actions/gnql_query/action.py b/plugins/greynoise/icon_greynoise/actions/gnql_query/action.py index 2f6daff478..1c7988eb31 100755 --- a/plugins/greynoise/icon_greynoise/actions/gnql_query/action.py +++ b/plugins/greynoise/icon_greynoise/actions/gnql_query/action.py @@ -1,9 +1,8 @@ import insightconnect_plugin_runtime -from .schema import GnqlQueryInput, GnqlQueryOutput, Input, Component +from .schema import GnqlQueryInput, GnqlQueryOutput, Input, Output, Component # Custom imports below from insightconnect_plugin_runtime.exceptions import PluginException -from icon_greynoise.util.util import GNRequestFailure from greynoise.exceptions import RequestFailure @@ -24,7 +23,16 @@ def run(self, params={}): try: resp = self.connection.gn_client.query(query, size=size) - except RequestFailure as e: - raise GNRequestFailure(e.args[0], e.args[1]) + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) - return resp + return { + Output.QUERY: resp.get("query"), + Output.DATA: resp.get("data"), + Output.COUNT: resp.get("count"), + Output.MESSAGE: resp.get("message"), + Output.COMPLETE: resp.get("complete"), + } diff --git a/plugins/greynoise/icon_greynoise/actions/gnql_query/schema.py b/plugins/greynoise/icon_greynoise/actions/gnql_query/schema.py index 935f4ffe03..845cb8e5d4 100755 --- a/plugins/greynoise/icon_greynoise/actions/gnql_query/schema.py +++ b/plugins/greynoise/icon_greynoise/actions/gnql_query/schema.py @@ -1,4 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import insightconnect_plugin_runtime import json @@ -10,7 +10,7 @@ class Component: class Input: QUERY = "query" SIZE = "size" - + class Output: COMPLETE = "complete" @@ -18,10 +18,10 @@ class Output: DATA = "data" MESSAGE = "message" QUERY = "query" - + class GnqlQueryInput(insightconnect_plugin_runtime.Input): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -42,7 +42,8 @@ class GnqlQueryInput(insightconnect_plugin_runtime.Input): }, "required": [ "query" - ] + ], + "definitions": {} } """) @@ -51,27 +52,27 @@ def __init__(self): class GnqlQueryOutput(insightconnect_plugin_runtime.Output): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", "properties": { "complete": { "type": "boolean", - "title": "GreyNoise Query", - "description": "GreyNoise Query Completed", + "title": "GreyNoise Complete Flag", + "description": "Indicates if all pages of the query have been returned by the API", "order": 1 }, "count": { "type": "integer", "title": "GreyNoise Count", - "description": "Count of IPs In Query", + "description": "Total count of IPs returned Query", "order": 2 }, "data": { "type": "array", "title": "GreyNoise Query Data", - "description": "GreyNoise Query Data", + "description": "GreyNoise Data Object, Contains IP Object for each IP returned by the query", "items": { "$ref": "#/definitions/data" }, @@ -80,7 +81,7 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "message": { "type": "string", "title": "GreyNoise Query Message", - "description": "GreyNoise Query Message", + "description": "GreyNoise Query Message, indicates if there were issues with the query", "order": 4 }, "query": { @@ -95,85 +96,73 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "type": "object", "title": "data", "properties": { - "actor": { - "type": "string", - "title": "GreyNoise Actor", - "description": "GreyNoise Actor Associated with IP", - "order": 6 - }, - "bot": { - "type": "boolean", - "title": "GreyNoise Bot", - "description": "GreyNoise has identified this as a Bot", - "order": 10 - }, - "classification": { + "ip": { "type": "string", - "title": "GreyNoise Classification", - "description": "GreyNoise Classification", - "order": 8 - }, - "cve": { - "type": "array", - "title": "GreyNoise CVEs", - "description": "CVEs associated with GreyNoise Tags", - "items": { - "type": "string" - }, - "order": 9 + "title": "IP Address", + "description": "IP Address", + "order": 1 }, "first_seen": { "type": "string", - "title": "GreyNoise First Seen", + "format": "date-time", "displayType": "date", + "title": "GreyNoise First Seen", "description": "First Seen By GreyNoise", - "format": "date-time", "order": 2 }, - "ip": { - "type": "string", - "title": "IP Address", - "description": "IP Address", - "order": 1 - }, "last_seen": { "type": "string", "title": "GreyNoise Last Seen", "description": "Last Seen By GreyNoise", "order": 3 }, - "metadata": { - "$ref": "#/definitions/metadata", - "title": "GreyNoise Metadata", - "description": "GreyNoise IP Metadata", - "order": 13 - }, - "raw_data": { - "$ref": "#/definitions/raw_data", - "title": "GreyNoise Raw Data", - "description": "GreyNoise IP Raw Data", - "order": 14 - }, "seen": { "type": "boolean", "title": "GreyNoise Seen", "description": "Has this IP been Seen by GreyNoise", "order": 4 }, + "tags": { + "type": "array", + "title": "GreyNoise Tags", + "description": "GreyNoise Tags Associated with IP", + "items": { + "type": "string" + }, + "order": 5 + }, + "actor": { + "type": "string", + "title": "GreyNoise Actor", + "description": "GreyNoise Actor Associated with IP", + "order": 6 + }, "spoofable": { "type": "boolean", "title": "GreyNoise Spoofable", "description": "IP address may be spoofed", "order": 7 }, - "tags": { + "classification": { + "type": "string", + "title": "GreyNoise Classification", + "description": "GreyNoise Classification", + "order": 8 + }, + "cve": { "type": "array", - "title": "GreyNoise Tags", - "description": "GreyNoise Tags Associated with IP", + "title": "GreyNoise CVEs", + "description": "CVEs associated with GreyNoise Tags", "items": { "type": "string" }, - "order": 5 + "order": 9 + }, + "bot": { + "type": "boolean", + "title": "GreyNoise Bot", + "description": "GreyNoise has identified this as a Bot", + "order": 10 }, "vpn": { "type": "boolean", @@ -186,151 +175,18 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "title": "GreyNoise VPN Service", "description": "Name of VPN Service", "order": 12 - } - }, - "definitions": { + }, "metadata": { - "type": "object", - "title": "metadata", - "properties": { - "asn": { - "type": "string", - "title": "ASN", - "description": "ASN", - "order": 1 - }, - "category": { - "type": "string", - "title": "Category", - "description": "Category", - "order": 2 - }, - "city": { - "type": "string", - "title": "City", - "description": "City", - "order": 3 - }, - "country": { - "type": "string", - "title": "Country", - "description": "Country", - "order": 4 - }, - "country_code": { - "type": "string", - "title": "Country Code", - "description": "Country Code", - "order": 5 - }, - "organization": { - "type": "string", - "title": "Organization", - "description": "Organization", - "order": 6 - }, - "os": { - "type": "string", - "title": "OS", - "description": "OS", - "order": 7 - }, - "rdns": { - "type": "string", - "title": "rDNS", - "description": "rDNS", - "order": 8 - }, - "region": { - "type": "string", - "title": "Region", - "description": "Region", - "order": 9 - }, - "tor": { - "type": "boolean", - "title": "TOR", - "description": "TOR", - "order": 10 - } - } + "$ref": "#/definitions/metadata", + "title": "GreyNoise Metadata", + "description": "GreyNoise IP Metadata", + "order": 13 }, "raw_data": { - "type": "object", - "title": "raw_data", - "properties": { - "hassh": { - "type": "array", - "title": "HASSH", - "description": "HASSH", - "items": { - "type": "object" - }, - "order": 1 - }, - "ja3": { - "type": "array", - "title": "JA3", - "description": "Ja3", - "items": { - "type": "object" - }, - "order": 2 - }, - "scan": { - "type": "array", - "title": "Scan", - "description": "Scan", - "items": { - "$ref": "#/definitions/scan" - }, - "order": 3 - }, - "web": { - "type": "object", - "title": "Web", - "description": "Web", - "order": 4 - } - }, - "definitions": { - "scan": { - "type": "object", - "title": "scan", - "properties": { - "port": { - "type": "integer", - "title": "Port", - "description": "Port", - "order": 1 - }, - "protocol": { - "type": "string", - "title": "Protocol", - "description": "Protocol", - "order": 2 - } - } - } - } - }, - "scan": { - "type": "object", - "title": "scan", - "properties": { - "port": { - "type": "integer", - "title": "Port", - "description": "Port", - "order": 1 - }, - "protocol": { - "type": "string", - "title": "Protocol", - "description": "Protocol", - "order": 2 - } - } + "$ref": "#/definitions/raw_data", + "title": "GreyNoise Raw Data", + "description": "GreyNoise IP Raw Data", + "order": 14 } } }, @@ -397,6 +253,48 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "title": "TOR", "description": "TOR", "order": 10 + }, + "sensor_count": { + "type": "integer", + "title": "Sensor Count", + "description": "Count of Sensors that observed traffic from this IP", + "order": 11 + }, + "sensor_hits": { + "type": "integer", + "title": "Sensor Hits", + "description": "Count of Sensor events observed from this IP", + "order": 12 + }, + "destination_countries": { + "type": "array", + "title": "Destination Countries", + "description": "List of countries with GreyNoise sensors that observed this IP", + "items": { + "type": "string" + }, + "order": 13 + }, + "destination_country_codes": { + "type": "array", + "title": "Destination Country Codes", + "description": "List of countries (by code) with GreyNoise sensors that observed this IP", + "items": { + "type": "string" + }, + "order": 14 + }, + "source_country": { + "type": "string", + "title": "Source Country", + "description": "Source country where this IP is located", + "order": 15 + }, + "source_country_code": { + "type": "string", + "title": "Source Country Code", + "description": "Source country (by code) where this IP is located", + "order": 16 } } }, @@ -409,7 +307,7 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "title": "HASSH", "description": "HASSH", "items": { - "type": "object" + "$ref": "#/definitions/hassh" }, "order": 1 }, @@ -418,7 +316,7 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "title": "JA3", "description": "Ja3", "items": { - "type": "object" + "$ref": "#/definitions/ja3" }, "order": 2 }, @@ -432,30 +330,46 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "order": 3 }, "web": { - "type": "object", + "$ref": "#/definitions/web", "title": "Web", "description": "Web", "order": 4 } - }, - "definitions": { - "scan": { - "type": "object", - "title": "scan", - "properties": { - "port": { - "type": "integer", - "title": "Port", - "description": "Port", - "order": 1 - }, - "protocol": { - "type": "string", - "title": "Protocol", - "description": "Protocol", - "order": 2 - } - } + } + }, + "hassh": { + "type": "object", + "title": "hassh", + "properties": { + "port": { + "type": "integer", + "title": "Port", + "description": "Port", + "order": 1 + }, + "fingerprint": { + "type": "string", + "title": "Fingerprint", + "description": "Fingerprint", + "order": 2 + } + } + }, + "ja3": { + "type": "object", + "title": "ja3", + "properties": { + "port": { + "type": "integer", + "title": "Port", + "description": "Port", + "order": 1 + }, + "fingerprint": { + "type": "string", + "title": "Fingerprint", + "description": "Fingerprint", + "order": 2 } } }, @@ -476,6 +390,30 @@ class GnqlQueryOutput(insightconnect_plugin_runtime.Output): "order": 2 } } + }, + "web": { + "type": "object", + "title": "web", + "properties": { + "useragents": { + "type": "array", + "title": "User Agents", + "description": "User Agents", + "items": { + "type": "string" + }, + "order": 1 + }, + "paths": { + "type": "array", + "title": "Web Paths", + "description": "User Agents", + "items": { + "type": "string" + }, + "order": 2 + } + } } } } diff --git a/plugins/greynoise/icon_greynoise/actions/quick_lookup/__init__.py b/plugins/greynoise/icon_greynoise/actions/quick_lookup/__init__.py index a4e3f24b65..7befb31bd2 100755 --- a/plugins/greynoise/icon_greynoise/actions/quick_lookup/__init__.py +++ b/plugins/greynoise/icon_greynoise/actions/quick_lookup/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .action import QuickLookup diff --git a/plugins/greynoise/icon_greynoise/actions/quick_lookup/action.py b/plugins/greynoise/icon_greynoise/actions/quick_lookup/action.py index e0b30e53f4..e8d99ef11f 100755 --- a/plugins/greynoise/icon_greynoise/actions/quick_lookup/action.py +++ b/plugins/greynoise/icon_greynoise/actions/quick_lookup/action.py @@ -1,8 +1,8 @@ import insightconnect_plugin_runtime -from .schema import QuickLookupInput, QuickLookupOutput, Input, Component +from .schema import QuickLookupInput, QuickLookupOutput, Input, Output, Component # Custom imports below -from icon_greynoise.util.util import GNRequestFailure, GNValueError +from insightconnect_plugin_runtime.exceptions import PluginException from greynoise.exceptions import RequestFailure @@ -20,9 +20,22 @@ def run(self, params={}): else: resp_out = {"ip": params.get(Input.IP_ADDRESS), "code": "0x07", "code_message": "Input Not A Valid IP"} - except RequestFailure as e: - raise GNRequestFailure(e.args[0], e.args[1]) - except ValueError as e: - raise GNValueError(e.args[0]) + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) - return resp_out + except ValueError as error: + raise PluginException( + cause=f"Input does not appear to be valid: {Input.IP_ADDRESS}. Error Message: {error.args[0]}", + assistance="Please provide a valid public IPv4 address.", + ) + + return { + Output.IP: resp_out.get("ip"), + Output.CODE: resp_out.get("code"), + Output.NOISE: resp_out.get("noise"), + Output.RIOT: resp_out.get("riot"), + Output.CODE_MESSAGE: resp_out.get("code_message"), + } diff --git a/plugins/greynoise/icon_greynoise/actions/quick_lookup/schema.py b/plugins/greynoise/icon_greynoise/actions/quick_lookup/schema.py index f437edffc0..d5bc7d7cb4 100755 --- a/plugins/greynoise/icon_greynoise/actions/quick_lookup/schema.py +++ b/plugins/greynoise/icon_greynoise/actions/quick_lookup/schema.py @@ -1,4 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import insightconnect_plugin_runtime import json @@ -9,17 +9,18 @@ class Component: class Input: IP_ADDRESS = "ip_address" - + class Output: CODE = "code" CODE_MESSAGE = "code_message" IP = "ip" NOISE = "noise" - + RIOT = "riot" + class QuickLookupInput(insightconnect_plugin_runtime.Input): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -33,7 +34,8 @@ class QuickLookupInput(insightconnect_plugin_runtime.Input): }, "required": [ "ip_address" - ] + ], + "definitions": {} } """) @@ -42,7 +44,7 @@ def __init__(self): class QuickLookupOutput(insightconnect_plugin_runtime.Output): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -51,13 +53,13 @@ class QuickLookupOutput(insightconnect_plugin_runtime.Output): "type": "string", "title": "API Response Code", "description": "Response Code from Quick API endpoint", - "order": 3 + "order": 4 }, "code_message": { "type": "string", "title": "API Response Code Message", "description": "Response Code Message from Quick API endpoint", - "order": 4 + "order": 5 }, "ip": { "type": "string", @@ -70,8 +72,15 @@ class QuickLookupOutput(insightconnect_plugin_runtime.Output): "title": "GreyNoise Noise", "description": "Defines if IP is Internet Noise", "order": 2 + }, + "riot": { + "type": "boolean", + "title": "GreyNoise RIOT", + "description": "Defines if IP is a Common Business Service", + "order": 3 } - } + }, + "definitions": {} } """) diff --git a/plugins/greynoise/icon_greynoise/actions/riot_lookup/__init__.py b/plugins/greynoise/icon_greynoise/actions/riot_lookup/__init__.py index 44b5291e85..1fe778e09a 100755 --- a/plugins/greynoise/icon_greynoise/actions/riot_lookup/__init__.py +++ b/plugins/greynoise/icon_greynoise/actions/riot_lookup/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .action import RiotLookup diff --git a/plugins/greynoise/icon_greynoise/actions/riot_lookup/action.py b/plugins/greynoise/icon_greynoise/actions/riot_lookup/action.py index 201983eba4..89ead17f71 100755 --- a/plugins/greynoise/icon_greynoise/actions/riot_lookup/action.py +++ b/plugins/greynoise/icon_greynoise/actions/riot_lookup/action.py @@ -1,8 +1,8 @@ import insightconnect_plugin_runtime -from .schema import RiotLookupInput, RiotLookupOutput, Input, Component +from .schema import RiotLookupInput, RiotLookupOutput, Input, Output, Component # Custom imports below -from icon_greynoise.util.util import GNRequestFailure, GNValueError +from insightconnect_plugin_runtime.exceptions import PluginException from greynoise.exceptions import RequestFailure @@ -14,13 +14,32 @@ def __init__(self): def run(self, params={}): try: + viz_base_url = "https://viz.greynoise.io/ip/" resp = self.connection.gn_client.riot(params.get(Input.IP_ADDRESS)) if resp["riot"]: resp.pop("logo_url", None) - resp["viz_url"] = "https://viz.greynoise.io/riot/" + str(params.get(Input.IP_ADDRESS)) - except RequestFailure as e: - raise GNRequestFailure(e.args[0], e.args[1]) - except ValueError as e: - raise GNValueError(e.args[0]) + resp["viz_url"] = viz_base_url + str(resp["ip"]) + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) - return resp + except ValueError as error: + raise PluginException( + cause=f"Input does not appear to be valid: {Input.IP_ADDRESS}. Error Message: {error.args[0]}", + assistance="Please provide a valid public IPv4 address.", + ) + + return { + Output.IP: resp.get("ip"), + Output.RIOT: resp.get("riot"), + Output.DESCRIPTION: resp.get("description"), + Output.VIZ_URL: resp.get("viz_url"), + Output.NAME: resp.get("name"), + Output.CATEGORY: resp.get("category"), + Output.EXPLANATION: resp.get("explanation"), + Output.LAST_UPDATED: resp.get("last_updated"), + Output.REFERENCE: resp.get("reference"), + Output.TRUST_LEVEL: resp.get("trust_level"), + } diff --git a/plugins/greynoise/icon_greynoise/actions/riot_lookup/schema.py b/plugins/greynoise/icon_greynoise/actions/riot_lookup/schema.py index 4e788798a6..135272d876 100755 --- a/plugins/greynoise/icon_greynoise/actions/riot_lookup/schema.py +++ b/plugins/greynoise/icon_greynoise/actions/riot_lookup/schema.py @@ -1,4 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import insightconnect_plugin_runtime import json @@ -9,7 +9,7 @@ class Component: class Input: IP_ADDRESS = "ip_address" - + class Output: CATEGORY = "category" @@ -20,11 +20,12 @@ class Output: NAME = "name" REFERENCE = "reference" RIOT = "riot" + TRUST_LEVEL = "trust_level" VIZ_URL = "viz_url" - + class RiotLookupInput(insightconnect_plugin_runtime.Input): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -38,7 +39,8 @@ class RiotLookupInput(insightconnect_plugin_runtime.Input): }, "required": [ "ip_address" - ] + ], + "definitions": {} } """) @@ -47,7 +49,7 @@ def __init__(self): class RiotLookupOutput(insightconnect_plugin_runtime.Output): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -67,7 +69,7 @@ class RiotLookupOutput(insightconnect_plugin_runtime.Output): "explanation": { "type": "string", "title": "GreyNoise RIOT Explanation", - "description": "Explanation for why this is likely benign", + "description": "Explanation for why this is likely a common service", "order": 6 }, "ip": { @@ -78,10 +80,10 @@ class RiotLookupOutput(insightconnect_plugin_runtime.Output): }, "last_updated": { "type": "string", - "title": "GreyNoise RIOT Last Updated", + "format": "date-time", "displayType": "date", + "title": "GreyNoise RIOT Last Updated", "description": "Last time this IP was updated in RIOT dataset", - "format": "date-time", "order": 7 }, "name": { @@ -102,13 +104,20 @@ class RiotLookupOutput(insightconnect_plugin_runtime.Output): "description": "Defines if IP is part of GreyNoise RIOT dataset", "order": 2 }, + "trust_level": { + "type": "string", + "title": "GreyNoise RIOT Trust Level", + "description": "IP Trust Level information", + "order": 9 + }, "viz_url": { "type": "string", "title": "GreyNoise Visualizer Link", "description": "Link to GreyNoise Visualizer for IP Details", - "order": 9 + "order": 10 } - } + }, + "definitions": {} } """) diff --git a/plugins/greynoise/icon_greynoise/actions/similar_lookup/__init__.py b/plugins/greynoise/icon_greynoise/actions/similar_lookup/__init__.py new file mode 100644 index 0000000000..18b46d5fad --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/similar_lookup/__init__.py @@ -0,0 +1,2 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +from .action import SimilarLookup diff --git a/plugins/greynoise/icon_greynoise/actions/similar_lookup/action.py b/plugins/greynoise/icon_greynoise/actions/similar_lookup/action.py new file mode 100644 index 0000000000..bf325eb70f --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/similar_lookup/action.py @@ -0,0 +1,38 @@ +import insightconnect_plugin_runtime +from .schema import SimilarLookupInput, SimilarLookupOutput, Input, Output, Component + +# Custom imports below +from insightconnect_plugin_runtime.exceptions import PluginException +from greynoise.exceptions import RequestFailure + + +class SimilarLookup(insightconnect_plugin_runtime.Action): + def __init__(self): + super(self.__class__, self).__init__( + name="similar_lookup", + description=Component.DESCRIPTION, + input=SimilarLookupInput(), + output=SimilarLookupOutput(), + ) + + def run(self, params={}): + # START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION + ip_address = params.get(Input.IP_ADDRESS) + # END INPUT BINDING - DO NOT REMOVE + + try: + resp = self.connection.gn_client.similar(ip_address) + + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) + + except ValueError as error: + raise PluginException( + cause=f"Input does not appear to be valid: {ip_address}. Error Message: {error.args[0]}", + assistance="Please provide a valid IPv4 Address.", + ) + + return {Output.IP: resp.get("ip"), Output.SIMILAR_IPS: resp.get("similar_ips"), Output.TOTAL: resp.get("total")} diff --git a/plugins/greynoise/icon_greynoise/actions/similar_lookup/schema.py b/plugins/greynoise/icon_greynoise/actions/similar_lookup/schema.py new file mode 100644 index 0000000000..1cae2639ee --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/similar_lookup/schema.py @@ -0,0 +1,225 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import insightconnect_plugin_runtime +import json + + +class Component: + DESCRIPTION = "Query a routable IPv4 address in the GreyNoise for similar IPs" + + +class Input: + IP_ADDRESS = "ip_address" + + +class Output: + IP = "ip" + SIMILAR_IPS = "similar_ips" + TOTAL = "total" + + +class SimilarLookupInput(insightconnect_plugin_runtime.Input): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "ip_address": { + "type": "string", + "title": "IP Address", + "description": "Routable IPv4 address to query", + "order": 1 + } + }, + "required": [ + "ip_address" + ], + "definitions": {} +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) + + +class SimilarLookupOutput(insightconnect_plugin_runtime.Output): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "ip": { + "$ref": "#/definitions/ip_sim", + "title": "IP Similarity Metadata", + "description": "IP Similarity Metadata", + "order": 1 + }, + "similar_ips": { + "type": "array", + "title": "Similar IPs", + "description": "Similar IPs", + "items": { + "$ref": "#/definitions/similar_ip" + }, + "order": 2 + }, + "total": { + "type": "integer", + "title": "Total Number of IPs", + "description": "Total Number of Similar IPs returned", + "order": 3 + } + }, + "definitions": { + "ip_sim": { + "type": "object", + "title": "ip_sim", + "properties": { + "actor": { + "type": "string", + "title": "Actor", + "description": "Actor", + "order": 1 + }, + "asn": { + "type": "string", + "title": "ASN", + "description": "ASN", + "order": 2 + }, + "city": { + "type": "string", + "title": "City", + "description": "City", + "order": 3 + }, + "classification": { + "type": "string", + "title": "Classification", + "description": "Classification", + "order": 4 + }, + "country": { + "type": "string", + "title": "Country", + "description": "Country", + "order": 5 + }, + "country_code": { + "type": "string", + "title": "Country Code", + "description": "Country Code", + "order": 6 + }, + "first_seen": { + "type": "string", + "title": "First Seen", + "description": "First Seen", + "order": 7 + }, + "ip": { + "type": "string", + "title": "IP Address", + "description": "IP Address", + "order": 8 + }, + "last_seen": { + "type": "string", + "title": "Last Seen", + "description": "Last Seen", + "order": 9 + }, + "organization": { + "type": "string", + "title": "Organization", + "description": "Organization", + "order": 10 + } + } + }, + "similar_ip": { + "type": "object", + "title": "similar_ip", + "properties": { + "actor": { + "type": "string", + "title": "Actor", + "description": "Actor", + "order": 1 + }, + "asn": { + "type": "string", + "title": "ASN", + "description": "ASN", + "order": 2 + }, + "city": { + "type": "string", + "title": "City", + "description": "City", + "order": 3 + }, + "classification": { + "type": "string", + "title": "Classification", + "description": "Classification", + "order": 4 + }, + "country": { + "type": "string", + "title": "Country", + "description": "Country", + "order": 5 + }, + "country_code": { + "type": "string", + "title": "Country Code", + "description": "Country Code", + "order": 6 + }, + "features": { + "type": "array", + "title": "Features Matched", + "description": "Features Matched", + "items": { + "type": "string" + }, + "order": 7 + }, + "first_seen": { + "type": "string", + "title": "First Seen", + "description": "First Seen", + "order": 8 + }, + "ip": { + "type": "string", + "title": "IP Address", + "description": "IP Address", + "order": 9 + }, + "last_seen": { + "type": "string", + "title": "Last Seen", + "description": "Last Seen", + "order": 10 + }, + "organization": { + "type": "string", + "title": "Organization", + "description": "Organization", + "order": 11 + }, + "score": { + "type": "number", + "title": "Similarity Score", + "description": "Similarity Score", + "order": 12 + } + } + } + } +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) diff --git a/plugins/greynoise/icon_greynoise/actions/timeline_lookup/__init__.py b/plugins/greynoise/icon_greynoise/actions/timeline_lookup/__init__.py new file mode 100644 index 0000000000..b308fcdd27 --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/timeline_lookup/__init__.py @@ -0,0 +1,2 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +from .action import TimelineLookup diff --git a/plugins/greynoise/icon_greynoise/actions/timeline_lookup/action.py b/plugins/greynoise/icon_greynoise/actions/timeline_lookup/action.py new file mode 100644 index 0000000000..0688882944 --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/timeline_lookup/action.py @@ -0,0 +1,38 @@ +import insightconnect_plugin_runtime +from .schema import TimelineLookupInput, TimelineLookupOutput, Input, Output, Component + +# Custom imports below +from insightconnect_plugin_runtime.exceptions import PluginException +from greynoise.exceptions import RequestFailure + + +class TimelineLookup(insightconnect_plugin_runtime.Action): + def __init__(self): + super(self.__class__, self).__init__( + name="timeline_lookup", + description=Component.DESCRIPTION, + input=TimelineLookupInput(), + output=TimelineLookupOutput(), + ) + + def run(self, params={}): + # START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION + ip_address = params.get(Input.IP_ADDRESS) + # END INPUT BINDING - DO NOT REMOVE + + try: + resp = self.connection.gn_client.timelinedaily(ip_address) + + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) + + except ValueError as error: + raise PluginException( + cause=f"Input does not appear to be valid: {ip_address}. Error Message: {error.args[0]}", + assistance="Please provide a valid IPv4 Address.", + ) + + return {Output.IP: resp.get("ip"), Output.ACTIVITY: resp.get("activity"), Output.METADATA: resp.get("metadata")} diff --git a/plugins/greynoise/icon_greynoise/actions/timeline_lookup/schema.py b/plugins/greynoise/icon_greynoise/actions/timeline_lookup/schema.py new file mode 100644 index 0000000000..c7475f5e37 --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/timeline_lookup/schema.py @@ -0,0 +1,345 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import insightconnect_plugin_runtime +import json + + +class Component: + DESCRIPTION = "Query a routable IPv4 address in the GreyNoise for Scanner Daily Timeline details" + + +class Input: + IP_ADDRESS = "ip_address" + + +class Output: + ACTIVITY = "activity" + IP = "ip" + METADATA = "metadata" + + +class TimelineLookupInput(insightconnect_plugin_runtime.Input): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "ip_address": { + "type": "string", + "title": "IP Address", + "description": "Routable IPv4 address to query", + "order": 1 + } + }, + "required": [ + "ip_address" + ], + "definitions": {} +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) + + +class TimelineLookupOutput(insightconnect_plugin_runtime.Output): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "activity": { + "type": "array", + "title": "IP Timeline Activity", + "description": "IP Timeline Activity Events", + "items": { + "$ref": "#/definitions/timeline_activity" + }, + "order": 3 + }, + "ip": { + "type": "string", + "title": "IP Queried", + "description": "Value that was Queried", + "order": 1 + }, + "metadata": { + "$ref": "#/definitions/timeline_metadata", + "title": "IP Timeline Metadata", + "description": "IP Timeline Metadata", + "order": 2 + } + }, + "definitions": { + "timeline_metadata": { + "type": "object", + "title": "timeline_metadata", + "properties": { + "end_time": { + "type": "string", + "format": "date-time", + "displayType": "date", + "title": "Timeline Period End Time", + "description": "Timeline Period End Time", + "order": 1 + }, + "ip": { + "type": "string", + "title": "IP Address", + "description": "IP Queried", + "order": 2 + }, + "limit": { + "type": "integer", + "title": "Event Limit", + "description": "Max number of events to return", + "order": 3 + }, + "next_cursor": { + "type": "string", + "title": "Cursor Value", + "description": "Cursor value for additional pages of details", + "order": 4 + }, + "start_time": { + "type": "string", + "format": "date-time", + "displayType": "date", + "title": "Timeline Period Start Time", + "description": "Timeline Period Start Time", + "order": 5 + } + } + }, + "timeline_activity": { + "type": "object", + "title": "timeline_activity", + "properties": { + "asn": { + "type": "string", + "title": "ASN", + "description": "ASN", + "order": 1 + }, + "category": { + "type": "string", + "title": "Category", + "description": "Category", + "order": 2 + }, + "city": { + "type": "string", + "title": "City", + "description": "City", + "order": 3 + }, + "classification": { + "type": "string", + "title": "GreyNoise Classification", + "description": "GreyNoise Classification", + "order": 4 + }, + "country": { + "type": "string", + "title": "Country", + "description": "Country", + "order": 5 + }, + "country_code": { + "type": "string", + "title": "Country Code", + "description": "Country Code", + "order": 6 + }, + "destinations": { + "type": "array", + "title": "Destinations", + "description": "Destinations", + "items": { + "$ref": "#/definitions/destinations" + }, + "order": 7 + }, + "hassh_fingerprints": { + "type": "array", + "title": "HASSH Fingerprints", + "description": "HASSH Fingerprints", + "items": { + "type": "string" + }, + "order": 8 + }, + "http_paths": { + "type": "array", + "title": "HTTP Web Paths", + "description": "HTTP Web Paths", + "items": { + "type": "string" + }, + "order": 9 + }, + "http_user_agents": { + "type": "array", + "title": "HTTP User Agents", + "description": "HTTP User Agents", + "items": { + "type": "string" + }, + "order": 10 + }, + "ja3_fingerprints": { + "type": "array", + "title": "JA3 Fingerprints", + "description": "JA3 Fingerprints", + "items": { + "type": "string" + }, + "order": 11 + }, + "organization": { + "type": "string", + "title": "Organization", + "description": "Organization", + "order": 12 + }, + "protocols": { + "type": "array", + "title": "Protocols", + "description": "Destinations", + "items": { + "$ref": "#/definitions/protocols" + }, + "order": 13 + }, + "rdns": { + "type": "string", + "title": "rDNS", + "description": "rDNS", + "order": 14 + }, + "region": { + "type": "string", + "title": "Region", + "description": "Region", + "order": 15 + }, + "spoofable": { + "type": "boolean", + "title": "Spoofable", + "description": "Spoofable", + "order": 16 + }, + "tags": { + "type": "array", + "title": "Tags", + "description": "Tags", + "items": { + "$ref": "#/definitions/tags" + }, + "order": 17 + }, + "timestamp": { + "type": "string", + "format": "date-time", + "displayType": "date", + "title": "Event Timestamp", + "description": "Event Timestamp", + "order": 18 + }, + "tor": { + "type": "boolean", + "title": "Tor Exit Node", + "description": "Tor Exit Node", + "order": 19 + }, + "vpn": { + "type": "boolean", + "title": "VPN", + "description": "VPN", + "order": 20 + }, + "vpn_service": { + "type": "string", + "title": "VPN Service", + "description": "VPN Service", + "order": 21 + } + } + }, + "destinations": { + "type": "object", + "title": "destinations", + "properties": { + "country": { + "type": "string", + "title": "Country", + "description": "Country", + "order": 1 + }, + "country_code": { + "type": "string", + "title": "Country Code", + "description": "Country Code", + "order": 2 + } + } + }, + "protocols": { + "type": "object", + "title": "protocols", + "properties": { + "port": { + "type": "integer", + "title": "Port", + "description": "Port", + "order": 1 + }, + "transport_protocol": { + "type": "string", + "title": "Transport Protocol", + "description": "Transport Protocol", + "order": 2 + }, + "app_protocol": { + "type": "string", + "title": "App Protocol", + "description": "App Protocol", + "order": 3 + } + } + }, + "tags": { + "type": "object", + "title": "tags", + "properties": { + "category": { + "type": "string", + "title": "Tag Category", + "description": "Tag Category", + "order": 1 + }, + "description": { + "type": "string", + "title": "Tag Description", + "description": "Tag Description", + "order": 2 + }, + "intention": { + "type": "string", + "title": "Tag Intention", + "description": "Tag Intention", + "order": 3 + }, + "name": { + "type": "string", + "title": "Tag Name", + "description": "Tag Name", + "order": 4 + } + } + } + } +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) diff --git a/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/__init__.py b/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/__init__.py new file mode 100644 index 0000000000..c96a6cb8ba --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/__init__.py @@ -0,0 +1,2 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +from .action import VulnerabilityLookup diff --git a/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/action.py b/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/action.py new file mode 100644 index 0000000000..5bb6d125ca --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/action.py @@ -0,0 +1,45 @@ +import insightconnect_plugin_runtime +from .schema import VulnerabilityLookupInput, VulnerabilityLookupOutput, Input, Output, Component + +# Custom imports below +from insightconnect_plugin_runtime.exceptions import PluginException +from greynoise.exceptions import RequestFailure + + +class VulnerabilityLookup(insightconnect_plugin_runtime.Action): + def __init__(self): + super(self.__class__, self).__init__( + name="vulnerability_lookup", + description=Component.DESCRIPTION, + input=VulnerabilityLookupInput(), + output=VulnerabilityLookupOutput(), + ) + + def run(self, params={}): + # START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION + cve_id = params.get(Input.CVE_ID) + # END INPUT BINDING - DO NOT REMOVE + + try: + resp = self.connection.gn_client.cve(cve_id) + + except RequestFailure as error: + raise PluginException( + cause=f"API responded with ERROR: {error.args[0]} - {error.args[1]}.", + assistance="Please check error and try again.", + ) + + except ValueError as error: + raise PluginException( + cause=f"Input does not appear to be valid: {cve_id}. Error Message: {error.args[0]}", + assistance="Please provide a valid CVE ID.", + ) + + return { + Output.DETAILS: resp.get("details"), + Output.ID: resp.get("id"), + Output.TIMELINE: resp.get("timeline"), + Output.EXPLOITATION_STATS: resp.get("exploitation_stats"), + Output.EXPLOITATION_DETAILS: resp.get("exploitation_details"), + Output.EXPLOITATION_ACTIVITY: resp.get("exploitation_activity"), + } diff --git a/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/schema.py b/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/schema.py new file mode 100755 index 0000000000..1693d1b4b9 --- /dev/null +++ b/plugins/greynoise/icon_greynoise/actions/vulnerability_lookup/schema.py @@ -0,0 +1,270 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import insightconnect_plugin_runtime +import json + + +class Component: + DESCRIPTION = "Check GreyNoise for Vulnerability information" + + +class Input: + CVE_ID = "cve_id" + + +class Output: + DETAILS = "details" + EXPLOITATION_ACTIVITY = "exploitation_activity" + EXPLOITATION_DETAILS = "exploitation_details" + EXPLOITATION_STATS = "exploitation_stats" + ID = "id" + TIMELINE = "timeline" + + +class VulnerabilityLookupInput(insightconnect_plugin_runtime.Input): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "cve_id": { + "type": "string", + "title": "CVE ID", + "description": "A CVE ID to look up in GreyNoise", + "order": 1 + } + }, + "required": [ + "cve_id" + ], + "definitions": {} +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) + + +class VulnerabilityLookupOutput(insightconnect_plugin_runtime.Output): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "details": { + "$ref": "#/definitions/vuln_details", + "title": "GreyNoise Vulnerability Details", + "description": "GreyNoise Vulnerability Details", + "order": 2 + }, + "exploitation_activity": { + "$ref": "#/definitions/vuln_exploitation_activity", + "title": "GreyNoise Vulnerability Exploitation Activity", + "description": "GreyNoise Vulnerability Exploitation Activity", + "order": 3 + }, + "exploitation_details": { + "$ref": "#/definitions/vuln_exploitation_details", + "title": "GreyNoise Vulnerability Exploitation Details", + "description": "GreyNoise Vulnerability Exploitation Details", + "order": 4 + }, + "exploitation_stats": { + "$ref": "#/definitions/vuln_exploitation_stats", + "title": "GreyNoise Vulnerability Exploitation Stats", + "description": "GreyNoise Vulnerability Exploitation Stats", + "order": 5 + }, + "id": { + "type": "string", + "title": "CVE ID", + "description": "Value that was searched", + "order": 1 + }, + "timeline": { + "$ref": "#/definitions/vuln_timeline", + "title": "GreyNoise Vulnerability Timeline", + "description": "GreyNoise Vulnerability Timeline", + "order": 6 + } + }, + "definitions": { + "vuln_details": { + "type": "object", + "title": "vuln_details", + "properties": { + "cve_cvss_score": { + "type": "number", + "title": "CVE CVSS Score", + "description": "CVE CVSS Score", + "order": 1 + }, + "product": { + "type": "string", + "title": "Product Name", + "description": "Product Name", + "order": 2 + }, + "published_to_nist_nvd": { + "type": "boolean", + "title": "Is CVE Published in NIST NVD", + "description": "Is CVE Published in NIST NVD", + "order": 3 + }, + "vendor": { + "type": "string", + "title": "Vendor Name", + "description": "Vendor Name", + "order": 4 + }, + "vulnerability_description": { + "type": "string", + "title": "Vulnerability Description", + "description": "Vulnerability Description", + "order": 5 + }, + "vulnerability_name": { + "type": "string", + "title": "Vulnerability Name", + "description": "Vulnerability Name", + "order": 6 + } + } + }, + "vuln_exploitation_activity": { + "type": "object", + "title": "vuln_exploitation_activity", + "properties": { + "activity_seen": { + "type": "boolean", + "title": "GreyNoise Observed Activity", + "description": "GreyNoise Observed Activity", + "order": 1 + }, + "benign_ip_count_10d": { + "type": "integer", + "title": "Benign IP Count - 10 days", + "description": "Benign IP Count - 10 days", + "order": 2 + }, + "benign_ip_count_1d": { + "type": "integer", + "title": "Benign IP Count - 1 day", + "description": "Benign IP Count - 1 day", + "order": 3 + }, + "benign_ip_count_30d": { + "type": "integer", + "title": "Benign IP Count - 30 days", + "description": "Benign IP Count - 30 days", + "order": 4 + }, + "threat_ip_count_10d": { + "type": "integer", + "title": "Threat IP Count - 10 days", + "description": "Threat IP Count - 10 days", + "order": 5 + }, + "threat_ip_count_1d": { + "type": "integer", + "title": "Threat IP Count - 1 day", + "description": "Threat IP Count - 1 day", + "order": 6 + }, + "threat_ip_count_30d": { + "type": "integer", + "title": "Threat IP Count - 30 days", + "description": "Threat IP Count - 30 days", + "order": 7 + } + } + }, + "vuln_exploitation_details": { + "type": "object", + "title": "vuln_exploitation_details", + "properties": { + "attack_vector": { + "type": "string", + "title": "Attack Vector", + "description": "Attack Vector", + "order": 1 + }, + "epss_score": { + "type": "number", + "title": "EPSS Score", + "description": "EPSS Score", + "order": 2 + }, + "exploit_found": { + "type": "boolean", + "title": "Exploit Found", + "description": "Exploit Found", + "order": 3 + }, + "exploitation_registered_in_kev": { + "type": "boolean", + "title": "Exploitation Registered in KEV", + "description": "Exploitation Registered in KEV", + "order": 4 + } + } + }, + "vuln_exploitation_stats": { + "type": "object", + "title": "vuln_exploitation_stats", + "properties": { + "number_of_available_exploits": { + "type": "integer", + "title": "Number of Available Exploits", + "description": "Number of Available Exploits", + "order": 1 + }, + "number_of_botnets_exploiting_vulnerability": { + "type": "integer", + "title": "Number of Associated Botnets", + "description": "Number of Associated Botnets", + "order": 2 + }, + "number_of_threat_actors_exploiting_vulnerability": { + "type": "integer", + "title": "Number of Threat Actors Exploiting Vulnerability", + "description": "Number of Threat Actors Exploiting Vulnerability", + "order": 3 + } + } + }, + "vuln_timeline": { + "type": "object", + "title": "vuln_timeline", + "properties": { + "cisa_kev_date_added": { + "type": "string", + "title": "Date Added to CISA KEV", + "description": "Date Added to CISA KEV", + "order": 1 + }, + "cve_last_updated_date": { + "type": "string", + "title": "Date CVE was Last Updated", + "description": "Date CVE was Last Updated", + "order": 2 + }, + "cve_published_date": { + "type": "string", + "title": "Date CVE was Published", + "description": "Date CVE was Published", + "order": 3 + }, + "first_known_published_date": { + "type": "string", + "title": "Date of First Published POC", + "description": "Date of First Published POC", + "order": 4 + } + } + } + } +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) diff --git a/plugins/greynoise/icon_greynoise/connection/__init__.py b/plugins/greynoise/icon_greynoise/connection/__init__.py index a515dcf6b0..c78d3356be 100755 --- a/plugins/greynoise/icon_greynoise/connection/__init__.py +++ b/plugins/greynoise/icon_greynoise/connection/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .connection import Connection diff --git a/plugins/greynoise/icon_greynoise/connection/connection.py b/plugins/greynoise/icon_greynoise/connection/connection.py index 02585e3d1e..0ea3756d23 100755 --- a/plugins/greynoise/icon_greynoise/connection/connection.py +++ b/plugins/greynoise/icon_greynoise/connection/connection.py @@ -27,12 +27,12 @@ def test(self): try: resp = self.gn_client.test_connection() - except RequestFailure as e: - if e.args[0] == 401: - raise ConnectionTestException(preset=ConnectionTestException.Preset.API_KEY, data=e.args[1]) - elif e.args[0] == 429: - raise ConnectionTestException(preset=ConnectionTestException.Preset.RATE_LIMIT, data=e.args[1]) - elif e.args[0] == 500: - raise ConnectionTestException(preset=ConnectionTestException.Preset.SERVER_ERROR, data=e.args[1]) + except RequestFailure as error: + if error.args[0] == 401: + raise ConnectionTestException(preset=ConnectionTestException.Preset.API_KEY, data=error.args[1]) + elif error.args[0] == 429: + raise ConnectionTestException(preset=ConnectionTestException.Preset.RATE_LIMIT, data=error.args[1]) + elif error.args[0] == 500: + raise ConnectionTestException(preset=ConnectionTestException.Preset.SERVER_ERROR, data=error.args[1]) return resp diff --git a/plugins/greynoise/icon_greynoise/connection/schema.py b/plugins/greynoise/icon_greynoise/connection/schema.py index 55cd591603..c71f5d381c 100755 --- a/plugins/greynoise/icon_greynoise/connection/schema.py +++ b/plugins/greynoise/icon_greynoise/connection/schema.py @@ -1,14 +1,14 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT import insightconnect_plugin_runtime import json class Input: CREDENTIALS = "credentials" - + class ConnectionSchema(insightconnect_plugin_runtime.Input): - schema = json.loads(""" + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -29,18 +29,18 @@ class ConnectionSchema(insightconnect_plugin_runtime.Input): "type": "object", "title": "Credential: Secret Key", "description": "A shared secret key", + "required": [ + "secretKey" + ], "properties": { "secretKey": { "type": "string", "title": "Secret Key", - "displayType": "password", "description": "The shared secret key", - "format": "password" + "format": "password", + "displayType": "password" } - }, - "required": [ - "secretKey" - ] + } } } } diff --git a/plugins/greynoise/icon_greynoise/tasks/__init__.py b/plugins/greynoise/icon_greynoise/tasks/__init__.py new file mode 100644 index 0000000000..7020c9a4ad --- /dev/null +++ b/plugins/greynoise/icon_greynoise/tasks/__init__.py @@ -0,0 +1,2 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT + diff --git a/plugins/greynoise/icon_greynoise/triggers/__init__.py b/plugins/greynoise/icon_greynoise/triggers/__init__.py index bace8db897..05f770bf45 100755 --- a/plugins/greynoise/icon_greynoise/triggers/__init__.py +++ b/plugins/greynoise/icon_greynoise/triggers/__init__.py @@ -1 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT + +from .monitor_ips_in_greynoise.trigger import MonitorIpsInGreynoise + diff --git a/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/__init__.py b/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/__init__.py new file mode 100755 index 0000000000..5bdf778d3f --- /dev/null +++ b/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/__init__.py @@ -0,0 +1,2 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +from .trigger import MonitorIpsInGreynoise diff --git a/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/schema.py b/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/schema.py new file mode 100644 index 0000000000..b50b3dce9c --- /dev/null +++ b/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/schema.py @@ -0,0 +1,84 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import insightconnect_plugin_runtime +import json + + +class Component: + DESCRIPTION = "Query a list of IPs in GreyNoise based on IP List every interval to identify if any of them are actively scanning the internet" + + +class Input: + INTERVAL = "interval" + IP_LIST = "ip_list" + LOOKBACK_DAYS = "lookback_days" + + +class Output: + ALERT_IP_LIST = "alert_ip_list" + + +class MonitorIpsInGreynoiseInput(insightconnect_plugin_runtime.Input): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "interval": { + "type": "integer", + "title": "Interval", + "description": "How frequently (in seconds) to trigger a greeting", + "default": 3600, + "order": 1 + }, + "ip_list": { + "type": "array", + "title": "List of IPs to Monitor", + "description": "List of IP Addresses or CIDR blocks to check for scanning activity", + "items": { + "type": "string" + }, + "order": 2 + }, + "lookback_days": { + "type": "integer", + "title": "Number of Days", + "description": "Number of Days to look back for scanning activity. Recommended \"1\", Max \"90\"", + "default": 1, + "order": 3 + } + }, + "required": [ + "interval", + "ip_list", + "lookback_days" + ], + "definitions": {} +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) + + +class MonitorIpsInGreynoiseOutput(insightconnect_plugin_runtime.Output): + schema = json.loads(r""" + { + "type": "object", + "title": "Variables", + "properties": { + "alert_ip_list": { + "type": "array", + "title": "List of IPs Found Scanning", + "description": "The list of IPs that were found scanning", + "items": { + "type": "string" + }, + "order": 1 + } + }, + "definitions": {} +} + """) + + def __init__(self): + super(self.__class__, self).__init__(self.schema) diff --git a/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/trigger.py b/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/trigger.py new file mode 100644 index 0000000000..a27133f609 --- /dev/null +++ b/plugins/greynoise/icon_greynoise/triggers/monitor_ips_in_greynoise/trigger.py @@ -0,0 +1,47 @@ +import insightconnect_plugin_runtime +import time +from .schema import MonitorIpsInGreynoiseInput, MonitorIpsInGreynoiseOutput, Input, Output, Component + +# Custom imports below + +from insightconnect_plugin_runtime.exceptions import PluginException + + +class MonitorIpsInGreynoise(insightconnect_plugin_runtime.Trigger): + def __init__(self): + super(self.__class__, self).__init__( + name="monitor_ips_in_greynoise", + description=Component.DESCRIPTION, + input=MonitorIpsInGreynoiseInput(), + output=MonitorIpsInGreynoiseOutput(), + ) + + def run(self, params={}): + # START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION + interval = params.get(Input.INTERVAL) + ip_list = params.get(Input.IP_LIST) + lookback_days = params.get(Input.LOOKBACK_DAYS) + # END INPUT BINDING - DO NOT REMOVE + + self.logger.info("Loading GreyNoise Alert Trigger") + while True: + try: + query = f"({' OR '.join(ip_list)}) last_seen:{lookback_days}d" + + self.logger.info("Checking GreyNoise for IP list") + response = self.connection.gn_client.query(query) + + if response.get("count", 0) != 0: + self.logger.info("IPs found in GreyNoise") + alert_ip_list = [item["ip"] for item in response["data"]] + self.send( + { + Output.ALERT_IP_LIST: alert_ip_list, + } + ) + except Exception as error: + raise PluginException( + cause=f"Plugin exception occurred: {error}", + assistance="Please check the input and try again.", + ) + time.sleep(interval) diff --git a/plugins/greynoise/icon_greynoise/util/__init__.py b/plugins/greynoise/icon_greynoise/util/__init__.py old mode 100755 new mode 100644 index bace8db897..797e426edf --- a/plugins/greynoise/icon_greynoise/util/__init__.py +++ b/plugins/greynoise/icon_greynoise/util/__init__.py @@ -1 +1 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT diff --git a/plugins/greynoise/icon_greynoise/util/util.py b/plugins/greynoise/icon_greynoise/util/util.py deleted file mode 100644 index ecb54dc306..0000000000 --- a/plugins/greynoise/icon_greynoise/util/util.py +++ /dev/null @@ -1,24 +0,0 @@ -from insightconnect_plugin_runtime.exceptions import PluginException - - -class GNRequestFailure(Exception): - def __init__(self, status_code, message): - self.status_code = status_code - self.message = message["message"] - - raise PluginException( - cause="Received HTTP %d status code from GreyNoise. Verify your input and try again." % self.status_code, - assistance="If the issue persists please contact GreyNoise support.", - data=f"{self.status_code}, {self.message}", - ) - - -class GNValueError(Exception): - def __init__(self, message): - self.message = message - - raise PluginException( - cause="Received HTTP 404 status code from GreyNoise." "Input provided was not found, please try another.", - assistance="If the issue persists please contact GreyNoise support.", - data=f"{self.message}", - ) diff --git a/plugins/greynoise/plugin.spec.yaml b/plugins/greynoise/plugin.spec.yaml index 05bc466121..c18b6efd42 100644 --- a/plugins/greynoise/plugin.spec.yaml +++ b/plugins/greynoise/plugin.spec.yaml @@ -3,24 +3,50 @@ extension: plugin products: [insightconnect] name: greynoise title: GreyNoise +description: GreyNoise helps analysts recognize events not worth their attention. Indicators in GreyNoise are likely associated with opportunistic internet scanning or common business services, not targeted threats. This context helps analysts focus on what matters most +version: 2.0.0 +connection_version: 2 +cloud_ready: true +sdk: + type: slim + version: 6.2.2 + user: nobody +supported_versions: ["GreyNoise API v1/2/3"] vendor: greynoise -support: partner status: [] -description: GreyNoise helps analysts recognize events not worth their attention. Indicators in GreyNoise are likely associated with opportunistic internet scanning or common business services, not targeted threats. This context helps analysts focus on what matters most -version: 1.0.1 +tags: [greynoise, ip lookup, threat intel, intelligence] +support: partner resources: source_url: https://github.com/rapid7/insightconnect-plugins/tree/master/plugins/greynoise license_url: https://github.com/rapid7/insightconnect-plugins/blob/master/LICENSE vendor_url: https://greynoise.io -tags: - - greynoise - - ip - - threat intel - - intelligence hub_tags: - use_cases: [data_enrichment, threat_detection_and_response] - keywords: [ip, intelligence, greynoise] + use_cases: [data_enrichment, threat_detection_and_response,vulnerability_management] + keywords: [ip lookup, intelligence, greynoise] features: [] +requirements: + - "A GreyNoise API key" +key_features: + - "Perform a GreyNoise IP Context Lookup" + - "Perform a GreyNoise IP Quick Lookup" + - "Perform a GreyNoise IP RIOT Lookup" + - "Query for additional Tag details" + - "Perform a GreyNoise Community IP Lookup" + - "Perform a GreyNoise Vulnerability Lookup" + - "Perform a GreyNoise IP Timeline Lookup" + - "Perform a GreyNoise IP Similarity Lookup" + - "Query a list of IPs on a Trigger" +troubleshooting: "Ensure that the GreyNoise API key used has appropriate access for the actions being used." +version_history: + - "2.0.0 - Upgrade GreyNoise SDK v2.3.0 | Fix Action Outputs | New actions:`vulnerability_lookup`, `timeline_lookup`, `similar_lookup` | New trigger: `greynoise_alert`" + - "1.0.1 - Fix bug with connection parameters" + - "1.0.0 - Initial plugin." +links: + - "[GreyNoise](https://greynoise.io)" +references: + - "[GreyNoise Documentation](https://docs.greynoise.io)" + - "[GreyNoise Free Trial Signup](https://viz.greynoise.io/signup)" + - "[GreyNoise Account Info](https://viz.greynoise.io/account)" enable_cache: false types: metadata: @@ -29,71 +55,158 @@ types: type: string description: ASN required: false + example: "AS12345" category: title: Category type: string description: Category required: false + example: "isp" city: title: City type: string description: City required: false + example: "Reno" country: title: Country type: string description: Country required: false + example: "Brazil" country_code: title: Country Code type: string description: Country Code required: false + example: "BZ" organization: title: Organization type: string description: Organization required: false + example: "Acme Inc." os: title: OS type: string description: OS required: false + example: "Windows XP" rdns: title: rDNS type: string description: rDNS required: false + example: "scanner.example.io" region: title: Region type: string description: Region required: false + example: "Arizona" tor: title: TOR type: boolean description: TOR required: false + example: false + sensor_count: + title: Sensor Count + type: integer + description: Count of Sensors that observed traffic from this IP + required: false + example: 5 + sensor_hits: + title: Sensor Hits + type: integer + description: Count of Sensor events observed from this IP + required: false + example: 5 + destination_countries: + title: Destination Countries + type: "[]string" + description: List of countries with GreyNoise sensors that observed this IP + required: false + example: ["Brazil","Spain"] + destination_country_codes: + title: Destination Country Codes + type: "[]string" + description: List of countries (by code) with GreyNoise sensors that observed this IP + required: false + example: ["BZ","ES"] + source_country: + title: Source Country + type: string + description: Source country where this IP is located + required: false + example: "Brazil" + source_country_code: + title: Source Country Code + type: string + description: Source country (by code) where this IP is located + required: false + example: "BE" + web: + useragents: + title: "User Agents" + type: "[]string" + description: "User Agents" + required: false + example: ["user-agent"] + paths: + title: "Web Paths" + type: "[]string" + description: "User Agents" + required: false + example: ["/","/robots.txt"] scan: port: title: "Port" type: integer description: "Port" required: false + example: 22 protocol: title: "Protocol" type: string description: "Protocol" required: false + example: "TCP" + hassh: + port: + title: "Port" + type: integer + description: "Port" + required: false + example: 22 + fingerprint: + title: "Fingerprint" + type: string + description: "Fingerprint" + required: false + example: "abcdefg1234567" + ja3: + port: + title: "Port" + type: integer + description: "Port" + required: false + example: 22 + fingerprint: + title: "Fingerprint" + type: string + description: "Fingerprint" + required: false + example: "abcdefg1234567" raw_data: hassh: title: "HASSH" - type: "[]object" + type: "[]hassh" description: "HASSH" required: false ja3: title: "JA3" - type: "[]object" + type: "[]ja3" description: "Ja3" required: false scan: @@ -103,7 +216,7 @@ types: required: false web: title: "Web" - type: object + type: web description: "Web" required: false data: @@ -112,71 +225,580 @@ types: type: string description: IP Address required: false + example: "1.2.4.5" first_seen: title: GreyNoise First Seen type: date description: First Seen By GreyNoise required: false + example: "2024-01-01" last_seen: title: GreyNoise Last Seen type: string description: Last Seen By GreyNoise required: false + example: "2024-01-01" seen: title: GreyNoise Seen type: boolean description: Has this IP been Seen by GreyNoise required: false + example: false tags: title: GreyNoise Tags type: "[]string" description: GreyNoise Tags Associated with IP required: false + example: ["tag1","tag2"] actor: title: GreyNoise Actor type: string description: GreyNoise Actor Associated with IP required: false + example: "Actor Name" spoofable: title: GreyNoise Spoofable type: boolean description: IP address may be spoofed required: false + example: false classification: title: GreyNoise Classification type: string description: GreyNoise Classification required: false + example: "benign" cve: title: GreyNoise CVEs type: "[]string" description: CVEs associated with GreyNoise Tags required: false + example: "CVE-1234-12345" bot: title: GreyNoise Bot type: boolean description: GreyNoise has identified this as a Bot required: false + example: false vpn: title: GreyNoise VPN type: boolean description: GreyNoise has identified this as a VPN required: false + example: false vpn_service: title: GreyNoise VPN Service type: string description: Name of VPN Service required: false + example: "VPN Name" metadata: title: GreyNoise Metadata type: metadata description: GreyNoise IP Metadata required: false + example: {"ASN": "AS12345","Category": "isp","City": "Reno","Country": "Brazil","Country Code": "BZ","Destination Countries": ["Brazil","Spain"],"Destination Country Codes": ["BZ","ES"],"Organization": "Acme Inc.","OS": "Windows XP","rDNS": "scanner.example.io","Region": "Arizona","Sensor Count": 5,"Sensor Hits": 5,"Source Country": "Brazil","Source Country Code": "BE","TOR": false} raw_data: title: GreyNoise Raw Data type: raw_data description: GreyNoise IP Raw Data required: false + example: {"HASSH": [{"Fingerprint": "abcdefg1234567","Port": 22}],"JA3": [{"Fingerprint": "abcdefg1234567","Port": 22}],"Scan": [{"Port": 22,"Protocol": "TCP"}],"Web": {"Web Paths": ["/","/robots.txt"],"User Agents": ["user-agent"]}} + vuln_timeline: + cisa_kev_date_added: + title: "Date Added to CISA KEV" + type: string + description: "Date Added to CISA KEV" + required: false + example: "2020-07-08T17:15:10Z" + cve_last_updated_date: + title: "Date CVE was Last Updated" + type: string + description: "Date CVE was Last Updated" + required: false + example: "2020-07-08T17:15:10Z" + cve_published_date: + title: "Date CVE was Published" + type: string + description: "Date CVE was Published" + required: false + example: "2020-07-08T17:15:10Z" + first_known_published_date: + title: "Date of First Published POC" + type: string + description: "Date of First Published POC" + required: false + example: "2020-07-08T17:15:10Z" + vuln_exploitation_stats: + number_of_available_exploits: + title: "Number of Available Exploits" + type: integer + description: "Number of Available Exploits" + required: false + example: 1 + number_of_botnets_exploiting_vulnerability: + title: "Number of Associated Botnets" + type: integer + description: "Number of Associated Botnets" + required: false + example: 1 + number_of_threat_actors_exploiting_vulnerability: + title: "Number of Threat Actors Exploiting Vulnerability" + type: integer + description: "Number of Threat Actors Exploiting Vulnerability" + required: false + example: 1 + vuln_exploitation_details: + attack_vector: + title: "Attack Vector" + type: string + description: "Attack Vector" + required: false + example: "NETWORK" + epss_score: + title: "EPSS Score" + type: float + description: "EPSS Score" + required: false + example: 0.0 + exploit_found: + title: "Exploit Found" + type: boolean + description: "Exploit Found" + required: false + example: false + exploitation_registered_in_kev: + title: "Exploitation Registered in KEV" + type: boolean + description: "Exploitation Registered in KEV" + required: false + example: false + vuln_exploitation_activity: + activity_seen: + title: "GreyNoise Observed Activity" + type: boolean + description: "GreyNoise Observed Activity" + required: false + example: true + benign_ip_count_10d: + title: "Benign IP Count - 10 days" + type: integer + description: "Benign IP Count - 10 days" + required: false + example: 5 + benign_ip_count_1d: + title: "Benign IP Count - 1 day" + type: integer + description: "Benign IP Count - 1 day" + required: false + example: 5 + benign_ip_count_30d: + title: "Benign IP Count - 30 days" + type: integer + description: "Benign IP Count - 30 days" + required: false + example: 5 + threat_ip_count_10d: + title: "Threat IP Count - 10 days" + type: integer + description: "Threat IP Count - 10 days" + required: false + example: 5 + threat_ip_count_1d: + title: "Threat IP Count - 1 day" + type: integer + description: "Threat IP Count - 1 day" + required: false + example: 5 + threat_ip_count_30d: + title: "Threat IP Count - 30 days" + type: integer + description: "Threat IP Count - 30 days" + required: false + example: 5 + vuln_details: + cve_cvss_score: + title: "CVE CVSS Score" + type: float + description: "CVE CVSS Score" + required: false + example: 9.8 + product: + title: "Product Name" + type: string + description: "Product Name" + required: false + example: "Product Name" + published_to_nist_nvd: + title: "Is CVE Published in NIST NVD" + type: boolean + description: "Is CVE Published in NIST NVD" + required: false + example: false + vendor: + title: "Vendor Name" + type: string + description: "Vendor Name" + required: false + example: "Acme Inc" + vulnerability_description: + title: "Vulnerability Description" + type: string + description: "Vulnerability Description" + required: false + example: "This is a product description." + vulnerability_name: + title: "Vulnerability Name" + type: string + description: "Vulnerability Name" + required: false + example: "This is a vuln name." + timeline_metadata: + end_time: + title: "Timeline Period End Time" + type: date + description: "Timeline Period End Time" + required: false + example: "2020-07-08T17:15:10Z" + ip: + title: "IP Address" + type: string + description: "IP Queried" + required: false + example: "1.2.3.4" + limit: + title: "Event Limit" + type: integer + description: "Max number of events to return" + required: false + example: 5 + next_cursor: + title: "Cursor Value" + type: string + description: "Cursor value for additional pages of details" + required: false + example: "asdf142qas3241asdf234sfa" + start_time: + title: "Timeline Period Start Time" + type: date + description: "Timeline Period Start Time" + required: false + example: "2020-07-08T17:15:10Z" + timeline_activity: + asn: + title: ASN + type: string + description: ASN + required: false + example: "AS12345" + category: + title: Category + type: string + description: Category + required: false + example: "isp" + city: + title: City + type: string + description: City + required: false + example: "Seattle" + classification: + title: GreyNoise Classification + type: string + description: GreyNoise Classification + required: false + example: "benign" + country: + title: Country + type: string + description: Country + required: false + example: "Spain" + country_code: + title: Country Code + type: string + description: Country Code + required: false + example: "ES" + destinations: + title: Destinations + type: "[]destinations" + description: Destinations + required: false + hassh_fingerprints: + title: HASSH Fingerprints + type: "[]string" + description: HASSH Fingerprints + required: false + example: ["asdfa1412","asasdf2125"] + http_paths: + title: HTTP Web Paths + type: "[]string" + description: HTTP Web Paths + required: false + example: ["/","/robots.txt"] + http_user_agents: + title: HTTP User Agents + type: "[]string" + description: HTTP User Agents + required: false + example: ["/","/robots.txt"] + ja3_fingerprints: + title: JA3 Fingerprints + type: "[]string" + description: JA3 Fingerprints + required: false + example: ["abasdfas","abasdfasdf"] + organization: + title: Organization + type: string + description: Organization + required: false + example: "Acme Inc" + protocols: + title: Protocols + type: "[]protocols" + description: Destinations + required: false + rdns: + title: rDNS + type: string + description: rDNS + required: false + example: "scanner.acme.io" + region: + title: Region + type: string + description: Region + required: false + example: "Arizona" + spoofable: + title: Spoofable + type: boolean + description: Spoofable + required: false + example: false + tags: + title: Tags + type: "[]tags" + description: Tags + required: false + timestamp: + title: Event Timestamp + type: date + description: Event Timestamp + required: false + example: "2020-07-08T17:15:10Z" + tor: + title: Tor Exit Node + type: boolean + description: Tor Exit Node + required: false + example: false + vpn: + title: VPN + type: boolean + description: VPN + required: false + example: false + vpn_service: + title: VPN Service + type: string + description: VPN Service + required: false + example: "VPN Name" + destinations: + country: + title: Country + type: string + description: Country + required: false + example: "Brazil" + country_code: + title: Country Code + type: string + description: Country Code + required: false + example: "BE" + protocols: + port: + title: Port + type: integer + description: Port + required: false + example: 22 + transport_protocol: + title: Transport Protocol + type: string + description: Transport Protocol + required: false + example: "TCP" + app_protocol: + title: App Protocol + type: string + description: App Protocol + required: false + example: "http" + tags: + category: + title: Tag Category + type: string + description: Tag Category + required: false + example: "activity" + description: + title: Tag Description + type: string + description: Tag Description + required: false + example: "This is a description of the tag." + intention: + title: Tag Intention + type: string + description: Tag Intention + required: false + example: "malicious" + name: + title: Tag Name + type: string + description: Tag Name + required: false + example: "IoT Bot Tag" + ip_sim: + actor: + title: Actor + type: string + description: Actor + required: false + example: "Acme Inc." + asn: + title: ASN + type: string + description: ASN + required: false + example: "AS12345" + city: + title: City + type: string + description: City + required: false + example: "Seattle" + classification: + title: Classification + type: string + description: Classification + required: false + example: "benign" + country: + title: Country + type: string + description: Country + required: false + example: "Brazil" + country_code: + title: Country Code + type: string + description: Country Code + required: false + example: "BE" + first_seen: + title: First Seen + type: string + description: First Seen + required: false + example: "2020-07-08T17:15:10Z" + ip: + title: IP Address + type: string + description: IP Address + required: false + example: "1.2.3.4" + last_seen: + title: Last Seen + type: string + description: Last Seen + required: false + example: "2020-07-08T17:15:10Z" + organization: + title: Organization + type: string + description: Organization + required: false + example: "Acme Inc" + similar_ip: + actor: + title: Actor + type: string + description: Actor + required: false + example: "Acme Inc" + asn: + title: ASN + type: string + description: ASN + required: false + example: "AS12345" + city: + title: City + type: string + description: City + required: false + example: "New York" + classification: + title: Classification + type: string + description: Classification + required: false + example: "benign" + country: + title: Country + type: string + description: Country + required: false + example: "Ukraine" + country_code: + title: Country Code + type: string + description: Country Code + required: false + example: "UK" + features: + title: Features Matched + type: "[]string" + description: Features Matched + required: false + example: ["feature-1","feature-2"] + first_seen: + title: First Seen + type: string + description: First Seen + required: false + example: "2020-07-08T17:15:10Z" + ip: + title: IP Address + type: string + description: IP Address + required: false + example: "1.2.3.4" + last_seen: + title: Last Seen + type: string + description: Last Seen + required: false + example: "2020-07-08T17:15:10Z" + organization: + title: Organization + type: string + description: Organization + required: false + example: "Acme Inc" + score: + title: Similarity Score + type: float + description: Similarity Score + required: false + example: 0.83 connection: credentials: title: GreyNoise API Key @@ -184,6 +806,38 @@ connection: type: credential_secret_key required: true example: abcdefghijklmnopqrstuvwxyz0123456789 +triggers: + monitor_ips_in_greynoise: + title: Monitor IP List in GreyNoise + description: Query a list of IPs in GreyNoise based on IP List every interval to identify if any of them are actively scanning the internet + input: + interval: + title: Interval + description: How frequently (in seconds) to trigger a greeting + type: integer + default: 3600 + required: true + example: 3600 + ip_list: + title: List of IPs to Monitor + description: List of IP Addresses or CIDR blocks to check for scanning activity + type: "[]string" + required: true + example: "[1.2.3.4,5.2.3.0/24]" + lookback_days: + title: Number of Days + description: Number of Days to look back for scanning activity. Recommended "1", Max "90" + type: integer + required: true + default: 1 + example: 1 + output: + alert_ip_list: + title: List of IPs Found Scanning + description: The list of IPs that were found scanning + type: "[]string" + required: false + example: "1.2.3.4,5.2.3.5" actions: context_lookup: title: Context IP Lookup @@ -201,76 +855,91 @@ actions: type: string description: Value that was Queried required: false + example: 1.2.3.4 first_seen: title: GreyNoise First Seen type: date description: First Seen By GreyNoise required: false + example: "2024-01-01" last_seen: title: GreyNoise Last Seen type: string description: Last Seen By GreyNoise required: false + example: "2024-01-01" seen: title: GreyNoise Seen type: boolean description: Has this IP been Seen by GreyNoise required: false + example: true tags: title: GreyNoise Tags type: "[]string" description: GreyNoise Tags Associated with IP required: false + example: "Tag 1, Tag2" actor: title: GreyNoise Actor type: string description: GreyNoise Actor Associated with IP required: false + example: "Acme, Inc" spoofable: title: GreyNoise Spoofable type: boolean description: IP address may be spoofed required: false + example: false classification: title: GreyNoise Classification type: string description: GreyNoise Classification required: false + example: "malicious" cve: title: GreyNoise CVEs type: "[]string" description: CVEs associated with GreyNoise Tags required: false + example: ["CVE-1111-1111", "CVE-2222-2222"] bot: title: GreyNoise Bot type: boolean description: GreyNoise has identified this as a Bot required: false + example: false vpn: title: GreyNoise VPN type: boolean description: GreyNoise has identified this as a VPN required: false + example: false vpn_service: title: GreyNoise VPN Service type: string description: Name of VPN Service required: false + example: "My VPN" metadata: title: GreyNoise Metadata type: metadata description: GreyNoise IP Metadata required: false + example: {"asn": "AS12345","category": "isp","city": "Reno","country": "Brazil","country_code": "BZ","destination_countries": ["Brazil","Spain"],"destination_country_codes": ["BZ","ES"],"organization": "Acme Inc.","os": "Windows XP","rdns": "scanner.example.io","region": "Arizona","sensor_count": 5,"sensor_hits": 5,"source_country": "Brazil","source_country_code": "BE","tor": false} raw_data: title: GreyNoise Raw Data type: raw_data description: GreyNoise IP Raw Data required: false + example: {"hassh": [{"fingerprint": "abcdefg1234567","port": 22}],"ja3": [{"fingerprint": "abcdefg1234567","port": 22}],"scan": [{"port": 22,"protocol": "TCP"}],"web": {"paths": ["/","/robots.txt"],"useragents": ["user-agent"]}} viz_url: title: GreyNoise Visualizer Link type: string description: Link to GreyNoise Visualizer for IP Details required: false + example: "https://viz.greynoise.io/ip/1.1.1.1" riot_lookup: title: RIOT IP Lookup description: Query a routable IPv4 address in the GreyNoise RIOT API endpoint @@ -287,46 +956,61 @@ actions: description: Value that was Queried type: string required: false + example: 1.2.3.4 riot: title: GreyNoise RIOT description: Defines if IP is part of GreyNoise RIOT dataset type: boolean required: false + example: true category: title: GreyNoise RIOT Category description: RIOT Category IP is part of type: string required: false + example: "cdn" name: title: GreyNoise RIOT Vendor Name description: Vendor Name IP belongs to type: string required: false + example: "Acme Inc." description: title: GreyNoise RIOT Service Description description: Description of the IP service type: string required: false + example: "Acme Inc is just an example." explanation: title: GreyNoise RIOT Explanation - description: Explanation for why this is likely benign + description: Explanation for why this is likely a common service type: string required: false + example: "This is an explanation." last_updated: title: GreyNoise RIOT Last Updated description: Last time this IP was updated in RIOT dataset type: date required: false + example: "2024-01-01" reference: title: GreyNoise RIOT Reference description: Additional reference information type: string required: false + example: "http://one.one.one.one" + trust_level: + title: GreyNoise RIOT Trust Level + description: IP Trust Level information + type: string + required: false + example: "1" viz_url: title: GreyNoise Visualizer Link type: string description: Link to GreyNoise Visualizer for IP Details required: false + example: "https://viz.greynoise.io/ip/1.1.1.1" quick_lookup: title: Quick IP Lookup description: Query a routable IPv4 address in the GreyNoise Quick API endpoint @@ -343,21 +1027,31 @@ actions: description: Value that was Queried type: string required: false + example: 1.2.3.4 noise: title: GreyNoise Noise description: Defines if IP is Internet Noise type: boolean required: false + example: true + riot: + title: GreyNoise RIOT + description: Defines if IP is a Common Business Service + type: boolean + required: false + example: true code: title: API Response Code description: Response Code from Quick API endpoint type: string required: false + example: "00x0" code_message: title: API Response Code Message description: Response Code Message from Quick API endpoint type: string required: false + example: "Internet noise found" get_tag_details: title: Get Tag Details description: Get Details of a GreyNoise Tag @@ -367,43 +1061,80 @@ actions: description: Tag Name to get additional Details From type: string required: true - example: BingBot + example: "BingBot" output: name: title: "Tag Name" type: string description: "Name of GreyNoise Tag" required: false + example: "BingBot" category: title: "Tag Category" type: string description: "Tag Category" required: false + example: "activity" intention: title: "Tag Intention" type: string description: "Tag Intention" required: false + example: "malicious" description: title: "Tag Description" type: string description: "Description of the Tag" required: false + example: "This is a tag description" references: - title: "References" - type: "[]object" + title: "Tag References" + type: "[]string" description: "References" required: false + example: "https://thisisareference.url" recommend_block: - title: "Recommend Block" + title: "Tag Recommend Block" type: boolean description: "GreyNoise Recommends Blocking IPs associated with this Tag" required: false + example: false cves: - title: "CVEs" - type: "[]object" + title: "Tag Associated CVEs" + type: "[]string" description: "CVEs associate with Tag" required: false + example: "CVE-2020-1234,CVE-1241-23521" + created_at: + title: "Tag Created At" + type: string + description: "The date the tag was added to GreyNoise tag library" + required: false + example: "2024-01-01" + id: + title: "Tag ID" + type: string + description: "The unique ID for the tag" + required: false + example: "aa-bb-cc-dd" + label: + title: "Tag Label" + type: string + description: "The unique label for the tag" + required: false + example: "BINGBOT_SCANNER" + slug: + title: "Tag Slug" + type: string + description: "The unique slug for the tag" + required: false + example: "bingbot-scanner" + related_tags: + title: "Tag Related Tags" + type: "[]string" + description: "Tags that are related to this tag" + required: false + example: ["BingBot Scanner"] gnql_query: title: GreyNoise Query description: Perform a GreyNoise GNQL Query @@ -413,7 +1144,7 @@ actions: description: Query in GreyNoise Query Language (GNQL) Syntax type: string required: true - example: "last_seen:1d" + example: "last_seen:1d classification:'malicious' metadata.asn:'AS8452'" size: title: Max Size description: Max Number of IPs to Return Data For @@ -423,30 +1154,35 @@ actions: example: "10" output: complete: - title: GreyNoise Query + title: GreyNoise Complete Flag type: boolean - description: GreyNoise Query Completed + description: Indicates if all pages of the query have been returned by the API required: false + example: true count: title: GreyNoise Count type: integer - description: Count of IPs In Query + description: Total count of IPs returned Query required: false + example: 10 data: title: GreyNoise Query Data type: "[]data" - description: GreyNoise Query Data + description: GreyNoise Data Object, Contains IP Object for each IP returned by the query required: false + example: [{"actor": "Acme, Inc","bot": false,"classification": "malicious","cve": ["CVE-1111-1111","CVE-2222-2222"],"first_seen": "2024-01-01","ip": "1.2.3.4","last_seen": "2024-01-01","metadata": {"asn": "AS12345","category": "isp","city": "Reno","country": "Brazil","country_code": "BZ","destination_countries": ["Brazil","Spain"],"destination_country_codes": ["BZ","ES"],"organization": "Acme Inc.","os": "Windows XP","rdns": "scanner.example.io","region": "Arizona","sensor_count": 5,"sensor_hits": 5,"source_country": "Brazil","source_country_code": "BE","tor": false},"raw_data": {"hassh": [{"fingerprint": "abcdefg1234567","port": 22}],"ja3": [{"fingerprint": "abcdefg1234567","port": 22}],"scan": [{"port": 22,"protocol": "TCP"}],"web": {"paths": ["/","/robots.txt"],"useragents": ["user-agent"]}},"seen": true,"spoofable": false,"tags": "Tag 1, Tag2","vpn": false,"vpn_service": "My VPN"}] message: title: GreyNoise Query Message type: string - description: GreyNoise Query Message + description: GreyNoise Query Message, indicates if there were issues with the query required: false + example: "ok" query: title: GreyNoise Query type: string description: GreyNoise Query Sent to API required: false + example: "sample query" community_lookup: title: Community IP Lookup description: Query a routable IPv4 address in the GreyNoise Community API @@ -463,38 +1199,151 @@ actions: description: Value that was Queried type: string required: false + example: 1.2.3.4 noise: title: GreyNoise Noise description: Defines if IP is Internet Noise type: boolean required: false + example: true riot: title: GreyNoise RIOT description: Defines if IP is part of GreyNoise RIOT dataset type: boolean required: false + example: true classification: title: GreyNoise Classification type: string description: GreyNoise Classification required: false + example: "benign" link: title: GreyNoise Visualizer Link type: string description: Link to GreyNoise Visualizer for IP Details required: false + example: "https://viz.greynoise.io/ip/1.1.1.1" last_seen: title: GreyNoise Last Seen type: string description: Last Seen By GreyNoise required: false + example: "2024-01-01" message: title: GreyNoise Status Message type: string description: GreyNoise Community API Status Message required: false + example: "IP found" name: title: GreyNoise Name type: string description: GreyNoise Actor or Service Name Associated with IP required: false + example: "Acme Inc." + vulnerability_lookup: + title: Vulnerability Lookup + description: Check GreyNoise for Vulnerability information + input: + cve_id: + title: CVE ID + description: A CVE ID to look up in GreyNoise + type: string + required: true + example: CVE-2020-12345 + output: + id: + title: CVE ID + description: Value that was searched + type: string + required: false + example: CVE-2020-12345 + details: + title: GreyNoise Vulnerability Details + description: GreyNoise Vulnerability Details + type: vuln_details + required: false + example: {"cve_cvss_score": 9.8,"product": "Product Name","published_to_nist_nvd": false,"vendor": "Acme Inc","vulnerability_description": "This is a product description.","vulnerability_name": "This is a vuln name."} + exploitation_activity: + title: GreyNoise Vulnerability Exploitation Activity + description: GreyNoise Vulnerability Exploitation Activity + type: vuln_exploitation_activity + required: false + example: {"activity_seen": true,"benign_ip_count_10d": 5,"benign_ip_count_1d": 5,"benign_ip_count_30d": 5,"threat_ip_count_10d": 5,"threat_ip_count_1d": 5,"threat_ip_count_30d": 5} + exploitation_details: + title: GreyNoise Vulnerability Exploitation Details + description: GreyNoise Vulnerability Exploitation Details + type: vuln_exploitation_details + required: false + example: {"attack_vector": "NETWORK","epss_score": 0.0,"exploit_found": true,"exploitation_registered_in_kev": false} + exploitation_stats: + title: GreyNoise Vulnerability Exploitation Stats + description: GreyNoise Vulnerability Exploitation Stats + type: vuln_exploitation_stats + required: false + example: {"number_of_available_exploits": 1,"number_of_botnets_exploiting_vulnerability": 1,"number_of_threat_actors_exploiting_vulnerability": 1} + timeline: + title: GreyNoise Vulnerability Timeline + description: GreyNoise Vulnerability Timeline + type: vuln_timeline + required: false + example: {"cisa_kev_date_added": "2020-07-08T17:15:10Z","cve_last_updated_date": "2020-07-08T17:15:10Z","cve_published_date": "2020-07-08T17:15:10Z","first_known_published_date": "2020-07-08T17:15:10Z"} + timeline_lookup: + title: IP Timeline Lookup + description: Query a routable IPv4 address in the GreyNoise for Scanner Daily Timeline details + input: + ip_address: + title: IP Address + description: Routable IPv4 address to query + type: string + required: true + example: 1.2.3.4 + output: + ip: + title: IP Queried + type: string + description: Value that was Queried + required: false + example: 1.2.3.4 + metadata: + title: IP Timeline Metadata + type: timeline_metadata + description: IP Timeline Metadata + required: false + example: {"end_time": "2020-07-08T17:15:10Z","ip": "1.2.3.4","limit": 5,"next_cursor": "asdf142qas3241asdf234sfa","start_time": "2020-07-08T17:15:10Z"} + activity: + title: IP Timeline Activity + type: "[]timeline_activity" + description: IP Timeline Activity Events + required: false + example: [{"asn": "AS12345","category": "isp","city": "Seattle","classification": "benign","country": "Spain","country_code": "ES","destinations": [{"country": "Brazil","country_code": "BE"}],"hassh_fingerprints": ["asdfa1412","asasdf2125"],"http_web_paths": ["robots.txt"],"http_user_agents": ["Hello World"],"ja3_fingerprints": ["abasdfas","abasdfasdf"],"organization": "Acme Inc","protocols": [{"port": 22,"transport_protocol": "TCP","app_protocol": "TCP"}],"rdns": "scanner.acme.io","region": "Arizona","spoofable": false,"tags": [{"tag_category": "activity","tag_description": "This is a description of the tag.","tag_intention": "malicious","tag_name": "IoT Bot Tag"}],"timestampe": "2020-07-08T17:15:10Z","tor": false,"vpn": false,"vpn_service": "VPN Name"}] + similar_lookup: + title: IP Similarity Lookup + description: Query a routable IPv4 address in the GreyNoise for similar IPs + input: + ip_address: + title: IP Address + description: Routable IPv4 address to query + type: string + required: true + example: 1.2.3.4 + output: + ip: + title: IP Similarity Metadata + type: ip_sim + description: IP Similarity Metadata + required: false + example: {"actor": "Acme Inc.","asn": "AS12345","city": "Seattle","classification": "benign","country": "Brazil","country_code": "BE","first_seen": "2020-07-08T17:15:10Z","ip": "1.2.3.4","last_seen": "2020-07-08T17:15:10Z","organization": "Acme Inc"} + similar_ips: + title: Similar IPs + type: "[]similar_ip" + description: Similar IPs + required: false + example: [{"actor": "Acme Inc","asn": "AS12345","city": "New York","classification": "benign","country": "Ukraine","country_code": "UK","features_matched": ["feature-1","feature-2"],"first_seen": "2020-07-08T17:15:10Z","ip": "1.2.3.4","last_seen": "2020-07-08T17:15:10Z","organization": "Acme Inc","score": 0.83}] + total: + title: Total Number of IPs + type: integer + description: Total Number of Similar IPs returned + required: false + example: 5 diff --git a/plugins/greynoise/requirements.txt b/plugins/greynoise/requirements.txt index cf522c0076..11541c68b5 100755 --- a/plugins/greynoise/requirements.txt +++ b/plugins/greynoise/requirements.txt @@ -1,5 +1,5 @@ # List third-party dependencies here, separated by newlines. # All dependencies must be version-pinned, eg. requests==1.2.0 # See: https://pip.pypa.io/en/stable/user_guide/#requirements-files -greynoise==0.9.1 -pendulum==2.1.2 \ No newline at end of file +greynoise==2.3.0 +pendulum==3.0.0 \ No newline at end of file diff --git a/plugins/greynoise/setup.py b/plugins/greynoise/setup.py index 8e717f2d60..c898b32b0e 100755 --- a/plugins/greynoise/setup.py +++ b/plugins/greynoise/setup.py @@ -1,9 +1,9 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from setuptools import setup, find_packages setup(name="greynoise-greynoise-plugin", - version="1.0.0", + version="2.0.0", description="GreyNoise helps analysts recognize events not worth their attention. Indicators in GreyNoise are likely associated with opportunistic internet scanning or common business services, not targeted threats. This context helps analysts focus on what matters most", author="greynoise", author_email="", diff --git a/plugins/greynoise/unit_test/__init__.py b/plugins/greynoise/unit_test/__init__.py new file mode 100644 index 0000000000..68fb582d95 --- /dev/null +++ b/plugins/greynoise/unit_test/__init__.py @@ -0,0 +1,4 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import sys + +sys.path.append("../") diff --git a/plugins/greynoise/unit_test/payloads/__init__.py b/plugins/greynoise/unit_test/payloads/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/greynoise/unit_test/payloads/community_ip.json b/plugins/greynoise/unit_test/payloads/community_ip.json new file mode 100644 index 0000000000..c941a586c0 --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/community_ip.json @@ -0,0 +1,10 @@ +{ + "ip": "1.2.3.4", + "noise": false, + "riot": true, + "classification": "benign", + "name": "Acme, Inc", + "link": "https://viz.greynoise.io/ip/1.2.3.4", + "last_seen": "2020-01-01", + "message": "Success" +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/context_ip.json b/plugins/greynoise/unit_test/payloads/context_ip.json new file mode 100644 index 0000000000..8039e93e2d --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/context_ip.json @@ -0,0 +1,68 @@ +{ + "ip": "1.2.3.4", + "first_seen": "2019-07-29", + "last_seen": "2024-11-04", + "seen": true, + "tags": [ + "Acme Inc" + ], + "actor": "Acme Inc", + "spoofable": false, + "classification": "benign", + "cve": [ + "CVE-2021-38645" + ], + "bot": false, + "vpn": false, + "vpn_service": "", + "metadata": { + "asn": "AS12345", + "city": "Berlin", + "country": "Germany", + "country_code": "DE", + "organization": "Acme Inc", + "category": "hosting", + "tor": false, + "rdns": "", + "os": "Linux 2.2.x-3.x (barebone)", + "sensor_count": 352, + "sensor_hits": 799, + "region": "Berlin", + "destination_countries": [ + "Australia" + ], + "destination_country_codes": [ + "AU" + ], + "source_country": "Germany", + "source_country_code": "DE" + }, + "raw_data": { + "scan": [ + { + "port": 50050, + "protocol": "TCP" + } + ], + "web": { + "paths": [ + "/favicon.ico" + ], + "useragents": [ + "Microsoft WinRM Client" + ] + }, + "ja3": [ + { + "fingerprint": "12345", + "port": 22 + } + ], + "hassh": [ + { + "fingerprint": "12345", + "port": 22 + } + ] + } +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/cve_details.json b/plugins/greynoise/unit_test/payloads/cve_details.json new file mode 100644 index 0000000000..092b0484d3 --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/cve_details.json @@ -0,0 +1,37 @@ +{ + "id": "CVE-1234-1234", + "details": { + "vulnerability_name": "name", + "vulnerability_description": "description", + "cve_cvss_score": 8.1, + "product": "product", + "vendor": "vendor", + "published_to_nist_nvd": true + }, + "timeline": { + "cve_published_date": "2020-07-08T17:15:10Z", + "cve_last_updated_date": "2020-07-14T17:44:41Z", + "first_known_published_date": "", + "cisa_kev_date_added": "" + }, + "exploitation_details": { + "attack_vector": "NETWORK", + "exploit_found": false, + "exploitation_registered_in_kev": false, + "epss_score": 0 + }, + "exploitation_stats": { + "number_of_available_exploits": 0, + "number_of_threat_actors_exploiting_vulnerability": 0, + "number_of_botnets_exploiting_vulnerability": 0 + }, + "exploitation_activity": { + "activity_seen": true, + "benign_ip_count_1d": 0, + "benign_ip_count_10d": 0, + "benign_ip_count_30d": 0, + "threat_ip_count_1d": 5, + "threat_ip_count_10d": 20, + "threat_ip_count_30d": 53 + } +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/gnql_query.json b/plugins/greynoise/unit_test/payloads/gnql_query.json new file mode 100644 index 0000000000..34ee2676ad --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/gnql_query.json @@ -0,0 +1,77 @@ +{ + "complete": true, + "count": 1, + "data": [ + { + "ip": "1.2.3.4", + "first_seen": "2019-07-29", + "last_seen": "2024-11-04", + "seen": true, + "tags": [ + "Acme Inc" + ], + "actor": "Acme Inc", + "spoofable": false, + "classification": "benign", + "cve": [ + "CVE-2021-38645" + ], + "bot": false, + "vpn": false, + "vpn_service": "", + "metadata": { + "asn": "AS12345", + "city": "Berlin", + "country": "Germany", + "country_code": "DE", + "organization": "Acme Inc", + "category": "hosting", + "tor": false, + "rdns": "", + "os": "Linux 2.2.x-3.x (barebone)", + "sensor_count": 352, + "sensor_hits": 799, + "region": "Berlin", + "destination_countries": [ + "Australia" + ], + "destination_country_codes": [ + "AU" + ], + "source_country": "Germany", + "source_country_code": "DE" + }, + "raw_data": { + "scan": [ + { + "port": 50050, + "protocol": "TCP" + } + ], + "web": { + "paths": [ + "/favicon.ico" + ], + "useragents": [ + "Microsoft WinRM Client" + ] + }, + "ja3": [ + { + "fingerprint": "12345", + "port": 22 + } + ], + "hassh": [ + { + "fingerprint": "12345", + "port": 22 + } + ] + } + } + ], + "message": "ok", + "query": "query", + "scroll": "token" +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/quick_ip.json b/plugins/greynoise/unit_test/payloads/quick_ip.json new file mode 100644 index 0000000000..1a532af5e8 --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/quick_ip.json @@ -0,0 +1,9 @@ +[ + { + "code": "0x01", + "ip": "1.2.3.4", + "code_message": "IP has been observed by the GreyNoise sensor network", + "noise": true, + "riot": false + } +] \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/riot_ip.json b/plugins/greynoise/unit_test/payloads/riot_ip.json new file mode 100644 index 0000000000..235be97054 --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/riot_ip.json @@ -0,0 +1,11 @@ +{ + "ip": "1.2.3.4", + "riot": true, + "category": "public_dns", + "name": "Acme Inc", + "description": "description", + "explanation": "explanation", + "last_updated": "2024-11-04T17:10:58Z", + "reference": "reference", + "trust_level": "1" +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/similar_ip.json b/plugins/greynoise/unit_test/payloads/similar_ip.json new file mode 100644 index 0000000000..6e55fc2b14 --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/similar_ip.json @@ -0,0 +1,38 @@ +{ + "ip": { + "actor": "Acme Inc", + "asn": "AS12345", + "city": "Berlin", + "classification": "benign", + "country": "Germany", + "country_code": "DE", + "first_seen": "2019-07-29", + "ip": "1.2.3.4", + "last_seen": "2024-11-04", + "organization": "Acme Inc" + }, + "similar_ips": [ + { + "actor": "Alpha Strike Labs", + "asn": "AS12345", + "city": "Berlin", + "classification": "benign", + "country": "Germany", + "country_code": "DE", + "features": [ + "hassh_fp", + "mass_scan_bool", + "os", + "ports", + "useragents", + "web_paths" + ], + "first_seen": "2019-07-11", + "ip": "2.3.4.5", + "last_seen": "2024-11-04", + "organization": "Acme Inc", + "score": 0.98933446 + } + ], + "total": 1 +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/tag_details.json b/plugins/greynoise/unit_test/payloads/tag_details.json new file mode 100644 index 0000000000..45acd103c0 --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/tag_details.json @@ -0,0 +1,22 @@ +{ + "metadata": [ + { + "id": "1234", + "label": "label", + "slug": "slug", + "name": "Test Tag Name", + "category": "activity", + "intention": "malicious", + "description": "description", + "references": [ + "https://nvd.nist.gov/vuln/detail/CVE-2024-38289" + ], + "recommend_block": true, + "cves": [ + "CVE-2024-38289" + ], + "created_at": "2024-09-12", + "related_tags": [] + } + ] +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/payloads/timeline_ip.json b/plugins/greynoise/unit_test/payloads/timeline_ip.json new file mode 100644 index 0000000000..afa04f554e --- /dev/null +++ b/plugins/greynoise/unit_test/payloads/timeline_ip.json @@ -0,0 +1,58 @@ +{ + "activity": [ + { + "asn": "AS12345", + "category": "hosting", + "city": "Berlin", + "classification": "benign", + "country": "Germany", + "country_code": "DE", + "destinations": [ + { + "country": "South Africa", + "country_code": "ZA" + } + ], + "hassh_fingerprints": [], + "http_paths": [ + "/favicon.ico" + ], + "http_user_agents": [ + "Mozilla/5.0" + ], + "ja3_fingerprints": [ + "04b3f524166caafd433b6864250945be" + ], + "organization": "Alpha Strike Labs GmbH", + "protocols": [ + { + "port": 80, + "transport_protocol": "TCP" + } + ], + "rdns": "", + "region": "Berlin", + "spoofable": true, + "tags": [ + { + "category": "actor", + "description": "description.", + "intention": "benign", + "name": "Acme, Inc." + } + ], + "timestamp": "2024-11-03T00:00:00Z", + "tor": false, + "vpn": false, + "vpn_service": "" + } + ], + "ip": "1.2.3.4", + "metadata": { + "end_time": "2024-11-04T19:13:35.892189739Z", + "ip": "1.2.3.4", + "limit": 50, + "next_cursor": "", + "start_time": "2024-11-03T00:00:00Z" + } +} \ No newline at end of file diff --git a/plugins/greynoise/unit_test/test_community_lookup.py b/plugins/greynoise/unit_test/test_community_lookup.py new file mode 100644 index 0000000000..ea112cdd0e --- /dev/null +++ b/plugins/greynoise/unit_test/test_community_lookup.py @@ -0,0 +1,31 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.community_lookup import CommunityLookup + +from util import MockConnection, mocked_requests_get + + +class TestCommunityLookup(TestCase): + @mock.patch("greynoise.GreyNoise.ip", side_effect=mocked_requests_get) + def test_community_lookup(self, mock_get): + log = logging.getLogger("Test") + test_community = CommunityLookup() + test_community.connection = MockConnection() + test_community.logger = log + + working_params = {"ip_address": "community_lookup"} + results = test_community.run(working_params) + expected = { + "ip": "1.2.3.4", + "noise": False, + "riot": True, + "classification": "benign", + "name": "Acme, Inc", + "link": "https://viz.greynoise.io/ip/1.2.3.4", + "last_seen": "2020-01-01T00:00:00+00:00", + "message": "Success", + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_context_lookup.py b/plugins/greynoise/unit_test/test_context_lookup.py new file mode 100644 index 0000000000..c4994fe7c9 --- /dev/null +++ b/plugins/greynoise/unit_test/test_context_lookup.py @@ -0,0 +1,60 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.context_lookup import ContextLookup + +from util import MockConnection, mocked_requests_get + + +class TestContextLookup(TestCase): + @mock.patch("greynoise.GreyNoise.ip", side_effect=mocked_requests_get) + def test_context_lookup(self, mock_get): + log = logging.getLogger("Test") + test_context = ContextLookup() + test_context.connection = MockConnection() + test_context.logger = log + + working_params = {"ip_address": "context_lookup"} + results = test_context.run(working_params) + expected = { + "viz_url": "https://viz.greynoise.io/ip/1.2.3.4", + "ip": "1.2.3.4", + "first_seen": "2019-07-29T00:00:00+00:00", + "last_seen": "2024-11-04T00:00:00+00:00", + "seen": True, + "tags": ["Acme Inc"], + "actor": "Acme Inc", + "spoofable": False, + "classification": "benign", + "cve": ["CVE-2021-38645"], + "bot": False, + "vpn": False, + "vpn_service": "", + "metadata": { + "asn": "AS12345", + "city": "Berlin", + "country": "Germany", + "country_code": "DE", + "organization": "Acme Inc", + "category": "hosting", + "tor": False, + "rdns": "", + "os": "Linux 2.2.x-3.x (barebone)", + "sensor_count": 352, + "sensor_hits": 799, + "region": "Berlin", + "destination_countries": ["Australia"], + "destination_country_codes": ["AU"], + "source_country": "Germany", + "source_country_code": "DE", + }, + "raw_data": { + "scan": [{"port": 50050, "protocol": "TCP"}], + "web": {"paths": ["/favicon.ico"], "useragents": ["Microsoft WinRM Client"]}, + "ja3": [{"fingerprint": "12345", "port": 22}], + "hassh": [{"fingerprint": "12345", "port": 22}], + }, + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_get_tag_details.py b/plugins/greynoise/unit_test/test_get_tag_details.py new file mode 100644 index 0000000000..104f3a9218 --- /dev/null +++ b/plugins/greynoise/unit_test/test_get_tag_details.py @@ -0,0 +1,35 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.get_tag_details import GetTagDetails + +from util import MockConnection, mocked_requests_get + + +class TestGetTagDetails(TestCase): + @mock.patch("greynoise.GreyNoise.metadata", side_effect=mocked_requests_get) + def test_get_tag_details(self, mock_get): + log = logging.getLogger("Test") + test_tag_details = GetTagDetails() + test_tag_details.connection = MockConnection() + test_tag_details.logger = log + + working_params = {"tag_name": "Test Tag Name"} + results = test_tag_details.run(working_params) + expected = { + "id": "1234", + "label": "label", + "slug": "slug", + "name": "Test Tag Name", + "category": "activity", + "intention": "malicious", + "description": "description", + "references": ["https://nvd.nist.gov/vuln/detail/CVE-2024-38289"], + "recommend_block": True, + "cves": ["CVE-2024-38289"], + "created_at": "2024-09-12", + "related_tags": [], + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_gnql_query.py b/plugins/greynoise/unit_test/test_gnql_query.py new file mode 100644 index 0000000000..a6d69b8954 --- /dev/null +++ b/plugins/greynoise/unit_test/test_gnql_query.py @@ -0,0 +1,67 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.gnql_query import GnqlQuery + +from util import MockConnection, mocked_requests_get + + +class TestGnqlQuery(TestCase): + @mock.patch("greynoise.GreyNoise.query", side_effect=mocked_requests_get) + def test_gnql_query(self, mock_get): + log = logging.getLogger("Test") + test_gnql = GnqlQuery() + test_gnql.connection = MockConnection() + test_gnql.logger = log + + working_params = {"query": "gnql_query"} + results = test_gnql.run(working_params) + expected = { + "complete": True, + "count": 1, + "data": [ + { + "ip": "1.2.3.4", + "first_seen": "2019-07-29", + "last_seen": "2024-11-04", + "seen": True, + "tags": ["Acme Inc"], + "actor": "Acme Inc", + "spoofable": False, + "classification": "benign", + "cve": ["CVE-2021-38645"], + "bot": False, + "vpn": False, + "vpn_service": "", + "metadata": { + "asn": "AS12345", + "city": "Berlin", + "country": "Germany", + "country_code": "DE", + "organization": "Acme Inc", + "category": "hosting", + "tor": False, + "rdns": "", + "os": "Linux 2.2.x-3.x (barebone)", + "sensor_count": 352, + "sensor_hits": 799, + "region": "Berlin", + "destination_countries": ["Australia"], + "destination_country_codes": ["AU"], + "source_country": "Germany", + "source_country_code": "DE", + }, + "raw_data": { + "scan": [{"port": 50050, "protocol": "TCP"}], + "web": {"paths": ["/favicon.ico"], "useragents": ["Microsoft WinRM Client"]}, + "ja3": [{"fingerprint": "12345", "port": 22}], + "hassh": [{"fingerprint": "12345", "port": 22}], + }, + } + ], + "message": "ok", + "query": "query", + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_quick_lookup.py b/plugins/greynoise/unit_test/test_quick_lookup.py new file mode 100644 index 0000000000..4b3dadeaad --- /dev/null +++ b/plugins/greynoise/unit_test/test_quick_lookup.py @@ -0,0 +1,28 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.quick_lookup import QuickLookup + +from util import MockConnection, mocked_requests_get + + +class TestQuickLookup(TestCase): + @mock.patch("greynoise.GreyNoise.quick", side_effect=mocked_requests_get) + def test_quick_lookup(self, mock_get): + log = logging.getLogger("Test") + test_quick = QuickLookup() + test_quick.connection = MockConnection() + test_quick.logger = log + + working_params = {"ip_address": "quick_lookup"} + results = test_quick.run(working_params) + expected = { + "code": "0x01", + "ip": "1.2.3.4", + "code_message": "IP has been observed by the GreyNoise sensor network", + "noise": True, + "riot": False, + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_riot_lookup.py b/plugins/greynoise/unit_test/test_riot_lookup.py new file mode 100644 index 0000000000..9dd5c9eeec --- /dev/null +++ b/plugins/greynoise/unit_test/test_riot_lookup.py @@ -0,0 +1,33 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.riot_lookup import RiotLookup + +from util import MockConnection, mocked_requests_get + + +class TestRiotLookup(TestCase): + @mock.patch("greynoise.GreyNoise.riot", side_effect=mocked_requests_get) + def test_riot_lookup(self, mock_get): + log = logging.getLogger("Test") + test_riot = RiotLookup() + test_riot.connection = MockConnection() + test_riot.logger = log + + working_params = {"ip_address": "riot_lookup"} + results = test_riot.run(working_params) + expected = { + "ip": "1.2.3.4", + "riot": True, + "category": "public_dns", + "name": "Acme Inc", + "description": "description", + "explanation": "explanation", + "last_updated": "2024-11-04T17:10:58Z", + "reference": "reference", + "trust_level": "1", + "viz_url": "https://viz.greynoise.io/ip/1.2.3.4", + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_similar_lookup.py b/plugins/greynoise/unit_test/test_similar_lookup.py new file mode 100644 index 0000000000..12c33e03f9 --- /dev/null +++ b/plugins/greynoise/unit_test/test_similar_lookup.py @@ -0,0 +1,52 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.similar_lookup import SimilarLookup + +from util import MockConnection, mocked_requests_get + + +class TestSimilarLookup(TestCase): + @mock.patch("greynoise.GreyNoise.similar", side_effect=mocked_requests_get) + def test_similar_lookup(self, mock_get): + log = logging.getLogger("Test") + test_similar = SimilarLookup() + test_similar.connection = MockConnection() + test_similar.logger = log + + working_params = {"ip_address": "similar_lookup"} + results = test_similar.run(working_params) + expected = { + "ip": { + "actor": "Acme Inc", + "asn": "AS12345", + "city": "Berlin", + "classification": "benign", + "country": "Germany", + "country_code": "DE", + "first_seen": "2019-07-29", + "ip": "1.2.3.4", + "last_seen": "2024-11-04", + "organization": "Acme Inc", + }, + "similar_ips": [ + { + "actor": "Alpha Strike Labs", + "asn": "AS12345", + "city": "Berlin", + "classification": "benign", + "country": "Germany", + "country_code": "DE", + "features": ["hassh_fp", "mass_scan_bool", "os", "ports", "useragents", "web_paths"], + "first_seen": "2019-07-11", + "ip": "2.3.4.5", + "last_seen": "2024-11-04", + "organization": "Acme Inc", + "score": 0.98933446, + } + ], + "total": 1, + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_timeline_lookup.py b/plugins/greynoise/unit_test/test_timeline_lookup.py new file mode 100644 index 0000000000..9da8e2a100 --- /dev/null +++ b/plugins/greynoise/unit_test/test_timeline_lookup.py @@ -0,0 +1,63 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.timeline_lookup import TimelineLookup + +from util import MockConnection, mocked_requests_get + + +class TestTimelineLookup(TestCase): + @mock.patch("greynoise.GreyNoise.timelinedaily", side_effect=mocked_requests_get) + def test_timeline_lookup(self, mock_get): + log = logging.getLogger("Test") + test_timeline = TimelineLookup() + test_timeline.connection = MockConnection() + test_timeline.logger = log + + working_params = {"ip_address": "timeline_lookup"} + results = test_timeline.run(working_params) + expected = { + "activity": [ + { + "asn": "AS12345", + "category": "hosting", + "city": "Berlin", + "classification": "benign", + "country": "Germany", + "country_code": "DE", + "destinations": [{"country": "South Africa", "country_code": "ZA"}], + "hassh_fingerprints": [], + "http_paths": ["/favicon.ico"], + "http_user_agents": ["Mozilla/5.0"], + "ja3_fingerprints": ["04b3f524166caafd433b6864250945be"], + "organization": "Alpha Strike Labs GmbH", + "protocols": [{"port": 80, "transport_protocol": "TCP"}], + "rdns": "", + "region": "Berlin", + "spoofable": True, + "tags": [ + { + "category": "actor", + "description": "description.", + "intention": "benign", + "name": "Acme, Inc.", + } + ], + "timestamp": "2024-11-03T00:00:00Z", + "tor": False, + "vpn": False, + "vpn_service": "", + } + ], + "ip": "1.2.3.4", + "metadata": { + "end_time": "2024-11-04T19:13:35.892189739Z", + "ip": "1.2.3.4", + "limit": 50, + "next_cursor": "", + "start_time": "2024-11-03T00:00:00Z", + }, + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/test_vulnerability_lookup.py b/plugins/greynoise/unit_test/test_vulnerability_lookup.py new file mode 100644 index 0000000000..0e3e45df86 --- /dev/null +++ b/plugins/greynoise/unit_test/test_vulnerability_lookup.py @@ -0,0 +1,58 @@ +import logging +from unittest import TestCase, mock + +from icon_greynoise.actions.vulnerability_lookup import VulnerabilityLookup + +from util import MockConnection, mocked_requests_get + + +class TestVulnerabilityLookup(TestCase): + @mock.patch("greynoise.GreyNoise.cve", side_effect=mocked_requests_get) + def test_vulnerability_lookup(self, mock_get): + log = logging.getLogger("Test") + test_vuln = VulnerabilityLookup() + test_vuln.connection = MockConnection() + test_vuln.logger = log + + working_params = {"cve_id": "vulnerability_lookup"} + results = test_vuln.run(working_params) + expected = { + "id": "CVE-1234-1234", + "details": { + "vulnerability_name": "name", + "vulnerability_description": "description", + "cve_cvss_score": 8.1, + "product": "product", + "vendor": "vendor", + "published_to_nist_nvd": True, + }, + "timeline": { + "cve_published_date": "2020-07-08T17:15:10Z", + "cve_last_updated_date": "2020-07-14T17:44:41Z", + "first_known_published_date": "", + "cisa_kev_date_added": "", + }, + "exploitation_details": { + "attack_vector": "NETWORK", + "exploit_found": False, + "exploitation_registered_in_kev": False, + "epss_score": 0, + }, + "exploitation_stats": { + "number_of_available_exploits": 0, + "number_of_threat_actors_exploiting_vulnerability": 0, + "number_of_botnets_exploiting_vulnerability": 0, + }, + "exploitation_activity": { + "activity_seen": True, + "benign_ip_count_1d": 0, + "benign_ip_count_10d": 0, + "benign_ip_count_30d": 0, + "threat_ip_count_1d": 5, + "threat_ip_count_10d": 20, + "threat_ip_count_30d": 53, + }, + } + + self.assertNotEqual({}, results, "returns non - empty results") + self.assertEqual(expected, results) diff --git a/plugins/greynoise/unit_test/util.py b/plugins/greynoise/unit_test/util.py new file mode 100644 index 0000000000..978d48d36e --- /dev/null +++ b/plugins/greynoise/unit_test/util.py @@ -0,0 +1,39 @@ +import json +import os + +from greynoise import GreyNoise + +PAYLOAD_MAPPING = { + "community_lookup": "payloads/community_ip.json", + "context_lookup": "payloads/context_ip.json", + "gnql_query": "payloads/gnql_query.json", + "quick_lookup": "payloads/quick_ip.json", + "riot_lookup": "payloads/riot_ip.json", + "similar_lookup": "payloads/similar_ip.json", + "timeline_lookup": "payloads/timeline_ip.json", + "vulnerability_lookup": "payloads/cve_details.json", +} + + +def read_file_to_string(filename): + with open(filename) as my_file: + return my_file.read() + + +def mocked_requests_get(*args, **kwargs): + if len(args) == 0: + filepath = "payloads/tag_details.json" + else: + filepath = PAYLOAD_MAPPING[args[0]] + actual_path = os.path.dirname(os.path.realpath(__file__)) + actual_joined_path = os.path.join(actual_path, filepath) + get_messages_from_user_payload = read_file_to_string(actual_joined_path) + return json.loads(get_messages_from_user_payload) + + +class MockConnection: + def __init__(self): + self.server = "test_server" + self.api_key = "test_api_key" + self.user_agent = "test_user_agent" + self.gn_client = GreyNoise(api_key=self.api_key, api_server=self.server, integration_name=self.user_agent)