Skip to content

Commit

Permalink
Merge pull request #1 from Nclose-ZA/greynoise_analyzer_v3
Browse files Browse the repository at this point in the history
GreyNoise analyzer v3
  • Loading branch information
markus-nclose authored Nov 30, 2020
2 parents c22579a + 2d2730c commit ab032eb
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 90 deletions.
2 changes: 1 addition & 1 deletion analyzers/GreyNoise/GreyNoise.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "GreyNoise",
"version": "2.3",
"version": "3.0",
"author": "Nclose",
"url": "https://github.com/TheHive-Project/Cortex-Analyzers",
"license": "APLv2",
Expand Down
148 changes: 59 additions & 89 deletions analyzers/GreyNoise/greynoise.py
Original file line number Diff line number Diff line change
@@ -1,134 +1,104 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests

from collections import defaultdict, OrderedDict

from cortexutils.analyzer import Analyzer
from greynoise import GreyNoise
import requests


class GreyNoiseAnalyzer(Analyzer):
"""
GreyNoise API docs: https://github.com/GreyNoise-Intelligence/api.greynoise.io
GreyNoise API docs: https://developer.greynoise.io/reference#noisecontextip-1
"""

@staticmethod
def _get_level(current_level, new_intention):
"""
Map GreyNoise intentions to Cortex maliciousness levels.
Accept a Cortex level and a GreyNoise intention, the return the more malicious of the two.
:param current_level: A Cortex maliciousness level
https://github.com/TheHive-Project/CortexDocs/blob/master/api/how-to-create-an-analyzer.md#output
:param new_intention: An intention field value from a GreyNoise record
https://github.com/GreyNoise-Intelligence/api.greynoise.io#v1queryip
:return: The more malicious of the 2 submitted values as a Cortex maliciousness level
"""

intention_level_map = OrderedDict([
('info', 'info'),
('benign', 'safe'),
('suspicious', 'suspicious'),
('malicious', 'malicious')
])
levels = intention_level_map.values()

new_level = intention_level_map.get(new_intention, 'info')
new_index = levels.index(new_level)

try:
current_index = levels.index(current_level)
except ValueError: # There is no existing level
current_index = -1

return new_level if new_index > current_index else current_level

def run(self):

if self.data_type == "ip":
api_key = self.get_param('config.key', None)
url = 'https://api.greynoise.io/v1/query/ip'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
data = {'ip': self.get_data()}
if api_key:
data['key'] = api_key
response = requests.post(url, data=data, headers=headers)
if not (200 <= response.status_code < 300):
self.error('Unable to query GreyNoise API\n{}'.format(response.text))
self.report(response.json())
api_client = GreyNoise(api_key=api_key, timeout=30)
try:
self.report(api_client.ip(self.get_data()))
except Exception as e:
self.error('Unable to query GreyNoise API\n{}'.format(e))
else:
self.notSupported()

def summary(self, raw):
"""
Return one taxonomy summarizing the reported tags
If there is only one tag, use it as the predicate
If there are multiple tags, use "entries" as the predicate
Use the total count as the value
Use the most malicious level found
Return two taxonomies
Examples:
Input
{
"name": SCANNER1,
"intention": ""
"actor": "SCANNER1",
"classification": "benign",
"tags": ['a', 'b', 'c']
}
Output
GreyNoise:SCANNER1 = 1 (info)
GreyNoise:tags = 3 (Safe)
GreyNoise:actor = SCANNER1 (Safe)
Input
{
"name": SCANNER1,
"intention": "malicious"
},
{
"name": SCANNER1,
"intention": "benign"
"actor": "SCANNER1",
"classification": "unknown",
"tags": ['a', 'b', 'c']
}
Output
GreyNoise:SCANNER1 = 2 (malicious)
GreyNoise:tags = 3 (Suspicious)
GreyNoise:classification = unknown (Info)
Input
{
"name": SCANNER1,
"intention": ""
},
{
"name": SCANNER1,
"intention": "safe"
},
"actor": "SCANNER1",
"classification": "unknown",
"tags": ['a', 'b']
}
Output
GreyNoise:tags = 2 (Info)
GreyNoise:classification = unknown (Info)
Input
{
"name": SCANNER2,
"intention": ""
"actor": "SCANNER1",
"classification": "malicious",
"tags": ['a', 'b', 'c']
}
Output
GreyNoise:entries = 3 (safe)
GreyNoise:tags = 3 (Malicious)
GreyNoise:classification = malicious (Malicious)
"""


classification_level_map = {
'benign': lambda x: 'Safe',
'unknown': lambda tag_count: 'Info' if (not tag_count) or (tag_count <= 2) else 'Suspicious',
'malicious': lambda x: 'Malicious'
}

try:
taxonomies = []
if raw.get('records'):
final_level = None
taxonomy_data = defaultdict(int)
for record in raw.get('records', []):
name = record.get('name', 'unknown')
intention = record.get('intention', 'unknown')
taxonomy_data[name] += 1
final_level = self._get_level(final_level, intention)

if len(taxonomy_data) > 1: # Multiple tags have been found
taxonomies.append(self.build_taxonomy(final_level, 'GreyNoise', 'entries', len(taxonomy_data)))
else: # There is only one tag found, possibly multiple times
for name, count in taxonomy_data.iteritems():
taxonomies.append(self.build_taxonomy(final_level, 'GreyNoise', name, count))

else:
taxonomies.append(self.build_taxonomy('info', 'GreyNoise', 'Records', 'None'))

tag_count = len(raw.get('tags', []))
classification = raw.get('classification', 'unknown')
actor = raw.get('actor')

t1_level = classification_level_map.get(classification)(tag_count)
t1_namespace = 'GreyNoise'
t1_predicate = 'tags'
t1_value = tag_count
# print('{}:{} = {} ({})'.format(t1_namespace, t1_predicate, t1_value, t1_level))
taxonomies.append(self.build_taxonomy(t1_level, t1_namespace, t1_predicate, t1_value))

t2_level = classification_level_map.get(classification)(None)
t2_namespace = 'GreyNoise'
t2_predicate = 'actor' if classification == 'benign' else 'classification'
t2_value = actor if classification == 'benign' else classification
# print('{}:{} = {} ({})'.format(t2_namespace, t2_predicate, t2_value, t2_level))
taxonomies.append(self.build_taxonomy(t2_level, t2_namespace, t2_predicate, t2_value))

return {"taxonomies": taxonomies}

Expand Down
1 change: 1 addition & 0 deletions analyzers/GreyNoise/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
cortexutils
requests
greynoise

0 comments on commit ab032eb

Please sign in to comment.