progress
This commit is contained in:
parent
dfa3a9fc53
commit
e97f8d3a70
143
misp_analyzer.py
143
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}")
|
||||
|
Reference in New Issue
Block a user