From a80506686dbab2e933a84a6653c316b61a9cbc46 Mon Sep 17 00:00:00 2001 From: Issel Parra <14161286+isselparra@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:17:19 +0100 Subject: [PATCH 1/5] [microsoft-sentinel] detect alert is prevented --- .../src/openbas_microsoft_sentinel.py | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/microsoft-sentinel/src/openbas_microsoft_sentinel.py b/microsoft-sentinel/src/openbas_microsoft_sentinel.py index 41debee..b1bce3f 100644 --- a/microsoft-sentinel/src/openbas_microsoft_sentinel.py +++ b/microsoft-sentinel/src/openbas_microsoft_sentinel.py @@ -162,16 +162,22 @@ def _extract_ip_addresses(self, columns_index, alert): def _is_prevented(self, columns_index, alert): extended_properties = json.loads(alert[columns_index["ExtendedProperties"]]) - if "Action" in extended_properties and extended_properties["Action"] in [ - "blocked", - "quarantine", - "remove", - ]: - return True - return False + result_action = ( + True + if "Action" in extended_properties + and extended_properties["Action"] + in [ + "blocked", + "quarantine", + "remove", + ] + else False + ) + alert_name = alert[columns_index["AlertName"]] + result_alert_name = True if "prevented" in alert_name.strip().lower() else False + return result_action or result_alert_name def _match_alert(self, endpoint, columns_index, alert, expectation): - print(alert) self.helper.collector_logger.info( "Trying to match alert " + str(alert[columns_index["SystemAlertId"]]) @@ -306,7 +312,6 @@ def _process_alerts(self): alert_date = parse( str(alert[columns_index["TimeGenerated"]]) ).astimezone(pytz.UTC) - print(alert) if alert_date > limit_date: result = self._match_alert( endpoint, columns_index, alert, expectation From 86077865baf2fd6c6b6ba59ed2b32abd03c06ed3 Mon Sep 17 00:00:00 2001 From: Issel Parra <14161286+isselparra@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:19:07 +0100 Subject: [PATCH 2/5] [microsoft-sentinel] verify keywords on alertname --- .../src/openbas_microsoft_sentinel.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/microsoft-sentinel/src/openbas_microsoft_sentinel.py b/microsoft-sentinel/src/openbas_microsoft_sentinel.py index b1bce3f..4e14996 100644 --- a/microsoft-sentinel/src/openbas_microsoft_sentinel.py +++ b/microsoft-sentinel/src/openbas_microsoft_sentinel.py @@ -161,21 +161,12 @@ def _extract_ip_addresses(self, columns_index, alert): return ip_addresses def _is_prevented(self, columns_index, alert): - extended_properties = json.loads(alert[columns_index["ExtendedProperties"]]) - result_action = ( - True - if "Action" in extended_properties - and extended_properties["Action"] - in [ - "blocked", - "quarantine", - "remove", - ] - else False + prevented_keywords = ["blocked", "quarantine", "remove", "prevented"] + alert_name = alert[columns_index["AlertName"]].strip().lower() + result_alert_name = any( + prevented_keyword in alert_name for prevented_keyword in prevented_keywords ) - alert_name = alert[columns_index["AlertName"]] - result_alert_name = True if "prevented" in alert_name.strip().lower() else False - return result_action or result_alert_name + return result_alert_name def _match_alert(self, endpoint, columns_index, alert, expectation): self.helper.collector_logger.info( From 879b1d855a1927c12db99fae805cfbb43fafdda4 Mon Sep 17 00:00:00 2001 From: Romuald Lemesle Date: Wed, 6 Nov 2024 17:04:59 +0100 Subject: [PATCH 3/5] [microsoft-defender] Matching on parent process name --- .../src/openbas_microsoft_defender.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/microsoft-defender/src/openbas_microsoft_defender.py b/microsoft-defender/src/openbas_microsoft_defender.py index 8921119..91123fa 100644 --- a/microsoft-defender/src/openbas_microsoft_defender.py +++ b/microsoft-defender/src/openbas_microsoft_defender.py @@ -77,6 +77,7 @@ def __init__(self): # TODO Command line # self.relevant_signatures_types = ["process_name", "command_line", "file_name", "hostname", "ipv4_address"] self.relevant_signatures_types = [ + "parent_process_name", "process_name", "file_name", "hostname", @@ -102,6 +103,13 @@ def _extract_process_names(self, alert): process_names.append(evidence.file_details.file_name) return process_names + def _extract_parent_process_name(self, alert): + parent_process_names = [] + for evidence in alert.evidence: + if hasattr(evidence, 'parent_process_image_file') and evidence.parent_process_image_file: + parent_process_names.append(evidence.parent_process_image_file.file_name) + return parent_process_names + def _extract_command_lines(self, alert): command_lines = [] for evidence in alert.evidence: @@ -134,7 +142,7 @@ def _extract_ip_addresses(self, alert): def _is_prevented(self, alert): for evidence in alert.evidence: if evidence.odata_type == "#microsoft.graph.security.processEvidence": - if evidence.detection_status in [ + if evidence.detection_status.lower() in [ "prevented", "remediated", "blocked", @@ -174,6 +182,12 @@ def _match_alert(self, endpoint, alert, expectation): "data": self._extract_process_names(alert), "score": 80, } + elif type == "parent_process_name": + alert_data[type] = { + "type": "fuzzy", + "data": self._extract_parent_process_name(alert), + "score": 80, + } elif type == "command_line": alert_data[type] = { "type": "fuzzy", @@ -269,7 +283,7 @@ async def _process_alerts(self, graph_client): ) for i in range(len(alerts.value)): alert = alerts.value[i] - alert_date = parse(str(alert.created_date_time)).astimezone(pytz.UTC) + alert_date = parse(str(alert.last_update_date_time)).astimezone(pytz.UTC) if alert_date > limit_date: result = self._match_alert(endpoint, alert, expectation) if result is not False: From 74926d26dbf4ee94df311c854cd93a3383591c7c Mon Sep 17 00:00:00 2001 From: Romuald Lemesle Date: Wed, 6 Nov 2024 17:05:27 +0100 Subject: [PATCH 4/5] [microsoft-sentinel] Matching on parent process name --- .../src/openbas_microsoft_sentinel.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/microsoft-sentinel/src/openbas_microsoft_sentinel.py b/microsoft-sentinel/src/openbas_microsoft_sentinel.py index 4e14996..3b7d1c7 100644 --- a/microsoft-sentinel/src/openbas_microsoft_sentinel.py +++ b/microsoft-sentinel/src/openbas_microsoft_sentinel.py @@ -93,6 +93,7 @@ def __init__(self): # Initialize signatures helper self.relevant_signatures_types = [ + "parent_process_name", "process_name", "command_line", "file_name", @@ -122,6 +123,16 @@ def _extract_process_names(self, columns_index, alert): process_names.append(entity["Name"]) return process_names + def _extract_parent_process_name(self, columns_index, alert): + parent_process_names = [] + entities = json.loads(alert[columns_index["Entities"]]) + for entity in entities: + if "Type" in entity and entity["Type"] == "process": + if "ParentProcess" in entity and "ImageFile" in entity["ParentProcess"]: + if "ImageFile" in entity["ParentProcess"] and "Name" in entity["ParentProcess"]["ImageFile"]: + parent_process_names.append(entity["ParentProcess"]["ImageFile"]["Name"]) + return parent_process_names + def _extract_command_lines(self, columns_index, alert): command_lines = [] entities = json.loads(alert[columns_index["Entities"]]) @@ -198,6 +209,12 @@ def _match_alert(self, endpoint, columns_index, alert, expectation): "data": self._extract_process_names(columns_index, alert), "score": 80, } + if type == "parent_process_name": + alert_data[type] = { + "type": "fuzzy", + "data": self._extract_parent_process_name(columns_index, alert), + "score": 80, + } elif type == "command_line": alert_data[type] = { "type": "fuzzy", From ef62319d5deae9d34cefd715dac55432ba089b1b Mon Sep 17 00:00:00 2001 From: Romuald Lemesle Date: Wed, 6 Nov 2024 17:11:49 +0100 Subject: [PATCH 5/5] Format --- .../src/openbas_microsoft_defender.py | 13 ++++++++++--- .../src/openbas_microsoft_sentinel.py | 9 +++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/microsoft-defender/src/openbas_microsoft_defender.py b/microsoft-defender/src/openbas_microsoft_defender.py index 91123fa..e4f822e 100644 --- a/microsoft-defender/src/openbas_microsoft_defender.py +++ b/microsoft-defender/src/openbas_microsoft_defender.py @@ -106,8 +106,13 @@ def _extract_process_names(self, alert): def _extract_parent_process_name(self, alert): parent_process_names = [] for evidence in alert.evidence: - if hasattr(evidence, 'parent_process_image_file') and evidence.parent_process_image_file: - parent_process_names.append(evidence.parent_process_image_file.file_name) + if ( + hasattr(evidence, "parent_process_image_file") + and evidence.parent_process_image_file + ): + parent_process_names.append( + evidence.parent_process_image_file.file_name + ) return parent_process_names def _extract_command_lines(self, alert): @@ -283,7 +288,9 @@ async def _process_alerts(self, graph_client): ) for i in range(len(alerts.value)): alert = alerts.value[i] - alert_date = parse(str(alert.last_update_date_time)).astimezone(pytz.UTC) + alert_date = parse(str(alert.last_update_date_time)).astimezone( + pytz.UTC + ) if alert_date > limit_date: result = self._match_alert(endpoint, alert, expectation) if result is not False: diff --git a/microsoft-sentinel/src/openbas_microsoft_sentinel.py b/microsoft-sentinel/src/openbas_microsoft_sentinel.py index 3b7d1c7..3a9c4ac 100644 --- a/microsoft-sentinel/src/openbas_microsoft_sentinel.py +++ b/microsoft-sentinel/src/openbas_microsoft_sentinel.py @@ -129,8 +129,13 @@ def _extract_parent_process_name(self, columns_index, alert): for entity in entities: if "Type" in entity and entity["Type"] == "process": if "ParentProcess" in entity and "ImageFile" in entity["ParentProcess"]: - if "ImageFile" in entity["ParentProcess"] and "Name" in entity["ParentProcess"]["ImageFile"]: - parent_process_names.append(entity["ParentProcess"]["ImageFile"]["Name"]) + if ( + "ImageFile" in entity["ParentProcess"] + and "Name" in entity["ParentProcess"]["ImageFile"] + ): + parent_process_names.append( + entity["ParentProcess"]["ImageFile"]["Name"] + ) return parent_process_names def _extract_command_lines(self, columns_index, alert):