mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 20:42:02 +00:00
feat(teams): add new check teams_external_users_cannot_start_conversations (#7562)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
committed by
GitHub
parent
cbaddad358
commit
8713b74204
@@ -19,6 +19,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- 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 `teams_external_users_cannot_start_conversations` [(#7562)](https://github.com/prowler-cloud/prowler/pull/7562)
|
||||
- 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)
|
||||
|
||||
+4
-2
@@ -29,12 +29,14 @@ class teams_email_sending_to_channel_disabled(Check):
|
||||
resource_id="teamsSettings",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "Users can send emails to channel email addresses."
|
||||
report.status_extended = (
|
||||
"Teams users can send emails to channel email addresses."
|
||||
)
|
||||
|
||||
if teams_settings and not teams_settings.allow_email_into_channel:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
"Users can not send emails to channel email addresses."
|
||||
"Teams users cannot send emails to channel email addresses."
|
||||
)
|
||||
|
||||
findings.append(report)
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "m365",
|
||||
"CheckID": "teams_external_users_cannot_start_conversations",
|
||||
"CheckTitle": "Ensure external users cannot start conversations.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "teams",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "critical",
|
||||
"ResourceType": "Teams Settings",
|
||||
"Description": "Ensure external users cannot initiate conversations.",
|
||||
"Risk": "Allowing unmanaged external Teams users to initiate conversations increases the risk of phishing, malware distribution such as DarkGate, social engineering attacks like those by Midnight Blizzard, GIFShell exploitation, and username enumeration.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "Set-CsTenantFederationConfiguration -AllowTeamsConsumerInbound $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. Uncheck External users with Teams accounts not managed by an organization can contact users in my organization. 5. Click Save.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Disable the ability for external Teams users not managed by an organization to initiate conversations by unchecking the option that permits them to contact users in your organization. This provides an added layer of protection, especially if exceptions are made to allow limited communication with unmanaged users.",
|
||||
"Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-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.teams.teams_client import teams_client
|
||||
|
||||
|
||||
class teams_external_users_cannot_start_conversations(Check):
|
||||
"""Check if external users cannot start conversations.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""Execute the check for external users cannot start conversations.
|
||||
|
||||
This method checks if external users cannot start conversations.
|
||||
|
||||
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 = "External Teams users can initiate conversations."
|
||||
|
||||
if user_settings and not user_settings.allow_teams_consumer_inbound:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
"External Teams users cannot initiate conversations."
|
||||
)
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -47,6 +47,9 @@ class Teams(M365Service):
|
||||
user_settings = UserSettings(
|
||||
allow_external_access=settings.get("AllowFederatedUsers", True),
|
||||
allow_teams_consumer=settings.get("AllowTeamsConsumer", True),
|
||||
allow_teams_consumer_inbound=settings.get(
|
||||
"AllowTeamsConsumerInbound", True
|
||||
),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -71,3 +74,4 @@ class TeamsSettings(BaseModel):
|
||||
class UserSettings(BaseModel):
|
||||
allow_external_access: bool = True
|
||||
allow_teams_consumer: bool = True
|
||||
allow_teams_consumer_inbound: bool = True
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ class teams_unmanaged_communication_disabled(Check):
|
||||
"""
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""Execute the check for
|
||||
"""Execute the check for unmanaged communication disabled.
|
||||
|
||||
This method checks if unmanaged communication is disabled in Teams admin center.
|
||||
|
||||
@@ -29,12 +29,12 @@ class teams_unmanaged_communication_disabled(Check):
|
||||
resource_id="userSettings",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "Users can communicate with unmanaged users."
|
||||
report.status_extended = "Teams 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."
|
||||
"Teams users cannot communicate with unmanaged users."
|
||||
)
|
||||
|
||||
findings.append(report)
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ class Test_teams_email_sending_to_channel_disabled:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Users can send emails to channel email addresses."
|
||||
== "Teams users can send emails to channel email addresses."
|
||||
)
|
||||
assert result[0].resource == teams_client.teams_settings.dict()
|
||||
assert result[0].resource_name == "Teams Settings"
|
||||
@@ -97,7 +97,7 @@ class Test_teams_email_sending_to_channel_disabled:
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Users can not send emails to channel email addresses."
|
||||
== "Teams users cannot send emails to channel email addresses."
|
||||
)
|
||||
assert result[0].resource == teams_client.teams_settings.dict()
|
||||
assert result[0].resource_name == "Teams Settings"
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_teams_external_users_cannot_start_conversations:
|
||||
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_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations import (
|
||||
teams_external_users_cannot_start_conversations,
|
||||
)
|
||||
|
||||
check = teams_external_users_cannot_start_conversations()
|
||||
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_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations import (
|
||||
teams_external_users_cannot_start_conversations,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import UserSettings
|
||||
|
||||
teams_client.user_settings = UserSettings(
|
||||
allow_teams_consumer_inbound=True,
|
||||
)
|
||||
|
||||
check = teams_external_users_cannot_start_conversations()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "External Teams users can initiate conversations."
|
||||
)
|
||||
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_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_external_users_cannot_start_conversations.teams_external_users_cannot_start_conversations import (
|
||||
teams_external_users_cannot_start_conversations,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import UserSettings
|
||||
|
||||
teams_client.user_settings = UserSettings(
|
||||
allow_teams_consumer_inbound=False,
|
||||
)
|
||||
|
||||
check = teams_external_users_cannot_start_conversations()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "External Teams users cannot initiate conversations."
|
||||
)
|
||||
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"
|
||||
@@ -27,6 +27,7 @@ def mock_get_user_settings(_):
|
||||
return UserSettings(
|
||||
allow_external_access=False,
|
||||
allow_teams_consumer=False,
|
||||
allow_teams_consumer_inbound=False,
|
||||
)
|
||||
|
||||
|
||||
@@ -91,5 +92,6 @@ class Test_Teams_Service:
|
||||
assert teams_client.user_settings == UserSettings(
|
||||
allow_external_access=False,
|
||||
allow_teams_consumer=False,
|
||||
allow_teams_consumer_inbound=False,
|
||||
)
|
||||
teams_client.powershell.close()
|
||||
|
||||
+2
-2
@@ -64,7 +64,7 @@ class Test_teams_unmanaged_communication_disabled:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Users can communicate with unmanaged users."
|
||||
== "Teams users can communicate with unmanaged users."
|
||||
)
|
||||
assert result[0].resource == teams_client.user_settings.dict()
|
||||
assert result[0].resource_name == "Teams User Settings"
|
||||
@@ -104,7 +104,7 @@ class Test_teams_unmanaged_communication_disabled:
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Users can not communicate with unmanaged users."
|
||||
== "Teams users cannot communicate with unmanaged users."
|
||||
)
|
||||
assert result[0].resource == teams_client.user_settings.dict()
|
||||
assert result[0].resource_name == "Teams User Settings"
|
||||
|
||||
Reference in New Issue
Block a user