mirror of https://github.com/MISP/misp-modules
Added HYAS Insight Module
parent
7d26d11378
commit
f3b2ea7c41
|
@ -0,0 +1,812 @@
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from typing import Dict, List, Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import re
|
||||||
|
from requests.exceptions import (
|
||||||
|
HTTPError,
|
||||||
|
ProxyError,
|
||||||
|
InvalidURL,
|
||||||
|
ConnectTimeout
|
||||||
|
)
|
||||||
|
from . import check_input_attribute, standard_error_message
|
||||||
|
from pymisp import MISPEvent, MISPAttribute, MISPObject, MISPTag, Distribution
|
||||||
|
|
||||||
|
ip_query_input_type = [
|
||||||
|
'ip-src',
|
||||||
|
'ip-dst'
|
||||||
|
]
|
||||||
|
domain_query_input_type = [
|
||||||
|
'hostname',
|
||||||
|
'domain'
|
||||||
|
]
|
||||||
|
email_query_input_type = [
|
||||||
|
'email',
|
||||||
|
'email-src',
|
||||||
|
'email-dst',
|
||||||
|
'target-email',
|
||||||
|
'whois-registrant-email'
|
||||||
|
]
|
||||||
|
phone_query_input_type = [
|
||||||
|
'phone-number',
|
||||||
|
'whois-registrant-phone'
|
||||||
|
]
|
||||||
|
|
||||||
|
md5_query_input_type = [
|
||||||
|
'md5',
|
||||||
|
'x509-fingerprint-md5',
|
||||||
|
'ja3-fingerprint-md5',
|
||||||
|
'hassh-md5',
|
||||||
|
'hasshserver-md5'
|
||||||
|
]
|
||||||
|
|
||||||
|
sha1_query_input_type = [
|
||||||
|
'sha1',
|
||||||
|
'x509-fingerprint-sha1'
|
||||||
|
]
|
||||||
|
|
||||||
|
sha256_query_input_type = [
|
||||||
|
'sha256',
|
||||||
|
'x509-fingerprint-sha256'
|
||||||
|
]
|
||||||
|
|
||||||
|
sha512_query_input_type = [
|
||||||
|
'sha512'
|
||||||
|
]
|
||||||
|
|
||||||
|
misperrors = {
|
||||||
|
'error': 'Error'
|
||||||
|
}
|
||||||
|
mispattributes = {
|
||||||
|
'input': ip_query_input_type + domain_query_input_type + email_query_input_type + phone_query_input_type
|
||||||
|
+ md5_query_input_type + sha1_query_input_type + sha256_query_input_type + sha512_query_input_type,
|
||||||
|
'format': 'misp_standard'
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleinfo = {
|
||||||
|
'version': '0.1',
|
||||||
|
'author': 'Mike Champ',
|
||||||
|
'description': '',
|
||||||
|
'module-type': ['expansion', 'hover']
|
||||||
|
}
|
||||||
|
moduleconfig = ['apikey']
|
||||||
|
TIMEOUT = 60
|
||||||
|
logger = logging.getLogger('hyasinsight')
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
HYAS_API_BASE_URL = 'https://insight.hyas.com/api/ext/'
|
||||||
|
WHOIS_CURRENT_BASE_URL = 'https://api.hyas.com/'
|
||||||
|
DEFAULT_DISTRIBUTION_SETTING = Distribution.your_organisation_only.value
|
||||||
|
IPV4_REGEX = r'\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b([^\/]|$)'
|
||||||
|
IPV6_REGEX = r'\b(?:(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:(?:(:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\b' # noqa: E501
|
||||||
|
# Enrichment Types
|
||||||
|
# HYAS API endpoints
|
||||||
|
PASSIVE_DNS_ENDPOINT = 'passivedns'
|
||||||
|
DYNAMIC_DNS_ENDPOINT = 'dynamicdns'
|
||||||
|
PASSIVE_HASH_ENDPOINT = 'passivehash'
|
||||||
|
SINKHOLE_ENDPOINT = 'sinkhole'
|
||||||
|
SSL_CERTIFICATE_ENDPOINT = 'ssl_certificate'
|
||||||
|
DEVICE_GEO_ENDPOINT = 'device_geo'
|
||||||
|
WHOIS_HISTORIC_ENDPOINT = 'whois'
|
||||||
|
WHOIS_CURRENT_ENDPOINT = 'whois/v1'
|
||||||
|
MALWARE_RECORDS_ENDPOINT = 'sample'
|
||||||
|
MALWARE_INFORMATION_ENDPOINT = 'sample/information'
|
||||||
|
C2ATTRIBUTION_ENDPOINT = 'c2attribution'
|
||||||
|
OPEN_SOURCE_INDICATORS_ENDPOINT = 'os_indicators'
|
||||||
|
|
||||||
|
# HYAS API endpoint params
|
||||||
|
DOMAIN_PARAM = 'domain'
|
||||||
|
IP_PARAM = 'ip'
|
||||||
|
IPV4_PARAM = 'ipv4'
|
||||||
|
IPV6_PARAM = 'ipv6'
|
||||||
|
EMAIL_PARAM = 'email'
|
||||||
|
PHONE_PARAM = 'phone'
|
||||||
|
MD5_PARAM = 'md5'
|
||||||
|
SHA256_PARAM = 'sha256'
|
||||||
|
SHA512_PARAM = 'sha512'
|
||||||
|
HASH_PARAM = 'hash'
|
||||||
|
SHA1_PARAM = 'sha1'
|
||||||
|
|
||||||
|
HYAS_IP_ENRICHMENT_ENDPOINTS_LIST = [DYNAMIC_DNS_ENDPOINT, PASSIVE_HASH_ENDPOINT, SINKHOLE_ENDPOINT,
|
||||||
|
SSL_CERTIFICATE_ENDPOINT, DEVICE_GEO_ENDPOINT, C2ATTRIBUTION_ENDPOINT]
|
||||||
|
HYAS_DOMAIN_ENRICHMENT_ENDPOINTS_LIST = [PASSIVE_DNS_ENDPOINT, WHOIS_HISTORIC_ENDPOINT, WHOIS_CURRENT_ENDPOINT,
|
||||||
|
C2ATTRIBUTION_ENDPOINT]
|
||||||
|
HYAS_EMAIL_ENRICHMENT_ENDPOINTS_LIST = [DYNAMIC_DNS_ENDPOINT, WHOIS_HISTORIC_ENDPOINT, C2ATTRIBUTION_ENDPOINT]
|
||||||
|
HYAS_PHONE_ENRICHMENT_ENDPOINTS_LIST = [WHOIS_HISTORIC_ENDPOINT]
|
||||||
|
HYAS_SHA1_ENRICHMENT_ENDPOINTS_LIST = [SSL_CERTIFICATE_ENDPOINT, MALWARE_INFORMATION_ENDPOINT,
|
||||||
|
OPEN_SOURCE_INDICATORS_ENDPOINT]
|
||||||
|
HYAS_SHA256_ENRICHMENT_ENDPOINTS_LIST = [C2ATTRIBUTION_ENDPOINT, MALWARE_INFORMATION_ENDPOINT,
|
||||||
|
OPEN_SOURCE_INDICATORS_ENDPOINT]
|
||||||
|
HYAS_SHA512_ENRICHMENT_ENDPOINTS_LIST = [MALWARE_INFORMATION_ENDPOINT]
|
||||||
|
HYAS_MD5_ENRICHMENT_ENDPOINTS_LIST = [MALWARE_RECORDS_ENDPOINT, MALWARE_INFORMATION_ENDPOINT,
|
||||||
|
OPEN_SOURCE_INDICATORS_ENDPOINT]
|
||||||
|
|
||||||
|
HYAS_OBJECT_NAMES = {
|
||||||
|
DYNAMIC_DNS_ENDPOINT: "Dynamic DNS Information",
|
||||||
|
PASSIVE_HASH_ENDPOINT: "Passive Hash Information",
|
||||||
|
SINKHOLE_ENDPOINT: "Sinkhole Information",
|
||||||
|
SSL_CERTIFICATE_ENDPOINT: "SSL Certificate Information",
|
||||||
|
DEVICE_GEO_ENDPOINT: "Mobile Geolocation Information",
|
||||||
|
C2ATTRIBUTION_ENDPOINT: "C2 Attribution Information",
|
||||||
|
PASSIVE_DNS_ENDPOINT: "Passive DNS Information",
|
||||||
|
WHOIS_HISTORIC_ENDPOINT: "Whois Related Information",
|
||||||
|
WHOIS_CURRENT_ENDPOINT: "Whois Current Related Information",
|
||||||
|
MALWARE_INFORMATION_ENDPOINT: "Malware Sample Information",
|
||||||
|
OPEN_SOURCE_INDICATORS_ENDPOINT: "Open Source Intel for malware, ssl certificates and other indicators Information",
|
||||||
|
MALWARE_RECORDS_ENDPOINT: "Malware Sample Records Information"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_attribute(comment, feature, value):
|
||||||
|
"""Generic Method for parsing the attributes in the object"""
|
||||||
|
attribute = {
|
||||||
|
'type': 'text',
|
||||||
|
'value': value,
|
||||||
|
'comment': comment,
|
||||||
|
'distribution': DEFAULT_DISTRIBUTION_SETTING,
|
||||||
|
'object_relation': feature
|
||||||
|
}
|
||||||
|
return attribute
|
||||||
|
|
||||||
|
|
||||||
|
def misp_object(endpoint, attribute_value):
|
||||||
|
object_name = HYAS_OBJECT_NAMES[endpoint]
|
||||||
|
hyas_object = MISPObject(object_name)
|
||||||
|
hyas_object.distribution = DEFAULT_DISTRIBUTION_SETTING
|
||||||
|
hyas_object.template_uuid = "d69d3d15-7b4d-49b1-9e0a-bb29f3d421d9"
|
||||||
|
hyas_object.template_id = "1"
|
||||||
|
hyas_object.description = "HYAS INSIGHT " + object_name
|
||||||
|
hyas_object.comment = "HYAS INSIGHT " + object_name + " for " + attribute_value
|
||||||
|
setattr(hyas_object, 'meta-category', 'network')
|
||||||
|
description = (
|
||||||
|
"An object containing the enriched attribute and "
|
||||||
|
"related entities from HYAS Insight."
|
||||||
|
)
|
||||||
|
hyas_object.from_dict(
|
||||||
|
**{"meta-category": "misc", "description": description,
|
||||||
|
"distribution": DEFAULT_DISTRIBUTION_SETTING}
|
||||||
|
)
|
||||||
|
return hyas_object
|
||||||
|
|
||||||
|
|
||||||
|
def flatten_json(y: Dict) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
:param y: raw_response from HYAS api
|
||||||
|
:return: Flatten json response
|
||||||
|
"""
|
||||||
|
out = {}
|
||||||
|
|
||||||
|
def flatten(x, name=''):
|
||||||
|
# If the Nested key-value
|
||||||
|
# pair is of dict type
|
||||||
|
if type(x) is dict:
|
||||||
|
for a in x:
|
||||||
|
flatten(x[a], name + a + '_')
|
||||||
|
else:
|
||||||
|
out[name[:-1]] = x
|
||||||
|
|
||||||
|
flatten(y)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def get_flatten_json_response(raw_api_response: List[Dict]) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
:param raw_api_response: raw_api response from the API
|
||||||
|
:return: Flatten Json response
|
||||||
|
"""
|
||||||
|
flatten_json_response = []
|
||||||
|
if raw_api_response:
|
||||||
|
for obj in raw_api_response:
|
||||||
|
flatten_json_response.append(flatten_json(obj))
|
||||||
|
|
||||||
|
return flatten_json_response
|
||||||
|
|
||||||
|
|
||||||
|
def request_body(query_input, query_param, current):
|
||||||
|
"""
|
||||||
|
This Method returns the request body for specific endpoint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if current:
|
||||||
|
return {
|
||||||
|
"applied_filters": {
|
||||||
|
query_input: query_param,
|
||||||
|
"current": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"applied_filters": {
|
||||||
|
query_input: query_param
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RequestHandler:
|
||||||
|
"""A class for handling any outbound requests from this module."""
|
||||||
|
|
||||||
|
def __init__(self, apikey):
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.api_key = apikey
|
||||||
|
|
||||||
|
def get(self, url: str, headers: dict = None, req_body=None) -> requests.Response:
|
||||||
|
"""General post method to fetch the response from HYAS Insight."""
|
||||||
|
response = []
|
||||||
|
try:
|
||||||
|
response = self.session.post(
|
||||||
|
url, headers=headers, json=req_body
|
||||||
|
)
|
||||||
|
if response:
|
||||||
|
response = response.json()
|
||||||
|
except (ConnectTimeout, ProxyError, InvalidURL) as error:
|
||||||
|
msg = "Error connecting with the HYAS Insight."
|
||||||
|
logger.error(f"{msg} Error: {error}")
|
||||||
|
misperrors["error"] = msg
|
||||||
|
return response
|
||||||
|
|
||||||
|
def hyas_lookup(self, end_point: str, query_input, query_param, current=False) -> requests.Response:
|
||||||
|
"""Do a lookup call."""
|
||||||
|
# Building the request
|
||||||
|
if current:
|
||||||
|
url = f'{WHOIS_CURRENT_BASE_URL}{WHOIS_CURRENT_ENDPOINT}'
|
||||||
|
else:
|
||||||
|
url = f'{HYAS_API_BASE_URL}{end_point}'
|
||||||
|
headers = {
|
||||||
|
'Content-type': 'application/json',
|
||||||
|
'X-API-Key': self.api_key,
|
||||||
|
}
|
||||||
|
req_body = request_body(query_input, query_param, current)
|
||||||
|
try:
|
||||||
|
response = self.get(url, headers, req_body)
|
||||||
|
except HTTPError as error:
|
||||||
|
msg = f"Error when requesting data from HYAS Insight. {error.response}: {error.response.reason}"
|
||||||
|
logger.error(msg)
|
||||||
|
misperrors["error"] = msg
|
||||||
|
raise
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class HyasInsightParser:
|
||||||
|
"""A class for handling the enrichment objects"""
|
||||||
|
|
||||||
|
def __init__(self, attribute):
|
||||||
|
self.attribute = attribute
|
||||||
|
self.misp_event = MISPEvent()
|
||||||
|
self.misp_event.add_attribute(**attribute)
|
||||||
|
|
||||||
|
self.c2_attribution_data_items = [
|
||||||
|
'actor_ipv4',
|
||||||
|
'c2_domain',
|
||||||
|
'c2_ipv4',
|
||||||
|
'c2_url',
|
||||||
|
'datetime',
|
||||||
|
'email',
|
||||||
|
'email_domain',
|
||||||
|
'referrer_domain',
|
||||||
|
'referrer_ipv4',
|
||||||
|
'referrer_url',
|
||||||
|
'sha256'
|
||||||
|
]
|
||||||
|
self.c2_attribution_data_items_friendly_names = {
|
||||||
|
'actor_ipv4': 'Actor IPv4',
|
||||||
|
'c2_domain': 'C2 Domain',
|
||||||
|
'c2_ipv4': 'C2 IPv4',
|
||||||
|
'c2_url': 'C2 URL',
|
||||||
|
'datetime': 'DateTime',
|
||||||
|
'email': 'Email',
|
||||||
|
'email_domain': 'Email Domain',
|
||||||
|
'referrer_domain': 'Referrer Domain',
|
||||||
|
'referrer_ipv4': 'Referrer IPv4',
|
||||||
|
'referrer_url': 'Referrer URL',
|
||||||
|
'sha256': 'SHA256'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.device_geo_data_items = [
|
||||||
|
'datetime',
|
||||||
|
'device_user_agent',
|
||||||
|
'geo_country_alpha_2',
|
||||||
|
'geo_horizontal_accuracy',
|
||||||
|
'ipv4',
|
||||||
|
'ipv6',
|
||||||
|
'latitude',
|
||||||
|
'longitude',
|
||||||
|
'wifi_bssid'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.device_geo_data_items_friendly_names = {
|
||||||
|
'datetime': 'DateTime',
|
||||||
|
'device_user_agent': 'Device User Agent',
|
||||||
|
'geo_country_alpha_2': 'Alpha-2 Code',
|
||||||
|
'geo_horizontal_accuracy': 'GPS Horizontal Accuracy',
|
||||||
|
'ipv4': 'IPv4 Address',
|
||||||
|
'ipv6': 'IPv6 Address',
|
||||||
|
'latitude': 'Latitude',
|
||||||
|
'longitude': 'Longitude',
|
||||||
|
'wifi_bssid': 'WIFI BSSID'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.dynamic_dns_data_items = [
|
||||||
|
'a_record',
|
||||||
|
'account',
|
||||||
|
'created',
|
||||||
|
'created_ip',
|
||||||
|
'domain',
|
||||||
|
'domain_creator_ip',
|
||||||
|
'email',
|
||||||
|
]
|
||||||
|
|
||||||
|
self.dynamic_dns_data_items_friendly_names = {
|
||||||
|
'a_record': 'A Record',
|
||||||
|
'account': 'Account Holder',
|
||||||
|
'created': 'Created Date',
|
||||||
|
'created_ip': 'Account Holder IP Address',
|
||||||
|
'domain': 'Domain',
|
||||||
|
'domain_creator_ip': 'Domain Creator IP Address',
|
||||||
|
'email': 'Email Address',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.os_indicators_data_items = [
|
||||||
|
'context',
|
||||||
|
'datetime',
|
||||||
|
'domain',
|
||||||
|
'domain_2tld',
|
||||||
|
'first_seen',
|
||||||
|
'ipv4',
|
||||||
|
'ipv6',
|
||||||
|
'last_seen',
|
||||||
|
'md5',
|
||||||
|
'sha1',
|
||||||
|
'sha256',
|
||||||
|
'source_name',
|
||||||
|
'source_url',
|
||||||
|
'url'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.os_indicators_data_items_friendly_names = {
|
||||||
|
'context': 'Context',
|
||||||
|
'datetime': 'DateTime',
|
||||||
|
'domain': 'Domain',
|
||||||
|
'domain_2tld': 'Domain 2TLD',
|
||||||
|
'first_seen': 'First Seen',
|
||||||
|
'ipv4': 'IPv4 Address',
|
||||||
|
'ipv6': 'IPv6 Address',
|
||||||
|
'last_seen': 'Last Seen',
|
||||||
|
'md5': 'MD5',
|
||||||
|
'sha1': 'SHA1',
|
||||||
|
'sha256': 'SHA256',
|
||||||
|
'source_name': 'Source Name',
|
||||||
|
'source_url': 'Source URL',
|
||||||
|
'url': 'URL'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.passive_dns_data_items = [
|
||||||
|
'cert_name',
|
||||||
|
'count',
|
||||||
|
'domain',
|
||||||
|
'first_seen',
|
||||||
|
'ip_geo_city_name',
|
||||||
|
'ip_geo_country_iso_code',
|
||||||
|
'ip_geo_country_name',
|
||||||
|
'ip_geo_location_latitude',
|
||||||
|
'ip_geo_location_longitude',
|
||||||
|
'ip_geo_postal_code',
|
||||||
|
'ip_ip',
|
||||||
|
'ip_isp_autonomous_system_number',
|
||||||
|
'ip_isp_autonomous_system_organization',
|
||||||
|
'ip_isp_ip_address'
|
||||||
|
'ip_isp_isp',
|
||||||
|
'ip_isp_organization',
|
||||||
|
'ipv4',
|
||||||
|
'ipv6',
|
||||||
|
'last_seen'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.passive_dns_data_items_friendly_names = {
|
||||||
|
'cert_name': 'Certificate Provider Name',
|
||||||
|
'count': 'Passive DNS Count',
|
||||||
|
'domain': 'Domain',
|
||||||
|
'first_seen': 'First Seen',
|
||||||
|
'ip_geo_city_name': 'IP Organization City',
|
||||||
|
'ip_geo_country_iso_code': 'IP Organization Country ISO Code',
|
||||||
|
'ip_geo_country_name': 'IP Organization Country Name',
|
||||||
|
'ip_geo_location_latitude': 'IP Organization Latitude',
|
||||||
|
'ip_geo_location_longitude': 'IP Organization Longitude',
|
||||||
|
'ip_geo_postal_code': 'IP Organization Postal Code',
|
||||||
|
'ip_ip': 'IP Address',
|
||||||
|
'ip_isp_autonomous_system_number': 'ASN IP',
|
||||||
|
'ip_isp_autonomous_system_organization': 'ASO IP',
|
||||||
|
'ip_isp_ip_address': 'IP Address',
|
||||||
|
'ip_isp_isp': 'ISP',
|
||||||
|
'ip_isp_organization': 'ISP Organization',
|
||||||
|
'ipv4': 'IPv4 Address',
|
||||||
|
'ipv6': 'IPv6 Address',
|
||||||
|
'last_seen': 'Last Seen'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.passive_hash_data_items = [
|
||||||
|
'domain',
|
||||||
|
'md5_count'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.passive_hash_data_items_friendly_names = {
|
||||||
|
'domain': 'Domain',
|
||||||
|
'md5_count': 'Passive DNS Count'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.malware_records_data_items = [
|
||||||
|
'datetime',
|
||||||
|
'domain',
|
||||||
|
'ipv4',
|
||||||
|
'ipv6',
|
||||||
|
'md5',
|
||||||
|
'sha1',
|
||||||
|
'sha256'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.malware_records_data_items_friendly_names = {
|
||||||
|
'datetime': 'DateTime',
|
||||||
|
'domain': 'Domain',
|
||||||
|
'ipv4': 'IPv4 Address',
|
||||||
|
'ipv6': 'IPv6 Address',
|
||||||
|
'md5': 'MD5',
|
||||||
|
'sha1': 'SHA1',
|
||||||
|
'sha256': 'SHA256'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.malware_information_data_items = [
|
||||||
|
'avscan_score',
|
||||||
|
'md5',
|
||||||
|
'av_name',
|
||||||
|
'def_time',
|
||||||
|
'threat_found',
|
||||||
|
'scan_time',
|
||||||
|
'sha1',
|
||||||
|
'sha256',
|
||||||
|
'sha512'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.malware_information_data_items_friendly_names = {
|
||||||
|
'avscan_score': 'AV Scan Score',
|
||||||
|
'md5': 'MD5',
|
||||||
|
'av_name': 'AV Name',
|
||||||
|
'def_time': 'AV DateTime',
|
||||||
|
'threat_found': 'Source',
|
||||||
|
'scan_time': 'Scan DateTime',
|
||||||
|
'sha1': 'SHA1',
|
||||||
|
'sha256': 'SHA256',
|
||||||
|
'sha512': 'SHA512'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sinkhole_data_items = [
|
||||||
|
'count',
|
||||||
|
'country_name',
|
||||||
|
'data_port',
|
||||||
|
'datetime',
|
||||||
|
'ipv4',
|
||||||
|
'last_seen',
|
||||||
|
'organization_name',
|
||||||
|
'sink_source'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.sinkhole_data_items_friendly_names = {
|
||||||
|
'count': 'Sinkhole Count',
|
||||||
|
'country_name': 'IP Address Country',
|
||||||
|
'data_port': 'Data Port',
|
||||||
|
'datetime': 'First Seen',
|
||||||
|
'ipv4': 'IP Address',
|
||||||
|
'last_seen': 'Last Seen',
|
||||||
|
'organization_name': 'ISP Organization',
|
||||||
|
'sink_source': 'Sink Source IP'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ssl_certificate_data_items = [
|
||||||
|
'ip',
|
||||||
|
'ssl_cert_cert_key',
|
||||||
|
'ssl_cert_expire_date',
|
||||||
|
'ssl_cert_issue_date',
|
||||||
|
'ssl_cert_issuer_commonName',
|
||||||
|
'ssl_cert_issuer_countryName',
|
||||||
|
'ssl_cert_issuer_localityName',
|
||||||
|
'ssl_cert_issuer_organizationName',
|
||||||
|
'ssl_cert_issuer_organizationalUnitName',
|
||||||
|
'ssl_cert_issuer_stateOrProvinceName',
|
||||||
|
'ssl_cert_md5',
|
||||||
|
'ssl_cert_serial_number',
|
||||||
|
'ssl_cert_sha1',
|
||||||
|
'ssl_cert_sha_256',
|
||||||
|
'ssl_cert_sig_algo',
|
||||||
|
'ssl_cert_ssl_version',
|
||||||
|
'ssl_cert_subject_commonName',
|
||||||
|
'ssl_cert_subject_countryName',
|
||||||
|
'ssl_cert_subject_localityName',
|
||||||
|
'ssl_cert_subject_organizationName',
|
||||||
|
'ssl_cert_subject_organizationalUnitName',
|
||||||
|
'ssl_cert_timestamp'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.ssl_certificate_data_items_friendly_names = {
|
||||||
|
'ip': 'IP Address',
|
||||||
|
'ssl_cert_cert_key': 'Certificate Key',
|
||||||
|
'ssl_cert_expire_date': 'Certificate Expiration Date',
|
||||||
|
'ssl_cert_issue_date': 'Certificate Issue Date',
|
||||||
|
'ssl_cert_issuer_commonName': 'Issuer Common Name',
|
||||||
|
'ssl_cert_issuer_countryName': 'Issuer Country Name',
|
||||||
|
'ssl_cert_issuer_localityName': 'Issuer City Name',
|
||||||
|
'ssl_cert_issuer_organizationName': 'Issuer Organization Name',
|
||||||
|
'ssl_cert_issuer_organizationalUnitName': 'Issuer Organization Unit Name',
|
||||||
|
'ssl_cert_issuer_stateOrProvinceName': 'Issuer State or Province Name',
|
||||||
|
'ssl_cert_md5': 'Certificate MD5',
|
||||||
|
'ssl_cert_serial_number': 'Certificate Serial Number',
|
||||||
|
'ssl_cert_sha1': 'Certificate SHA1',
|
||||||
|
'ssl_cert_sha_256': 'Certificate SHA256',
|
||||||
|
'ssl_cert_sig_algo': 'Certificate Signature Algorith',
|
||||||
|
'ssl_cert_ssl_version': 'SSL Version',
|
||||||
|
'ssl_cert_subject_commonName': 'Reciever Subject Name',
|
||||||
|
'ssl_cert_subject_countryName': 'Receiver Country Name',
|
||||||
|
'ssl_cert_subject_localityName': 'Receiver City Name',
|
||||||
|
'ssl_cert_subject_organizationName': 'Receiver Organization Name',
|
||||||
|
'ssl_cert_subject_organizationalUnitName': 'Receiver Organization Unit Name',
|
||||||
|
'ssl_cert_timestamp': 'Certificate DateTime'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.whois_historic_data_items = [
|
||||||
|
'address',
|
||||||
|
'city',
|
||||||
|
'country',
|
||||||
|
'domain',
|
||||||
|
'domain_2tld',
|
||||||
|
'domain_created_datetime',
|
||||||
|
'domain_expires_datetime',
|
||||||
|
'domain_updated_datetime',
|
||||||
|
'email',
|
||||||
|
'idn_name',
|
||||||
|
'nameserver',
|
||||||
|
'phone',
|
||||||
|
'privacy_punch',
|
||||||
|
'registrar'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.whois_historic_data_items_friendly_names = {
|
||||||
|
'address': 'Address',
|
||||||
|
'city': 'City',
|
||||||
|
'country': 'Country',
|
||||||
|
'domain': 'Domain',
|
||||||
|
'domain_2tld': 'Domain 2tld',
|
||||||
|
'domain_created_datetime': 'Domain Created Time',
|
||||||
|
'domain_expires_datetime': 'Domain Expires Time',
|
||||||
|
'domain_updated_datetime': 'Domain Updated Time',
|
||||||
|
'email': 'Email Address',
|
||||||
|
'idn_name': 'IDN Name',
|
||||||
|
'nameserver': 'Nameserver',
|
||||||
|
'phone': 'Phone Info',
|
||||||
|
'privacy_punch': 'Privacy Punch',
|
||||||
|
'registrar': 'Registrar'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.whois_current_data_items = [
|
||||||
|
'abuse_emails',
|
||||||
|
'address',
|
||||||
|
'city',
|
||||||
|
'country',
|
||||||
|
'domain',
|
||||||
|
'domain_2tld',
|
||||||
|
'domain_created_datetime',
|
||||||
|
'domain_expires_datetime',
|
||||||
|
'domain_updated_datetime',
|
||||||
|
'email',
|
||||||
|
'idn_name',
|
||||||
|
'nameserver',
|
||||||
|
'organization',
|
||||||
|
'phone',
|
||||||
|
'registrar',
|
||||||
|
'state'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.whois_current_data_items_friendly_names = {
|
||||||
|
'abuse_emails': 'Abuse Emails',
|
||||||
|
'address': 'Address',
|
||||||
|
'city': 'City',
|
||||||
|
'country': 'Country',
|
||||||
|
'domain': 'Domain',
|
||||||
|
'domain_2tld': 'Domain 2tld',
|
||||||
|
'domain_created_datetime': 'Domain Created Time',
|
||||||
|
'domain_expires_datetime': 'Domain Expires Time',
|
||||||
|
'domain_updated_datetime': 'Domain Updated Time',
|
||||||
|
'email': 'Email Address',
|
||||||
|
'idn_name': 'IDN Name',
|
||||||
|
'nameserver': 'Nameserver',
|
||||||
|
'organization': 'Organization',
|
||||||
|
'phone': 'Phone Info',
|
||||||
|
'registrar': 'Registrar',
|
||||||
|
'state': 'State'
|
||||||
|
}
|
||||||
|
|
||||||
|
def create_misp_attributes_and_objects(self, response, endpoint, attribute_value):
|
||||||
|
flatten_json_response = get_flatten_json_response(response)
|
||||||
|
data_items: List[str] = []
|
||||||
|
data_items_friendly_names: Dict[str, str] = {}
|
||||||
|
if endpoint == DEVICE_GEO_ENDPOINT:
|
||||||
|
data_items: List[str] = self.device_geo_data_items
|
||||||
|
data_items_friendly_names: Dict[str, str] = self.device_geo_data_items_friendly_names
|
||||||
|
elif endpoint == DYNAMIC_DNS_ENDPOINT:
|
||||||
|
data_items: List[str] = self.dynamic_dns_data_items
|
||||||
|
data_items_friendly_names: Dict[str, str] = self.dynamic_dns_data_items_friendly_names
|
||||||
|
elif endpoint == PASSIVE_DNS_ENDPOINT:
|
||||||
|
data_items: List[str] = self.passive_dns_data_items
|
||||||
|
data_items_friendly_names: Dict[str, str] = self.passive_dns_data_items_friendly_names
|
||||||
|
elif endpoint == PASSIVE_HASH_ENDPOINT:
|
||||||
|
data_items: List[str] = self.passive_hash_data_items
|
||||||
|
data_items_friendly_names: Dict[str, str] = self.passive_hash_data_items_friendly_names
|
||||||
|
elif endpoint == SINKHOLE_ENDPOINT:
|
||||||
|
data_items: List[str] = self.sinkhole_data_items
|
||||||
|
data_items_friendly_names: Dict[str, str] = self.sinkhole_data_items_friendly_names
|
||||||
|
elif endpoint == WHOIS_HISTORIC_ENDPOINT:
|
||||||
|
data_items = self.whois_historic_data_items
|
||||||
|
data_items_friendly_names = self.whois_historic_data_items_friendly_names
|
||||||
|
elif endpoint == WHOIS_CURRENT_ENDPOINT:
|
||||||
|
data_items: List[str] = self.whois_current_data_items
|
||||||
|
data_items_friendly_names: Dict[str, str] = self.whois_current_data_items_friendly_names
|
||||||
|
elif endpoint == SSL_CERTIFICATE_ENDPOINT:
|
||||||
|
data_items: List[str] = self.ssl_certificate_data_items
|
||||||
|
data_items_friendly_names: Dict[str, str] = self.ssl_certificate_data_items_friendly_names
|
||||||
|
elif endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
data_items: List[str] = self.malware_information_data_items
|
||||||
|
data_items_friendly_names = self.malware_information_data_items_friendly_names
|
||||||
|
elif endpoint == MALWARE_RECORDS_ENDPOINT:
|
||||||
|
data_items: List[str] = self.malware_records_data_items
|
||||||
|
data_items_friendly_names = self.malware_records_data_items_friendly_names
|
||||||
|
elif endpoint == OPEN_SOURCE_INDICATORS_ENDPOINT:
|
||||||
|
data_items: List[str] = self.os_indicators_data_items
|
||||||
|
data_items_friendly_names = self.os_indicators_data_items_friendly_names
|
||||||
|
elif endpoint == C2ATTRIBUTION_ENDPOINT:
|
||||||
|
data_items: List[str] = self.c2_attribution_data_items
|
||||||
|
data_items_friendly_names = self.c2_attribution_data_items_friendly_names
|
||||||
|
for result in flatten_json_response:
|
||||||
|
hyas_object = misp_object(endpoint, attribute_value)
|
||||||
|
for data_item in result.keys():
|
||||||
|
if data_item in data_items:
|
||||||
|
data_item_text = data_items_friendly_names[data_item]
|
||||||
|
data_item_value = str(result[data_item])
|
||||||
|
hyas_object.add_attribute(
|
||||||
|
**parse_attribute(hyas_object.comment, data_item_text, data_item_value))
|
||||||
|
hyas_object.add_reference(self.attribute['uuid'], 'related-to')
|
||||||
|
self.misp_event.add_object(hyas_object)
|
||||||
|
|
||||||
|
def get_results(self):
|
||||||
|
"""returns the dictionary object to MISP Instance"""
|
||||||
|
event = json.loads(self.misp_event.to_json())
|
||||||
|
results = {key: event[key] for key in ('Attribute', 'Object')}
|
||||||
|
return {'results': results}
|
||||||
|
|
||||||
|
|
||||||
|
def handler(q=False):
|
||||||
|
"""The function which accepts a JSON document to expand the values and return a dictionary of the expanded
|
||||||
|
values. """
|
||||||
|
if q is False:
|
||||||
|
return False
|
||||||
|
request = json.loads(q)
|
||||||
|
# check if the apikey is provided
|
||||||
|
if not request.get('config') or not request['config'].get('apikey'):
|
||||||
|
misperrors['error'] = 'HYAS Insight apikey is missing'
|
||||||
|
return misperrors
|
||||||
|
apikey = request['config'].get('apikey')
|
||||||
|
# check attribute is added to the event
|
||||||
|
if not request.get('attribute') or not check_input_attribute(request['attribute']):
|
||||||
|
return {'error': f'{standard_error_message}, which should contain at least a type, a value and an uuid.'}
|
||||||
|
|
||||||
|
attribute = request['attribute']
|
||||||
|
attribute_type = attribute['type']
|
||||||
|
attribute_value = attribute['value']
|
||||||
|
|
||||||
|
# check if the attribute type is supported by IPQualityScore
|
||||||
|
if attribute_type not in mispattributes['input']:
|
||||||
|
return {'error': 'Unsupported attributes type for HYAS Insight Enrichment'}
|
||||||
|
request_handler = RequestHandler(apikey)
|
||||||
|
parser = HyasInsightParser(attribute)
|
||||||
|
has_results = False
|
||||||
|
if attribute_type in ip_query_input_type:
|
||||||
|
ip_param = ''
|
||||||
|
for endpoint in HYAS_IP_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
if endpoint == DEVICE_GEO_ENDPOINT:
|
||||||
|
if re.match(IPV4_REGEX, attribute_value):
|
||||||
|
ip_param = IPV4_PARAM
|
||||||
|
elif re.match(IPV6_REGEX, attribute_value):
|
||||||
|
ip_param = IPV6_PARAM
|
||||||
|
elif endpoint == PASSIVE_HASH_ENDPOINT:
|
||||||
|
ip_param = IPV4_PARAM
|
||||||
|
elif endpoint == SINKHOLE_ENDPOINT:
|
||||||
|
ip_param = IPV4_PARAM
|
||||||
|
else:
|
||||||
|
ip_param = IP_PARAM
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, ip_param, attribute_value)
|
||||||
|
if endpoint == SSL_CERTIFICATE_ENDPOINT:
|
||||||
|
enrich_response = enrich_response.get('ssl_certs')
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
elif attribute_type in domain_query_input_type:
|
||||||
|
for endpoint in HYAS_DOMAIN_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
if not endpoint == WHOIS_CURRENT_ENDPOINT:
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, DOMAIN_PARAM, attribute_value)
|
||||||
|
else:
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, DOMAIN_PARAM, attribute_value,
|
||||||
|
endpoint == WHOIS_CURRENT_ENDPOINT)
|
||||||
|
enrich_response = enrich_response.get('items')
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
elif attribute_type in email_query_input_type:
|
||||||
|
for endpoint in HYAS_EMAIL_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, EMAIL_PARAM, attribute_value)
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
elif attribute_type in phone_query_input_type:
|
||||||
|
for endpoint in HYAS_PHONE_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, PHONE_PARAM, attribute_value)
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
elif attribute_type in md5_query_input_type:
|
||||||
|
for endpoint in HYAS_MD5_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
if endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
md5_param = HASH_PARAM
|
||||||
|
else:
|
||||||
|
md5_param = MD5_PARAM
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, md5_param, attribute_value)
|
||||||
|
if endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
if not enrich_response.get("Message"):
|
||||||
|
enrich_response = enrich_response.get("scan_results")
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
elif attribute_type in sha1_query_input_type:
|
||||||
|
for endpoint in HYAS_SHA1_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, SHA1_PARAM, attribute_value)
|
||||||
|
if endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
if not enrich_response.get("Message"):
|
||||||
|
enrich_response = enrich_response.get("scan_results")
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
elif attribute_type in sha256_query_input_type:
|
||||||
|
for endpoint in HYAS_SHA256_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
if endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
sha256_param = HASH_PARAM
|
||||||
|
else:
|
||||||
|
sha256_param = SHA256_PARAM
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, sha256_param, attribute_value)
|
||||||
|
if endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
if not enrich_response.get("Message"):
|
||||||
|
enrich_response = enrich_response.get("scan_results")
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
elif attribute_type in sha512_query_input_type:
|
||||||
|
for endpoint in HYAS_SHA512_ENRICHMENT_ENDPOINTS_LIST:
|
||||||
|
if endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
sha512_param = HASH_PARAM
|
||||||
|
enrich_response = request_handler.hyas_lookup(endpoint, sha512_param, attribute_value)
|
||||||
|
if endpoint == MALWARE_INFORMATION_ENDPOINT:
|
||||||
|
if not enrich_response.get("Message"):
|
||||||
|
enrich_response = enrich_response.get("scan_results")
|
||||||
|
if enrich_response:
|
||||||
|
has_results = True
|
||||||
|
parser.create_misp_attributes_and_objects(enrich_response, endpoint, attribute_value)
|
||||||
|
|
||||||
|
if has_results:
|
||||||
|
return parser.get_results()
|
||||||
|
else:
|
||||||
|
return {'error': 'No records found in HYAS Insight for the provided attribute.'}
|
||||||
|
|
||||||
|
|
||||||
|
def introspection():
|
||||||
|
"""The function that returns a dict of the supported attributes (input and output) by your expansion module."""
|
||||||
|
return mispattributes
|
||||||
|
|
||||||
|
|
||||||
|
def version():
|
||||||
|
"""The function that returns a dict with the version and the associated meta-data including potential
|
||||||
|
configurations required of the module. """
|
||||||
|
moduleinfo['config'] = moduleconfig
|
||||||
|
return moduleinfo
|
Loading…
Reference in New Issue