From 9b5657a0506757ef2c2be95b93c115a921491522 Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 11:48:37 -0700 Subject: [PATCH 01/11] Added section 9 --- powershell/Maester.psd1 | 2 +- powershell/internal/Get-MtSkippedReason.ps1 | 1 + powershell/public/Add-MtTestResultDetail.ps1 | 3 +- .../public/Get-MtLicenseInformation.ps1 | 23 ++++- .../exchange/Test-MtCisaAttachmentFileType.md | 23 +++++ .../exchange/Test-MtCisaAttachmentFilter.md | 23 +++++ .../exchange/Test-MtCisaBlockExecutable.md | 23 +++++ .../cisa/exchange/Test-MtCisaBlockFileType.md | 23 +++++ .../Test-MtCisaEmailFilterAlternative.md | 25 ++++++ .../exchange/Test-MtCisaPresetSecurity.ps1 | 88 +++++++++++++++++++ .../Test-MtCisaAttachmentFileType.Tests.ps1 | 10 +++ .../Test-MtCisaAttachmentFilter.Tests.ps1 | 10 +++ .../Test-MtCisaBlockExecutable.Tests.ps1 | 10 +++ .../Test-MtCisaBlockFileType.Tests.ps1 | 10 +++ ...est-MtCisaEmailFilterAlternative.Tests.ps1 | 10 +++ website/docs/tests/cisa/exo.md | 5 ++ 16 files changed, 286 insertions(+), 3 deletions(-) create mode 100644 powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaBlockFileType.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 38fa1d96..795927ef 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -121,7 +121,7 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae 'Test-MtCisaDmarcRecordExist', 'Test-MtCisaDmarcRecordReject', 'Test-MtCisaDmarcAggregateCisa', 'Test-MtCisaDmarcReport', 'Test-MtCisaDlp', 'Test-MtCisaDlpPii', 'Test-MtCisaDlpAlternate', - 'Test-MtCisaDlpBaselineRule', + 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity ', 'Test-MtConditionalAccessWhatIf', 'Test-MtConnection', 'Test-MtEidscaControl', diff --git a/powershell/internal/Get-MtSkippedReason.ps1 b/powershell/internal/Get-MtSkippedReason.ps1 index 41659ae8..79888bb5 100644 --- a/powershell/internal/Get-MtSkippedReason.ps1 +++ b/powershell/internal/Get-MtSkippedReason.ps1 @@ -19,6 +19,7 @@ function Get-MtSkippedReason { "NotLicensedEntraIDGovernance" { "This test is for tenants that are licensed for Entra ID Governance. See [Entra ID Governance licensing](https://learn.microsoft.com/entra/fundamentals/licensing#microsoft-entra-id-governance)"; break} "NotLicensedEntraWorkloadID" { "This test is for tenants that are licensed for Entra Workload ID. See [Entra Workload ID licensing](https://learn.microsoft.com/entra/workload-id/workload-identities-faqs)"; break} "NotLicensedExoDlp" { "This test is for tenants that are licensed for Exchange Online DLP. See [Microsoft Purview Data Loss Prevention: Data Loss Prevention (DLP) for Exchange Online, SharePoint Online, and OneDrive for Business](https://learn.microsoft.com/en-us/office365/servicedescriptions/microsoft-365-service-descriptions/microsoft-365-tenantlevel-services-licensing-guidance/microsoft-365-security-compliance-licensing-guidance#which-licenses-provide-the-rights-for-a-user-to-benefit-from-the-service-7)"; break} + "NotLicensedMdo" { "This test is for tenants that are licensed for Defender for Office 365 Plan 2. See [Microsoft Defender for Office 365 service description](https://learn.microsoft.com/en-us/office365/servicedescriptions/office-365-advanced-threat-protection-service-description)"; break} "LicensedEntraIDPremium" { "This test is for tenants that are not licensed for any Entra ID Premium license. See [Entra ID licensing](https://learn.microsoft.com/entra/fundamentals/licensing)"; break} "NotSupported" { "This test relies on capabilities not currently available (e.g., cmdlets that are not available on all platforms, Resolve-DnsName)"; break} default { $SkippedBecause; break} diff --git a/powershell/public/Add-MtTestResultDetail.ps1 b/powershell/public/Add-MtTestResultDetail.ps1 index 4b036047..89b61dc9 100644 --- a/powershell/public/Add-MtTestResultDetail.ps1 +++ b/powershell/public/Add-MtTestResultDetail.ps1 @@ -65,7 +65,8 @@ function Add-MtTestResultDetail { [Parameter(Mandatory = $false)] [ValidateSet('NotConnectedAzure', 'NotConnectedExchange', 'NotDotGovDomain', 'NotLicensedEntraIDP1', 'NotConnectedSecurityCompliance', - 'NotLicensedEntraIDP2', 'NotLicensedEntraIDGovernance', 'NotLicensedEntraWorkloadID', 'NotLicensedExoDlp', "LicensedEntraIDPremium", 'NotSupported', 'Custom' + 'NotLicensedEntraIDP2', 'NotLicensedEntraIDGovernance', 'NotLicensedEntraWorkloadID', 'NotLicensedExoDlp', "LicensedEntraIDPremium", 'NotSupported', 'Custom', + 'NotLicensedMdo' )] # Common reasons for why the test was skipped. [string] $SkippedBecause, diff --git a/powershell/public/Get-MtLicenseInformation.ps1 b/powershell/public/Get-MtLicenseInformation.ps1 index e538de98..6c273023 100644 --- a/powershell/public/Get-MtLicenseInformation.ps1 +++ b/powershell/public/Get-MtLicenseInformation.ps1 @@ -73,7 +73,28 @@ function Get-MtLicenseInformation { $LicenseType = "ExoDlp" } } - Write-Information "The license type for Entra ID is $LicenseType" + Write-Information "The license type for Exchange Online DLP is $LicenseType" + return $LicenseType + Break + } + "Mdo" { + Write-Verbose "Retrieving license SKU for ExoDlp" + #TODO, Refactor to store in module variable + $skus = Invoke-MtGraphRequest -RelativeUri "subscribedSkus" + $requiredSkus = @( + #servicePlanId + "8e0c0a52-6a6c-4d40-8370-dd62790dcd70" #Microsoft Defender for Office 365 (Plan 2) + ) + $LicenseType = $null + #TODO, Refactor to test function + foreach($sku in $requiredSkus){ + $skuId = $sku -in $skus.skuId + $servicePlanId = $sku -in $skus.servicePlans.servicePlanId + if($skuId -or $servicePlanId){ + $LicenseType = "Mdo" + } + } + Write-Information "The license type for Defender for Office is $LicenseType" return $LicenseType Break } diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md new file mode 100644 index 00000000..561243d0 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md @@ -0,0 +1,23 @@ +The attachment filter SHOULD attempt to determine the true file type and assess the file extension. + +Rationale: Users can change a file extension at the end of a file name (e.g., notepad.exe to notepad.txt) to obscure the actual file type. Verifying the file type and checking that this matches the designated file extension can help detect instances where the file extension was changed. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 9 Attachment File Type - MS.EXO.9.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo92v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L502) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md new file mode 100644 index 00000000..468e3522 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md @@ -0,0 +1,23 @@ +Emails SHALL be filtered by attachment file types. + +Rationale: Malicious attachments often take the form of click-to-run files. Sharing high risk file types, when necessary, is better left to a means other than email; the dangers of allowing them to be sent over email outweigh any potential benefits. Filtering email attachments based on file types can prevent spread of malware distributed via click-to-run email attachments. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 9 Attachment File Type - MS.EXO.9.1v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo91v2) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L487) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.md b/powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.md new file mode 100644 index 00000000..f39ae69c --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.md @@ -0,0 +1,23 @@ +At a minimum, click-to-run files SHOULD be blocked (e.g., .exe, .cmd, and .vbe). + +Rationale: Malicious attachments often take the form of click-to-run files. Blocking a list of common executable files helps mitigate the risk of adversarial exploitation. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 9 Attachment File Type - MS.EXO.9.5v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo95v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L547) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaBlockFileType.md b/powershell/public/cisa/exchange/Test-MtCisaBlockFileType.md new file mode 100644 index 00000000..c749acd1 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaBlockFileType.md @@ -0,0 +1,23 @@ +Disallowed file types SHALL be determined and enforced. + +Rationale: Malicious attachments often take the form of click-to-run files, though other file types can contain malicious content as well. As such, determining the full list of file types to block is left to each organization, to be made in accordance with their risk tolerance. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 9 Attachment File Type - MS.EXO.9.3v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo93v2) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L517) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.md b/powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.md new file mode 100644 index 00000000..a08a3935 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.md @@ -0,0 +1,25 @@ +Alternatively chosen filtering solutions SHOULD offer services comparable to Microsoft Defender's Common Attachment Filter. + +Rationale: Malicious attachments often take the form of click-to-run files. Sharing high risk file types, when necessary, is better left to a means other than email; the dangers of allowing them to be sent over email outweigh any potential benefits. Filtering email attachments based on file types can prevent spread of malware distributed via click-to-run email attachments. + +> Note: This test will always result in a skip result. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 9 Attachment File Type - MS.EXO.9.4v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo94v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L532) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 b/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 new file mode 100644 index 00000000..fb74f1c7 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 @@ -0,0 +1,88 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Emails SHALL be filtered by attachment file types + +.EXAMPLE + Test-MtCisaPresetSecurity + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaPresetSecurity +#> +function Test-MtCisaPresetSecurity { + [CmdletBinding()] + [OutputType([bool])] + param() + + if(!(Test-MtConnection ExchangeOnline)){ + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + }elseif(!(Test-MtConnection SecurityCompliance)){ + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + }elseif($null -eq (Get-MtLicenseInformation -Product Mdo)){ + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + <# + $policies = @{ + "MalwareFilterPolicy" = Get-MalwareFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "HostedContentFilterPolicy" = Get-HostedContentFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "AntiPhishPolicy" = Get-AntiPhishPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "SafeAttachmentPolicy" = Get-SafeAttachmentPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "SafeLinksPolicy" = Get-SafeLinksPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "ATPBuiltInProtectionRule" = Get-ATPBuiltInProtectionRule + "EOPProtectionPolicyRule" = Get-EOPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection + "ATPProtectionPolicyRule" = Get-ATPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection + } + #> + + #TODO, cache in module variable + $policies = Get-ATPProtectionPolicyRule + + $standard = $policies | Where-Object { ` + $_.State -eq "Enabled" -and + $_.Identity -eq "Standard Preset Security Policy" + } + + $strict = $policies | Where-Object { ` + $_.State -eq "Enabled" -and + $_.Identity -eq "Strict Preset Security Policy" + } + + $testResult = $standard -and $strict + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if($standard){ + $result += "| Standard | $passResult |`n" + }else{ + $result += "| Standard | $failResult |`n" + } + if($strict){ + $result += "| Strict | $passResult |`n" + }else{ + $result += "| Strict | $failResult |`n" + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 new file mode 100644 index 00000000..8413f12e --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.2", "CISA", "Security", "All" { + It "MS.EXO.9.2: The attachment filter SHOULD attempt to determine the true file type and assess the file extension." { + + $result = Test-MtCisaPresetSecurity + + if ($null -ne $result) { + $result | Should -Be $true -Because "preset policies are enabled." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 new file mode 100644 index 00000000..58248f4f --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.1", "CISA", "Security", "All" { + It "MS.EXO.9.1: Emails SHALL be filtered by attachment file types." { + + $result = Test-MtCisaPresetSecurity + + if ($null -ne $result) { + $result | Should -Be $true -Because "preset policies are enabled." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 new file mode 100644 index 00000000..e8499cc0 --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.5", "CISA", "Security", "All" { + It "MS.EXO.9.5: At a minimum, click-to-run files SHOULD be blocked (e.g., .exe, .cmd, and .vbe)." { + + $result = Test-MtCisaPresetSecurity + + if ($null -ne $result) { + $result | Should -Be $true -Because "preset policies are enabled." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 new file mode 100644 index 00000000..907878c7 --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.3", "CISA", "Security", "All" { + It "MS.EXO.9.3: Disallowed file types SHALL be determined and enforced." { + + $result = Test-MtCisaPresetSecurity + + if ($null -ne $result) { + $result | Should -Be $true -Because "preset policies are enabled." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 new file mode 100644 index 00000000..8648610d --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.4", "CISA", "Security", "All" { + It "MS.EXO.9.4: Alternatively chosen filtering solutions SHOULD offer services comparable to Microsoft Defender's Common Attachment Filter." { + + $result = $null + + if ($null -ne $result) { + $result | Should -Be $true -Because "should not pass." + } + } +} \ No newline at end of file diff --git a/website/docs/tests/cisa/exo.md b/website/docs/tests/cisa/exo.md index cd6f6e55..1a07b968 100644 --- a/website/docs/tests/cisa/exo.md +++ b/website/docs/tests/cisa/exo.md @@ -35,6 +35,11 @@ See the [Installation guide](/docs/installation#optional-modules-and-permissions | Test-MtCisaDlpPii | [MS.EXO.8.2v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo82v2) | | Test-MtCisaDlpAlternate | [MS.EXO.8.3v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo83v1) | | Test-MtCisaDlpBaselineRules | [MS.EXO.8.4v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo84v1) | +| Test-MtCisaPresetSecurity | [MS.EXO.9.1v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo91v2) | +| Test-MtCisaPresetSecurity | [MS.EXO.9.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo92v1) | +| Test-MtCisaPresetSecurity | [MS.EXO.9.3v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo93v2) | +| Test-MtCisaPresetSecurity | [MS.EXO.9.4v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo94v1) | +| Test-MtCisaPresetSecurity | [MS.EXO.9.5v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo95v1) | | Test-MtCisaAntiSpamAllowList | [MS.EXO.12.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo121v1) | | Test-MtCisaAntiSpamSafeList | [MS.EXO.12.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo122v1) | | Test-MtCisaMailboxAuditing | [MS.EXO.13.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo131v1) | \ No newline at end of file From 1bfb0c549983a4b3bd15f8eff44e44053b21b782 Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 13:00:52 -0700 Subject: [PATCH 02/11] a space --- powershell/Maester.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 795927ef..875eeaa2 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -121,7 +121,7 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae 'Test-MtCisaDmarcRecordExist', 'Test-MtCisaDmarcRecordReject', 'Test-MtCisaDmarcAggregateCisa', 'Test-MtCisaDmarcReport', 'Test-MtCisaDlp', 'Test-MtCisaDlpPii', 'Test-MtCisaDlpAlternate', - 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity ', + 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity', 'Test-MtConditionalAccessWhatIf', 'Test-MtConnection', 'Test-MtEidscaControl', From e1fdc7b3b9d62eee3a2808973e9fd20a23b74cb5 Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 17:32:03 -0700 Subject: [PATCH 03/11] Added cahcing EXO get cmdlet --- powershell/Maester.psd1 | 2 +- powershell/Maester.psm1 | 1 + powershell/public/Clear-MtExoCache.ps1 | 26 ++++++ .../public/Get-MtLicenseInformation.ps1 | 4 +- powershell/public/cisa/exchange/Get-MtExo.ps1 | 84 ++++++++++++++++++ .../exchange/Test-MtCisaAttachmentFileType.md | 1 + .../Test-MtCisaAttachmentFileType.ps1 | 88 +++++++++++++++++++ .../exchange/Test-MtCisaPresetSecurity.ps1 | 14 --- 8 files changed, 202 insertions(+), 18 deletions(-) create mode 100644 powershell/public/Clear-MtExoCache.ps1 create mode 100644 powershell/public/cisa/exchange/Get-MtExo.ps1 create mode 100644 powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 875eeaa2..ecab8f7c 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -121,7 +121,7 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae 'Test-MtCisaDmarcRecordExist', 'Test-MtCisaDmarcRecordReject', 'Test-MtCisaDmarcAggregateCisa', 'Test-MtCisaDmarcReport', 'Test-MtCisaDlp', 'Test-MtCisaDlpPii', 'Test-MtCisaDlpAlternate', - 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity', + 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity', 'Get-MtExo', 'Test-MtConditionalAccessWhatIf', 'Test-MtConnection', 'Test-MtEidscaControl', diff --git a/powershell/Maester.psm1 b/powershell/Maester.psm1 index b79aad92..015a0437 100644 --- a/powershell/Maester.psm1 +++ b/powershell/Maester.psm1 @@ -19,6 +19,7 @@ $__MtSession = @{ TestResultDetail = @{} Connections = @() DnsCache = @() + ExoCache = @{} } New-Variable -Name __MtSession -Value $__MtSession -Scope Script -Force diff --git a/powershell/public/Clear-MtExoCache.ps1 b/powershell/public/Clear-MtExoCache.ps1 new file mode 100644 index 00000000..2f0d6e7b --- /dev/null +++ b/powershell/public/Clear-MtExoCache.ps1 @@ -0,0 +1,26 @@ +<# +.SYNOPSIS + Resets the local cache of Exchange Online queries. Use this if you need to force a refresh of the cache in the current session. + +.DESCRIPTION + By default all requests are cached and re-used for the duration of the session. + + Use this function to clear the cache and force a refresh of the data. + +.EXAMPLE + Clear-MtExoCache + + This example clears the cache of all EXO requests. + +.LINK + https://maester.dev/docs/commands/Clear-MtExoCache +#> +function Clear-MtExoCache { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification='Setting module level variable')] + [CmdletBinding()] + param() + + Write-Verbose -Message "Clearing the results for EXO requests in this session" + + $__MtSession.ExoCache = @{} +} \ No newline at end of file diff --git a/powershell/public/Get-MtLicenseInformation.ps1 b/powershell/public/Get-MtLicenseInformation.ps1 index 6c273023..980aadc0 100644 --- a/powershell/public/Get-MtLicenseInformation.ps1 +++ b/powershell/public/Get-MtLicenseInformation.ps1 @@ -19,7 +19,7 @@ function Get-MtLicenseInformation { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0, Mandatory)] - [ValidateSet('EntraID', 'EntraWorkloadID', 'ExoDlp')] + [ValidateSet('EntraID', 'EntraWorkloadID', 'ExoDlp', 'Mdo')] [string] $Product ) @@ -79,14 +79,12 @@ function Get-MtLicenseInformation { } "Mdo" { Write-Verbose "Retrieving license SKU for ExoDlp" - #TODO, Refactor to store in module variable $skus = Invoke-MtGraphRequest -RelativeUri "subscribedSkus" $requiredSkus = @( #servicePlanId "8e0c0a52-6a6c-4d40-8370-dd62790dcd70" #Microsoft Defender for Office 365 (Plan 2) ) $LicenseType = $null - #TODO, Refactor to test function foreach($sku in $requiredSkus){ $skuId = $sku -in $skus.skuId $servicePlanId = $sku -in $skus.servicePlans.servicePlanId diff --git a/powershell/public/cisa/exchange/Get-MtExo.ps1 b/powershell/public/cisa/exchange/Get-MtExo.ps1 new file mode 100644 index 00000000..1404453f --- /dev/null +++ b/powershell/public/cisa/exchange/Get-MtExo.ps1 @@ -0,0 +1,84 @@ +<# +.SYNOPSIS + Retrieves cached response or requests from cmdlet + +.DESCRIPTION + Manages the EXO cmdlet caching + +.EXAMPLE + Get-MtExo -Request AcceptedDomain + + Returns accepted domains for a tenant + +.EXAMPLE + Get-MtAcceptedDomain + + Returns accepted domains for a tenant + +.LINK + https://maester.dev/docs/commands/Get-MtExo +#> +function Get-MtExo { + [Alias( + "Get-MtAcceptedDomain", + "Get-MtRemoteDomain", + "Get-MtTransportConfig", + "Get-MtTransportRule", + "Get-MtOrganizationConfig", + "Get-MtDkimSigningConfig", + "Get-MtSharingPolicy", + "Get-MtDlpComplianceRule", + "Get-MtDlpCompliancePolicy", + "Get-MtMalwareFilterPolicy", + "Get-MtHostedContentFilterPolicy", + "Get-MtAntiPhishPolicy", + "Get-MtSafeAttachmentPolicy", + "Get-MtSafeLinksPolicy", + "Get-MtATPBuiltInProtectionRule", + "Get-MtEOPProtectionPolicyRule", + "Get-MtATPProtectionPolicyRule" + )] + [CmdletBinding()] + [OutputType([string],[object[]],[psobject])] + param( + [string] $Request = ($MyInvocation.InvocationName).Substring(6) + ) + + if($Request -eq "Exo"){ + Write-Error "$($MyInvocation.InvocationName) called with invalid -Request" + return "Unable to obtain policy" + } + + ### To add new commands + ### - add them to the hashtable below + ### - add them as an alias + ### - confirm the command's return type is in OutputType (e.g. (Get-AcceptedDomain).GetType().Name) + $commands = @{ + "AcceptedDomain" = "Get-AcceptedDomain" + "RemoteDomain" = "Get-RemoteDomain" + "TransportConfig" = "Get-TransportConfig" + "TransportRule" = "Get-TransportRule" + "OrganizationConfig" = "Get-OrganizationConfig" + "DkimSigningConfig" = "Get-DkimSigningConfig" + "SharingPolicy" = "Get-SharingPolicy" + "DlpComplianceRule" = "Get-DlpComplianceRule" + "DlpCompliancePolicy" = "Get-DlpCompliancePolicy" + "MalwareFilterPolicy" = "Get-MalwareFilterPolicy" + "HostedContentFilterPolicy" = "Get-HostedContentFilterPolicy" + "AntiPhishPolicy" = "Get-AntiPhishPolicy" + "SafeAttachmentPolicy" = "Get-SafeAttachmentPolicy" + "SafeLinksPolicy" = "Get-SafeLinksPolicy" + "ATPBuiltInProtectionRule" = "Get-ATPBuiltInProtectionRule" + "EOPProtectionPolicyRule" = "Get-EOPProtectionPolicyRule" + "ATPProtectionPolicyRule" = "Get-ATPProtectionPolicyRule" + } + + if($null -eq $__MtSession.ExoCache.$Request){ + $response = $commands.$Request + $__MtSession.ExoCache.$Request = $response + }else{ + $response = $__MtSession.ExoCache.$Request + } + + return $response +} \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md index 561243d0..c802442d 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md @@ -18,6 +18,7 @@ Note: If the toggle slider in step 5 is grayed out, click on **Manage protection * [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) * [CISA 9 Attachment File Type - MS.EXO.9.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo92v1) * [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L502) +* [Microsoft Learn - True type matching in the common attachments filter](https://learn.microsoft.com/en-us/defender-office-365/anti-malware-protection-about#true-type-matching-in-the-common-attachments-filter) %TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 new file mode 100644 index 00000000..8fd6dbed --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 @@ -0,0 +1,88 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Emails SHALL be filtered by attachment file types + +.EXAMPLE + Test-MtCisaPresetSecurity + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaPresetSecurity +#> +function Test-MtCisaPresetSecurity { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + <# + $policies = @{ + "MalwareFilterPolicy" = Get-MalwareFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "HostedContentFilterPolicy" = Get-HostedContentFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "AntiPhishPolicy" = Get-AntiPhishPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "SafeAttachmentPolicy" = Get-SafeAttachmentPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "SafeLinksPolicy" = Get-SafeLinksPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "ATPBuiltInProtectionRule" = Get-ATPBuiltInProtectionRule + "EOPProtectionPolicyRule" = Get-EOPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection + "ATPProtectionPolicyRule" = Get-ATPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection + } + #> + + #TODO, cache in module variable + $policies = Get-ATPProtectionPolicyRule + + $standard = $policies | Where-Object { ` + $_.State -eq "Enabled" -and + $_.Identity -eq "Standard Preset Security Policy" + } + + $strict = $policies | Where-Object { ` + $_.State -eq "Enabled" -and + $_.Identity -eq "Strict Preset Security Policy" + } + + $testResult = $standard -and $strict + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n" + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 b/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 index fb74f1c7..8a66ef4b 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 @@ -29,20 +29,6 @@ function Test-MtCisaPresetSecurity { return $null } - <# - $policies = @{ - "MalwareFilterPolicy" = Get-MalwareFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "HostedContentFilterPolicy" = Get-HostedContentFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "AntiPhishPolicy" = Get-AntiPhishPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "SafeAttachmentPolicy" = Get-SafeAttachmentPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "SafeLinksPolicy" = Get-SafeLinksPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "ATPBuiltInProtectionRule" = Get-ATPBuiltInProtectionRule - "EOPProtectionPolicyRule" = Get-EOPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection - "ATPProtectionPolicyRule" = Get-ATPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection - } - #> - - #TODO, cache in module variable $policies = Get-ATPProtectionPolicyRule $standard = $policies | Where-Object { ` From 925f7440072bbacae7d0787466af5f27d1f826e0 Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 18:30:50 -0700 Subject: [PATCH 04/11] Updating to use caching and more specific testing --- powershell/Maester.psd1 | 4 ++- powershell/public/cisa/exchange/Get-MtExo.ps1 | 19 ++++++++--- .../Test-MtCisaAttachmentFileType.ps1 | 34 ++++++++++++------- .../exchange/Test-MtCisaPresetSecurity.ps1 | 4 +-- .../Test-MtCisaAttachmentFileType.Tests.ps1 | 2 +- 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index ecab8f7c..e211e22b 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -121,7 +121,9 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae 'Test-MtCisaDmarcRecordExist', 'Test-MtCisaDmarcRecordReject', 'Test-MtCisaDmarcAggregateCisa', 'Test-MtCisaDmarcReport', 'Test-MtCisaDlp', 'Test-MtCisaDlpPii', 'Test-MtCisaDlpAlternate', - 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity', 'Get-MtExo', + 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity', + 'Test-MtCisaAttachmentFileType', + 'Get-MtExo', 'Clear-MtExoCache', 'Test-MtConditionalAccessWhatIf', 'Test-MtConnection', 'Test-MtEidscaControl', diff --git a/powershell/public/cisa/exchange/Get-MtExo.ps1 b/powershell/public/cisa/exchange/Get-MtExo.ps1 index 1404453f..5dd2ddcd 100644 --- a/powershell/public/cisa/exchange/Get-MtExo.ps1 +++ b/powershell/public/cisa/exchange/Get-MtExo.ps1 @@ -5,6 +5,9 @@ .DESCRIPTION Manages the EXO cmdlet caching +.PARAMETER Request + Provide the name of the EXO Cmdlet without the Get- prepended (e.g. Get-AcceptedDomain = -Request AcceptedDomain) + .EXAMPLE Get-MtExo -Request AcceptedDomain @@ -44,11 +47,6 @@ function Get-MtExo { [string] $Request = ($MyInvocation.InvocationName).Substring(6) ) - if($Request -eq "Exo"){ - Write-Error "$($MyInvocation.InvocationName) called with invalid -Request" - return "Unable to obtain policy" - } - ### To add new commands ### - add them to the hashtable below ### - add them as an alias @@ -73,10 +71,21 @@ function Get-MtExo { "ATPProtectionPolicyRule" = "Get-ATPProtectionPolicyRule" } + + if($Request -eq "Exo"){ + Write-Error "$($MyInvocation.InvocationName) called with invalid -Request, specify value (e.g., AcceptedDomain)" + return "Unable to obtain policy" + }elseif($Request -notin $commands.Keys){ + Write-Error "$($MyInvocation.InvocationName) called with unsupported -Request" + return "Unable to obtain policy" + } + if($null -eq $__MtSession.ExoCache.$Request){ + Write-Verbose "$request not in cache, requesting." $response = $commands.$Request $__MtSession.ExoCache.$Request = $response }else{ + Write-Verbose "$request in cache." $response = $__MtSession.ExoCache.$Request } diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 index 8fd6dbed..23de1dee 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 @@ -6,14 +6,14 @@ Emails SHALL be filtered by attachment file types .EXAMPLE - Test-MtCisaPresetSecurity + Test-MtCisaAttachmentFileType Returns true if standard and strict protection is on .LINK - https://maester.dev/docs/commands/Test-MtCisaPresetSecurity + https://maester.dev/docs/commands/Test-MtCisaAttachmentFileType #> -function Test-MtCisaPresetSecurity { +function Test-MtCisaAttachmentFileType { [CmdletBinding()] [OutputType([bool])] param() @@ -29,6 +29,7 @@ function Test-MtCisaPresetSecurity { return $null } + $policies = Get-MtMalwareFilterPolicy <# $policies = @{ "MalwareFilterPolicy" = Get-MalwareFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" @@ -42,27 +43,26 @@ function Test-MtCisaPresetSecurity { } #> - #TODO, cache in module variable - $policies = Get-ATPProtectionPolicyRule + $fileFilter = $policies | Where-Object { ` + $_.EnableFileFilter + } $standard = $policies | Where-Object { ` - $_.State -eq "Enabled" -and - $_.Identity -eq "Standard Preset Security Policy" + $_.RecommendedPolicyType -eq "Standard" } $strict = $policies | Where-Object { ` - $_.State -eq "Enabled" -and - $_.Identity -eq "Strict Preset Security Policy" + $_.RecommendedPolicyType -eq "Strict" } - $testResult = $standard -and $strict + $testResult = $standard -and $strict -and (($fileFilter|Measure-Object).Count -ge 1) $portalLink = "https://security.microsoft.com/presetSecurityPolicies" $passResult = "✅ Pass" $failResult = "❌ Fail" if ($testResult) { - $testResultMarkdown = "Well done. Your tenant [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" } else { $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" } @@ -77,7 +77,17 @@ function Test-MtCisaPresetSecurity { if ($strict) { $result += "| Strict | $passResult |`n" } else { - $result += "| Strict | $failResult |`n" + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | File Filter Enabled |`n" + $result += "| --- | --- |`n" + foreach($item in $policies | Sort-Object -Property Identity){ + if($item.EnableFileFilter){ + $result += "| $($item.Identity) | $($passResult) |`n" + }else{ + $result += "| $($item.Identity) | $($failResult) |`n" + } } $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result diff --git a/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 b/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 index 8a66ef4b..9267cd30 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 @@ -29,7 +29,7 @@ function Test-MtCisaPresetSecurity { return $null } - $policies = Get-ATPProtectionPolicyRule + $policies = Get-MtATPProtectionPolicyRule $standard = $policies | Where-Object { ` $_.State -eq "Enabled" -and @@ -48,7 +48,7 @@ function Test-MtCisaPresetSecurity { $failResult = "❌ Fail" if ($testResult) { - $testResultMarkdown = "Well done. Your tenant [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" } else { $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" } diff --git a/tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 index 8413f12e..cc19dcb0 100644 --- a/tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 +++ b/tests/cisa/exchange/Test-MtCisaAttachmentFileType.Tests.ps1 @@ -1,7 +1,7 @@ Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.2", "CISA", "Security", "All" { It "MS.EXO.9.2: The attachment filter SHOULD attempt to determine the true file type and assess the file extension." { - $result = Test-MtCisaPresetSecurity + $result = Test-MtCisaAttachmentFileType if ($null -ne $result) { $result | Should -Be $true -Because "preset policies are enabled." From cebfc6514f4b5f2820db40dc7e30a3943db60331 Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 18:38:49 -0700 Subject: [PATCH 05/11] Updating to use caching --- .../public/cisa/exchange/Test-MtCisaAntiSpamAllowList.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaAntiSpamSafeList.ps1 | 2 +- .../cisa/exchange/Test-MtCisaAutoExternalForwarding.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaCalendarSharing.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaContactSharing.ps1 | 2 +- powershell/public/cisa/exchange/Test-MtCisaDkim.ps1 | 4 ++-- powershell/public/cisa/exchange/Test-MtCisaDlp.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaDlpBaselineRule.ps1 | 5 ++--- powershell/public/cisa/exchange/Test-MtCisaDlpPii.ps1 | 5 ++--- .../public/cisa/exchange/Test-MtCisaDmarcAggregateCisa.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaDmarcRecordExist.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaDmarcRecordReject.ps1 | 2 +- powershell/public/cisa/exchange/Test-MtCisaDmarcReport.ps1 | 2 +- .../cisa/exchange/Test-MtCisaExternalSenderWarning.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaMailboxAuditing.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaSmtpAuthentication.ps1 | 2 +- powershell/public/cisa/exchange/Test-MtCisaSpfDirective.ps1 | 2 +- .../public/cisa/exchange/Test-MtCisaSpfRestriction.ps1 | 2 +- 18 files changed, 21 insertions(+), 23 deletions(-) diff --git a/powershell/public/cisa/exchange/Test-MtCisaAntiSpamAllowList.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAntiSpamAllowList.ps1 index d9cbd628..4ee60b09 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAntiSpamAllowList.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaAntiSpamAllowList.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaAntiSpamAllowList { return $null } - $policy = Get-HostedConnectionFilterPolicy + $policy = Get-MtHostedConnectionFilterPolicy $resultPolicy = $policy | Where-Object {` ($_.IPAllowList | Measure-Object).Count -gt 0 diff --git a/powershell/public/cisa/exchange/Test-MtCisaAntiSpamSafeList.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAntiSpamSafeList.ps1 index 6e07e274..fbe50a32 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAntiSpamSafeList.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaAntiSpamSafeList.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaAntiSpamSafeList { return $null } - $policy = Get-HostedConnectionFilterPolicy + $policy = Get-MtHostedConnectionFilterPolicy $resultPolicy = $policy | Where-Object {` -not $_.EnableSafeList diff --git a/powershell/public/cisa/exchange/Test-MtCisaAutoExternalForwarding.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAutoExternalForwarding.ps1 index 0213fb20..dc35d0ee 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAutoExternalForwarding.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaAutoExternalForwarding.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaAutoExternalForwarding { return $null } - $domains = Get-RemoteDomain + $domains = Get-MtRemoteDomain $forwardingDomains = $domains | Where-Object { ` $_.AutoForwardEnabled diff --git a/powershell/public/cisa/exchange/Test-MtCisaCalendarSharing.ps1 b/powershell/public/cisa/exchange/Test-MtCisaCalendarSharing.ps1 index 27d9b171..c8bb5476 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaCalendarSharing.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaCalendarSharing.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaCalendarSharing { return $null } - $policies = Get-SharingPolicy + $policies = Get-MtSharingPolicy $resultPolicies = $policies | Where-Object {` $_.Enabled -and ` diff --git a/powershell/public/cisa/exchange/Test-MtCisaContactSharing.ps1 b/powershell/public/cisa/exchange/Test-MtCisaContactSharing.ps1 index 036868ab..4fa341b0 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaContactSharing.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaContactSharing.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaContactSharing { return $null } - $policies = Get-SharingPolicy + $policies = Get-MtSharingPolicy $resultPolicies = $policies | Where-Object {` $_.Enabled -and ` diff --git a/powershell/public/cisa/exchange/Test-MtCisaDkim.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDkim.ps1 index 21c3a453..aef47baa 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDkim.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDkim.ps1 @@ -26,8 +26,8 @@ function Test-MtCisaDkim { return $null } - $signingConfig = Get-DkimSigningConfig - $acceptedDomains = Get-AcceptedDomain + $signingConfig = Get-MtDkimSigningConfig + $acceptedDomains = Get-MtAcceptedDomain <# DKIM record without key for parked domains $sendingDomains = $acceptedDomains | Where-Object {` -not $_.SendingFromDomainDisabled diff --git a/powershell/public/cisa/exchange/Test-MtCisaDlp.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDlp.ps1 index 69f5b1a1..07b491dd 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDlp.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDlp.ps1 @@ -29,7 +29,7 @@ function Test-MtCisaDlp { return $null } - $policies = Get-DlpCompliancePolicy + $policies = Get-MtDlpCompliancePolicy $resultPolicies = $policies | Where-Object {` $_.ExchangeLocation.DisplayName -contains "All" -and ` diff --git a/powershell/public/cisa/exchange/Test-MtCisaDlpBaselineRule.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDlpBaselineRule.ps1 index 209071b3..d12a27e6 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDlpBaselineRule.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDlpBaselineRule.ps1 @@ -29,7 +29,7 @@ function Test-MtCisaDlpBaselineRule { return $null } - $policies = Get-DlpCompliancePolicy + $policies = Get-MtDlpCompliancePolicy $resultPolicies = $policies | Where-Object {` $_.ExchangeLocation.DisplayName -contains "All" -and ` @@ -38,9 +38,8 @@ function Test-MtCisaDlpBaselineRule { $_.Enabled } - # This is a really slow call $rules = $resultPolicies | ForEach-Object { - Get-DlpComplianceRule -Policy $_.Name + Get-MtDlpComplianceRule -Policy $_.Name } $sits = [pscustomobject]@{ diff --git a/powershell/public/cisa/exchange/Test-MtCisaDlpPii.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDlpPii.ps1 index 14446750..ee8a7b2c 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDlpPii.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDlpPii.ps1 @@ -29,7 +29,7 @@ function Test-MtCisaDlpPii { return $null } - $policies = Get-DlpCompliancePolicy + $policies = Get-MtDlpCompliancePolicy $resultPolicies = $policies | Where-Object {` $_.ExchangeLocation.DisplayName -contains "All" -and ` @@ -38,9 +38,8 @@ function Test-MtCisaDlpPii { $_.Enabled } - # This is a really slow call $rules = $resultPolicies | ForEach-Object { - Get-DlpComplianceRule -Policy $_.Name + Get-MtDlpComplianceRule -Policy $_.Name } $resultRules = $rules | Where-Object {` diff --git a/powershell/public/cisa/exchange/Test-MtCisaDmarcAggregateCisa.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDmarcAggregateCisa.ps1 index 3d79b3a3..ba3aef15 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDmarcAggregateCisa.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDmarcAggregateCisa.ps1 @@ -31,7 +31,7 @@ function Test-MtCisaDmarcAggregateCisa { return $null } - $acceptedDomains = Get-AcceptedDomain + $acceptedDomains = Get-MtAcceptedDomain <# Parked domains should have DMARC with reject policy $sendingDomains = $acceptedDomains | Where-Object {` -not $_.SendingFromDomainDisabled diff --git a/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordExist.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordExist.ps1 index 57673e84..bc1d76fc 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordExist.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordExist.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaDmarcRecordExist { return $null } - $acceptedDomains = Get-AcceptedDomain + $acceptedDomains = Get-MtAcceptedDomain <# Parked domains should have DMARC with reject policy $sendingDomains = $acceptedDomains | Where-Object {` -not $_.SendingFromDomainDisabled diff --git a/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordReject.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordReject.ps1 index 86a4d1ba..59d884d3 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordReject.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDmarcRecordReject.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaDmarcRecordReject { return $null } - $acceptedDomains = Get-AcceptedDomain + $acceptedDomains = Get-MtAcceptedDomain <# Parked domains should have DMARC with reject policy $sendingDomains = $acceptedDomains | Where-Object {` -not $_.SendingFromDomainDisabled diff --git a/powershell/public/cisa/exchange/Test-MtCisaDmarcReport.ps1 b/powershell/public/cisa/exchange/Test-MtCisaDmarcReport.ps1 index 06bc54d1..f97c305c 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaDmarcReport.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaDmarcReport.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaDmarcReport { return $null } - $acceptedDomains = Get-AcceptedDomain + $acceptedDomains = Get-MtAcceptedDomain <# Parked domains should have DMARC with reject policy $sendingDomains = $acceptedDomains | Where-Object {` -not $_.SendingFromDomainDisabled diff --git a/powershell/public/cisa/exchange/Test-MtCisaExternalSenderWarning.ps1 b/powershell/public/cisa/exchange/Test-MtCisaExternalSenderWarning.ps1 index a2274d80..9128aa01 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaExternalSenderWarning.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaExternalSenderWarning.ps1 @@ -29,7 +29,7 @@ function Test-MtCisaExternalSenderWarning { $testResult = $true } else { - $rules = Get-TransportRule + $rules = Get-MtTransportRule $resultRules = $rules | Where-Object {` $_.State -eq "Enabled" -and ` diff --git a/powershell/public/cisa/exchange/Test-MtCisaMailboxAuditing.ps1 b/powershell/public/cisa/exchange/Test-MtCisaMailboxAuditing.ps1 index 3a948eb3..0dd7fe16 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaMailboxAuditing.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaMailboxAuditing.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaMailboxAuditing { return $null } - $config = Get-OrganizationConfig + $config = Get-MtOrganizationConfig $testResult = (-not $config.AuditDisabled) diff --git a/powershell/public/cisa/exchange/Test-MtCisaSmtpAuthentication.ps1 b/powershell/public/cisa/exchange/Test-MtCisaSmtpAuthentication.ps1 index 65090ba6..79256892 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaSmtpAuthentication.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaSmtpAuthentication.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaSmtpAuthentication { return $null } - $config = Get-TransportConfig + $config = Get-MtTransportConfig $testResult = $config.SmtpClientAuthenticationDisabled diff --git a/powershell/public/cisa/exchange/Test-MtCisaSpfDirective.ps1 b/powershell/public/cisa/exchange/Test-MtCisaSpfDirective.ps1 index fa4da5e1..b98b3ef4 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaSpfDirective.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaSpfDirective.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaSpfDirective { return $null } - $acceptedDomains = Get-AcceptedDomain + $acceptedDomains = Get-MtAcceptedDomain $sendingDomains = $acceptedDomains | Where-Object {` -not $_.SendingFromDomainDisabled } diff --git a/powershell/public/cisa/exchange/Test-MtCisaSpfRestriction.ps1 b/powershell/public/cisa/exchange/Test-MtCisaSpfRestriction.ps1 index 966201db..a58af885 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaSpfRestriction.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaSpfRestriction.ps1 @@ -23,7 +23,7 @@ function Test-MtCisaSpfRestriction { return $null } - $acceptedDomains = Get-AcceptedDomain + $acceptedDomains = Get-MtAcceptedDomain <# Parked domains should have SPF ending in -all too $sendingDomains = $acceptedDomains | Where-Object {` -not $_.SendingFromDomainDisabled From e6db16c50cb93a790370609162c683a5d1338928 Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 19:20:13 -0700 Subject: [PATCH 06/11] Cleanup --- powershell/Maester.psd1 | 6 +- powershell/public/cisa/exchange/Get-MtExo.ps1 | 11 ++ .../exchange/Test-MtCisaAttachmentFileType.md | 2 +- .../Test-MtCisaAttachmentFileType.ps1 | 12 -- .../exchange/Test-MtCisaAttachmentFilter.md | 1 + .../exchange/Test-MtCisaAttachmentFilter.ps1 | 88 ++++++++++++++ .../exchange/Test-MtCisaBlockExecutable.ps1 | 110 ++++++++++++++++++ .../Test-MtCisaEmailFilterAlternative.ps1 | 34 ++++++ .../Test-MtCisaAttachmentFilter.Tests.ps1 | 2 +- .../Test-MtCisaBlockExecutable.Tests.ps1 | 2 +- .../Test-MtCisaBlockFileType.Tests.ps1 | 2 +- ...est-MtCisaEmailFilterAlternative.Tests.ps1 | 2 +- website/docs/tests/cisa/exo.md | 10 +- 13 files changed, 257 insertions(+), 25 deletions(-) create mode 100644 powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 create mode 100644 powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.ps1 create mode 100644 powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index e211e22b..22f69771 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -121,9 +121,9 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae 'Test-MtCisaDmarcRecordExist', 'Test-MtCisaDmarcRecordReject', 'Test-MtCisaDmarcAggregateCisa', 'Test-MtCisaDmarcReport', 'Test-MtCisaDlp', 'Test-MtCisaDlpPii', 'Test-MtCisaDlpAlternate', - 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaPresetSecurity', - 'Test-MtCisaAttachmentFileType', - 'Get-MtExo', 'Clear-MtExoCache', + 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaAttachmentFilter', + 'Test-MtCisaAttachmentFileType', 'Test-MtCisaEmailFilterAlternative', + 'Test-MtCisaBlockExecutable', 'Get-MtExo', 'Clear-MtExoCache', 'Test-MtConditionalAccessWhatIf', 'Test-MtConnection', 'Test-MtEidscaControl', diff --git a/powershell/public/cisa/exchange/Get-MtExo.ps1 b/powershell/public/cisa/exchange/Get-MtExo.ps1 index 5dd2ddcd..0607c6e7 100644 --- a/powershell/public/cisa/exchange/Get-MtExo.ps1 +++ b/powershell/public/cisa/exchange/Get-MtExo.ps1 @@ -46,6 +46,17 @@ function Get-MtExo { param( [string] $Request = ($MyInvocation.InvocationName).Substring(6) ) + <# + $policies = @{ + "HostedContentFilterPolicy" = Get-HostedContentFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "AntiPhishPolicy" = Get-AntiPhishPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "SafeAttachmentPolicy" = Get-SafeAttachmentPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "SafeLinksPolicy" = Get-SafeLinksPolicy #RecommendedPolicyType -eq "Standard", "Strict" + "ATPBuiltInProtectionRule" = Get-ATPBuiltInProtectionRule + "EOPProtectionPolicyRule" = Get-EOPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection + "ATPProtectionPolicyRule" = Get-ATPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection + } + #> ### To add new commands ### - add them to the hashtable below diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md index c802442d..fd7dd5b4 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.md @@ -7,7 +7,7 @@ Rationale: Users can change a file extension at the end of a file name (e.g., no 1. Sign in to **Microsoft 365 Defender**. 2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. 3. Select **Threat Policies**. -4. From the **Templated policies** section, select **Preset Security Policies**. +4. From the **Templated policies** section, select [**Preset Security Policies**](https://security.microsoft.com/presetSecurityPolicies). 5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. 6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 index 23de1dee..01006f88 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFileType.ps1 @@ -30,18 +30,6 @@ function Test-MtCisaAttachmentFileType { } $policies = Get-MtMalwareFilterPolicy - <# - $policies = @{ - "MalwareFilterPolicy" = Get-MalwareFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "HostedContentFilterPolicy" = Get-HostedContentFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "AntiPhishPolicy" = Get-AntiPhishPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "SafeAttachmentPolicy" = Get-SafeAttachmentPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "SafeLinksPolicy" = Get-SafeLinksPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "ATPBuiltInProtectionRule" = Get-ATPBuiltInProtectionRule - "EOPProtectionPolicyRule" = Get-EOPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection - "ATPProtectionPolicyRule" = Get-ATPProtectionPolicyRule #-Identity "*Preset Security Policy" #IsBuiltInProtection - } - #> $fileFilter = $policies | Where-Object { ` $_.EnableFileFilter diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md index 468e3522..9c69e7f9 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.md @@ -18,6 +18,7 @@ Note: If the toggle slider in step 5 is grayed out, click on **Manage protection * [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) * [CISA 9 Attachment File Type - MS.EXO.9.1v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo91v2) * [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L487) +* [Microsoft Learn - Common attachments filter in anti-malware policies](https://learn.microsoft.com/en-us/defender-office-365/anti-malware-protection-about#common-attachments-filter-in-anti-malware-policies) %TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 new file mode 100644 index 00000000..2c2479aa --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 @@ -0,0 +1,88 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Emails SHALL be filtered by attachment file types + +.EXAMPLE + Test-MtCisaAttachmentFilter + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaAttachmentFilter +#> +function Test-MtCisaAttachmentFilter { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + $policies = Get-MtMalwareFilterPolicy + + $fileFilter = $policies | Where-Object { ` + $_.EnableFileFilter + } + + $standard = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Standard" + } + + $strict = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Strict" + } + + $testResult = $standard -and $strict -and (($fileFilter|Measure-Object).Count -ge 1) + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | File Filter Enabled | Extensions |`n" + $result += "| --- | --- | --- |`n" + foreach($item in $policies | Sort-Object -Property Identity){ + if($item.EnableFileFilter){ + $resultFilesList = ($item.FileTypes | Select-Object -First 5) -join ", " + $resultFilesList += ", & $(($item.FileTypes|Measure-Object).Count -5) others" + $result += "| $($item.Identity) | $($passResult) | $resultFilesList |`n" + }else{ + $result += "| $($item.Identity) | $($failResult) | |`n" + } + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.ps1 b/powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.ps1 new file mode 100644 index 00000000..c68ddfe1 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaBlockExecutable.ps1 @@ -0,0 +1,110 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Emails SHALL be filtered by attachment file types + +.EXAMPLE + Test-MtCisaBlockExecutable + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaBlockExecutable +#> +function Test-MtCisaBlockExecutable { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + $policies = Get-MtMalwareFilterPolicy + + $clickToRunExtensions = @( + "cmd", + "exe", + "vbe" + ) + + $resultPolicies = @() + foreach($policy in $policies){ + $p = [PSCustomObject]@{ + Identity = $policy.Identity + EnableFileFilter = $policy.EnableFileFilter + RecommendedPolicyType = $policy.RecommendedPolicyType + clickToRunExtensions = @() + } + foreach($extension in $clickToRunExtensions){ + if($extension -in $policy.FileTypes){ + $p.clickToRunExtensions += $extension + } + } + $resultPolicies += $p + } + + $fileFilter = $resultPolicies | Where-Object { ` + $_.EnableFileFilter -and ` + ($_.clickToRunExtensions|Measure-Object).Count -eq ($clickToRunExtensions|Measure-Object).Count + } + + $standard = $resultPolicies | Where-Object { ` + $_.RecommendedPolicyType -eq "Standard" + } + + $strict = $resultPolicies | Where-Object { ` + $_.RecommendedPolicyType -eq "Strict" + } + + $testResult = $standard -and $strict -and (($fileFilter|Measure-Object).Count -ge 1) + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | File Filter Enabled | Extensions |`n" + $result += "| --- | --- | --- |`n" + foreach($item in $resultPolicies | Sort-Object -Property Identity){ + if($item.EnableFileFilter){ + $resultFilesList = ($item.clickToRunExtensions) -join ", " + $result += "| $($item.Identity) | $($passResult) | $resultFilesList |`n" + }else{ + $result += "| $($item.Identity) | $($failResult) | |`n" + } + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.ps1 b/powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.ps1 new file mode 100644 index 00000000..319025a5 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaEmailFilterAlternative.ps1 @@ -0,0 +1,34 @@ +<# +.SYNOPSIS + Placeholder + +.DESCRIPTION + Alternatively chosen filtering solutions SHOULD offer services comparable to Microsoft Defender's Common Attachment Filter. + +.EXAMPLE + Test-MtCisaEmailFilterAlternative + + Allways returns null + +.LINK + https://maester.dev/docs/commands/Test-MtCisaEmailFilterAlternative +#> +function Test-MtCisaEmailFilterAlternative { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } else { + Add-MtTestResultDetail -SkippedBecause Custom -SkippedCustomReason "Only testing of MDO is supported" + return $null + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 index 58248f4f..bc05c770 100644 --- a/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 +++ b/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 @@ -1,7 +1,7 @@ Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.1", "CISA", "Security", "All" { It "MS.EXO.9.1: Emails SHALL be filtered by attachment file types." { - $result = Test-MtCisaPresetSecurity + $result = Test-MtCisaAttachmentFilter if ($null -ne $result) { $result | Should -Be $true -Because "preset policies are enabled." diff --git a/tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 index e8499cc0..4557ee5d 100644 --- a/tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 +++ b/tests/cisa/exchange/Test-MtCisaBlockExecutable.Tests.ps1 @@ -1,7 +1,7 @@ Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.5", "CISA", "Security", "All" { It "MS.EXO.9.5: At a minimum, click-to-run files SHOULD be blocked (e.g., .exe, .cmd, and .vbe)." { - $result = Test-MtCisaPresetSecurity + $result = Test-MtCisaBlockExecutable if ($null -ne $result) { $result | Should -Be $true -Because "preset policies are enabled." diff --git a/tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 index 907878c7..6d5ec7d9 100644 --- a/tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 +++ b/tests/cisa/exchange/Test-MtCisaBlockFileType.Tests.ps1 @@ -1,7 +1,7 @@ Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.3", "CISA", "Security", "All" { It "MS.EXO.9.3: Disallowed file types SHALL be determined and enforced." { - $result = Test-MtCisaPresetSecurity + $result = Test-MtCisaAttachmentFileType if ($null -ne $result) { $result | Should -Be $true -Because "preset policies are enabled." diff --git a/tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 index 8648610d..29ae02a0 100644 --- a/tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 +++ b/tests/cisa/exchange/Test-MtCisaEmailFilterAlternative.Tests.ps1 @@ -1,7 +1,7 @@ Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.4", "CISA", "Security", "All" { It "MS.EXO.9.4: Alternatively chosen filtering solutions SHOULD offer services comparable to Microsoft Defender's Common Attachment Filter." { - $result = $null + $result = Test-MtCisaEmailFilterAlternative if ($null -ne $result) { $result | Should -Be $true -Because "should not pass." diff --git a/website/docs/tests/cisa/exo.md b/website/docs/tests/cisa/exo.md index 1a07b968..7f4fff7c 100644 --- a/website/docs/tests/cisa/exo.md +++ b/website/docs/tests/cisa/exo.md @@ -35,11 +35,11 @@ See the [Installation guide](/docs/installation#optional-modules-and-permissions | Test-MtCisaDlpPii | [MS.EXO.8.2v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo82v2) | | Test-MtCisaDlpAlternate | [MS.EXO.8.3v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo83v1) | | Test-MtCisaDlpBaselineRules | [MS.EXO.8.4v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo84v1) | -| Test-MtCisaPresetSecurity | [MS.EXO.9.1v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo91v2) | -| Test-MtCisaPresetSecurity | [MS.EXO.9.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo92v1) | -| Test-MtCisaPresetSecurity | [MS.EXO.9.3v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo93v2) | -| Test-MtCisaPresetSecurity | [MS.EXO.9.4v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo94v1) | -| Test-MtCisaPresetSecurity | [MS.EXO.9.5v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo95v1) | +| Test-MtCisaAttachmentFileType | [MS.EXO.9.1v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo91v2) | +| Test-MtCisaAttachmentFileType | [MS.EXO.9.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo92v1) | +| Test-MtCisaAttachmentFileType | [MS.EXO.9.3v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo93v2) | +| Test-MtCisaEmailFilterAlternative | [MS.EXO.9.4v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo94v1) | +| Test-MtCisaBlockExecutable | [MS.EXO.9.5v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo95v1) | | Test-MtCisaAntiSpamAllowList | [MS.EXO.12.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo121v1) | | Test-MtCisaAntiSpamSafeList | [MS.EXO.12.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo122v1) | | Test-MtCisaMailboxAuditing | [MS.EXO.13.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo131v1) | \ No newline at end of file From 14e13470c1f68944869d9c8dcfd153fa74de195f Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 19:25:21 -0700 Subject: [PATCH 07/11] Remove of unused --- .../exchange/Test-MtCisaPresetSecurity.ps1 | 74 ------------------- 1 file changed, 74 deletions(-) delete mode 100644 powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 diff --git a/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 b/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 deleted file mode 100644 index 9267cd30..00000000 --- a/powershell/public/cisa/exchange/Test-MtCisaPresetSecurity.ps1 +++ /dev/null @@ -1,74 +0,0 @@ -<# -.SYNOPSIS - Checks state of preset security policies - -.DESCRIPTION - Emails SHALL be filtered by attachment file types - -.EXAMPLE - Test-MtCisaPresetSecurity - - Returns true if standard and strict protection is on - -.LINK - https://maester.dev/docs/commands/Test-MtCisaPresetSecurity -#> -function Test-MtCisaPresetSecurity { - [CmdletBinding()] - [OutputType([bool])] - param() - - if(!(Test-MtConnection ExchangeOnline)){ - Add-MtTestResultDetail -SkippedBecause NotConnectedExchange - return $null - }elseif(!(Test-MtConnection SecurityCompliance)){ - Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance - return $null - }elseif($null -eq (Get-MtLicenseInformation -Product Mdo)){ - Add-MtTestResultDetail -SkippedBecause NotLicensedMdo - return $null - } - - $policies = Get-MtATPProtectionPolicyRule - - $standard = $policies | Where-Object { ` - $_.State -eq "Enabled" -and - $_.Identity -eq "Standard Preset Security Policy" - } - - $strict = $policies | Where-Object { ` - $_.State -eq "Enabled" -and - $_.Identity -eq "Strict Preset Security Policy" - } - - $testResult = $standard -and $strict - - $portalLink = "https://security.microsoft.com/presetSecurityPolicies" - $passResult = "✅ Pass" - $failResult = "❌ Fail" - - if ($testResult) { - $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" - } else { - $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" - } - - $result = "| Policy | Status |`n" - $result += "| --- | --- |`n" - if($standard){ - $result += "| Standard | $passResult |`n" - }else{ - $result += "| Standard | $failResult |`n" - } - if($strict){ - $result += "| Strict | $passResult |`n" - }else{ - $result += "| Strict | $failResult |`n" - } - - $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result - - Add-MtTestResultDetail -Result $testResultMarkdown - - return $testResult -} \ No newline at end of file From 1e22bb9c04dc04785d4a813e270b5359d71c6338 Mon Sep 17 00:00:00 2001 From: Snozz Date: Sun, 11 Aug 2024 19:52:55 -0700 Subject: [PATCH 08/11] Add 10.x --- powershell/Maester.psd1 | 3 +- .../exchange/Test-MtCisaAttachmentFilter.ps1 | 1 + .../cisa/exchange/Test-MtCisaMalwareAction.md | 24 ++++++ .../exchange/Test-MtCisaMalwareAction.ps1 | 86 +++++++++++++++++++ .../cisa/exchange/Test-MtCisaMalwareScan.md | 24 ++++++ .../cisa/exchange/Test-MtCisaMalwareZap.md | 24 ++++++ .../cisa/exchange/Test-MtCisaMalwareZap.ps1 | 86 +++++++++++++++++++ .../Test-MtCisaAttachmentFilter.Tests.ps1 | 2 +- .../Test-MtCisaMalwareAction.Tests.ps1 | 10 +++ .../exchange/Test-MtCisaMalwareScan.Tests.ps1 | 10 +++ .../exchange/Test-MtCisaMalwareZap.Tests.ps1 | 10 +++ website/docs/tests/cisa/exo.md | 3 + 12 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 powershell/public/cisa/exchange/Test-MtCisaMalwareAction.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaMalwareAction.ps1 create mode 100644 powershell/public/cisa/exchange/Test-MtCisaMalwareScan.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaMalwareZap.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaMalwareZap.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaMalwareAction.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaMalwareScan.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaMalwareZap.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 22f69771..2edf3f6a 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -123,7 +123,8 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae 'Test-MtCisaDlp', 'Test-MtCisaDlpPii', 'Test-MtCisaDlpAlternate', 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaAttachmentFilter', 'Test-MtCisaAttachmentFileType', 'Test-MtCisaEmailFilterAlternative', - 'Test-MtCisaBlockExecutable', 'Get-MtExo', 'Clear-MtExoCache', + 'Test-MtCisaBlockExecutable', 'Test-MtCisaMalwareAction', 'Test-MtCisaMalwareZap', + 'Get-MtExo', 'Clear-MtExoCache', 'Test-MtConditionalAccessWhatIf', 'Test-MtConnection', 'Test-MtEidscaControl', diff --git a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 index 2c2479aa..e5537e4c 100644 --- a/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 +++ b/powershell/public/cisa/exchange/Test-MtCisaAttachmentFilter.ps1 @@ -4,6 +4,7 @@ .DESCRIPTION Emails SHALL be filtered by attachment file types + Emails SHALL be scanned for malware. .EXAMPLE Test-MtCisaAttachmentFilter diff --git a/powershell/public/cisa/exchange/Test-MtCisaMalwareAction.md b/powershell/public/cisa/exchange/Test-MtCisaMalwareAction.md new file mode 100644 index 00000000..1ab88513 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaMalwareAction.md @@ -0,0 +1,24 @@ +Emails identified as containing malware SHALL be quarantined or dropped. + +Rationale: Email can be used as a mechanism for delivering malware. Preventing emails with known malware from reaching user mailboxes helps ensure users cannot interact with those emails. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 10 Malware Scanning - MS.EXO.10.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo102v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L582) +* [Microsoft Learn - Anatomy of a quarantine policy](https://learn.microsoft.com/en-us/defender-office-365/quarantine-policies#anatomy-of-a-quarantine-policy) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaMalwareAction.ps1 b/powershell/public/cisa/exchange/Test-MtCisaMalwareAction.ps1 new file mode 100644 index 00000000..b2a739a7 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaMalwareAction.ps1 @@ -0,0 +1,86 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Emails identified as containing malware SHALL be quarantined or dropped. + +.EXAMPLE + Test-MtCisaMalwareAction + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaMalwareAction +#> +function Test-MtCisaMalwareAction { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + $policies = Get-MtMalwareFilterPolicy + + $fileFilter = $policies | Where-Object { ` + $_.QuarantineTag -eq "AdminOnlyAccessPolicy" + } + + $standard = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Standard" + } + + $strict = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Strict" + } + + $testResult = $standard -and $strict -and (($fileFilter|Measure-Object).Count -ge 1) + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | Quarantine Tag | Result |`n" + $result += "| --- | --- | --- |`n" + foreach($item in $policies | Sort-Object -Property Identity){ + if($item.QuarantineTag -eq "AdminOnlyAccessPolicy"){ + $result += "| $($item.Identity) | $($item.QuarantineTag) | $($passResult) |`n" + }else{ + $result += "| $($item.Identity) | $($item.QuarantineTag) | $($failResult) |`n" + } + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaMalwareScan.md b/powershell/public/cisa/exchange/Test-MtCisaMalwareScan.md new file mode 100644 index 00000000..e65fd5cf --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaMalwareScan.md @@ -0,0 +1,24 @@ +Emails SHALL be scanned for malware. + +Rationale: Email can be used as a mechanism for delivering malware. In many cases, malware can be detected through scanning, reducing the risk for end users. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 10 Malware Scanning - MS.EXO.10.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo101v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L567) +* [Microsoft Learn - Common attachments filter in anti-malware policies](https://learn.microsoft.com/en-us/defender-office-365/anti-malware-protection-about#common-attachments-filter-in-anti-malware-policies) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaMalwareZap.md b/powershell/public/cisa/exchange/Test-MtCisaMalwareZap.md new file mode 100644 index 00000000..f1f5f1ec --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaMalwareZap.md @@ -0,0 +1,24 @@ +Email scanning SHALL be capable of reviewing emails after delivery. + +Rationale: As known malware signatures are updated, it is possible for an email to be retroactively identified as containing malware after delivery. By scanning emails, the number of malware-infected in users' mailboxes can be reduced. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 10 Malware Scanning - MS.EXO.10.3v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo103v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L597) +* [Microsoft Learn - Zero-hour auto purge (ZAP) for malware](https://learn.microsoft.com/en-us/defender-office-365/zero-hour-auto-purge#zero-hour-auto-purge-zap-for-email-messages) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaMalwareZap.ps1 b/powershell/public/cisa/exchange/Test-MtCisaMalwareZap.ps1 new file mode 100644 index 00000000..1254167c --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaMalwareZap.ps1 @@ -0,0 +1,86 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Email scanning SHALL be capable of reviewing emails after delivery. + +.EXAMPLE + Test-MtCisaMalwareZap + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaMalwareZap +#> +function Test-MtCisaMalwareZap { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + $policies = Get-MtMalwareFilterPolicy + + $fileFilter = $policies | Where-Object { ` + $_.ZapEnabled + } + + $standard = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Standard" + } + + $strict = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Strict" + } + + $testResult = $standard -and $strict -and (($fileFilter|Measure-Object).Count -ge 1) + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | Result |`n" + $result += "| --- | --- |`n" + foreach($item in $policies | Sort-Object -Property Identity){ + if($item.ZapEnabled){ + $result += "| $($item.Identity) | $($passResult) |`n" + }else{ + $result += "| $($item.Identity) | $($failResult) |`n" + } + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 index bc05c770..8abd5ff4 100644 --- a/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 +++ b/tests/cisa/exchange/Test-MtCisaAttachmentFilter.Tests.ps1 @@ -4,7 +4,7 @@ Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.9.1", "CISA", "Security", "All" { $result = Test-MtCisaAttachmentFilter if ($null -ne $result) { - $result | Should -Be $true -Because "preset policies are enabled." + $result | Should -Be $true -Because "policies exist." } } } \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaMalwareAction.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaMalwareAction.Tests.ps1 new file mode 100644 index 00000000..e686b38c --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaMalwareAction.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.10.2", "CISA", "Security", "All" { + It "MS.EXO.10.2: Emails identified as containing malware SHALL be quarantined or dropped." { + + $result = Test-MtCisaMalwareAction + + if ($null -ne $result) { + $result | Should -Be $true -Because "policies exist." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaMalwareScan.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaMalwareScan.Tests.ps1 new file mode 100644 index 00000000..4c90bb4c --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaMalwareScan.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.10.1", "CISA", "Security", "All" { + It "MS.EXO.10.1: Emails SHALL be scanned for malware." { + + $result = Test-MtCisaAttachmentFilter + + if ($null -ne $result) { + $result | Should -Be $true -Because "malware scanning policy exists." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaMalwareZap.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaMalwareZap.Tests.ps1 new file mode 100644 index 00000000..c2b35d3e --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaMalwareZap.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.10.3", "CISA", "Security", "All" { + It "MS.EXO.10.3: Email scanning SHALL be capable of reviewing emails after delivery." { + + $result = Test-MtCisaMalwareZap + + if ($null -ne $result) { + $result | Should -Be $true -Because "malware scanning policy exists." + } + } +} \ No newline at end of file diff --git a/website/docs/tests/cisa/exo.md b/website/docs/tests/cisa/exo.md index 7f4fff7c..b1aaf1a3 100644 --- a/website/docs/tests/cisa/exo.md +++ b/website/docs/tests/cisa/exo.md @@ -40,6 +40,9 @@ See the [Installation guide](/docs/installation#optional-modules-and-permissions | Test-MtCisaAttachmentFileType | [MS.EXO.9.3v2](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo93v2) | | Test-MtCisaEmailFilterAlternative | [MS.EXO.9.4v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo94v1) | | Test-MtCisaBlockExecutable | [MS.EXO.9.5v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo95v1) | +| Test-MtCisaAttachmentFilter | [MS.EXO.10.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo101v1) | +| Test-MtCisaMalwareAction | [MS.EXO.10.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo102v1) | +| Test-MtCisaMalwareZap | [MS.EXO.10.3v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo103v1) | | Test-MtCisaAntiSpamAllowList | [MS.EXO.12.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo121v1) | | Test-MtCisaAntiSpamSafeList | [MS.EXO.12.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo122v1) | | Test-MtCisaMailboxAuditing | [MS.EXO.13.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo131v1) | \ No newline at end of file From 87eecf2d592619a6dc090f744e91c6ace82e35f1 Mon Sep 17 00:00:00 2001 From: Snozz Date: Mon, 12 Aug 2024 19:07:12 -0700 Subject: [PATCH 09/11] Missed fix --- powershell/public/cisa/exchange/Get-MtExo.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell/public/cisa/exchange/Get-MtExo.ps1 b/powershell/public/cisa/exchange/Get-MtExo.ps1 index 0607c6e7..81637a5a 100644 --- a/powershell/public/cisa/exchange/Get-MtExo.ps1 +++ b/powershell/public/cisa/exchange/Get-MtExo.ps1 @@ -93,7 +93,7 @@ function Get-MtExo { if($null -eq $__MtSession.ExoCache.$Request){ Write-Verbose "$request not in cache, requesting." - $response = $commands.$Request + $response = Invoke-Expression $commands.$Request $__MtSession.ExoCache.$Request = $response }else{ Write-Verbose "$request in cache." From 7a3015848573b9c26e1f4566cb4b80914e7bca71 Mon Sep 17 00:00:00 2001 From: Snozz Date: Mon, 12 Aug 2024 19:14:12 -0700 Subject: [PATCH 10/11] Pester --- powershell/public/cisa/exchange/Get-MtExo.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/powershell/public/cisa/exchange/Get-MtExo.ps1 b/powershell/public/cisa/exchange/Get-MtExo.ps1 index 81637a5a..4a3054c9 100644 --- a/powershell/public/cisa/exchange/Get-MtExo.ps1 +++ b/powershell/public/cisa/exchange/Get-MtExo.ps1 @@ -22,6 +22,7 @@ https://maester.dev/docs/commands/Get-MtExo #> function Get-MtExo { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression","")] [Alias( "Get-MtAcceptedDomain", "Get-MtRemoteDomain", From 73e139b26d340765f4cfc202847ea009479da2ac Mon Sep 17 00:00:00 2001 From: Snozz Date: Mon, 12 Aug 2024 19:57:48 -0700 Subject: [PATCH 11/11] Added 11.x --- powershell/Maester.psd1 | 1 + powershell/public/cisa/exchange/Get-MtExo.ps1 | 1 - .../cisa/exchange/Test-MtCisaImpersonation.md | 24 +++++ .../exchange/Test-MtCisaImpersonation.ps1 | 90 +++++++++++++++++++ .../exchange/Test-MtCisaImpersonationTip.md | 24 +++++ .../exchange/Test-MtCisaImpersonationTip.ps1 | 89 ++++++++++++++++++ .../Test-MtCisaMailboxIntelligence.md | 24 +++++ .../Test-MtCisaMailboxIntelligence.ps1 | 88 ++++++++++++++++++ .../Test-MtCisaImpersonation.Tests.ps1 | 10 +++ .../Test-MtCisaImpersonationTip.Tests.ps1 | 10 +++ .../Test-MtCisaMailboxIntelligence.Tests.ps1 | 10 +++ website/docs/tests/cisa/exo.md | 3 + 12 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 powershell/public/cisa/exchange/Test-MtCisaImpersonation.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaImpersonation.ps1 create mode 100644 powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.ps1 create mode 100644 powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.md create mode 100644 powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaImpersonation.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaImpersonationTip.Tests.ps1 create mode 100644 tests/cisa/exchange/Test-MtCisaMailboxIntelligence.Tests.ps1 diff --git a/powershell/Maester.psd1 b/powershell/Maester.psd1 index 2edf3f6a..bcd86ad1 100644 --- a/powershell/Maester.psd1 +++ b/powershell/Maester.psd1 @@ -124,6 +124,7 @@ FunctionsToExport = 'Add-MtTestResultDetail', 'Clear-MtGraphCache', 'Connect-Mae 'Test-MtCisaDlpBaselineRule', 'Test-MtCisaAttachmentFilter', 'Test-MtCisaAttachmentFileType', 'Test-MtCisaEmailFilterAlternative', 'Test-MtCisaBlockExecutable', 'Test-MtCisaMalwareAction', 'Test-MtCisaMalwareZap', + 'Test-MtCisaImpersonation', 'Test-MtCisaImpersonationTip', 'Test-MtCisaMailboxIntelligence', 'Get-MtExo', 'Clear-MtExoCache', 'Test-MtConditionalAccessWhatIf', 'Test-MtConnection', diff --git a/powershell/public/cisa/exchange/Get-MtExo.ps1 b/powershell/public/cisa/exchange/Get-MtExo.ps1 index 4a3054c9..e0db30f1 100644 --- a/powershell/public/cisa/exchange/Get-MtExo.ps1 +++ b/powershell/public/cisa/exchange/Get-MtExo.ps1 @@ -50,7 +50,6 @@ function Get-MtExo { <# $policies = @{ "HostedContentFilterPolicy" = Get-HostedContentFilterPolicy #RecommendedPolicyType -eq "Standard", "Strict" - "AntiPhishPolicy" = Get-AntiPhishPolicy #RecommendedPolicyType -eq "Standard", "Strict" "SafeAttachmentPolicy" = Get-SafeAttachmentPolicy #RecommendedPolicyType -eq "Standard", "Strict" "SafeLinksPolicy" = Get-SafeLinksPolicy #RecommendedPolicyType -eq "Standard", "Strict" "ATPBuiltInProtectionRule" = Get-ATPBuiltInProtectionRule diff --git a/powershell/public/cisa/exchange/Test-MtCisaImpersonation.md b/powershell/public/cisa/exchange/Test-MtCisaImpersonation.md new file mode 100644 index 00000000..9cd75749 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaImpersonation.md @@ -0,0 +1,24 @@ +Impersonation protection checks SHOULD be used. + +Rationale: Users might not be able to reliably identify phishing emails, especially if the `FROM` address is nearly indistinguishable from that of a known entity. By automatically identifying senders who appear to be impersonating known senders, the risk of a successful phishing attempt can be reduced. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 11 Phishing Protections - MS.EXO.11.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo111v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L617) +* [Microsoft Learn - Impersonation settings in anti-phishing policies in Microsoft Defender for Office 365](https://learn.microsoft.com/en-us/defender-office-365/anti-phishing-policies-about#impersonation-settings-in-anti-phishing-policies-in-microsoft-defender-for-office-365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaImpersonation.ps1 b/powershell/public/cisa/exchange/Test-MtCisaImpersonation.ps1 new file mode 100644 index 00000000..78bc566a --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaImpersonation.ps1 @@ -0,0 +1,90 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Impersonation protection checks SHOULD be used. + +.EXAMPLE + Test-MtCisaImpersonation + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaImpersonation +#> +function Test-MtCisaImpersonation { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + $policies = Get-MtAntiPhishPolicy + + $resultPolicies = $policies | Where-Object { ` + $_.Enabled -and ` + $_.ImpersonationProtectionState -eq "Automatic" -and ` + $_.EnableOrganizationDomainsProtection -and ` + $_.EnableTargetedDomainsProtection -and ` + $_.EnableTargetedUserProtection + } + + $standard = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Standard" + } + + $strict = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Strict" + } + + $testResult = $standard -and $strict -and (($resultPolicies|Measure-Object).Count -ge 1) + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | Result |`n" + $result += "| --- | --- |`n" + foreach($item in $policies | Sort-Object -Property Identity){ + if($item.Guid -in $resultPolicies.Guid){ + $result += "| $($item.Identity) | $($passResult) |`n" + }else{ + $result += "| $($item.Identity) | $($failResult) |`n" + } + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.md b/powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.md new file mode 100644 index 00000000..ac6ecaf4 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.md @@ -0,0 +1,24 @@ +User warnings, comparable to the user safety tips included with EOP, SHOULD be displayed. + +Rationale: Many tasks are better suited for automated processes, such as identifying unusual characters in the `FROM` address or identifying a first-time sender. User warnings can handle these tasks, reducing the burden on end users and the risk of successful phishing attempts. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 11 Phishing Protections - MS.EXO.11.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo112v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L632) +* [Microsoft Learn - Impersonation settings in anti-phishing policies in Microsoft Defender for Office 365](https://learn.microsoft.com/en-us/defender-office-365/anti-phishing-policies-about#impersonation-settings-in-anti-phishing-policies-in-microsoft-defender-for-office-365) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.ps1 b/powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.ps1 new file mode 100644 index 00000000..ac62403f --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaImpersonationTip.ps1 @@ -0,0 +1,89 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + Impersonation protection checks SHOULD be used. + +.EXAMPLE + Test-MtCisaImpersonationTip + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaImpersonationTip +#> +function Test-MtCisaImpersonationTip { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + $policies = Get-MtAntiPhishPolicy + + $resultPolicies = $policies | Where-Object { ` + $_.Enabled -and ` + $_.EnableSimilarDomainsSafetyTips -and ` + $_.EnableSimilarUsersSafetyTips -and ` + $_.EnableUnusualCharactersSafetyTips + } + + $standard = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Standard" + } + + $strict = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Strict" + } + + $testResult = $standard -and $strict -and (($resultPolicies|Measure-Object).Count -ge 1) + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | Result |`n" + $result += "| --- | --- |`n" + foreach($item in $policies | Sort-Object -Property Identity){ + if($item.Guid -in $resultPolicies.Guid){ + $result += "| $($item.Identity) | $($passResult) |`n" + }else{ + $result += "| $($item.Identity) | $($failResult) |`n" + } + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.md b/powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.md new file mode 100644 index 00000000..db228a8b --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.md @@ -0,0 +1,24 @@ +The phishing protection solution SHOULD include an AI-based phishing detection tool comparable to EOP Mailbox Intelligence. + +Rationale: Phishing attacks can result in unauthorized data disclosure and unauthorized access. Using AI-based phishing detection tools to improve the detection rate of phishing attempts helps reduce the risk of successful phishing attacks. + +#### Remediation action: + +1. Sign in to **Microsoft 365 Defender**. +2. In the left-hand menu, go to **Email & Collaboration** > **Policies & Rules**. +3. Select **Threat Policies**. +4. From the **Templated policies** section, select **Preset Security Policies**. +5. Under **Standard protection**, slide the toggle switch to the right so the text next to the toggle reads **Standard protection is on**. +6. Under **Strict protection**, slide the toggle switch to the right so the text next to the toggle reads **Strict protection is on**. + +Note: If the toggle slider in step 5 is grayed out, click on **Manage protection settings** instead and configure the policy settings according to [Use the Microsoft 365 Defender portal to assign Standard and Strict preset security policies to users | Microsoft Learn](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/preset-security-policies?view=o365-worldwide#use-the-microsoft-365-defender-portal-to-assign-standard-and-strict-preset-security-policies-to-users). + +#### Related links + +* [Defender admin center - Preset security policies](https://security.microsoft.com/presetSecurityPolicies) +* [CISA 11 Phishing Protections - MS.EXO.11.3v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo113v1) +* [CISA ScubaGear Rego Reference](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Rego/EXOConfig.rego#L647) +* [Microsoft Learn - Mailbox intelligence impersonation protection](https://learn.microsoft.com/en-us/defender-office-365/anti-phishing-policies-about#mailbox-intelligence-impersonation-protection) + + +%TestResult% \ No newline at end of file diff --git a/powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.ps1 b/powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.ps1 new file mode 100644 index 00000000..18388966 --- /dev/null +++ b/powershell/public/cisa/exchange/Test-MtCisaMailboxIntelligence.ps1 @@ -0,0 +1,88 @@ +<# +.SYNOPSIS + Checks state of preset security policies + +.DESCRIPTION + The phishing protection solution SHOULD include an AI-based phishing detection tool comparable to EOP Mailbox Intelligence. + +.EXAMPLE + Test-MtCisaMailboxIntelligence + + Returns true if standard and strict protection is on + +.LINK + https://maester.dev/docs/commands/Test-MtCisaMailboxIntelligence +#> +function Test-MtCisaMailboxIntelligence { + [CmdletBinding()] + [OutputType([bool])] + param() + + if (!(Test-MtConnection ExchangeOnline)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedExchange + return $null + } elseif (!(Test-MtConnection SecurityCompliance)) { + Add-MtTestResultDetail -SkippedBecause NotConnectedSecurityCompliance + return $null + } elseif ($null -eq (Get-MtLicenseInformation -Product Mdo)) { + Add-MtTestResultDetail -SkippedBecause NotLicensedMdo + return $null + } + + $policies = Get-MtAntiPhishPolicy + + $resultPolicies = $policies | Where-Object { ` + $_.Enabled -and ` + $_.EnableMailboxIntelligence -and ` + $_.EnableMailboxIntelligenceProtection + } + + $standard = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Standard" + } + + $strict = $policies | Where-Object { ` + $_.RecommendedPolicyType -eq "Strict" + } + + $testResult = $standard -and $strict -and (($resultPolicies|Measure-Object).Count -ge 1) + + $portalLink = "https://security.microsoft.com/presetSecurityPolicies" + $passResult = "✅ Pass" + $failResult = "❌ Fail" + + if ($testResult) { + $testResultMarkdown = "Well done. Your tenant has [standard and strict preset security policies for the common file filter]($portalLink).`n`n%TestResult%" + } else { + $testResultMarkdown = "Your tenant does not have [standard and strict preset security policies enabled]($portalLink).`n`n%TestResult%" + } + + $result = "| Policy | Status |`n" + $result += "| --- | --- |`n" + if ($standard) { + $result += "| Standard | $passResult |`n" + } else { + $result += "| Standard | $failResult |`n" + } + if ($strict) { + $result += "| Strict | $passResult |`n" + } else { + $result += "| Strict | $failResult |`n`n" + } + + $result += "| Policy Name | Result |`n" + $result += "| --- | --- |`n" + foreach($item in $policies | Sort-Object -Property Identity){ + if($item.Guid -in $resultPolicies.Guid){ + $result += "| $($item.Identity) | $($passResult) |`n" + }else{ + $result += "| $($item.Identity) | $($failResult) |`n" + } + } + + $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $result + + Add-MtTestResultDetail -Result $testResultMarkdown + + return $testResult +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaImpersonation.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaImpersonation.Tests.ps1 new file mode 100644 index 00000000..74c5c88f --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaImpersonation.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.11.1", "CISA", "Security", "All" { + It "MS.EXO.11.1: Impersonation protection checks SHOULD be used." { + + $result = Test-MtCisaImpersonation + + if ($null -ne $result) { + $result | Should -Be $true -Because "preset policies are enabled." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaImpersonationTip.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaImpersonationTip.Tests.ps1 new file mode 100644 index 00000000..086c6985 --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaImpersonationTip.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.11.2", "CISA", "Security", "All" { + It "MS.EXO.11.2: User warnings, comparable to the user safety tips included with EOP, SHOULD be displayed." { + + $result = Test-MtCisaImpersonationTip + + if ($null -ne $result) { + $result | Should -Be $true -Because "preset policies are enabled." + } + } +} \ No newline at end of file diff --git a/tests/cisa/exchange/Test-MtCisaMailboxIntelligence.Tests.ps1 b/tests/cisa/exchange/Test-MtCisaMailboxIntelligence.Tests.ps1 new file mode 100644 index 00000000..c8f938ba --- /dev/null +++ b/tests/cisa/exchange/Test-MtCisaMailboxIntelligence.Tests.ps1 @@ -0,0 +1,10 @@ +Describe "CISA SCuBA" -Tag "MS.EXO", "MS.EXO.11.3", "CISA", "Security", "All" { + It "MS.EXO.11.3: The phishing protection solution SHOULD include an AI-based phishing detection tool comparable to EOP Mailbox Intelligence." { + + $result = Test-MtCisaMailboxIntelligence + + if ($null -ne $result) { + $result | Should -Be $true -Because "preset policies are enabled." + } + } +} \ No newline at end of file diff --git a/website/docs/tests/cisa/exo.md b/website/docs/tests/cisa/exo.md index b1aaf1a3..4b0f8bcc 100644 --- a/website/docs/tests/cisa/exo.md +++ b/website/docs/tests/cisa/exo.md @@ -43,6 +43,9 @@ See the [Installation guide](/docs/installation#optional-modules-and-permissions | Test-MtCisaAttachmentFilter | [MS.EXO.10.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo101v1) | | Test-MtCisaMalwareAction | [MS.EXO.10.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo102v1) | | Test-MtCisaMalwareZap | [MS.EXO.10.3v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo103v1) | +| Test-MtCisaImpersonation | [MS.EXO.11.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo111v1) | +| Test-MtCisaImpersonationTip | [MS.EXO.11.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo112v1) | +| Test-MtCisaMailboxIntelligence | [MS.EXO.11.3v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo113v1) | | Test-MtCisaAntiSpamAllowList | [MS.EXO.12.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo121v1) | | Test-MtCisaAntiSpamSafeList | [MS.EXO.12.2v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo122v1) | | Test-MtCisaMailboxAuditing | [MS.EXO.13.1v1](https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md#msexo131v1) | \ No newline at end of file