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_domains_restricted (#7557)
Co-authored-by: Sergio Garcia <hello@mistercloudsec.com>
This commit is contained in:
committed by
Pepe Fagoaga
parent
253847e3cd
commit
08f52ee668
@@ -16,6 +16,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Support CLOUDSDK_AUTH_ACCESS_TOKEN in GCP [(#7495)](https://github.com/prowler-cloud/prowler/pull/7495).
|
||||
- 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_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 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)
|
||||
|
||||
@@ -137,6 +137,23 @@ class M365PowerShell(PowerShellSession):
|
||||
"""
|
||||
return self.execute("Get-CsTeamsClientConfiguration | ConvertTo-Json")
|
||||
|
||||
def get_user_settings(self) -> dict:
|
||||
"""
|
||||
Get Teams User Settings.
|
||||
|
||||
Retrieves the current Microsoft Teams user settings.
|
||||
|
||||
Returns:
|
||||
dict: Teams user settings in JSON format.
|
||||
|
||||
Example:
|
||||
>>> get_user_settings()
|
||||
{
|
||||
"AllowExternalAccess": true
|
||||
}
|
||||
"""
|
||||
return self.execute("Get-CsTenantFederationConfiguration | ConvertTo-Json")
|
||||
|
||||
def connect_exchange_online(self) -> dict:
|
||||
"""
|
||||
Connect to Exchange Online PowerShell Module.
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"Provider": "m365",
|
||||
"CheckID": "teams_external_domains_restricted",
|
||||
"CheckTitle": "Ensure external domains are restricted.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "teams",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "",
|
||||
"Severity": "high",
|
||||
"ResourceType": "Teams Settings",
|
||||
"Description": "Ensure external domains are restricted from being used in Teams admin center.",
|
||||
"Risk": "Allowing unrestricted communication with external domains in Microsoft Teams increases the risk of exposure to social engineering attacks, phishing, malware delivery (e.g., DarkGate), and exploitation tactics such as GIFShell or username enumeration.",
|
||||
"RelatedUrl": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "Set-CsTenantFederationConfiguration -AllowFederatedUsers $false",
|
||||
"NativeIaC": "",
|
||||
"Other": "1. Navigate to Microsoft Teams admin center https://admin.teams.microsoft.com/. 2. Click to expand Users select External access. 3. Under Teams and Skype for Business users in external organizations set Choose which external domains your users have access to to one of the following: Allow only specific external domains or Block all external domains. 4. Click Save.",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Restrict external collaboration by configuring Teams to either Block all external domains or Allow only specific, trusted external domains. This ensures users can only interact with vetted organizations, significantly reducing the attack surface.",
|
||||
"Url": "https://learn.microsoft.com/en-us/powershell/module/teams/set-cstenantfederationconfiguration?view=teams-ps"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": ""
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
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_domains_restricted(Check):
|
||||
"""Check if external domains are restricted from being used 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 external domains are restricted from being used 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 access external domains."
|
||||
|
||||
if user_settings and not user_settings.allow_external_access:
|
||||
report.status = "PASS"
|
||||
report.status_extended = "Users can not access external domains."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -10,6 +10,7 @@ class Teams(M365Service):
|
||||
super().__init__(provider)
|
||||
self.powershell.connect_microsoft_teams()
|
||||
self.teams_settings = self._get_teams_client_configuration()
|
||||
self.user_settings = self._get_user_settings()
|
||||
self.powershell.close()
|
||||
|
||||
def _get_teams_client_configuration(self):
|
||||
@@ -37,6 +38,21 @@ class Teams(M365Service):
|
||||
)
|
||||
return teams_settings
|
||||
|
||||
def _get_user_settings(self):
|
||||
logger.info("M365 - Getting Teams user settings...")
|
||||
user_settings = None
|
||||
try:
|
||||
settings = self.powershell.get_user_settings()
|
||||
if settings:
|
||||
user_settings = UserSettings(
|
||||
allow_external_access=settings.get("AllowFederatedUsers", True),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return user_settings
|
||||
|
||||
|
||||
class CloudStorageSettings(BaseModel):
|
||||
allow_box: bool
|
||||
@@ -49,3 +65,7 @@ class CloudStorageSettings(BaseModel):
|
||||
class TeamsSettings(BaseModel):
|
||||
cloud_storage_settings: CloudStorageSettings
|
||||
allow_email_into_channel: bool = True
|
||||
|
||||
|
||||
class UserSettings(BaseModel):
|
||||
allow_external_access: bool = True
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_teams_external_domains_restricted:
|
||||
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_domains_restricted.teams_external_domains_restricted.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted import (
|
||||
teams_external_domains_restricted,
|
||||
)
|
||||
|
||||
check = teams_external_domains_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_external_domains_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_domains_restricted.teams_external_domains_restricted.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted import (
|
||||
teams_external_domains_restricted,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import UserSettings
|
||||
|
||||
teams_client.user_settings = UserSettings(
|
||||
allow_external_access=True,
|
||||
)
|
||||
|
||||
check = teams_external_domains_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status_extended == "Users can access external domains."
|
||||
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_external_domains_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_domains_restricted.teams_external_domains_restricted.teams_client",
|
||||
new=teams_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.teams.teams_external_domains_restricted.teams_external_domains_restricted import (
|
||||
teams_external_domains_restricted,
|
||||
)
|
||||
from prowler.providers.m365.services.teams.teams_service import UserSettings
|
||||
|
||||
teams_client.user_settings = UserSettings(
|
||||
allow_external_access=False,
|
||||
)
|
||||
|
||||
check = teams_external_domains_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].status_extended == "Users can not access external domains."
|
||||
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"
|
||||
@@ -6,6 +6,7 @@ from prowler.providers.m365.services.teams.teams_service import (
|
||||
CloudStorageSettings,
|
||||
Teams,
|
||||
TeamsSettings,
|
||||
UserSettings,
|
||||
)
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
@@ -22,6 +23,12 @@ def mock_get_teams_client_configuration(_):
|
||||
)
|
||||
|
||||
|
||||
def mock_get_user_settings(_):
|
||||
return UserSettings(
|
||||
allow_external_access=False,
|
||||
)
|
||||
|
||||
|
||||
class Test_Teams_Service:
|
||||
def test_get_client(self):
|
||||
with (
|
||||
@@ -63,3 +70,23 @@ class Test_Teams_Service:
|
||||
)
|
||||
)
|
||||
teams_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.teams.teams_service.Teams._get_user_settings",
|
||||
new=mock_get_user_settings,
|
||||
)
|
||||
def test_get_user_settings(self):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_microsoft_teams"
|
||||
),
|
||||
):
|
||||
teams_client = Teams(
|
||||
set_mocked_m365_provider(
|
||||
identity=M365IdentityInfo(tenant_domain=DOMAIN)
|
||||
)
|
||||
)
|
||||
assert teams_client.user_settings == UserSettings(
|
||||
allow_external_access=False,
|
||||
)
|
||||
teams_client.powershell.close()
|
||||
|
||||
Reference in New Issue
Block a user