feat(teams): add new check teams_unmanaged_communication_disabled (#7561)

Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
Hugo Pereira Brito
2025-04-22 19:25:30 +02:00
committed by GitHub
parent 2379544425
commit cbaddad358
7 changed files with 191 additions and 1 deletions
+1
View File
@@ -18,6 +18,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
- 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_external_domains_restricted` [(#7557)](https://github.com/prowler-cloud/prowler/pull/7557)
- Add new check `teams_email_sending_to_channel_disabled` [(#7533)](https://github.com/prowler-cloud/prowler/pull/7533)
- Add new check `teams_unmanaged_communication_disabled` [(#7561)](https://github.com/prowler-cloud/prowler/pull/7561)
- Add new check for AllowList not used in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492)
- Add new check for SafeList not enabled in the Connection Filter Policy from service Defender in M365 [(#7492)](https://github.com/prowler-cloud/prowler/pull/7492)
- Add new check for DKIM enabled for service Defender in M365 [(#7485)](https://github.com/prowler-cloud/prowler/pull/7485)
@@ -46,6 +46,7 @@ class Teams(M365Service):
if settings:
user_settings = UserSettings(
allow_external_access=settings.get("AllowFederatedUsers", True),
allow_teams_consumer=settings.get("AllowTeamsConsumer", True),
)
except Exception as error:
logger.error(
@@ -69,3 +70,4 @@ class TeamsSettings(BaseModel):
class UserSettings(BaseModel):
allow_external_access: bool = True
allow_teams_consumer: bool = True
@@ -0,0 +1,30 @@
{
"Provider": "m365",
"CheckID": "teams_unmanaged_communication_disabled",
"CheckTitle": "Ensure unmanaged communication is disabled.",
"CheckType": [],
"ServiceName": "teams",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "critical",
"ResourceType": "Teams Settings",
"Description": "Ensure unmanaged communication is disabled in Teams admin center.",
"Risk": "Allowing communication with unmanaged Microsoft Teams users increases the risk of targeted attacks such as phishing, malware distribution (e.g., DarkGate), and exploitation techniques like GIFShell and username enumeration. Unmanaged accounts are easier for threat actors to create and use as attack vectors.",
"RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps",
"Remediation": {
"Code": {
"CLI": "Set-CsTenantFederationConfiguration -AllowTeamsConsumer $false",
"NativeIaC": "",
"Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com/. 2. Click to expand Users select External access. 3. Scroll to Teams accounts not managed by an organization. 4. Set People in my organization can communicate with Teams users whose accounts aren't managed by an organization to Off. 5. Click Save.",
"Terraform": ""
},
"Recommendation": {
"Text": "Disable communication with Teams users whose accounts aren't managed by an organization by setting 'People in my organization can communicate with Teams users whose accounts aren't managed by an organization' to Off. This helps prevent unauthorized or risky external interactions.",
"Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,42 @@
from typing import List
from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.teams.teams_client import teams_client
class teams_unmanaged_communication_disabled(Check):
"""Check if unmanaged communication is disabled in Teams admin center.
Attributes:
metadata: Metadata associated with the check (inherited from Check).
"""
def execute(self) -> List[CheckReportM365]:
"""Execute the check for
This method checks if unmanaged communication is disabled in Teams admin center.
Returns:
List[CheckReportM365]: A list of reports containing the result of the check.
"""
findings = []
user_settings = teams_client.user_settings
if user_settings:
report = CheckReportM365(
metadata=self.metadata(),
resource=user_settings if user_settings else {},
resource_name="Teams User Settings",
resource_id="userSettings",
)
report.status = "FAIL"
report.status_extended = "Users can communicate with unmanaged users."
if user_settings and not user_settings.allow_teams_consumer:
report.status = "PASS"
report.status_extended = (
"Users can not communicate with unmanaged users."
)
findings.append(report)
return findings
@@ -26,6 +26,7 @@ def mock_get_teams_client_configuration(_):
def mock_get_user_settings(_):
return UserSettings(
allow_external_access=False,
allow_teams_consumer=False,
)
@@ -67,7 +68,8 @@ class Test_Teams_Service:
allow_egnyte=False,
allow_google_drive=False,
allow_share_file=False,
)
),
allow_email_into_channel=True,
)
teams_client.powershell.close()
@@ -88,5 +90,6 @@ class Test_Teams_Service:
)
assert teams_client.user_settings == UserSettings(
allow_external_access=False,
allow_teams_consumer=False,
)
teams_client.powershell.close()
@@ -0,0 +1,112 @@
from unittest import mock
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
class Test_teams_unmanaged_communication_disabled:
def test_no_user_settings(self):
teams_client = mock.MagicMock()
teams_client.audited_tenant = "audited_tenant"
teams_client.audited_domain = DOMAIN
teams_client.user_settings = None
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_microsoft_teams"
),
mock.patch(
"prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled.teams_client",
new=teams_client,
),
):
from prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled import (
teams_unmanaged_communication_disabled,
)
check = teams_unmanaged_communication_disabled()
result = check.execute()
assert len(result) == 0
def test_unmanaged_communication_allowed(self):
teams_client = mock.MagicMock()
teams_client.audited_tenant = "audited_tenant"
teams_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_microsoft_teams"
),
mock.patch(
"prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled.teams_client",
new=teams_client,
),
):
from prowler.providers.m365.services.teams.teams_service import UserSettings
from prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled import (
teams_unmanaged_communication_disabled,
)
teams_client.user_settings = UserSettings(
allow_teams_consumer=True,
)
check = teams_unmanaged_communication_disabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "Users can communicate with unmanaged users."
)
assert result[0].resource == teams_client.user_settings.dict()
assert result[0].resource_name == "Teams User Settings"
assert result[0].resource_id == "userSettings"
assert result[0].location == "global"
def test_unmanaged_communication_restricted(self):
teams_client = mock.MagicMock()
teams_client.audited_tenant = "audited_tenant"
teams_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_microsoft_teams"
),
mock.patch(
"prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled.teams_client",
new=teams_client,
),
):
from prowler.providers.m365.services.teams.teams_service import UserSettings
from prowler.providers.m365.services.teams.teams_unmanaged_communication_disabled.teams_unmanaged_communication_disabled import (
teams_unmanaged_communication_disabled,
)
teams_client.user_settings = UserSettings(
allow_teams_consumer=False,
)
check = teams_unmanaged_communication_disabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== "Users can not communicate with unmanaged users."
)
assert result[0].resource == teams_client.user_settings.dict()
assert result[0].resource_name == "Teams User Settings"
assert result[0].resource_id == "userSettings"
assert result[0].location == "global"