mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
feat(defender): add service and new check defender_malware_policy_common_attachments_filter_enabled (#7425)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com> Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
committed by
Adrián Jesús Peña Rodríguez
parent
f8d9873655
commit
3ee420769a
@@ -8,8 +8,9 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
- Add SOC2 compliance framework to Azure [(#7489)](https://github.com/prowler-cloud/prowler/pull/7489).
|
||||
- Add check for unused Service Accounts in GCP [(#7419)](https://github.com/prowler-cloud/prowler/pull/7419).
|
||||
- Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331).
|
||||
- Add service Defender to Microsoft365 with one check for Common Attachments filter enabled in Malware Policies [(#7425)](https://github.com/prowler-cloud/prowler/pull/7425).
|
||||
- Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495).
|
||||
- Add Powershell to Microsoft365 [(#7331)](https://github.com/prowler-cloud/prowler/pull/7331)
|
||||
- Add service Exchange to Microsoft365 with one check for Organizations Mailbox Auditing enabled [(#7408)](https://github.com/prowler-cloud/prowler/pull/7408)
|
||||
- Add check for Bypass Disable in every Mailbox for service Defender in M365 [(#7418)](https://github.com/prowler-cloud/prowler/pull/7418)
|
||||
- Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533)
|
||||
|
||||
@@ -189,6 +189,24 @@ class M365PowerShell(PowerShellSession):
|
||||
"Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled | ConvertTo-Json"
|
||||
)
|
||||
|
||||
def get_malware_filter_policy(self) -> dict:
|
||||
"""
|
||||
Get Defender Malware Filter Policy.
|
||||
|
||||
Retrieves the current Defender anti-malware filter policy settings.
|
||||
|
||||
Returns:
|
||||
dict: Malware filter policy settings in JSON format.
|
||||
|
||||
Example:
|
||||
>>> get_malware_filter_policy()
|
||||
{
|
||||
"EnableFileFilter": true,
|
||||
"Identity": "Default"
|
||||
}
|
||||
"""
|
||||
return self.execute("Get-MalwareFilterPolicy | ConvertTo-Json")
|
||||
|
||||
def get_organization_config(self) -> dict:
|
||||
"""
|
||||
Get Exchange Online Organization Configuration.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from prowler.providers.common.provider import Provider
|
||||
from prowler.providers.m365.services.defender.defender_service import Defender
|
||||
|
||||
defender_client = Defender(Provider.get_global_provider())
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "m365",
|
||||
"CheckID": "defender_malware_policy_common_attachments_filter_enabled",
|
||||
"CheckTitle": "Ensure the Common Attachment Types Filter is enabled.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "defender",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "critical",
|
||||
"ResourceType": "Defender Malware Policy",
|
||||
"Description": "Ensure that the Common Attachment Types Filter is enabled in anti-malware policies to block known and custom malicious file types from being attached to emails.",
|
||||
"Risk": "If this setting is not enabled, users may receive emails with malicious attachments that could contain malware, increasing the risk of endpoint infection or data compromise.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/anti-malware-policies-configure?view=o365-worldwide",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "Set-MalwareFilterPolicy -Identity Default -EnableFileFilter $true",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Navigate to Microsoft 365 Defender https://security.microsoft.com. 2. Click to expand Email & collaboration and select Policies & rules. 3. On the Policies & rules page select Threat policies. 4. Under Policies, select Anti-malware and click on the Default (Default) policy. 5. On the policy page, scroll to the bottom and click Edit protection settings. 6. Check the option Enable the common attachments filter. 7. Click Save.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Enable the common attachment types filter in your default or custom anti-malware policy to prevent the delivery of emails with potentially dangerous attachments.",
|
||||
"Url": "https://learn.microsoft.com/en-us/powershell/module/exchange/set-malwarefilterpolicy?view=exchange-ps"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportM365
|
||||
from prowler.providers.m365.services.defender.defender_client import defender_client
|
||||
|
||||
|
||||
class defender_malware_policy_common_attachments_filter_enabled(Check):
|
||||
"""
|
||||
Check if the Common Attachment Types Filter is enabled in the Defender anti-malware policy.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""
|
||||
Execute the check to verify if the Common Attachment Types Filter is enabled.
|
||||
|
||||
This method checks the Defender anti-malware policy to determine if the
|
||||
Common Attachment Types Filter is enabled.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for policy in defender_client.malware_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Malware Policy",
|
||||
resource_id="defenderMalwarePolicy",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Common Attachment Types Filter is not enabled in the Defender anti-malware policy {policy.identity}."
|
||||
|
||||
if policy.enable_file_filter:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Common Attachment Types Filter is enabled in the Defender anti-malware policy {policy.identity}."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,38 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
from prowler.lib.logger import logger
|
||||
from prowler.providers.m365.lib.service.service import M365Service
|
||||
from prowler.providers.m365.m365_provider import M365Provider
|
||||
|
||||
|
||||
class Defender(M365Service):
|
||||
def __init__(self, provider: M365Provider):
|
||||
super().__init__(provider)
|
||||
self.powershell.connect_exchange_online()
|
||||
self.malware_policies = self._get_malware_filter_policy()
|
||||
self.powershell.close()
|
||||
|
||||
def _get_malware_filter_policy(self):
|
||||
logger.info("M365 - Getting Defender malware filter policy...")
|
||||
malware_policies = []
|
||||
try:
|
||||
malware_policy = self.powershell.get_malware_filter_policy()
|
||||
if isinstance(malware_policy, dict):
|
||||
malware_policy = [malware_policy]
|
||||
for policy in malware_policy:
|
||||
malware_policies.append(
|
||||
DefenderMalwarePolicy(
|
||||
enable_file_filter=policy.get("EnableFileFilter", True),
|
||||
identity=policy.get("Identity", ""),
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return malware_policies
|
||||
|
||||
|
||||
class DefenderMalwarePolicy(BaseModel):
|
||||
enable_file_filter: bool
|
||||
identity: str
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_malware_policy_common_attachments_filter_enabled:
|
||||
def test_enable_file_filter_disabled(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||
defender_malware_policy_common_attachments_filter_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
DefenderMalwarePolicy,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
DefenderMalwarePolicy(enable_file_filter=False, identity="Policy1"),
|
||||
DefenderMalwarePolicy(enable_file_filter=False, identity="Policy2"),
|
||||
]
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is not enabled in the Defender anti-malware policy Policy1."
|
||||
)
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Common Attachment Types Filter is not enabled in the Defender anti-malware policy Policy2."
|
||||
)
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
assert result[1].resource_name == "Defender Malware Policy"
|
||||
assert result[1].resource_id == "defenderMalwarePolicy"
|
||||
assert result[1].location == "global"
|
||||
|
||||
def test_enable_file_filter_enabled(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||
defender_malware_policy_common_attachments_filter_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
DefenderMalwarePolicy,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
DefenderMalwarePolicy(enable_file_filter=True, identity="Policy1"),
|
||||
DefenderMalwarePolicy(enable_file_filter=True, identity="Policy2"),
|
||||
]
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is enabled in the Defender anti-malware policy Policy1."
|
||||
)
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Common Attachment Types Filter is enabled in the Defender anti-malware policy Policy2."
|
||||
)
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
assert result[1].resource_name == "Defender Malware Policy"
|
||||
assert result[1].resource_id == "defenderMalwarePolicy"
|
||||
assert result[1].location == "global"
|
||||
|
||||
def test_no_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_m365_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||
defender_malware_policy_common_attachments_filter_enabled,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = []
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
@@ -0,0 +1,54 @@
|
||||
from unittest import mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from prowler.providers.m365.models import M365IdentityInfo
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
Defender,
|
||||
DefenderMalwarePolicy,
|
||||
)
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
def mock_defender_get_malware_filter_policy(_):
|
||||
return [
|
||||
DefenderMalwarePolicy(enable_file_filter=False, identity="Policy1"),
|
||||
DefenderMalwarePolicy(enable_file_filter=True, identity="Policy2"),
|
||||
]
|
||||
|
||||
|
||||
class Test_Defender_Service:
|
||||
def test_get_client(self):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
),
|
||||
):
|
||||
defender_client = Defender(
|
||||
set_mocked_m365_provider(
|
||||
identity=M365IdentityInfo(tenant_domain=DOMAIN)
|
||||
)
|
||||
)
|
||||
assert defender_client.client.__class__.__name__ == "GraphServiceClient"
|
||||
assert defender_client.powershell.__class__.__name__ == "M365PowerShell"
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_malware_filter_policy",
|
||||
new=mock_defender_get_malware_filter_policy,
|
||||
)
|
||||
def test__get_malware_filter_policy(self):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
),
|
||||
):
|
||||
defender_client = Defender(
|
||||
set_mocked_m365_provider(
|
||||
identity=M365IdentityInfo(tenant_domain=DOMAIN)
|
||||
)
|
||||
)
|
||||
malware_policies = defender_client.malware_policies
|
||||
assert malware_policies[0].enable_file_filter is False
|
||||
assert malware_policies[0].identity == "Policy1"
|
||||
assert malware_policies[1].enable_file_filter is True
|
||||
assert malware_policies[1].identity == "Policy2"
|
||||
Reference in New Issue
Block a user