mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 20:42:02 +00:00
feat(m365): ensure all forms of mail forwarding are blocked or disabled (#7658)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
committed by
GitHub
parent
9d788af932
commit
7eec60f4d9
+1
-1
@@ -7,7 +7,7 @@
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "low",
|
||||
"ResourceType": "Defender Anti-Spam Policy",
|
||||
"ResourceType": "Defender Anti-Spam Outbound Policy",
|
||||
"Description": "Ensure that outbound anti-spam policies are configured to notify administrators and copy suspicious outbound messages to designated recipients when a sender is blocked for sending spam emails.",
|
||||
"Risk": "Without outbound spam notifications and message copies, compromised accounts may go undetected, increasing the risk of reputation damage or data leakage through unauthorized email activity.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/outbound-spam-protection-about",
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "m365",
|
||||
"CheckID": "defender_antispam_outbound_policy_forwarding_disabled",
|
||||
"CheckTitle": "Ensure Defender Outbound Spam Policies are set to disable mail forwarding.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "defender",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Defender Anti-Spam Outbound Policy",
|
||||
"Description": "Ensure Defender Outbound Spam Policies are set to disable mail forwarding.",
|
||||
"Risk": "Enabling email auto-forwarding can be exploited by attackers or malicious insiders to exfiltrate sensitive data outside the organization, often without detection.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/defender-office-365/outbound-spam-protection-about",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "Set-HostedOutboundSpamFilterPolicy -Identity {policyName} -AutoForwardingMode Off",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Navigate to Microsoft 365 Defender https://security.microsoft.com/. 2. Expand E-mail & collaboration then select Policies & rules. 3. Select Threat policies > Anti-spam. 4. Select Anti-spam outbound policy (default). 5. Click Edit protection settings. 6. Set Automatic forwarding rules dropdown to Off - Forwarding is disabled and click Save. 7. Repeat steps 4-6 for any additional higher priority, custom policies.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Block all forms of mail forwarding using Anti-spam outbound policies in Exchange Online. Apply exclusions only where justified by organizational policy.",
|
||||
"Url": "https://learn.microsoft.com/en-us/defender-office-365/outbound-spam-protection-about"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "Ensure settings are applied to the highest priority policy if custom policies exist."
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
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_antispam_outbound_policy_forwarding_disabled(Check):
|
||||
"""
|
||||
Check if the Defender Outbound Spam Policies are configured to disable mail forwarding.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""
|
||||
Execute the check to verify if the Defender Outbound Spam Policies disable mail forwarding.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for policy_name, policy in defender_client.outbound_spam_policies.items():
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Outbound Spam Policy",
|
||||
resource_id=policy_name,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Outbound Spam Policy {policy_name} does allow mail forwarding."
|
||||
)
|
||||
|
||||
if (
|
||||
not policy.default
|
||||
and policy_name in defender_client.outbound_spam_rules
|
||||
and defender_client.outbound_spam_rules[policy_name].state.lower()
|
||||
== "enabled"
|
||||
) or policy.default:
|
||||
if not policy.auto_forwarding_mode:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Outbound Spam Policy {policy_name} does not allow mail forwarding."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -164,6 +164,7 @@ class Defender(M365Service):
|
||||
notify_sender_blocked_addresses=policy.get(
|
||||
"NotifyOutboundSpamRecipients", []
|
||||
),
|
||||
auto_forwarding_mode=policy.get("AutoForwardingMode", True),
|
||||
default=policy.get("IsDefault", False),
|
||||
)
|
||||
except Exception as error:
|
||||
@@ -255,6 +256,7 @@ class OutboundSpamPolicy(BaseModel):
|
||||
notify_limit_exceeded: bool
|
||||
notify_limit_exceeded_addresses: List[str]
|
||||
notify_sender_blocked_addresses: List[str]
|
||||
auto_forwarding_mode: bool
|
||||
default: bool
|
||||
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ class Exchange(M365Service):
|
||||
name=rule.get("Name", ""),
|
||||
scl=rule.get("SetSCL", None),
|
||||
sender_domain_is=rule.get("SenderDomainIs", []),
|
||||
redirect_message_to=rule.get("RedirectMessageTo", None),
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
@@ -260,6 +261,7 @@ class TransportRule(BaseModel):
|
||||
name: str
|
||||
scl: Optional[int]
|
||||
sender_domain_is: list[str]
|
||||
redirect_message_to: Optional[list[str]]
|
||||
|
||||
|
||||
class TransportConfig(BaseModel):
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "m365",
|
||||
"CheckID": "exchange_transport_rules_mail_forwarding_disabled",
|
||||
"CheckTitle": "Ensure mail transport rules are set to disable mail forwarding.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "exchange",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Exchange Transport Rules",
|
||||
"Description": "Ensure mail transport rules are set to disable mail forwarding.",
|
||||
"Risk": "Enabling email auto-forwarding can be exploited by attackers or malicious insiders to exfiltrate sensitive data outside the organization, often without detection.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/exchange/security-and-compliance/mail-flow-rules/configuration-best-practices",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "Remove-TransportRule -Identity <RuleName>",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Select Exchange to open the Exchange admin center. 2. Select Mail Flow then Rules. 3. For each rule that redirects email to external domains, select the rule and click the 'Delete' icon.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Block all forms of mail forwarding using Transport rules in Exchange Online. Apply exclusions only where justified by organizational policy.",
|
||||
"Url": "https://learn.microsoft.com/en-us/exchange/security-and-compliance/mail-flow-rules/mail-flow-rules"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
from typing import List
|
||||
|
||||
from prowler.lib.check.models import Check, CheckReportM365
|
||||
from prowler.providers.m365.services.exchange.exchange_client import exchange_client
|
||||
|
||||
|
||||
class exchange_transport_rules_mail_forwarding_disabled(Check):
|
||||
"""
|
||||
Check to ensure that no mail transport rules allow forwarding mail to external domains.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""
|
||||
Execute the check to validate that no transport rules allow forwarding mail to external domains.
|
||||
|
||||
This method retrieves all transport rules from the Exchange service and evaluates
|
||||
whether any of them allow forwarding mail to external domains. A report is generated for each
|
||||
transport rule.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of findings with the status of each transport rule.
|
||||
"""
|
||||
findings = []
|
||||
for rule in exchange_client.transport_rules:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=rule,
|
||||
resource_name=rule.name,
|
||||
resource_id="ExchangeTransportRule",
|
||||
)
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Transport rule {rule.name} does not allow forwarding mail to external domains."
|
||||
|
||||
if rule.redirect_message_to:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Transport rule {rule.name} allows forwarding mail to external domains: {', '.join(rule.redirect_message_to)}."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
+4
@@ -37,6 +37,7 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
default=False,
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
@@ -92,6 +93,7 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
default=False,
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
@@ -146,6 +148,7 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
default=True,
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
@@ -198,6 +201,7 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
notify_limit_exceeded_addresses=["admin@org.com"],
|
||||
notify_sender_blocked_addresses=["admin@org.com"],
|
||||
default=False,
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_antispam_outbound_policy_forwarding_disabled:
|
||||
def test_no_outbound_spam_policies(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_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_forwarding_disabled_custom_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_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
default=False,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(state="Enabled")
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Policy1 does not allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy1"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_forwarding_enabled_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_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Policy2": OutboundSpamPolicy(
|
||||
default=False,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=True,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy2": OutboundSpamRule(state="Enabled")
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Policy2 does allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Policy2"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy2"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_forwarding_disabled_default_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_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
default=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Default does not allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_without_rule(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_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"PolicyX": OutboundSpamPolicy(
|
||||
default=False,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy PolicyX does allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["PolicyX"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "PolicyX"
|
||||
assert result[0].location == "global"
|
||||
@@ -106,6 +106,7 @@ def mock_defender_get_outbound_spam_filter_policy(_):
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["security@example.com"],
|
||||
notify_sender_blocked_addresses=["security@example.com"],
|
||||
auto_forwarding_mode=False,
|
||||
default=False,
|
||||
),
|
||||
"Policy2": OutboundSpamPolicy(
|
||||
@@ -113,6 +114,7 @@ def mock_defender_get_outbound_spam_filter_policy(_):
|
||||
notify_limit_exceeded=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
auto_forwarding_mode=True,
|
||||
default=True,
|
||||
),
|
||||
}
|
||||
@@ -308,6 +310,7 @@ class Test_Defender_Service:
|
||||
assert outbound_spam_policies[
|
||||
"Policy1"
|
||||
].notify_sender_blocked_addresses == ["security@example.com"]
|
||||
assert outbound_spam_policies["Policy1"].auto_forwarding_mode is False
|
||||
assert outbound_spam_policies["Policy1"].default is False
|
||||
assert outbound_spam_policies["Policy2"].notify_sender_blocked is False
|
||||
assert outbound_spam_policies["Policy2"].notify_limit_exceeded is False
|
||||
@@ -317,6 +320,7 @@ class Test_Defender_Service:
|
||||
assert (
|
||||
outbound_spam_policies["Policy2"].notify_sender_blocked_addresses == []
|
||||
)
|
||||
assert outbound_spam_policies["Policy2"].auto_forwarding_mode is True
|
||||
assert outbound_spam_policies["Policy2"].default is True
|
||||
|
||||
@patch(
|
||||
|
||||
@@ -55,11 +55,13 @@ def mock_exchange_get_transport_rules(_):
|
||||
name="test",
|
||||
scl=-1,
|
||||
sender_domain_is=["example.com"],
|
||||
redirect_message_to=None,
|
||||
),
|
||||
TransportRule(
|
||||
name="test2",
|
||||
scl=0,
|
||||
sender_domain_is=["example.com"],
|
||||
redirect_message_to=["test@example.com"],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -261,9 +263,11 @@ class Test_Exchange_Service:
|
||||
assert transport_rules[0].name == "test"
|
||||
assert transport_rules[0].scl == -1
|
||||
assert transport_rules[0].sender_domain_is == ["example.com"]
|
||||
assert transport_rules[0].redirect_message_to is None
|
||||
assert transport_rules[1].name == "test2"
|
||||
assert transport_rules[1].scl == 0
|
||||
assert transport_rules[1].sender_domain_is == ["example.com"]
|
||||
assert transport_rules[1].redirect_message_to == ["test@example.com"]
|
||||
|
||||
exchange_client.powershell.close()
|
||||
|
||||
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_exchange_transport_rules_mail_forwarding_disabled:
|
||||
def test_empty_rule_list(self):
|
||||
exchange_client = mock.MagicMock()
|
||||
exchange_client.audited_tenant = "audited_tenant"
|
||||
exchange_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.exchange.exchange_transport_rules_mail_forwarding_disabled.exchange_transport_rules_mail_forwarding_disabled.exchange_client",
|
||||
new=exchange_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.exchange.exchange_transport_rules_mail_forwarding_disabled.exchange_transport_rules_mail_forwarding_disabled import (
|
||||
exchange_transport_rules_mail_forwarding_disabled,
|
||||
)
|
||||
|
||||
exchange_client.transport_rules = []
|
||||
|
||||
check = exchange_transport_rules_mail_forwarding_disabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_forwarding_disabled(self):
|
||||
exchange_client = mock.MagicMock()
|
||||
exchange_client.audited_tenant = "audited_tenant"
|
||||
exchange_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.exchange.exchange_transport_rules_mail_forwarding_disabled.exchange_transport_rules_mail_forwarding_disabled.exchange_client",
|
||||
new=exchange_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.exchange.exchange_service import (
|
||||
TransportRule,
|
||||
)
|
||||
from prowler.providers.m365.services.exchange.exchange_transport_rules_mail_forwarding_disabled.exchange_transport_rules_mail_forwarding_disabled import (
|
||||
exchange_transport_rules_mail_forwarding_disabled,
|
||||
)
|
||||
|
||||
exchange_client.transport_rules = [
|
||||
TransportRule(
|
||||
name="Rule1", redirect_message_to=[], sender_domain_is=[]
|
||||
),
|
||||
TransportRule(
|
||||
name="Rule2", redirect_message_to=[], sender_domain_is=[]
|
||||
),
|
||||
]
|
||||
|
||||
check = exchange_transport_rules_mail_forwarding_disabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Transport rule Rule1 does not allow forwarding mail to external domains."
|
||||
)
|
||||
assert result[0].resource_name == "Rule1"
|
||||
assert result[0].resource_id == "ExchangeTransportRule"
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Transport rule Rule2 does not allow forwarding mail to external domains."
|
||||
)
|
||||
assert result[1].resource_name == "Rule2"
|
||||
|
||||
def test_forwarding_enabled(self):
|
||||
exchange_client = mock.MagicMock()
|
||||
exchange_client.audited_tenant = "audited_tenant"
|
||||
exchange_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.exchange.exchange_transport_rules_mail_forwarding_disabled.exchange_transport_rules_mail_forwarding_disabled.exchange_client",
|
||||
new=exchange_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.exchange.exchange_service import (
|
||||
TransportRule,
|
||||
)
|
||||
from prowler.providers.m365.services.exchange.exchange_transport_rules_mail_forwarding_disabled.exchange_transport_rules_mail_forwarding_disabled import (
|
||||
exchange_transport_rules_mail_forwarding_disabled,
|
||||
)
|
||||
|
||||
exchange_client.transport_rules = [
|
||||
TransportRule(
|
||||
name="ForwardingRule",
|
||||
redirect_message_to=["external@example.com"],
|
||||
sender_domain_is=[],
|
||||
),
|
||||
TransportRule(
|
||||
name="NoForwardingRule",
|
||||
redirect_message_to=[],
|
||||
sender_domain_is=[],
|
||||
),
|
||||
]
|
||||
|
||||
check = exchange_transport_rules_mail_forwarding_disabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Transport rule ForwardingRule allows forwarding mail to external domains: external@example.com."
|
||||
)
|
||||
assert result[0].resource_name == "ForwardingRule"
|
||||
assert result[0].resource_id == "ExchangeTransportRule"
|
||||
assert result[0].location == "global"
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Transport rule NoForwardingRule does not allow forwarding mail to external domains."
|
||||
)
|
||||
assert result[1].resource_name == "NoForwardingRule"
|
||||
assert result[1].resource_id == "ExchangeTransportRule"
|
||||
assert result[1].location == "global"
|
||||
Reference in New Issue
Block a user