From 59b05051663ec50d893fe317e80cbe48f7929758 Mon Sep 17 00:00:00 2001 From: ygalnezri Date: Thu, 16 Jan 2025 11:55:27 +0100 Subject: [PATCH] Adjustment of TLP, PAP, Severity, and Observable Tags in TheHive - Adjusted TLP and PAP values to 'Green' and changed 'Severity' to 'Low' in TheHive. - Removed irrelevant observables for the 'DNS Finder' module, which were not useful for analysts. - Added tags to observables to provide context and facilitate the search and linkage with other alert or case data. For example, the alert type for the 'Website Monitoring' module was added as a tag in the observables for that module. --- .env | 1 + Watcher/Watcher/common/core.py | 77 +++++++++++++------ .../common/utils/send_thehive_alerts.py | 10 ++- .../Watcher/common/utils/update_thehive.py | 32 ++++++-- Watcher/Watcher/watcher/settings.py | 41 ++++++---- 5 files changed, 116 insertions(+), 45 deletions(-) diff --git a/.env b/.env index 5f796b0..dbd5f66 100644 --- a/.env +++ b/.env @@ -48,6 +48,7 @@ THE_HIVE_KEY= # Ensure the custom field referenced here is CREATED IN THEHIVE. Otherwise, Alert exports to TheHive will be impacted THE_HIVE_CUSTOM_FIELD=watcher-id THE_HIVE_EMAIL_SENDER=watcher@watcher.com +THE_HIVE_TAGS=Watcher,Impersonation,Malicious Domain,Typosquatting # MISP Setup MISP_URL= diff --git a/Watcher/Watcher/common/core.py b/Watcher/Watcher/common/core.py index 60cb74c..8e03756 100644 --- a/Watcher/Watcher/common/core.py +++ b/Watcher/Watcher/common/core.py @@ -205,8 +205,10 @@ def generate_ref(): "**The following trendy words were detected:**\n" "{words_list}" ), - 'severity': 2, - 'tags': ["Threats Watcher", "Watcher", "Buzzword", "Trendy Words", "Threat Detection"] + 'severity': 1, + 'tlp': 1, + 'pap': 1, + 'tags': settings.THE_HIVE_TAGS }, 'data_leak': { 'title': "New Data Leakage - Alert #{alert_pk} for {keyword_name} keyword", @@ -216,8 +218,10 @@ def generate_ref(): "*Keyword:* {keyword_name}\n" "*Source:* {url}\n" ), - 'severity': 3, - 'tags': ["Data Leak", "Watcher", "Sensitive Data", "Leak Detection"] + 'severity': 1, + 'tlp': 1, + 'pap': 1, + 'tags': settings.THE_HIVE_TAGS }, 'website_monitoring': { 'title': "Website Monitoring Detected - {alert_type} on {domain_name_sanitized}", @@ -236,8 +240,10 @@ def generate_ref(): "*• New Mail Server:* {new_mail_A_record_ip}\n" "*• Old Mail Server:* {old_mail_A_record_ip}\n" ), - 'severity': 2, - 'tags': ["Website Monitoring", "Watcher", "Incident", "Website", "Domain Name", "Impersonation" , "Malicious Domain", "Typosquatting"] + 'severity': 1, + 'tlp': 1, + 'pap': 1, + 'tags': settings.THE_HIVE_TAGS }, 'dns_finder': { 'title': "New Twisted DNS found - {dns_domain_name_sanitized}", @@ -249,8 +255,10 @@ def generate_ref(): "*Corporate DNS:* {alert.dns_twisted.dns_monitored}\n" "*Fuzzer:* {alert.dns_twisted.fuzzer}\n" ), - 'severity': 3, - 'tags': ["DNS Finder", "Watcher", "Twisted DNS", "Corporate Keywords", "Corporate DNS Assets", "Impersonation" , "Malicious Domain", "Typosquatting"] + 'severity': 1, + 'tlp': 1, + 'pap': 1, + 'tags': settings.THE_HIVE_TAGS }, } @@ -306,41 +314,56 @@ def collect_observables(app_name, context_data): elif app_name == 'website_monitoring': site = context_data.get('site') alert_data = context_data.get('alert_data', {}) + alert_type = alert_data.get('type') if site: - observables.append({"dataType": "domain", "data": site.domain_name}) + domain_tag = f"domain_name:{site.domain_name}" + observable = {"dataType": "domain", "data": site.domain_name, "tags": [domain_tag]} + observables.append(observable) if alert_data.get('new_ip'): - observables.append({"dataType": "ip", "data": alert_data['new_ip']}) + observable = {"dataType": "ip", "data": alert_data['new_ip'], "tags": [domain_tag, f"type:{alert_type}", "details:new_ip"]} + observables.append(observable) if alert_data.get('old_ip'): - observables.append({"dataType": "ip", "data": alert_data['old_ip']}) + observable = {"dataType": "ip", "data": alert_data['old_ip'], "tags": [domain_tag, f"type:{alert_type}", "details:old_ip"]} + observables.append(observable) if alert_data.get('new_ip_second'): - observables.append({"dataType": "ip", "data": alert_data['new_ip_second']}) + observable = {"dataType": "ip", "data": alert_data['new_ip_second'], "tags": [domain_tag, f"type:{alert_type}", "details:new_ip_second"]} + observables.append(observable) if alert_data.get('old_ip_second'): - observables.append({"dataType": "ip", "data": alert_data['old_ip_second']}) + observable = {"dataType": "ip", "data": alert_data['old_ip_second'], "tags": [domain_tag, f"type:{alert_type}", "details:old_ip_second"]} + observables.append(observable) if alert_data.get('new_MX_records'): - observables.append({"dataType": "other", "data": alert_data['new_MX_records']}) + observable = {"dataType": "other", "data": alert_data['new_MX_records'], "tags": [domain_tag, f"type:{alert_type}", "details:new_MX_records"]} + observables.append(observable) if alert_data.get('old_MX_records'): - observables.append({"dataType": "other", "data": alert_data['old_MX_records']}) + observable = {"dataType": "other", "data": alert_data['old_MX_records'], "tags": [domain_tag, f"type:{alert_type}", "details:old_MX_records"]} + observables.append(observable) if alert_data.get('new_mail_A_record_ip'): - observables.append({"dataType": "ip", "data": alert_data['new_mail_A_record_ip']}) + observable = {"dataType": "ip", "data": alert_data['new_mail_A_record_ip'], "tags": [domain_tag, f"type:{alert_type}", "details:new_mail_A_record_ip"]} + observables.append(observable) if alert_data.get('old_mail_A_record_ip'): - observables.append({"dataType": "ip", "data": alert_data['old_mail_A_record_ip']}) + observable = {"dataType": "ip", "data": alert_data['old_mail_A_record_ip'], "tags": [domain_tag, f"type:{alert_type}", "details:old_mail_A_record_ip"]} + observables.append(observable) elif app_name == 'data_leak': alert = context_data.get('alert') if alert: - observables.append({"dataType": "url", "data": alert.url}) - observables.append({"dataType": "other", "data": alert.keyword.name}) + observable = {"dataType": "url", "data": alert.url, "tags": []} + if alert.keyword: + observable["tags"].append(f"keyword:{alert.keyword.name}") + observables.append(observable) elif app_name == 'dns_finder': alert = context_data.get('alert') if alert: - observables.append({"dataType": "domain", "data": alert.dns_twisted.domain_name}) - if alert.dns_twisted.keyword_monitored: - observables.append({"dataType": "other", "data": alert.dns_twisted.keyword_monitored.name}) - if alert.dns_twisted.dns_monitored: - observables.append({"dataType": "domain", "data": alert.dns_twisted.dns_monitored.domain_name}) + observable = {"dataType": "domain", "data": alert.dns_twisted.domain_name, "tags": []} if alert.dns_twisted.fuzzer: - observables.append({"dataType": "other", "data": alert.dns_twisted.fuzzer}) + observable["tags"].append(f"fuzzer:{alert.dns_twisted.fuzzer}") + if alert.dns_twisted.dns_monitored: + observable["tags"].append(f"corporate_dns:{alert.dns_twisted.dns_monitored.domain_name}") + if alert.dns_twisted.keyword_monitored: + observable["tags"].append(f"corporate_keyword:{alert.dns_twisted.keyword_monitored.name}") + + observables.append(observable) observables = [observable for observable in observables if observable['data'] is not None and observable['data'] != 'None'] @@ -513,6 +536,8 @@ def send_notification(channel, content_template, subscribers_filter, send_func, title=formatted_title, description=content, severity=app_config_thehive['severity'], + tlp=app_config_thehive['tlp'], + pap=app_config_thehive['pap'], tags=app_config_thehive['tags'], customFields=app_config_thehive.get('customFields'), app_name=app_name, @@ -527,6 +552,8 @@ def send_notification(channel, content_template, subscribers_filter, send_func, title=formatted_title, description=app_config_thehive['description_template'].format(**common_data), severity=app_config_thehive['severity'], + tlp=app_config_thehive['tlp'], + pap=app_config_thehive['pap'], tags=app_config_thehive['tags'], app_name=app_name, domain_name=None, diff --git a/Watcher/Watcher/common/utils/send_thehive_alerts.py b/Watcher/Watcher/common/utils/send_thehive_alerts.py index 98f1de0..65c16ff 100644 --- a/Watcher/Watcher/common/utils/send_thehive_alerts.py +++ b/Watcher/Watcher/common/utils/send_thehive_alerts.py @@ -43,7 +43,7 @@ def post_to_thehive(url, data, headers, proxies): return None -def send_thehive_alert(title, description, severity, tags, app_name, domain_name, observables=None, customFields=None, thehive_url=None, api_key=None): +def send_thehive_alert(title, description, severity, tlp, pap, tags, app_name, domain_name, observables=None, customFields=None, thehive_url=None, api_key=None): from common.core import generate_ref """ Send or update an alert in TheHive based on the application and ticket_id. @@ -51,8 +51,10 @@ def send_thehive_alert(title, description, severity, tags, app_name, domain_name :param title: The title of the alert. :param description: The description of the alert. :param severity: The severity level of the alert (integer). + :param tlp: The Traffic Light Protocol (TLP) level of the alert (integer). + :param pap: The Permissible Action Protocol (PAP) level of the alert (integer). :param tags: A list of tags associated with the alert. - :param app_name: The application triggering the alert (e.g., 'website_monitoring'). + :param app_name: The application triggering the alert. :param domain_name: The domain name related to the alert (used for ticket_id lookup). :param observables: Any observables (default is None). :param customFields: Custom fields for the alert (default is None). @@ -95,6 +97,8 @@ def send_thehive_alert(title, description, severity, tags, app_name, domain_name title=title, description=description, severity=severity, + tlp=tlp, + pap=pap, tags=tags, app_name=app_name, observables=observables, @@ -114,6 +118,8 @@ def send_thehive_alert(title, description, severity, tags, app_name, domain_name title=title, description=description, severity=severity, + tlp=tlp, + pap=pap, tags=tags, app_name=app_name, observables=observables, diff --git a/Watcher/Watcher/common/utils/update_thehive.py b/Watcher/Watcher/common/utils/update_thehive.py index 02ac89c..9483053 100644 --- a/Watcher/Watcher/common/utils/update_thehive.py +++ b/Watcher/Watcher/common/utils/update_thehive.py @@ -106,15 +106,31 @@ def create_observables(observables): observables_data = [] for obs in observables: + tag_info = [] + if 'tags' in obs: + for tag in obs['tags']: + tag_parts = tag.split(':') + if len(tag_parts) == 2: + tag_info.append(f"*{tag_parts[0]}:* {tag_parts[1]}") + + tags_message = "\n".join(tag_info) if tag_info else "No tags" + message = f"**More information(s)**:\n{tags_message}" + observable_data = { "dataType": obs['dataType'], "data": obs['data'], - "message": f"An observable was added on {current_date} at {current_time}.", + "message": message, "ioc": True, "sighted": True, - "tlp": 2 + "tlp": 1, + "pap": 1 } + + if 'tags' in obs: + observable_data['tags'] = obs['tags'] + observables_data.append(observable_data) + return observables_data @@ -140,7 +156,7 @@ def update_existing_alert_case(item_type, existing_item, observables, comment, t add_comment_to_item(item_type, item_id, comment, thehive_url, api_key) -def create_new_alert(ticket_id, title, description, severity, tags, app_name, observables, customFields, comment, thehive_url, api_key): +def create_new_alert(ticket_id, title, description, severity, tlp, pap, tags, app_name, observables, customFields, comment, thehive_url, api_key): from common.core import generate_ref """ Create a new alert in TheHive with the provided details. @@ -149,6 +165,8 @@ def create_new_alert(ticket_id, title, description, severity, tags, app_name, ob :param title: The title of the alert. :param description: The description of the alert. :param severity: The severity level of the alert (integer). + :param tlp: The Traffic Light Protocol (TLP) level of the alert (integer). + :param pap: The Permissible Action Protocol (PAP) level of the alert (integer). :param tags: A list of tags associated with the alert. :param app_name: The application triggering the alert. :param observables: A list of observables to associate with the alert. @@ -166,6 +184,8 @@ def create_new_alert(ticket_id, title, description, severity, tags, app_name, ob "title": title, "description": description, "severity": severity, + "tlp": tlp, + "pap": pap, "tags": tags, "type": app_name, "source": "watcher", @@ -201,7 +221,7 @@ def create_new_alert(ticket_id, title, description, severity, tags, app_name, ob return None -def handle_alert_or_case(ticket_id, observables, comment, title, description, severity, tags, app_name, customFields, thehive_url, api_key): +def handle_alert_or_case(ticket_id, observables, comment, title, description, severity, tlp, pap, tags, app_name, customFields, thehive_url, api_key): """ Handle the creation or updating of alerts and cases in TheHive. @@ -211,6 +231,8 @@ def handle_alert_or_case(ticket_id, observables, comment, title, description, se :param title: The title for the alert. :param description: The description for the alert. :param severity: The severity of the alert (integer). + :param tlp: The Traffic Light Protocol (TLP) level of the alert (integer). + :param pap: The Permissible Action Protocol (PAP) level of the alert (integer). :param tags: A list of tags for the alert. :param app_name: The name of the application triggering the alert. :param customFields: Custom fields to be included in the alert. @@ -235,6 +257,6 @@ def handle_alert_or_case(ticket_id, observables, comment, title, description, se else: create_new_alert( ticket_id=ticket_id, title=title, description=description, severity=severity, - tags=tags, app_name=app_name, observables=observables, + tlp=tlp, pap=pap, tags=tags, app_name=app_name, observables=observables, customFields=customFields, comment=comment, thehive_url=thehive_url, api_key=api_key ) \ No newline at end of file diff --git a/Watcher/Watcher/watcher/settings.py b/Watcher/Watcher/watcher/settings.py index 8a5adff..ba4529d 100755 --- a/Watcher/Watcher/watcher/settings.py +++ b/Watcher/Watcher/watcher/settings.py @@ -126,6 +126,7 @@ THE_HIVE_KEY = os.environ.get('THE_HIVE_KEY', '') THE_HIVE_CUSTOM_FIELD = os.environ.get('THE_HIVE_CUSTOM_FIELD', 'watcher-id') THE_HIVE_EMAIL_SENDER = os.environ.get('THE_HIVE_EMAIL_SENDER', 'watcher@watcher.com') +THE_HIVE_TAGS = os.environ.get('THE_HIVE_TAGS', "Watcher,Impersonation,Malicious Domain,Typosquatting").split(",") # MISP Setup MISP_URL = os.environ.get('MISP_URL', 'https://127.0.0.1') @@ -214,20 +215,34 @@ # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases # SECURITY WARNING: In production please set DB_USER and DB_PASSWORD environment variables in the .env file. +# DATABASES = { +# 'default': { +# 'ENGINE': 'django.db.backends.mysql', +# 'CONN_MAX_AGE': 3600, +# 'NAME': 'db_watcher', +# 'USER': os.environ.get('DB_USER', 'watcher'), +# 'PASSWORD': os.environ.get('DB_PASSWORD', 'Ee5kZm4fWWAmE9hs'), +# 'HOST': 'db_watcher', +# 'PORT': '3306', +# 'OPTIONS': { +# 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", +# "charset": "utf8mb4", +# }, +# } +# } DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'CONN_MAX_AGE': 3600, - 'NAME': 'db_watcher', - 'USER': os.environ.get('DB_USER', 'watcher'), - 'PASSWORD': os.environ.get('DB_PASSWORD', 'Ee5kZm4fWWAmE9hs'), - 'HOST': 'db_watcher', - 'PORT': '3306', - 'OPTIONS': { - 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", - "charset": "utf8mb4", - }, - } + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'CONN_MAX_AGE': 3600, + 'NAME': 'db_watcher3', + 'USER': 'watcher', + 'PASSWORD': 'Ee5kZm4fWWAmE9hs!', + 'HOST': 'localhost', + 'PORT': '3306', + 'OPTIONS': { + 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", + }, + } } # Password validation