From e97f8d3a70ad19f9ce480d36b2165225f0d4989c Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Wed, 30 Jul 2025 21:49:54 +0200 Subject: [PATCH] progress --- misp_analyzer.py | 143 +++++++++++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 67 deletions(-) diff --git a/misp_analyzer.py b/misp_analyzer.py index 5777edc..090197c 100644 --- a/misp_analyzer.py +++ b/misp_analyzer.py @@ -124,54 +124,67 @@ class MispAnalyzer(interface.BaseAnalyzer): return [] try: - payload = { - "returnFormat": "json", - "value": value, - "type": attr, - "enforceWarninglist": False, - "includeEventTags": True, - "includeContext": True, - } - - if self.include_community: - payload.update({ - "distribution": [0, 1, 2, 3, 5], - "includeEventUuid": True, - "includeCorrelations": True, - "includeDecayScore": False, - "includeFullModel": False, - }) - logger.debug(f"Community search enabled for {value} ({attr})") + # For IP searches, query both ip-src and ip-dst + search_types = [] + if attr.startswith("ip-"): + search_types = ["ip-src", "ip-dst"] else: - payload["distribution"] = [0] - logger.debug(f"Own org search only for {value} ({attr})") + search_types = [attr] - self.stats['api_calls'] += 1 + all_results = [] - response = requests.post( - f"{self.misp_url}/attributes/restSearch/", - json=payload, - headers={"Authorization": self.misp_api_key}, - verify=False, - timeout=45, - ) + for search_type in search_types: + payload = { + "returnFormat": "json", + "value": value, + "type": search_type, + "enforceWarninglist": False, + "includeEventTags": True, + "includeContext": True, + } + + if self.include_community: + payload.update({ + "distribution": [0, 1, 2, 3, 5], + "includeEventUuid": True, + "includeCorrelations": True, + "includeDecayScore": False, + "includeFullModel": False, + }) + logger.debug(f"Community search enabled for {value} ({search_type})") + else: + payload["distribution"] = [0] + logger.debug(f"Own org search only for {value} ({search_type})") + + self.stats['api_calls'] += 1 + + response = requests.post( + f"{self.misp_url}/attributes/restSearch/", + json=payload, + headers={"Authorization": self.misp_api_key}, + verify=False, + timeout=45, + ) - if response.status_code != 200: - logger.debug(f"MISP API returned status {response.status_code} for {value}") - return [] + if response.status_code == 200: + data = response.json() + attributes = data.get("response", {}).get("Attribute", []) + all_results.extend(attributes) + else: + logger.debug(f"MISP API returned status {response.status_code} for {value} ({search_type})") + + # Small delay between search types + time.sleep(0.1) - data = response.json() - attributes = data.get("response", {}).get("Attribute", []) - - if attributes and self.include_community: + if all_results and self.include_community: orgs = set() - for attr_data in attributes: + for attr_data in all_results: org = attr_data.get("Event", {}).get("Orgc", {}).get("name", "Unknown") orgs.add(org) if len(orgs) > 1 or (orgs and list(orgs)[0] not in ["Unknown", "Your Org"]): - logger.info(f"Community hit for {value}: {len(attributes)} matches from {', '.join(list(orgs)[:3])}") + logger.info(f"Community hit for {value}: {len(all_results)} matches from {', '.join(list(orgs)[:3])}") - return attributes + return all_results except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e: self.stats['api_timeouts'] += 1 @@ -198,10 +211,8 @@ class MispAnalyzer(interface.BaseAnalyzer): else: msg = "MISP: Known indicator" - correlating_events = [] + unique_events = {} orgs = set() - event_ids = set() - event_links = [] for res in result: event_info = res.get("Event", {}) @@ -209,23 +220,31 @@ class MispAnalyzer(interface.BaseAnalyzer): event_desc = event_info.get("info", "Unknown") org_name = event_info.get("Orgc", {}).get("name", "Unknown") - if event_id and event_id not in event_ids: - event_ids.add(event_id) - short_desc = event_desc[:60] + "..." if len(event_desc) > 60 else event_desc - correlating_events.append(short_desc) - event_links.append(f"{self.misp_url}/events/view/{event_id}") + if event_id and event_id not in unique_events: + unique_events[event_id] = { + 'description': event_desc, + 'url': f"{self.misp_url}/events/view/{event_id}" + } if org_name != "Unknown": orgs.add(org_name) - if len(correlating_events) == 1: - msg += f" | Event: {correlating_events[0]}" - elif len(correlating_events) > 1: - msg += f" | Events: {correlating_events[0]}" - if len(correlating_events) > 1: - msg += f" + {correlating_events[1]}" - if len(correlating_events) > 2: - msg += f" + {len(correlating_events)-2} more" + unique_event_list = list(unique_events.values()) + + if len(unique_event_list) == 1: + event_data = unique_event_list[0] + short_desc = event_data['description'][:50] + "..." if len(event_data['description']) > 50 else event_data['description'] + msg += f" | Event: {short_desc} | Link: {event_data['url']}" + elif len(unique_event_list) > 1: + msg += f" | {len(unique_event_list)} Events:" + for i, event_data in enumerate(unique_event_list[:2]): + short_desc = event_data['description'][:40] + "..." if len(event_data['description']) > 40 else event_data['description'] + msg += f" [{i+1}] {short_desc} ({event_data['url']})" + if i < len(unique_event_list) - 1 and i < 1: + msg += " |" + + if len(unique_event_list) > 2: + msg += f" | +{len(unique_event_list)-2} more events" if self.include_community and orgs: if len(orgs) > 1: @@ -236,22 +255,12 @@ class MispAnalyzer(interface.BaseAnalyzer): msg += f" | Source: {list(orgs)[0]}" if len(result) > 1: - msg += f" | {len(result)} correlations" - - if event_links: - if len(event_links) == 1: - msg += f" | MISP Event: {event_links[0]}" - else: - msg += f" | MISP Events: {event_links[0]}" - if len(event_links) > 1: - msg += f", {event_links[1]}" - if len(event_links) > 2: - msg += f" +{len(event_links)-2} more" + msg += f" | {len(result)} total correlations" tags = [f"MISP-{attr}", "threat-intel"] if self.include_community: tags.append("community-intel") - if len(correlating_events) > 1: + if len(unique_event_list) > 1: tags.append("multi-event-correlation") event.add_comment(msg) @@ -260,7 +269,7 @@ class MispAnalyzer(interface.BaseAnalyzer): self.stats['events_marked'] += 1 - logger.info(f"Marked event with {len(correlating_events)} correlating MISP events: {', '.join(correlating_events[:3])}") + logger.info(f"Marked event with {len(unique_event_list)} unique MISP events") except Exception as e: logger.error(f"Error marking event: {e}")