From bd4bc27382fec52be6df92ca98586594bce148b1 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Tue, 26 Nov 2024 13:13:11 -0500 Subject: [PATCH 01/28] Delete .github/workflows/test-github-token-write.yml --- .github/workflows/test-github-token-write.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 .github/workflows/test-github-token-write.yml diff --git a/.github/workflows/test-github-token-write.yml b/.github/workflows/test-github-token-write.yml deleted file mode 100644 index f4043e5..0000000 --- a/.github/workflows/test-github-token-write.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Test GITHUB_TOKEN Write Access - -on: - workflow_dispatch: # Allows you to manually trigger this test - -jobs: - test-write-access: - runs-on: ubuntu-latest - steps: - - name: Test GITHUB_TOKEN Write Access - env: - ISSUE_NUMBER: 138 # Replace with an existing issue number in your repository - run: | - curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ - -X POST \ - -d '{"body": "Testing GITHUB_TOKEN write access"}' \ - "https://api.github.com/repos/${{ github.repository }}/issues/${ISSUE_NUMBER}/comments" From e0a32e5b4cc82a893a6f779e9eb2e092718f5da2 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 12 Dec 2024 19:08:56 -0500 Subject: [PATCH 02/28] Refactor Search-HawkTenantEXOAuditLog to break it into smaller more managable functions to abide by the principle of SRP and allow for easier troubleshooting / code maintainability. The first function to be broken out, being Get-HawkTenantInboxRuleHistory --- Hawk/Hawk.psd1 | 3 +- .../Tenant/Get-HawkTenantInboxRuleHistory.ps1 | 150 ++++++++++++++++++ .../Tenant/Start-HawkTenantInvestigation.ps1 | 94 ++++++----- 3 files changed, 202 insertions(+), 45 deletions(-) create mode 100644 Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index 2521860..cdf18c5 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -51,7 +51,7 @@ 'Get-HawkTenantConfiguration', 'Get-HawkTenantEDiscoveryConfiguration', 'Get-HawkTenantInboxRules', - 'Get-HawkTenantConsentGrants', + 'Get-HawkTenantConsentGrant', 'Get-HawkTenantRBACChange', 'Get-HawkTenantAzureAppAuditLog', 'Get-HawkUserAuthHistory', @@ -60,6 +60,7 @@ 'Get-HawkUserInboxRule', 'Get-HawkUserMailboxAuditing', 'Search-HawkTenantActivityByIP', + 'Get-HawkTenantInboxRuleHistory', 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', diff --git a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 new file mode 100644 index 0000000..8224cee --- /dev/null +++ b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 @@ -0,0 +1,150 @@ +Function Get-HawkTenantInboxRuleHistory { + <# + .SYNOPSIS + Retrieves historical changes made to inbox rules across the tenant using audit logs. + + .DESCRIPTION + Analyzes the Microsoft 365 Unified Audit Log to identify historical changes made to inbox rules + across the tenant. This function focuses on detecting potentially suspicious rule changes by: + + - Finding newly created inbox rules + - Identifying rules with suspicious configurations (forwarding, deletion, etc.) + - Showing who made changes to rules and when + - Providing detailed audit trail of rule modifications + + This function complements Get-HawkTenantInboxRules: + - Get-HawkTenantInboxRules: Shows current rules that exist in mailboxes + - Get-HawkTenantInboxRuleHistory: Shows historical changes to rules over time + + Suspicious configurations that are flagged include: + - Rules that forward or redirect messages + - Rules that delete messages or move to Deleted Items + - Rules with suspicious keyword filters + - Rules targeting security-related senders + + .OUTPUTS + File: Simple_New_InboxRule.csv/.json + Path: \Tenant + Description: Simplified view of rule changes + + File: New_InboxRules.csv/.json + Path: \Tenant + Description: Detailed log data for rule changes + + File: _Investigate_InboxRules.csv/.json + Path: \Tenant + Description: Rules flagged as potentially suspicious + + File: Investigate_InboxRules_Raw.json + Path: \Tenant + Description: Raw audit data for suspicious rules + + .EXAMPLE + Get-HawkTenantInboxRuleHistory + + Retrieves all inbox rule changes from the audit logs within the configured search window, + analyzing them for suspicious configurations. + + .NOTES + This function focuses on historical changes through audit logs, while Get-HawkTenantInboxRules + shows current mailbox rules. Use both for comprehensive investigation: + - Get-HawkTenantInboxRuleHistory: Find when suspicious changes were made + - Get-HawkTenantInboxRules: Verify what rules currently exist + #> + [CmdletBinding()] + param() + + Test-EXOConnection + Send-AIEvent -Event "CmdRun" + + Out-LogFile "Analyzing historical inbox rule changes from audit logs" -Action + + # Create tenant folder if it doesn't exist + $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" + if (-not (Test-Path -Path $TenantPath)) { + New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null + } + + try { + # Search for new inbox rules + Out-LogFile "Searching audit logs for inbox rule changes" -action + $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'New-InboxRule'" + [array]$NewInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand + + if ($NewInboxRules.Count -gt 0) { + Out-LogFile ("Found " + $NewInboxRules.Count + " inbox rule changes in audit logs") + + # Write raw audit data for reference + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "New_InboxRules_Raw.json" + $NewInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath + + # Process and output the results + $ParsedRules = $NewInboxRules | Get-SimpleUnifiedAuditLog + if ($ParsedRules) { + # Output simple format for easy analysis + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_New_InboxRule" -csv -json + + # Output full audit logs for complete record + $NewInboxRules | Out-MultipleFileType -FilePrefix "New_InboxRules" -csv -json + + # Check for suspicious rules + $SuspiciousRules = $ParsedRules | Where-Object { + $rule = $_ + + # Check for forwarding/redirection + ($rule.Param_ForwardTo) -or + ($rule.Param_ForwardAsAttachmentTo) -or + ($rule.Param_RedirectTo) -or + ($rule.Param_DeleteMessage) -or + + # Check for moves to deleted items + ($rule.Param_MoveToFolder -eq 'Deleted Items') -or + + # Check for suspicious keywords in subject filters + ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') -or + + # Check for security-related sender filters + ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') + } + + if ($SuspiciousRules) { + Out-LogFile "Found suspicious historical rule changes requiring investigation" -Notice + $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_InboxRules" -csv -json -Notice + + # Write raw data for suspicious rules + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_InboxRules_Raw.json" + $SuspiciousRules | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath + + # Log details about why each rule was flagged + foreach ($rule in $SuspiciousRules) { + $reasons = @() + if ($rule.Param_ForwardTo) { $reasons += "forwards to: $($rule.Param_ForwardTo)" } + if ($rule.Param_ForwardAsAttachmentTo) { $reasons += "forwards as attachment to: $($rule.Param_ForwardAsAttachmentTo)" } + if ($rule.Param_RedirectTo) { $reasons += "redirects to: $($rule.Param_RedirectTo)" } + if ($rule.Param_DeleteMessage) { $reasons += "deletes messages" } + if ($rule.Param_MoveToFolder -eq 'Deleted Items') { $reasons += "moves to Deleted Items" } + if ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') { + $reasons += "suspicious subject filter: $($rule.Param_SubjectContainsWords)" + } + if ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') { + $reasons += "targets security sender: $($rule.Param_From)" + } + + Out-LogFile "Found historically suspicious rule: '$($rule.Param_Name)' created by $($rule.UserId) at $($rule.CreationTime)" -Notice + Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice + } + } + } + else { + Out-LogFile "Error: Failed to parse inbox rule audit data" -Notice + } + } + else { + Out-LogFile "No inbox rule changes found in audit logs" + } + } + catch { + Out-LogFile "Error analyzing inbox rule history: $($_.Exception.Message)" -Notice + Write-Error -ErrorRecord $_ -ErrorAction Continue + } +} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 0b9d002..0a71df1 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -51,53 +51,59 @@ Get-HawkTenantEDiscoveryConfiguration } - if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { - Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action - Search-HawkTenantEXOAuditLog + # if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { + # Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action + # Search-HawkTenantEXOAuditLog + # } + + if ($PSCmdlet.ShouldProcess("Inbox Rule History Audit Log", "Search Inbox Rule History Audit Log")) { + Out-LogFile "Running Get-HawkTenantInboxRuleHistory" -action + Get-HawkTenantInboxRuleHistory } if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action Get-HawkTenantEDiscoveryLogs } - - if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { - Out-LogFile "Running Get-HawkTenantDomainActivity" -action - Get-HawkTenantDomainActivity - } - - if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { - Out-LogFile "Running Get-HawkTenantRBACChange" -action - Get-HawkTenantRBACChange - } - - if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { - Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action - Get-HawkTenantAzureAppAuditLog - } - - if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { - Out-LogFile "Running Get-HawkTenantEXOAdmins" -action - Get-HawkTenantEXOAdmins - } - - if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { - Out-LogFile "Running Get-HawkTenantConsentGrant" -action - Get-HawkTenantConsentGrant - } - - if ($PSCmdlet.ShouldProcess("Azure Admins", "Get Azure admin list")) { - Out-LogFile "Running Get-HawkTenantAZAdmin" -action - Get-HawkTenantAZAdmin - } - - if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { - Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetail" -action - Get-HawkTenantAppAndSPNCredentialDetail - } - - if ($PSCmdlet.ShouldProcess("Entra ID Users", "Get Entra ID user list")) { - Out-LogFile "Running Get-HawkTenantEntraIDUser" -action - Get-HawkTenantEntraIDUser - } -} \ No newline at end of file +} + + # if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { + # Out-LogFile "Running Get-HawkTenantDomainActivity" -action + # Get-HawkTenantDomainActivity + # } + + # if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { + # Out-LogFile "Running Get-HawkTenantRBACChange" -action + # Get-HawkTenantRBACChange + # } + + # if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { + # Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action + # Get-HawkTenantAzureAppAuditLog + # } + + # if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { + # Out-LogFile "Running Get-HawkTenantEXOAdmins" -action + # Get-HawkTenantEXOAdmins + # } + + # if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { + # Out-LogFile "Running Get-HawkTenantConsentGrants" -action + # Get-HawkTenantConsentGrants + # } + + # if ($PSCmdlet.ShouldProcess("Azure Admins", "Get Azure admin list")) { + # Out-LogFile "Running Get-HawkTenantAZAdmins" -action + # Get-HawkTenantAZAdmins + # } + + # if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { + # Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetails" -action + # Get-HawkTenantAppAndSPNCredentialDetails + # } + + # if ($PSCmdlet.ShouldProcess("Azure AD Users", "Get Azure AD user list")) { + # Out-LogFile "Running Get-HawkTenantAzureADUsers" -action + # Get-HawkTenantAzureADUsers + # } +# } \ No newline at end of file From 2f260a8ccf6be4c427e891a3e2abe0590469a864 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Sat, 14 Dec 2024 11:30:22 -0500 Subject: [PATCH 03/28] Modify .gitignore to not allow .csv, .xlsx, .json, .docs files in the repo. --- .gitignore | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0d24381..61b077c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ - -# ignore the settings folder and files for VSCode and PSS +# ignore the settings folder and files for VSCode and PSS .vscode/* *.psproj *TempPoint* @@ -19,4 +18,11 @@ Hawk/Hawk.psproj TestResults/* # ignore the publishing Directory -publish/* \ No newline at end of file +publish/* + +# Ignore all .csv, .json, .docx, and .xlsx files +*.csv +*.json +*.docx +*.doc +*.xlsx From bf0544e9fcc06dfb1bfa0b2ce9b0506b6a683e55 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Sun, 15 Dec 2024 17:34:30 -0500 Subject: [PATCH 04/28] Merge development branch into current branch --- .../Tenant/Start-HawkTenantInvestigation.ps1 | 67 +++++++++---------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index b8a055b..44d1763 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -51,10 +51,10 @@ Get-HawkTenantEDiscoveryConfiguration } - # if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { - # Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action - # Search-HawkTenantEXOAuditLog - # } + if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { + Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action + Search-HawkTenantEXOAuditLog + } if ($PSCmdlet.ShouldProcess("Inbox Rule History Audit Log", "Search Inbox Rule History Audit Log")) { Out-LogFile "Running Get-HawkTenantInboxRuleHistory" -action @@ -65,45 +65,44 @@ Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action Get-HawkTenantEDiscoveryLogs } -} - # if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { - # Out-LogFile "Running Get-HawkTenantDomainActivity" -action - # Get-HawkTenantDomainActivity - # } + if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { + Out-LogFile "Running Get-HawkTenantDomainActivity" -action + Get-HawkTenantDomainActivity + } - # if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { - # Out-LogFile "Running Get-HawkTenantRBACChange" -action - # Get-HawkTenantRBACChange - # } + if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { + Out-LogFile "Running Get-HawkTenantRBACChange" -action + Get-HawkTenantRBACChange + } - # if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { - # Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action - # Get-HawkTenantAzureAppAuditLog - # } + if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { + Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action + Get-HawkTenantAzureAppAuditLog + } - # if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { - # Out-LogFile "Running Get-HawkTenantEXOAdmins" -action - # Get-HawkTenantEXOAdmins - # } + if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { + Out-LogFile "Running Get-HawkTenantEXOAdmins" -action + Get-HawkTenantEXOAdmins + } - # if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { - # Out-LogFile "Running Get-HawkTenantConsentGrants" -action - # Get-HawkTenantConsentGrants - # } + if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { + Out-LogFile "Running Get-HawkTenantConsentGrants" -action + Get-HawkTenantConsentGrants + } if ($PSCmdlet.ShouldProcess("Azure Admins", "Get Entra ID admin list")) { Out-LogFile "Running Get-HawkTenantEntraIDAdmin" -action Get-HawkTenantEntraIDAdmin } - # if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { - # Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetails" -action - # Get-HawkTenantAppAndSPNCredentialDetails - # } + if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { + Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetails" -action + Get-HawkTenantAppAndSPNCredentialDetails + } - # if ($PSCmdlet.ShouldProcess("Azure AD Users", "Get Azure AD user list")) { - # Out-LogFile "Running Get-HawkTenantAzureADUsers" -action - # Get-HawkTenantAzureADUsers - # } -# } \ No newline at end of file + if ($PSCmdlet.ShouldProcess("Azure AD Users", "Get Azure AD user list")) { + Out-LogFile "Running Get-HawkTenantAzureADUsers" -action + Get-HawkTenantAzureADUsers + } +} \ No newline at end of file From 9096357d2fb66bbaa4f359e8c9f3a153dce76374 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Wed, 18 Dec 2024 17:28:21 -0500 Subject: [PATCH 05/28] Add Entra ID function calls to Start-HawkTenantInvestigation that should have been in there from merging development into this branch. --- .../Tenant/Start-HawkTenantInvestigation.ps1 | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 44d1763..0723fa2 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -51,10 +51,10 @@ Get-HawkTenantEDiscoveryConfiguration } - if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { - Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action - Search-HawkTenantEXOAuditLog - } + # if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { + # Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action + # Search-HawkTenantEXOAuditLog + # } if ($PSCmdlet.ShouldProcess("Inbox Rule History Audit Log", "Search Inbox Rule History Audit Log")) { Out-LogFile "Running Get-HawkTenantInboxRuleHistory" -action @@ -87,22 +87,22 @@ } if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { - Out-LogFile "Running Get-HawkTenantConsentGrants" -action - Get-HawkTenantConsentGrants + Out-LogFile "Running Get-HawkTenantConsentGrant" -action + Get-HawkTenantConsentGrant } - if ($PSCmdlet.ShouldProcess("Azure Admins", "Get Entra ID admin list")) { + if ($PSCmdlet.ShouldProcess("Entra ID Admins", "Get Entra ID admin list")) { Out-LogFile "Running Get-HawkTenantEntraIDAdmin" -action Get-HawkTenantEntraIDAdmin } if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { - Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetails" -action - Get-HawkTenantAppAndSPNCredentialDetails + Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetail" -action + Get-HawkTenantAppAndSPNCredentialDetail } - if ($PSCmdlet.ShouldProcess("Azure AD Users", "Get Azure AD user list")) { - Out-LogFile "Running Get-HawkTenantAzureADUsers" -action - Get-HawkTenantAzureADUsers + if ($PSCmdlet.ShouldProcess("Entra ID Users", "Get Entra ID user list")) { + Out-LogFile "Running Get-HawkTenantEntraIDUser" -action + Get-HawkTenantEntraIDUser } } \ No newline at end of file From 34e5cbc19ac4416f19bab4b7fafd75251b1d9742 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 11:52:00 -0500 Subject: [PATCH 06/28] Update comment based help of Get-HawkTenantInboxRuleHistory and GetHawkTenantInboxRules to clearly dillineate the purpose of each function. --- .../Tenant/Get-HawkTenantInboxRuleHistory.ps1 | 65 +++++++------- .../Tenant/Get-HawkTenantInboxRules.ps1 | 85 +++++++++++-------- .../Tenant/Start-HawkTenantInvestigation.ps1 | 80 ++++++++--------- 3 files changed, 118 insertions(+), 112 deletions(-) diff --git a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 index 8224cee..79ffa08 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 @@ -1,55 +1,48 @@ Function Get-HawkTenantInboxRuleHistory { <# .SYNOPSIS - Retrieves historical changes made to inbox rules across the tenant using audit logs. + Retrieves audit log entries for newly created inbox rules within the tenant. .DESCRIPTION - Analyzes the Microsoft 365 Unified Audit Log to identify historical changes made to inbox rules - across the tenant. This function focuses on detecting potentially suspicious rule changes by: - - - Finding newly created inbox rules - - Identifying rules with suspicious configurations (forwarding, deletion, etc.) - - Showing who made changes to rules and when - - Providing detailed audit trail of rule modifications - - This function complements Get-HawkTenantInboxRules: - - Get-HawkTenantInboxRules: Shows current rules that exist in mailboxes - - Get-HawkTenantInboxRuleHistory: Shows historical changes to rules over time - - Suspicious configurations that are flagged include: - - Rules that forward or redirect messages - - Rules that delete messages or move to Deleted Items - - Rules with suspicious keyword filters - - Rules targeting security-related senders + This function queries the Microsoft 365 Unified Audit Logs for events where new inbox rules + were created (New-InboxRule events). It is focused on historical record-keeping and detection + of potentially suspicious rules that were added in the past. + + Key points: + - Shows historical creation events for inbox rules, including who created them and when. + - Flags any historically created rules that appear suspicious (e.g., rules that forward + externally, delete messages, or target certain keywords). + - Does not show whether the rules are still active or currently exist in the mailboxes. + + For current, active rules, use Get-HawkTenantInboxRules. .OUTPUTS - File: Simple_New_InboxRule.csv/.json - Path: \Tenant - Description: Simplified view of rule changes + File: Simple_New_InboxRule.csv/.json + Path: \Tenant + Description: Simplified view of newly created inbox rule events. - File: New_InboxRules.csv/.json - Path: \Tenant - Description: Detailed log data for rule changes + File: New_InboxRules.csv/.json + Path: \Tenant + Description: Detailed audit log data for newly created inbox rules. - File: _Investigate_InboxRules.csv/.json - Path: \Tenant - Description: Rules flagged as potentially suspicious + File: _Investigate_InboxRules.csv/.json + Path: \Tenant + Description: A subset of historically created rules flagged as suspicious. - File: Investigate_InboxRules_Raw.json - Path: \Tenant - Description: Raw audit data for suspicious rules + File: Investigate_InboxRules_Raw.json + Path: \Tenant + Description: Raw audit data for suspicious newly created rules. .EXAMPLE Get-HawkTenantInboxRuleHistory - Retrieves all inbox rule changes from the audit logs within the configured search window, - analyzing them for suspicious configurations. + Retrieves events for all newly created inbox rules from the audit logs within the specified + search window, highlighting any that appear suspicious. .NOTES - This function focuses on historical changes through audit logs, while Get-HawkTenantInboxRules - shows current mailbox rules. Use both for comprehensive investigation: - - Get-HawkTenantInboxRuleHistory: Find when suspicious changes were made - - Get-HawkTenantInboxRules: Verify what rules currently exist + - Focuses solely on the historical aspect of rule creation. + - Does not show if the rules currently exist or are active; it only surfaces past creation events. + - To view active rules in mailboxes, use Get-HawkTenantInboxRules. #> [CmdletBinding()] param() diff --git a/Hawk/functions/Tenant/Get-HawkTenantInboxRules.ps1 b/Hawk/functions/Tenant/Get-HawkTenantInboxRules.ps1 index c7e0b98..33b77c6 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantInboxRules.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantInboxRules.ps1 @@ -1,41 +1,54 @@ Function Get-HawkTenantInboxRules { <# -.SYNOPSIS - Gets inbox rules and forwarding directly from all mailboxes in the org. -.DESCRIPTION - Uses Start-RobustCloudCommand to gather data from each mailbox in the org. - Gathers inbox rules with Get-HawkUserInboxRule - Gathers forwarding with Get-HawkUserEmailForwarding -.PARAMETER CSVPath - Path to a CSV file with a list of users to run against. - CSV header should have DisplayName,PrimarySMTPAddress at minimum - -.PARAMETER UserPrincipalName - The UPN of the user that will authenticate against Exchange Online. - -.OUTPUTS - See Help for Get-HawkUserInboxRule for inbox rule output - See Help for Get-HawkUserEmailForwarding for email forwarding output - - File: Robust.log - Path: \ - Description: Logfile for Start-RobustCloudCommand - -.EXAMPLE - Start-HawkTenantInboxRules -UserPrincipalName userx@tenantdomain.onmicrosoft.com - - Runs Get-HawkUserInboxRule and Get-HawkUserEmailForwarding against all mailboxes in the org. The UserPrincipalName - is the Admin/User who is running the cmdlet. - -.EXAMPLE - Start-HawkTenantInboxRules -csvpath c:\temp\myusers.csv - - Runs Get-HawkUserInboxRule and Get-HawkUserEmailForwarding against all mailboxes listed in myusers.csv.The UserPrincipalName - is the Admin/User who is running the cmdlet. - -.LINK - https://gallery.technet.microsoft.com/office/Start-RobustCloudCommand-69fb349e -#> + .SYNOPSIS + Retrieves the currently active inbox rules and forwarding settings from all (or specified) mailboxes. + + .DESCRIPTION + This function directly queries each mailbox in the organization to list its currently configured + inbox rules and email forwarding settings. It provides a real-time snapshot of what rules are + active right now, as opposed to historical audit data. + + Key points: + - Directly collects the current state of each mailbox’s rules using Get-HawkUserInboxRule. + - Also gathers forwarding settings from Get-HawkUserEmailForwarding. + - Does not rely on audit logs; instead, uses live mailbox data. + + For historical records of when rules were created and past suspicious activity, use Get-HawkTenantInboxRuleHistory. + + .PARAMETER CSVPath + A CSV file specifying a list of users to query. + Expected columns: DisplayName, PrimarySMTPAddress (minimum). + + .PARAMETER UserPrincipalName + The UPN of the admin or account used to authenticate against Exchange Online. + + .OUTPUTS + This function calls Get-HawkUserInboxRule and Get-HawkUserEmailForwarding. + For detailed information about the output, see their respective help documentation. + + File: Robust.log + Path: \ + Description: The log file generated by Start-RobustCloudCommand, which is used to retrieve + the rules and forwarding information from each mailbox. + + .EXAMPLE + Start-HawkTenantInboxRules -UserPrincipalName userx@tenantdomain.onmicrosoft.com + + Retrieves the current inbox rules and forwarding for all mailboxes in the organization. + + .EXAMPLE + Start-HawkTenantInboxRules -csvpath c:\temp\myusers.csv -UserPrincipalName admin@tenantdomain.onmicrosoft.com + + Retrieves the current inbox rules and forwarding for all mailboxes listed in myusers.csv. + + .LINK + https://gallery.technet.microsoft.com/office/Start-RobustCloudCommand-69fb349e + + .NOTES + - This function shows the current (live) rules and forwarding settings. + - For historical data on when rules were created, refer to Get-HawkTenantInboxRuleHistory. + #> + param ( [string]$CSVPath, diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 0723fa2..d48f963 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -46,10 +46,10 @@ Get-HawkTenantConfiguration } - if ($PSCmdlet.ShouldProcess("EDiscovery Configuration", "Get eDiscovery configuration")) { - Out-LogFile "Running Get-HawkTenantEDiscoveryConfiguration" -action - Get-HawkTenantEDiscoveryConfiguration - } + # if ($PSCmdlet.ShouldProcess("EDiscovery Configuration", "Get eDiscovery configuration")) { + # Out-LogFile "Running Get-HawkTenantEDiscoveryConfiguration" -action + # Get-HawkTenantEDiscoveryConfiguration + # } # if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { # Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action @@ -61,48 +61,48 @@ Get-HawkTenantInboxRuleHistory } - if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { - Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action - Get-HawkTenantEDiscoveryLogs - } + # if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { + # Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action + # Get-HawkTenantEDiscoveryLogs + # } - if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { - Out-LogFile "Running Get-HawkTenantDomainActivity" -action - Get-HawkTenantDomainActivity - } + # if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { + # Out-LogFile "Running Get-HawkTenantDomainActivity" -action + # Get-HawkTenantDomainActivity + # } - if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { - Out-LogFile "Running Get-HawkTenantRBACChange" -action - Get-HawkTenantRBACChange - } + # if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { + # Out-LogFile "Running Get-HawkTenantRBACChange" -action + # Get-HawkTenantRBACChange + # } - if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { - Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action - Get-HawkTenantAzureAppAuditLog - } + # if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { + # Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action + # Get-HawkTenantAzureAppAuditLog + # } - if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { - Out-LogFile "Running Get-HawkTenantEXOAdmins" -action - Get-HawkTenantEXOAdmins - } + # if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { + # Out-LogFile "Running Get-HawkTenantEXOAdmins" -action + # Get-HawkTenantEXOAdmins + # } - if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { - Out-LogFile "Running Get-HawkTenantConsentGrant" -action - Get-HawkTenantConsentGrant - } + # if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { + # Out-LogFile "Running Get-HawkTenantConsentGrant" -action + # Get-HawkTenantConsentGrant + # } - if ($PSCmdlet.ShouldProcess("Entra ID Admins", "Get Entra ID admin list")) { - Out-LogFile "Running Get-HawkTenantEntraIDAdmin" -action - Get-HawkTenantEntraIDAdmin - } + # if ($PSCmdlet.ShouldProcess("Entra ID Admins", "Get Entra ID admin list")) { + # Out-LogFile "Running Get-HawkTenantEntraIDAdmin" -action + # Get-HawkTenantEntraIDAdmin + # } - if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { - Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetail" -action - Get-HawkTenantAppAndSPNCredentialDetail - } + # if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { + # Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetail" -action + # Get-HawkTenantAppAndSPNCredentialDetail + # } - if ($PSCmdlet.ShouldProcess("Entra ID Users", "Get Entra ID user list")) { - Out-LogFile "Running Get-HawkTenantEntraIDUser" -action - Get-HawkTenantEntraIDUser - } + # if ($PSCmdlet.ShouldProcess("Entra ID Users", "Get Entra ID user list")) { + # Out-LogFile "Running Get-HawkTenantEntraIDUser" -action + # Get-HawkTenantEntraIDUser + # } } \ No newline at end of file From 06b4bdb32a2979b365c88a0f82298c97c0515135 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 12:08:23 -0500 Subject: [PATCH 07/28] Update comment based help and file names to be more self explanitory. --- .../Tenant/Get-HawkTenantInboxRuleHistory.ps1 | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 index 79ffa08..e1f37d2 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 @@ -1,46 +1,46 @@ Function Get-HawkTenantInboxRuleHistory { <# .SYNOPSIS - Retrieves audit log entries for newly created inbox rules within the tenant. + Retrieves audit log entries for all inbox rules created within the tenant, whether they are active or not. .DESCRIPTION - This function queries the Microsoft 365 Unified Audit Logs for events where new inbox rules + This function queries the Microsoft 365 Unified Audit Logs for events where inbox rules were created (New-InboxRule events). It is focused on historical record-keeping and detection - of potentially suspicious rules that were added in the past. + of potentially suspicious rules that were created. Key points: - - Shows historical creation events for inbox rules, including who created them and when. - - Flags any historically created rules that appear suspicious (e.g., rules that forward + - Shows creation events for inbox rules, including who created them and when. + - Flags any created rules that appear suspicious (e.g., rules that forward externally, delete messages, or target certain keywords). - Does not show whether the rules are still active or currently exist in the mailboxes. For current, active rules, use Get-HawkTenantInboxRules. .OUTPUTS - File: Simple_New_InboxRule.csv/.json + File: Simple_InboxRules_Creation_History.csv/.json Path: \Tenant - Description: Simplified view of newly created inbox rule events. + Description: Simplified view of created inbox rule events. - File: New_InboxRules.csv/.json + File: InboxRules_Creation_History.csv/.json Path: \Tenant - Description: Detailed audit log data for newly created inbox rules. + Description: Detailed audit log data for created inbox rules. - File: _Investigate_InboxRules.csv/.json + File: _Investigate_InboxRules_Creation_History.csv/.json Path: \Tenant Description: A subset of historically created rules flagged as suspicious. - File: Investigate_InboxRules_Raw.json + File: Investigate_InboxRules_Creation_History_Raw.json Path: \Tenant - Description: Raw audit data for suspicious newly created rules. + Description: Raw audit data for suspicious created rules. .EXAMPLE Get-HawkTenantInboxRuleHistory - Retrieves events for all newly created inbox rules from the audit logs within the specified + Retrieves events for all created inbox rules from the audit logs within the specified search window, highlighting any that appear suspicious. .NOTES - - Focuses solely on the historical aspect of rule creation. + - Focuses solely on the aspect of rule creation. - Does not show if the rules currently exist or are active; it only surfaces past creation events. - To view active rules in mailboxes, use Get-HawkTenantInboxRules. #> @@ -50,7 +50,7 @@ Function Get-HawkTenantInboxRuleHistory { Test-EXOConnection Send-AIEvent -Event "CmdRun" - Out-LogFile "Analyzing historical inbox rule changes from audit logs" -Action + Out-LogFile "Analyzing inbox rule creation from audit logs" -Action # Create tenant folder if it doesn't exist $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" @@ -68,17 +68,17 @@ Function Get-HawkTenantInboxRuleHistory { Out-LogFile ("Found " + $NewInboxRules.Count + " inbox rule changes in audit logs") # Write raw audit data for reference - $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "New_InboxRules_Raw.json" + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "InboxRules_Creation_History_Raw.json" $NewInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath # Process and output the results $ParsedRules = $NewInboxRules | Get-SimpleUnifiedAuditLog if ($ParsedRules) { # Output simple format for easy analysis - $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_New_InboxRule" -csv -json + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_InboxRules_Creation_History" -csv -json # Output full audit logs for complete record - $NewInboxRules | Out-MultipleFileType -FilePrefix "New_InboxRules" -csv -json + $NewInboxRules | Out-MultipleFileType -FilePrefix "InboxRules_Creation_History" -csv -json # Check for suspicious rules $SuspiciousRules = $ParsedRules | Where-Object { @@ -101,11 +101,11 @@ Function Get-HawkTenantInboxRuleHistory { } if ($SuspiciousRules) { - Out-LogFile "Found suspicious historical rule changes requiring investigation" -Notice - $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_InboxRules" -csv -json -Notice + Out-LogFile "Found suspicious inbox rule creation requiring investigation" -Notice + $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_InboxRules_Creation_History" -csv -json -Notice # Write raw data for suspicious rules - $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_InboxRules_Raw.json" + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_InboxRules_Creation_History_Raw.json" $SuspiciousRules | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath # Log details about why each rule was flagged @@ -123,7 +123,7 @@ Function Get-HawkTenantInboxRuleHistory { $reasons += "targets security sender: $($rule.Param_From)" } - Out-LogFile "Found historically suspicious rule: '$($rule.Param_Name)' created by $($rule.UserId) at $($rule.CreationTime)" -Notice + Out-LogFile "Found suspicious rule creation: '$($rule.Param_Name)' created by $($rule.UserId) at $($rule.CreationTime)" -Notice Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice } } @@ -137,7 +137,7 @@ Function Get-HawkTenantInboxRuleHistory { } } catch { - Out-LogFile "Error analyzing inbox rule history: $($_.Exception.Message)" -Notice + Out-LogFile "Error analyzing inbox rule creation: $($_.Exception.Message)" -Notice Write-Error -ErrorRecord $_ -ErrorAction Continue } } \ No newline at end of file From 2136e1383a380fbf5982572188a57326a81f9dab Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 12:10:34 -0500 Subject: [PATCH 08/28] Update comment based help to mention that this searches for rules created via the shell or exchange admin console --- Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 index e1f37d2..91f81b1 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 @@ -1,11 +1,11 @@ Function Get-HawkTenantInboxRuleHistory { <# .SYNOPSIS - Retrieves audit log entries for all inbox rules created within the tenant, whether they are active or not. + Retrieves audit log entries for all inbox rules created within the tenant via PowerShell or the ExchangeAdmin Portal, whether they are active or not. .DESCRIPTION This function queries the Microsoft 365 Unified Audit Logs for events where inbox rules - were created (New-InboxRule events). It is focused on historical record-keeping and detection + were created (New-InboxRule events) via PowerShell or the Exchange Admin Portal. It is focused on historical record-keeping and detection of potentially suspicious rules that were created. Key points: From 5a622bfd78a51a7a0fb8fd11c70dd0db9ed933f7 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 14:51:27 -0500 Subject: [PATCH 09/28] Change function and filenames to indicate that the inbox rules pulled are from admin accounts. --- .../Get-HawkTenantAdminInboxRuleHistory.ps1 | 144 +++++++++++++++++ ...t-HawkTenantAdminInboxRuleModification.ps1 | 146 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 create mode 100644 Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 new file mode 100644 index 0000000..4ddd256 --- /dev/null +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 @@ -0,0 +1,144 @@ +Function Get-HawkTenantAdminInboxRuleHistory { + <# + .SYNOPSIS + Retrieves audit log entries for inbox rules that were historically created within the tenant. + + .DESCRIPTION + This function queries the Microsoft 365 Unified Audit Logs for events classified as inbox + rule creation (New-InboxRule). It focuses on historical record-keeping and identifying + potentially suspicious rules that were created. The logged events do not indicate the + specific method or interface used to create the rules. + + Key points: + - Displays creation events for inbox rules, including who created them and when. + - Flags created rules that appear suspicious (e.g., rules that forward externally, delete + messages, or filter based on suspicious keywords). + - Does not confirm whether the rules are currently active or still exist. + + For current, active rules, use Get-HawkTenantInboxRules. + + .OUTPUTS + File: Simple_Admin_Inbox_Rules_Creation_History.csv/.json + Path: \Tenant + Description: Simplified view of created inbox rule events. + + File: Admin_Inbox_Rules_Creation_History.csv/.json + Path: \Tenant + Description: Detailed audit log data for created inbox rules. + + File: _Investigate_Admin_Inbox_Rules_Creation_History.csv/.json + Path: \Tenant + Description: A subset of historically created rules flagged as suspicious. + + File: Investigate_Admin_Inbox_Rules_Creation_History_Raw.json + Path: \Tenant + Description: Raw audit data for suspicious created rules. + + .EXAMPLE + Get-HawkTenantAdminInboxRuleHistory + + Retrieves events for all created inbox rules from the audit logs within the specified + search window, highlighting any that appear suspicious. + + .NOTES + - Focuses solely on historical rule creation events. + - Does not show if the rules currently exist or are active. + - Does not specify the interface or method used to create the rules. + #> + [CmdletBinding()] + param() + + Test-EXOConnection + Send-AIEvent -Event "CmdRun" + + Out-LogFile "Analyzing admin inbox rule creation from audit logs" -Action + + # Create tenant folder if it doesn't exist + $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" + if (-not (Test-Path -Path $TenantPath)) { + New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null + } + + try { + # Search for new inbox rules + Out-LogFile "Searching audit logs for inbox rule changes" -action + $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'New-InboxRule'" + [array]$NewInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand + + if ($NewInboxRules.Count -gt 0) { + Out-LogFile ("Found " + $NewInboxRules.Count + " admin inbox rule changes in audit logs") + + # Write raw audit data for reference + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Creation_History_Raw.json" + $NewInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath + + # Process and output the results + $ParsedRules = $NewInboxRules | Get-SimpleUnifiedAuditLog + if ($ParsedRules) { + # Output simple format for easy analysis + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Creation_History" -csv -json + + # Output full audit logs for complete record + $NewInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Creation_History" -csv -json + + # Check for suspicious rules + $SuspiciousRules = $ParsedRules | Where-Object { + $rule = $_ + + # Check for forwarding/redirection + ($rule.Param_ForwardTo) -or + ($rule.Param_ForwardAsAttachmentTo) -or + ($rule.Param_RedirectTo) -or + ($rule.Param_DeleteMessage) -or + + # Check for moves to deleted items + ($rule.Param_MoveToFolder -eq 'Deleted Items') -or + + # Check for suspicious keywords in subject filters + ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') -or + + # Check for security-related sender filters + ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') + } + + if ($SuspiciousRules) { + Out-LogFile "Found suspicious admin inbox rule creation requiring investigation" -Notice + $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Creation_History" -csv -json -Notice + + # Write raw data for suspicious rules + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Creation_History_Raw.json" + $SuspiciousRules | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath + + # Log details about why each rule was flagged + foreach ($rule in $SuspiciousRules) { + $reasons = @() + if ($rule.Param_ForwardTo) { $reasons += "forwards to: $($rule.Param_ForwardTo)" } + if ($rule.Param_ForwardAsAttachmentTo) { $reasons += "forwards as attachment to: $($rule.Param_ForwardAsAttachmentTo)" } + if ($rule.Param_RedirectTo) { $reasons += "redirects to: $($rule.Param_RedirectTo)" } + if ($rule.Param_DeleteMessage) { $reasons += "deletes messages" } + if ($rule.Param_MoveToFolder -eq 'Deleted Items') { $reasons += "moves to Deleted Items" } + if ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') { + $reasons += "suspicious subject filter: $($rule.Param_SubjectContainsWords)" + } + if ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') { + $reasons += "targets security sender: $($rule.Param_From)" + } + + Out-LogFile "Found suspicious rule creation: '$($rule.Param_Name)' created by $($rule.UserId) at $($rule.CreationTime)" -Notice + Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice + } + } + } + else { + Out-LogFile "Error: Failed to parse inbox rule audit data" -Notice + } + } + else { + Out-LogFile "No inbox rule changes found in audit logs" + } + } + catch { + Out-LogFile "Error analyzing admin inbox rule creation: $($_.Exception.Message)" -Notice + Write-Error -ErrorRecord $_ -ErrorAction Continue + } +} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 new file mode 100644 index 0000000..1e92a0b --- /dev/null +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 @@ -0,0 +1,146 @@ +Function Get-HawkTenantAdminInboxRuleModification { + <# + .SYNOPSIS + Retrieves audit log entries for inbox rules that were historically modified within the tenant. + + .DESCRIPTION + This function queries the Microsoft 365 Unified Audit Logs for events classified as + inbox rule modifications (Set-InboxRule). It focuses on past changes to existing rules, + helping identify suspicious modifications (e.g., forwarding to external addresses, + enabling deletion, or targeting sensitive keywords). + + The logged events do not indicate how or where the modification took place, only that + an inbox rule was changed at a given time by a specific account. + + Key points: + - Shows modification events for inbox rules, including who modified them and when. + - Flags modifications that may be suspicious based on predefined criteria. + - Does not indicate whether the rules are currently active or still exist. + + For current, active rules, use Get-HawkTenantInboxRules. + + .OUTPUTS + File: Simple_Admin_Inbox_Rules_Modification_History.csv/.json + Path: \Tenant + Description: Simplified view of inbox rule modification events. + + File: Admin_Inbox_Rules_Modification_History.csv/.json + Path: \Tenant + Description: Detailed audit log data for modified inbox rules. + + File: _Investigate_Admin_Inbox_Rules_Modification_History.csv/.json + Path: \Tenant + Description: A subset of historically modified rules flagged as suspicious. + + File: Investigate_Admin_Inbox_Rules_Modification_History_Raw.json + Path: \Tenant + Description: Raw audit data for suspicious rule modifications. + + .EXAMPLE + Get-HawkTenantAdminInboxRuleModification + + Retrieves events for all modified inbox rules from the audit logs within the specified + search window, highlighting any that appear suspicious. + + .NOTES + - Focuses solely on historical rule modification events. + - Does not show if the rules currently exist or are active. + - Does not specify the interface or method used to modify the rules. + #> + [CmdletBinding()] + param() + + Test-EXOConnection + Send-AIEvent -Event "CmdRun" + + Out-LogFile "Analyzing admin inbox rule modifications from audit logs" -Action + + # Create tenant folder if it doesn't exist + $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" + if (-not (Test-Path -Path $TenantPath)) { + New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null + } + + try { + # Search for modified inbox rules + Out-LogFile "Searching audit logs for admin inbox rule modifications" -action + $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'Set-InboxRule'" + [array]$ModifiedInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand + + if ($ModifiedInboxRules.Count -gt 0) { + Out-LogFile ("Found " + $ModifiedInboxRules.Count + " admin inbox rule modifications in audit logs") + + # Write raw audit data for reference + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Modification_History_Raw.json" + $ModifiedInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath + + # Process and output the results + $ParsedRules = $ModifiedInboxRules | Get-SimpleUnifiedAuditLog + if ($ParsedRules) { + # Output simple format for easy analysis + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Modification_History" -csv -json + + # Output full audit logs for complete record + $ModifiedInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Modification_History" -csv -json + + # Check for suspicious modifications + $SuspiciousModifications = $ParsedRules | Where-Object { + $rule = $_ + + # Check for forwarding/redirection + ($rule.Param_ForwardTo) -or + ($rule.Param_ForwardAsAttachmentTo) -or + ($rule.Param_RedirectTo) -or + ($rule.Param_DeleteMessage) -or + + # Check for moves to deleted items + ($rule.Param_MoveToFolder -eq 'Deleted Items') -or + + # Check for suspicious keywords in subject filters + ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') -or + + # Check for security-related sender filters + ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') + } + + if ($SuspiciousModifications) { + Out-LogFile "Found suspicious rule modifications requiring investigation" -Notice + $SuspiciousModifications | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Modification_History" -csv -json -Notice + + # Write raw data for suspicious modifications + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Modification_History_Raw.json" + $SuspiciousModifications | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath + + # Log details about why each modification was flagged + foreach ($rule in $SuspiciousModifications) { + $reasons = @() + if ($rule.Param_ForwardTo) { $reasons += "modified forwarding to: $($rule.Param_ForwardTo)" } + if ($rule.Param_ForwardAsAttachmentTo) { $reasons += "modified forwarding as attachment to: $($rule.Param_ForwardAsAttachmentTo)" } + if ($rule.Param_RedirectTo) { $reasons += "modified redirection to: $($rule.Param_RedirectTo)" } + if ($rule.Param_DeleteMessage) { $reasons += "enabled message deletion" } + if ($rule.Param_MoveToFolder -eq 'Deleted Items') { $reasons += "modified to move to Deleted Items" } + if ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') { + $reasons += "modified suspicious subject filter: $($rule.Param_SubjectContainsWords)" + } + if ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') { + $reasons += "modified to target security sender: $($rule.Param_From)" + } + + Out-LogFile "Found suspicious rule modification: '$($rule.Param_Name)' modified by $($rule.UserId) at $($rule.CreationTime)" -Notice + Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice + } + } + } + else { + Out-LogFile "Error: Failed to parse inbox rule audit data" -Notice + } + } + else { + Out-LogFile "No admin inbox rule modifications found in audit logs" + } + } + catch { + Out-LogFile "Error analyzing admin inbox rule modifications: $($_.Exception.Message)" -Notice + Write-Error -ErrorRecord $_ -ErrorAction Continue + } +} \ No newline at end of file From b64c57a24f0e635690004b113f045e4b31fc79c0 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 14:53:19 -0500 Subject: [PATCH 10/28] Add comment to see if git commit prehook is working. --- Hawk/Hawk.psd1 | 3 +- .../Get-HawkTenantAdminInboxRuleHistory.ps1 | 2 +- ...t-HawkTenantAdminInboxRuleModification.ps1 | 2 +- .../Tenant/Get-HawkTenantInboxRuleHistory.ps1 | 143 ------------------ .../Tenant/Start-HawkTenantInvestigation.ps1 | 19 ++- 5 files changed, 16 insertions(+), 153 deletions(-) delete mode 100644 Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index 895f0d7..21aeed9 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -58,7 +58,8 @@ 'Get-HawkUserInboxRule', 'Get-HawkUserMailboxAuditing', 'Search-HawkTenantActivityByIP', - 'Get-HawkTenantInboxRuleHistory', + 'Get-HawkTenantAdminInboxRuleHistory', + 'Get-HawkTenantAdminInboxRuleModification', 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 index 4ddd256..fefb988 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 @@ -4,7 +4,7 @@ Function Get-HawkTenantAdminInboxRuleHistory { Retrieves audit log entries for inbox rules that were historically created within the tenant. .DESCRIPTION - This function queries the Microsoft 365 Unified Audit Logs for events classified as inbox + This function queries the Microsoft 365 Unified Audit Log for events classified as inbox rule creation (New-InboxRule). It focuses on historical record-keeping and identifying potentially suspicious rules that were created. The logged events do not indicate the specific method or interface used to create the rules. diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 index 1e92a0b..7ee089e 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 @@ -5,7 +5,7 @@ Function Get-HawkTenantAdminInboxRuleModification { .DESCRIPTION This function queries the Microsoft 365 Unified Audit Logs for events classified as - inbox rule modifications (Set-InboxRule). It focuses on past changes to existing rules, + inbox rule modification (Set-InboxRule). It focuses on past changes to existing rules, helping identify suspicious modifications (e.g., forwarding to external addresses, enabling deletion, or targeting sensitive keywords). diff --git a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 deleted file mode 100644 index 91f81b1..0000000 --- a/Hawk/functions/Tenant/Get-HawkTenantInboxRuleHistory.ps1 +++ /dev/null @@ -1,143 +0,0 @@ -Function Get-HawkTenantInboxRuleHistory { - <# - .SYNOPSIS - Retrieves audit log entries for all inbox rules created within the tenant via PowerShell or the ExchangeAdmin Portal, whether they are active or not. - - .DESCRIPTION - This function queries the Microsoft 365 Unified Audit Logs for events where inbox rules - were created (New-InboxRule events) via PowerShell or the Exchange Admin Portal. It is focused on historical record-keeping and detection - of potentially suspicious rules that were created. - - Key points: - - Shows creation events for inbox rules, including who created them and when. - - Flags any created rules that appear suspicious (e.g., rules that forward - externally, delete messages, or target certain keywords). - - Does not show whether the rules are still active or currently exist in the mailboxes. - - For current, active rules, use Get-HawkTenantInboxRules. - - .OUTPUTS - File: Simple_InboxRules_Creation_History.csv/.json - Path: \Tenant - Description: Simplified view of created inbox rule events. - - File: InboxRules_Creation_History.csv/.json - Path: \Tenant - Description: Detailed audit log data for created inbox rules. - - File: _Investigate_InboxRules_Creation_History.csv/.json - Path: \Tenant - Description: A subset of historically created rules flagged as suspicious. - - File: Investigate_InboxRules_Creation_History_Raw.json - Path: \Tenant - Description: Raw audit data for suspicious created rules. - - .EXAMPLE - Get-HawkTenantInboxRuleHistory - - Retrieves events for all created inbox rules from the audit logs within the specified - search window, highlighting any that appear suspicious. - - .NOTES - - Focuses solely on the aspect of rule creation. - - Does not show if the rules currently exist or are active; it only surfaces past creation events. - - To view active rules in mailboxes, use Get-HawkTenantInboxRules. - #> - [CmdletBinding()] - param() - - Test-EXOConnection - Send-AIEvent -Event "CmdRun" - - Out-LogFile "Analyzing inbox rule creation from audit logs" -Action - - # Create tenant folder if it doesn't exist - $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" - if (-not (Test-Path -Path $TenantPath)) { - New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null - } - - try { - # Search for new inbox rules - Out-LogFile "Searching audit logs for inbox rule changes" -action - $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'New-InboxRule'" - [array]$NewInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand - - if ($NewInboxRules.Count -gt 0) { - Out-LogFile ("Found " + $NewInboxRules.Count + " inbox rule changes in audit logs") - - # Write raw audit data for reference - $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "InboxRules_Creation_History_Raw.json" - $NewInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath - - # Process and output the results - $ParsedRules = $NewInboxRules | Get-SimpleUnifiedAuditLog - if ($ParsedRules) { - # Output simple format for easy analysis - $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_InboxRules_Creation_History" -csv -json - - # Output full audit logs for complete record - $NewInboxRules | Out-MultipleFileType -FilePrefix "InboxRules_Creation_History" -csv -json - - # Check for suspicious rules - $SuspiciousRules = $ParsedRules | Where-Object { - $rule = $_ - - # Check for forwarding/redirection - ($rule.Param_ForwardTo) -or - ($rule.Param_ForwardAsAttachmentTo) -or - ($rule.Param_RedirectTo) -or - ($rule.Param_DeleteMessage) -or - - # Check for moves to deleted items - ($rule.Param_MoveToFolder -eq 'Deleted Items') -or - - # Check for suspicious keywords in subject filters - ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') -or - - # Check for security-related sender filters - ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') - } - - if ($SuspiciousRules) { - Out-LogFile "Found suspicious inbox rule creation requiring investigation" -Notice - $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_InboxRules_Creation_History" -csv -json -Notice - - # Write raw data for suspicious rules - $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_InboxRules_Creation_History_Raw.json" - $SuspiciousRules | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath - - # Log details about why each rule was flagged - foreach ($rule in $SuspiciousRules) { - $reasons = @() - if ($rule.Param_ForwardTo) { $reasons += "forwards to: $($rule.Param_ForwardTo)" } - if ($rule.Param_ForwardAsAttachmentTo) { $reasons += "forwards as attachment to: $($rule.Param_ForwardAsAttachmentTo)" } - if ($rule.Param_RedirectTo) { $reasons += "redirects to: $($rule.Param_RedirectTo)" } - if ($rule.Param_DeleteMessage) { $reasons += "deletes messages" } - if ($rule.Param_MoveToFolder -eq 'Deleted Items') { $reasons += "moves to Deleted Items" } - if ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') { - $reasons += "suspicious subject filter: $($rule.Param_SubjectContainsWords)" - } - if ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') { - $reasons += "targets security sender: $($rule.Param_From)" - } - - Out-LogFile "Found suspicious rule creation: '$($rule.Param_Name)' created by $($rule.UserId) at $($rule.CreationTime)" -Notice - Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice - } - } - } - else { - Out-LogFile "Error: Failed to parse inbox rule audit data" -Notice - } - } - else { - Out-LogFile "No inbox rule changes found in audit logs" - } - } - catch { - Out-LogFile "Error analyzing inbox rule creation: $($_.Exception.Message)" -Notice - Write-Error -ErrorRecord $_ -ErrorAction Continue - } -} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index d48f963..c40b145 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -41,10 +41,10 @@ Send-AIEvent -Event "CmdRun" # Wrap operations in ShouldProcess checks - if ($PSCmdlet.ShouldProcess("Tenant Configuration", "Get configuration data")) { - Out-LogFile "Running Get-HawkTenantConfiguration" -action - Get-HawkTenantConfiguration - } + # if ($PSCmdlet.ShouldProcess("Tenant Configuration", "Get configuration data")) { + # Out-LogFile "Running Get-HawkTenantConfiguration" -action + # Get-HawkTenantConfiguration + # } # if ($PSCmdlet.ShouldProcess("EDiscovery Configuration", "Get eDiscovery configuration")) { # Out-LogFile "Running Get-HawkTenantEDiscoveryConfiguration" -action @@ -56,9 +56,14 @@ # Search-HawkTenantEXOAuditLog # } - if ($PSCmdlet.ShouldProcess("Inbox Rule History Audit Log", "Search Inbox Rule History Audit Log")) { - Out-LogFile "Running Get-HawkTenantInboxRuleHistory" -action - Get-HawkTenantInboxRuleHistory + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule History Audit Log", "Search Admin Inbox Rule History")) { + Out-LogFile "Running Get-HawkTenantAdminInboxRuleHistory" -action + Get-HawkTenantAdminInboxRuleHistory + } + + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule History Modification Audit Log", "Search Admin Inbox Rule Modification History")) { + Out-LogFile "Running Get-HawkTenantInboxRuleModification" -action + Get-HawkTenantAdminInboxRuleModification } # if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { From e827a2323ea04a867a8b477902b3690a4e73464d Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 15:32:57 -0500 Subject: [PATCH 11/28] Modify Out-LogFile to use the same formatted log tags as other logs, using brackets. Created an internal function to test for suspicious inbox rules, which can be called by all current and future functions that pull inbox rule data (e.g. Get-HawkTenantAdminInboxRuleModification, Get-HawkTenantAdminInboxRuleHistory) --- .../functions/Test-SuspiciousInboxRule.ps1 | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Hawk/internal/functions/Test-SuspiciousInboxRule.ps1 diff --git a/Hawk/internal/functions/Test-SuspiciousInboxRule.ps1 b/Hawk/internal/functions/Test-SuspiciousInboxRule.ps1 new file mode 100644 index 0000000..1f4e530 --- /dev/null +++ b/Hawk/internal/functions/Test-SuspiciousInboxRule.ps1 @@ -0,0 +1,78 @@ +Function Test-SuspiciousInboxRule { + <# + .SYNOPSIS + Internal helper function to detect suspicious inbox rule patterns. + + .DESCRIPTION + Analyzes inbox rule properties to identify potentially suspicious configurations + like external forwarding, message deletion, or targeting of security-related content. + Used by both rule creation and modification audit functions. + + .PARAMETER Rule + The parsed inbox rule object to analyze. + + .PARAMETER Reasons + [ref] array to store the reasons why a rule was flagged as suspicious. + + .OUTPUTS + Boolean indicating if the rule matches suspicious patterns. + Populates the Reasons array parameter with explanations if suspicious. + + .EXAMPLE + $reasons = @() + $isSuspicious = Test-SuspiciousInboxRule -Rule $ruleObject -Reasons ([ref]$reasons) + #> + [CmdletBinding()] + [OutputType([bool])] + param ( + [Parameter(Mandatory = $true)] + [object]$Rule, + + [Parameter(Mandatory = $true)] + [ref]$Reasons + ) + + $isSuspicious = $false + $suspiciousReasons = @() + + # Check forwarding/redirection configurations + if ($Rule.Param_ForwardTo) { + $isSuspicious = $true + $suspiciousReasons += "forwards to: $($Rule.Param_ForwardTo)" + } + if ($Rule.Param_ForwardAsAttachmentTo) { + $isSuspicious = $true + $suspiciousReasons += "forwards as attachment to: $($Rule.Param_ForwardAsAttachmentTo)" + } + if ($Rule.Param_RedirectTo) { + $isSuspicious = $true + $suspiciousReasons += "redirects to: $($Rule.Param_RedirectTo)" + } + + # Check deletion/move to deleted items + if ($Rule.Param_DeleteMessage) { + $isSuspicious = $true + $suspiciousReasons += "deletes messages" + } + if ($Rule.Param_MoveToFolder -eq 'Deleted Items') { + $isSuspicious = $true + $suspiciousReasons += "moves to Deleted Items" + } + + # Check for suspicious keywords in subject filters + if ($Rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') { + $isSuspicious = $true + $suspiciousReasons += "suspicious subject filter: $($Rule.Param_SubjectContainsWords)" + } + + # Check for targeting of security-related senders + if ($Rule.Param_From -match 'security|admin|support|microsoft|helpdesk') { + $isSuspicious = $true + $suspiciousReasons += "targets security sender: $($Rule.Param_From)" + } + + # Update the reasons array with our findings + $Reasons.Value = $suspiciousReasons + + return $isSuspicious +} \ No newline at end of file From c3eb7940a9eb9fb9693c659b138a66fc47e3e856 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 16:02:08 -0500 Subject: [PATCH 12/28] Modify Out-LogFile to use the same formatted log tags as other logs, using brackets. Created an internal function to test for suspicious inbox rules, which can be called by all current and future functions that pull inbox rule data (e.g. Get-HawkTenantAdminInboxRuleModification, Get-HawkTenantAdminInboxRuleHistory). Modify Get-AllUnifiedAuditLogEntry to not use invoke-expression as this is a security issue and is flagged by PSSA --- Hawk/Hawk.psd1 | 1 + .../Get-HawkTenantAdminInboxRuleHistory.ps1 | 67 +++------- ...t-HawkTenantAdminInboxRuleModification.ps1 | 68 ++++------ .../Get-HawkTenantAdminInboxRuleRemoval.ps1 | 121 ++++++++++++++++++ .../Tenant/Start-HawkTenantInvestigation.ps1 | 5 + .../functions/Get-AllUnifiedAuditLogEntry.ps1 | 11 +- Hawk/internal/functions/Out-LogFile.ps1 | 81 ++++++------ .../functions/Out-MultipleFileType.ps1 | 8 +- 8 files changed, 219 insertions(+), 143 deletions(-) create mode 100644 Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index 21aeed9..df3989f 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -60,6 +60,7 @@ 'Search-HawkTenantActivityByIP', 'Get-HawkTenantAdminInboxRuleHistory', 'Get-HawkTenantAdminInboxRuleModification', + 'Get-HawkTenantAdminInboxRuleRemoval', 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 index fefb988..d5547fa 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 @@ -33,17 +33,14 @@ Function Get-HawkTenantAdminInboxRuleHistory { File: Investigate_Admin_Inbox_Rules_Creation_History_Raw.json Path: \Tenant Description: Raw audit data for suspicious created rules. - .EXAMPLE Get-HawkTenantAdminInboxRuleHistory - Retrieves events for all created inbox rules from the audit logs within the specified - search window, highlighting any that appear suspicious. - - .NOTES - - Focuses solely on historical rule creation events. - - Does not show if the rules currently exist or are active. - - Does not specify the interface or method used to create the rules. + Retrieves events for all admin inbox rules created and available within the audit logs within the configured search window. + + Remarks: This basic example pulls all inbox rule creations from the audit log and analyzes them for + suspicious patterns. Output files will be created in the configured Hawk output directory under + the Tenant subfolder. #> [CmdletBinding()] param() @@ -61,71 +58,49 @@ Function Get-HawkTenantAdminInboxRuleHistory { try { # Search for new inbox rules - Out-LogFile "Searching audit logs for inbox rule changes" -action + Out-LogFile "Searching audit logs for inbox rule creation events" -Action $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'New-InboxRule'" [array]$NewInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand if ($NewInboxRules.Count -gt 0) { - Out-LogFile ("Found " + $NewInboxRules.Count + " admin inbox rule changes in audit logs") + Out-LogFile ("Found " + $NewInboxRules.Count + " admin inbox rule changes in audit logs") -Action - # Write raw audit data for reference + # Write raw audit data with action flag $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Creation_History_Raw.json" + Out-LogFile "Writing raw audit data to: $RawJsonPath" -Action $NewInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath # Process and output the results $ParsedRules = $NewInboxRules | Get-SimpleUnifiedAuditLog if ($ParsedRules) { - # Output simple format for easy analysis + Out-LogFile "Writing parsed admin inbox rule creation data" -Action $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Creation_History" -csv -json - - # Output full audit logs for complete record $NewInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Creation_History" -csv -json - # Check for suspicious rules + # Check for suspicious rules using the helper function $SuspiciousRules = $ParsedRules | Where-Object { - $rule = $_ - - # Check for forwarding/redirection - ($rule.Param_ForwardTo) -or - ($rule.Param_ForwardAsAttachmentTo) -or - ($rule.Param_RedirectTo) -or - ($rule.Param_DeleteMessage) -or - - # Check for moves to deleted items - ($rule.Param_MoveToFolder -eq 'Deleted Items') -or - - # Check for suspicious keywords in subject filters - ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') -or - - # Check for security-related sender filters - ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') + $reasons = @() + Test-SuspiciousInboxRule -Rule $_ -Reasons ([ref]$reasons) } if ($SuspiciousRules) { Out-LogFile "Found suspicious admin inbox rule creation requiring investigation" -Notice + + Out-LogFile "Writing suspicious rule creation data" -Action $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Creation_History" -csv -json -Notice - # Write raw data for suspicious rules + # Write raw data for suspicious rules with action flag $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Creation_History_Raw.json" + Out-LogFile "Writing raw suspicious rule data to: $RawSuspiciousPath" -Action $SuspiciousRules | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath # Log details about why each rule was flagged foreach ($rule in $SuspiciousRules) { $reasons = @() - if ($rule.Param_ForwardTo) { $reasons += "forwards to: $($rule.Param_ForwardTo)" } - if ($rule.Param_ForwardAsAttachmentTo) { $reasons += "forwards as attachment to: $($rule.Param_ForwardAsAttachmentTo)" } - if ($rule.Param_RedirectTo) { $reasons += "redirects to: $($rule.Param_RedirectTo)" } - if ($rule.Param_DeleteMessage) { $reasons += "deletes messages" } - if ($rule.Param_MoveToFolder -eq 'Deleted Items') { $reasons += "moves to Deleted Items" } - if ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') { - $reasons += "suspicious subject filter: $($rule.Param_SubjectContainsWords)" + if (Test-SuspiciousInboxRule -Rule $rule -Reasons ([ref]$reasons)) { + Out-LogFile "Found suspicious rule creation: '$($rule.Param_Name)' created by $($rule.UserId) at $($rule.CreationTime)" -Notice + Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice } - if ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') { - $reasons += "targets security sender: $($rule.Param_From)" - } - - Out-LogFile "Found suspicious rule creation: '$($rule.Param_Name)' created by $($rule.UserId) at $($rule.CreationTime)" -Notice - Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice } } } @@ -134,7 +109,7 @@ Function Get-HawkTenantAdminInboxRuleHistory { } } else { - Out-LogFile "No inbox rule changes found in audit logs" + Out-LogFile "No admin inbox rule creation events found in audit logs" } } catch { diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 index 7ee089e..aa44d84 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 @@ -35,17 +35,15 @@ Function Get-HawkTenantAdminInboxRuleModification { File: Investigate_Admin_Inbox_Rules_Modification_History_Raw.json Path: \Tenant Description: Raw audit data for suspicious rule modifications. - .EXAMPLE Get-HawkTenantAdminInboxRuleModification - Retrieves events for all modified inbox rules from the audit logs within the specified - search window, highlighting any that appear suspicious. - - .NOTES - - Focuses solely on historical rule modification events. - - Does not show if the rules currently exist or are active. - - Does not specify the interface or method used to modify the rules. + Retrieves events for all admin inbox rules modified and available within the audit logs within the configured search window. + + Remarks: This basic example pulls all inbox rule modification logs from the audit log and analyzes them for + suspicious patterns. Output files will be created in the configured Hawk output directory under + the Tenant subfolder. + #> #> [CmdletBinding()] param() @@ -63,71 +61,49 @@ Function Get-HawkTenantAdminInboxRuleModification { try { # Search for modified inbox rules - Out-LogFile "Searching audit logs for admin inbox rule modifications" -action + Out-LogFile "Searching audit logs for inbox rule modification events" -Action $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'Set-InboxRule'" [array]$ModifiedInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand if ($ModifiedInboxRules.Count -gt 0) { - Out-LogFile ("Found " + $ModifiedInboxRules.Count + " admin inbox rule modifications in audit logs") + Out-LogFile ("Found " + $ModifiedInboxRules.Count + " admin inbox rule modifications in audit logs") -Action - # Write raw audit data for reference + # Write raw audit data with action flag $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Modification_History_Raw.json" + Out-LogFile "Writing raw audit data to: $RawJsonPath" -Action $ModifiedInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath # Process and output the results $ParsedRules = $ModifiedInboxRules | Get-SimpleUnifiedAuditLog if ($ParsedRules) { - # Output simple format for easy analysis + Out-LogFile "Writing parsed admin inbox rule modification data" -Action $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Modification_History" -csv -json - - # Output full audit logs for complete record $ModifiedInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Modification_History" -csv -json - # Check for suspicious modifications + # Check for suspicious modifications using the helper function $SuspiciousModifications = $ParsedRules | Where-Object { - $rule = $_ - - # Check for forwarding/redirection - ($rule.Param_ForwardTo) -or - ($rule.Param_ForwardAsAttachmentTo) -or - ($rule.Param_RedirectTo) -or - ($rule.Param_DeleteMessage) -or - - # Check for moves to deleted items - ($rule.Param_MoveToFolder -eq 'Deleted Items') -or - - # Check for suspicious keywords in subject filters - ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') -or - - # Check for security-related sender filters - ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') + $reasons = @() + Test-SuspiciousInboxRule -Rule $_ -Reasons ([ref]$reasons) } if ($SuspiciousModifications) { Out-LogFile "Found suspicious rule modifications requiring investigation" -Notice + + Out-LogFile "Writing suspicious rule modification data" -Action $SuspiciousModifications | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Modification_History" -csv -json -Notice - # Write raw data for suspicious modifications + # Write raw data for suspicious modifications with action flag $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Modification_History_Raw.json" + Out-LogFile "Writing raw suspicious modification data to: $RawSuspiciousPath" -Action $SuspiciousModifications | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath # Log details about why each modification was flagged foreach ($rule in $SuspiciousModifications) { $reasons = @() - if ($rule.Param_ForwardTo) { $reasons += "modified forwarding to: $($rule.Param_ForwardTo)" } - if ($rule.Param_ForwardAsAttachmentTo) { $reasons += "modified forwarding as attachment to: $($rule.Param_ForwardAsAttachmentTo)" } - if ($rule.Param_RedirectTo) { $reasons += "modified redirection to: $($rule.Param_RedirectTo)" } - if ($rule.Param_DeleteMessage) { $reasons += "enabled message deletion" } - if ($rule.Param_MoveToFolder -eq 'Deleted Items') { $reasons += "modified to move to Deleted Items" } - if ($rule.Param_SubjectContainsWords -match 'password|credentials|login|secure|security') { - $reasons += "modified suspicious subject filter: $($rule.Param_SubjectContainsWords)" - } - if ($rule.Param_From -match 'security|admin|support|microsoft|helpdesk') { - $reasons += "modified to target security sender: $($rule.Param_From)" + if (Test-SuspiciousInboxRule -Rule $rule -Reasons ([ref]$reasons)) { + Out-LogFile "Found suspicious rule modification: '$($rule.Param_Name)' modified by $($rule.UserId) at $($rule.CreationTime)" -Notice + Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice } - - Out-LogFile "Found suspicious rule modification: '$($rule.Param_Name)' modified by $($rule.UserId) at $($rule.CreationTime)" -Notice - Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice } } } @@ -136,7 +112,7 @@ Function Get-HawkTenantAdminInboxRuleModification { } } else { - Out-LogFile "No admin inbox rule modifications found in audit logs" + Out-LogFile "No inbox rule modifications found in audit logs" } } catch { diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 new file mode 100644 index 0000000..5b8c808 --- /dev/null +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 @@ -0,0 +1,121 @@ +Function Get-HawkTenantAdminInboxRuleRemoval { + <# + .SYNOPSIS + Retrieves audit log entries for inbox rules that were removed within the tenant. + + .DESCRIPTION + This function queries the Microsoft 365 Unified Audit Log for events classified as inbox + rule removal (Remove-InboxRule). It focuses on historical record-keeping and identifying + when inbox rules were removed and by whom. The logged events do not indicate the + specific method or interface used to remove the rules. + + Key points: + - Displays removal events for inbox rules, including who removed them and when. + - Flags removals that might be suspicious (e.g., rules that were forwarding externally). + - Provides historical context for rule removals during investigations. + + For current, active rules, use Get-HawkTenantInboxRules. + + .OUTPUTS + File: Simple_Admin_Inbox_Rules_Removal_History.csv/.json + Path: \Tenant + Description: Simplified view of removed inbox rule events. + + File: Admin_Inbox_Rules_Removal_History.csv/.json + Path: \Tenant + Description: Detailed audit log data for removed inbox rules. + + File: _Investigate_Admin_Inbox_Rules_Removal_History.csv/.json + Path: \Tenant + Description: A subset of historically removed rules flagged as suspicious. + + File: Investigate_Admin_Inbox_Rules_Removal_History_Raw.json + Path: \Tenant + Description: Raw audit data for suspicious removed rules. + + .EXAMPLE + Get-HawkTenantAdminInboxRuleRemoval + + Retrieves events for all removed inbox rules from the audit logs within the specified + search window, highlighting any that appear suspicious. + #> + [CmdletBinding()] + param() + + Test-EXOConnection + Send-AIEvent -Event "CmdRun" + + Out-LogFile "Analyzing admin inbox rule removals from audit logs" -Action + + # Create tenant folder if it doesn't exist + $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" + if (-not (Test-Path -Path $TenantPath)) { + New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null + } + + try { + # Search for removed inbox rules + Out-LogFile "Searching audit logs for inbox rule removals" -action + $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'Remove-InboxRule'" + [array]$RemovedInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand + + if ($RemovedInboxRules.Count -gt 0) { + Out-LogFile ("Found " + $RemovedInboxRules.Count + " admin inbox rule removals in audit logs") + + # Write raw audit data for reference + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Removal_History_Raw.json" + $RemovedInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath + + # Process and output the results + $ParsedRules = $RemovedInboxRules | Get-SimpleUnifiedAuditLog + if ($ParsedRules) { + # Output simple format for easy analysis + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Removal_History" -csv -json + + # Output full audit logs for complete record + $RemovedInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Removal_History" -csv -json + + # Check for suspicious removals + $SuspiciousRemovals = $ParsedRules | Where-Object { + $reasons = @() + Test-SuspiciousInboxRule -Rule $_ -Reasons ([ref]$reasons) + } + + if ($SuspiciousRemovals) { + Out-LogFile "Found suspicious admin inbox rule removals requiring investigation" -Notice + + # Output files with timestamps + $csvPath = Join-Path -Path $TenantPath -ChildPath "_Investigate_Admin_Inbox_Rules_Removal_History.csv" + $jsonPath = Join-Path -Path $TenantPath -ChildPath "_Investigate_Admin_Inbox_Rules_Removal_History.json" + Out-LogFile "Additional Information: $csvPath" -Notice + Out-LogFile "Additional Information: $jsonPath" -Notice + + $SuspiciousRemovals | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Removal_History" -csv -json -Notice + + # Write raw data for suspicious rules + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Removal_History_Raw.json" + $SuspiciousRemovals | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath + + # Log details about why each removal was flagged + foreach ($rule in $SuspiciousRemovals) { + $reasons = @() + if (Test-SuspiciousInboxRule -Rule $rule -Reasons ([ref]$reasons)) { + Out-LogFile "Found suspicious rule removal: '$($rule.Param_Name)' removed by $($rule.UserId) at $($rule.CreationTime)" -Notice + Out-LogFile "Reasons for investigation: $($reasons -join '; ')" -Notice + } + } + } + } + else { + Out-LogFile "Error: Failed to parse inbox rule removal audit data" -Notice + } + } + else { + Out-LogFile "No inbox rule removals found in audit logs" + } + } + catch { + Out-LogFile "Error analyzing admin inbox rule removals: $($_.Exception.Message)" -Notice + Write-Error -ErrorRecord $_ -ErrorAction Continue + } +} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index c40b145..dc1913f 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -66,6 +66,11 @@ Get-HawkTenantAdminInboxRuleModification } + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Removal Audit Log", "Search Admin Inbox Rule Removal History")) { + Out-LogFile "Running Get-HawkTenantAdminInboxRuleRemoval" -action + Get-HawkTenantAdminInboxRuleRemoval + } + # if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { # Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action # Get-HawkTenantEDiscoveryLogs diff --git a/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 b/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 index 10d5e03..ec7870f 100644 --- a/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 +++ b/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 @@ -36,8 +36,8 @@ # build our search command to execute $cmd = $UnifiedSearch + " -StartDate `'" + (get-date ($StartDate) -UFormat %m/%d/%Y) + "`' -EndDate `'" + (get-date ($endDate) -UFormat %m/%d/%Y) + "`' -SessionCommand ReturnLargeSet -resultsize 5000 -sessionid " + (Get-Date -UFormat %H%M%S) - Out-LogFile ("Running Unified Audit Log Search") - Out-Logfile $cmd + Out-LogFile ("Running Unified Audit Log Search") -Action + Out-Logfile $cmd -NoDisplay # Run the initial command $Output = $null @@ -46,10 +46,13 @@ # Setup our run variable $Run = $true + # Convert the command string into a scriptblock to avoid Invoke-Expression + $searchScript = [ScriptBlock]::Create($cmd) + # Since we have more than 1k results we need to keep returning results until we have them all while ($Run) { - $Output += (Invoke-Expression $cmd) - + $Output += & $searchScript + # Check for null results if so warn and stop if ($null -eq $Output) { Out-LogFile ("[WARNING] - Unified Audit log returned no results.") diff --git a/Hawk/internal/functions/Out-LogFile.ps1 b/Hawk/internal/functions/Out-LogFile.ps1 index 11fc834..b769cd0 100644 --- a/Hawk/internal/functions/Out-LogFile.ps1 +++ b/Hawk/internal/functions/Out-LogFile.ps1 @@ -1,32 +1,33 @@ -<# -.SYNOPSIS - Writes output to a log file with a time date stamp -.DESCRIPTION - Writes output to a log file with a time date stamp -.PARAMETER string - Log Message -.PARAMETER action - What is happening -.PARAMETER notice - Verbose notification -.PARAMETER silentnotice - Silent notification -.EXAMPLE - Out-LogFile - Sends messages to the log file -.NOTES - This is will depracted soon. -#> -Function Out-LogFile { +Function Out-LogFile { + <# + .SYNOPSIS + Writes output to a log file with a time date stamp + .DESCRIPTION + Writes output to a log file with a time date stamp and appropriate prefixes + based on the type of message (action, notice, etc.) + .PARAMETER string + Log Message + .PARAMETER action + Switch indicating an action is being performed + .PARAMETER notice + Switch indicating this is a notice that requires investigation + .PARAMETER silentnotice + Switch indicating this is additional information for an investigation notice + .PARAMETER NoDisplay + Switch indicating the message should only be written to the log file, not displayed + #> + [CmdletBinding()] Param ( + [Parameter(Mandatory = $true)] [string]$string, [switch]$action, [switch]$notice, - [switch]$silentnotice - ) + [switch]$silentnotice, + [switch]$NoDisplay + ) - Write-PSFMessage -Message $string -ModuleName Hawk -FunctionName (Get-PSCallstack)[1].FunctionName + Write-PSFMessage -Message $string -ModuleName Hawk -FunctionName (Get-PSCallstack)[1].FunctionName # Make sure we have the Hawk Global Object if ([string]::IsNullOrEmpty($Hawk.FilePath)) { @@ -35,52 +36,46 @@ Function Out-LogFile { # Get our log file path $LogFile = Join-path $Hawk.FilePath "Hawk.log" - $ScreenOutput = $true + $ScreenOutput = -not $NoDisplay $LogOutput = $true # Get the current date - [string]$date = Get-Date -Format G + [string]$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + [string]$logstring = "" - # Deal with each switch and what log string it should put out and if any special output - - # Action indicates that we are starting to do something + # Build the log string based on the type of message if ($action) { - [string]$logstring = ( "[" + $date + "] - [ACTION] - " + $string) - + $logstring = "[$timestamp] - [ACTION] - $string" } - # If notice is true the we should write this to interesting.txt as well elseif ($notice) { - [string]$logstring = ( "[" + $date + "] - ## INVESTIGATE ## - " + $string) + $logstring = "[$timestamp] - [INVESTIGATE] - $string" - # Build the file name for Investigate stuff log + # Write to the investigation file [string]$InvestigateFile = Join-Path (Split-Path $LogFile -Parent) "_Investigate.txt" $logstring | Out-File -FilePath $InvestigateFile -Append } - # For silent we need to supress the screen output elseif ($silentnotice) { - [string]$logstring = ( "Addtional Information: " + $string) - # Build the file name for Investigate stuff log + $logstring = "[$timestamp] - [INVESTIGATE] - Additional Information: $string" + + # Write to the investigation file [string]$InvestigateFile = Join-Path (Split-Path $LogFile -Parent) "_Investigate.txt" $logstring | Out-File -FilePath $InvestigateFile -Append - # Supress screen and normal log output + # Suppress regular output for silentnotice $ScreenOutput = $false $LogOutput = $false - } - # Normal output else { - [string]$logstring = ( "[" + $date + "] - " + $string) + $logstring = "[$timestamp] - $string" } - # Write everything to our log file + # Write to log file if enabled if ($LogOutput) { $logstring | Out-File -FilePath $LogFile -Append } - # Output to the screen + # Write to screen if enabled if ($ScreenOutput) { Write-Information -MessageData $logstring -InformationAction Continue } - } \ No newline at end of file diff --git a/Hawk/internal/functions/Out-MultipleFileType.ps1 b/Hawk/internal/functions/Out-MultipleFileType.ps1 index b471a39..b028d08 100644 --- a/Hawk/internal/functions/Out-MultipleFileType.ps1 +++ b/Hawk/internal/functions/Out-MultipleFileType.ps1 @@ -113,7 +113,7 @@ Function Out-MultipleFileType { else { $filename = Join-Path $xmlPath ($FilePrefix + ".xml") } - Out-LogFile ("Writing Data to " + $filename) + Out-LogFile ("Writing Data to " + $filename) -Action # Output our objects to clixml $AllObject | Export-Clixml $filename @@ -143,7 +143,7 @@ Function Out-MultipleFileType { # Otherwise overwrite else { - Out-LogFile ("Writing Data to " + $filename) + Out-LogFile ("Writing Data to " + $filename) -Action $AllObject | Export-Csv $filename -NoTypeInformation -Encoding UTF8 } @@ -169,7 +169,7 @@ Function Out-MultipleFileType { # Otherwise overwrite else { - Out-LogFile ("Writing Data to " + $filename) + Out-LogFile ("Writing Data to " + $filename) -Action $AllObject | Format-List * | Out-File $filename } @@ -198,7 +198,7 @@ Function Out-MultipleFileType { # Otherwise overwrite else { - Out-LogFile ("Writing Data to " + $filename) + Out-LogFile ("Writing Data to " + $filename) -Action $AllObject | ConvertTo-Json -Depth 100 | Out-File -FilePath $filename } From 35a767c2bb65c7a5e336a8ae9b679fe050befdcd Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 16:04:15 -0500 Subject: [PATCH 13/28] Modify Out-LogFile to use the same formatted log tags as other logs, using brackets. Created an internal function to test for suspicious inbox rules, which can be called by all current and future functions that pull inbox rule data (e.g. Get-HawkTenantAdminInboxRuleModification, Get-HawkTenantAdminInboxRuleHistory). Modify Get-AllUnifiedAuditLogEntry to not use invoke-expression as this is a security issue and is flagged by PSSA --- Hawk/internal/functions/Out-LogFile.ps1 | 51 +++++++++++++++++++++---- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/Hawk/internal/functions/Out-LogFile.ps1 b/Hawk/internal/functions/Out-LogFile.ps1 index b769cd0..9fae30f 100644 --- a/Hawk/internal/functions/Out-LogFile.ps1 +++ b/Hawk/internal/functions/Out-LogFile.ps1 @@ -1,20 +1,57 @@ Function Out-LogFile { <# .SYNOPSIS - Writes output to a log file with a time date stamp + Writes output to a log file with a time date stamp. .DESCRIPTION Writes output to a log file with a time date stamp and appropriate prefixes - based on the type of message (action, notice, etc.) + based on the type of message (action, notice, etc.). By default, messages are + also displayed on the screen unless the -NoDisplay switch is used. + .PARAMETER string - Log Message + The log message to be written. + .PARAMETER action - Switch indicating an action is being performed + Switch indicating the log entry is describing an action being performed. + .PARAMETER notice - Switch indicating this is a notice that requires investigation + Switch indicating the log entry requires investigation or special attention. + .PARAMETER silentnotice - Switch indicating this is additional information for an investigation notice + Switch indicating additional investigative information that should not be + displayed on the screen. This is logged to the file but suppressed in console output. + .PARAMETER NoDisplay - Switch indicating the message should only be written to the log file, not displayed + Switch indicating the message should only be written to the log file, + not displayed in the console. + + .EXAMPLE + Out-LogFile "Routine scan completed." + + Writes a simple log message with a timestamp to the log file and displays it on the screen. + + .EXAMPLE + Out-LogFile "Starting mailbox export operation" -action + + Writes a log message indicating an action is being performed. + The output is prefixed with [ACTION] in the log file. + + .EXAMPLE + Out-LogFile "Detected suspicious login attempt from external IP" -notice + + Writes a log message indicating a situation requiring investigation. + The output is prefixed with [INVESTIGATE] and also recorded in a separate _Investigate.txt file. + + .EXAMPLE + Out-LogFile "User mailbox configuration details" -silentnotice + + Writes investigative detail to the log and _Investigate.txt file without printing to the console. + This is useful for adding detail to a previously logged [INVESTIGATE] event without cluttering the console. + + .EXAMPLE + Out-LogFile "Executing periodic health check" -NoDisplay + + Writes a log message to the file without displaying it on the console, + useful for routine logging that doesn't need immediate user visibility. #> [CmdletBinding()] Param From e603dbbd2faf79ce4dd406b15678653bcc3e704e Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 16:53:11 -0500 Subject: [PATCH 14/28] Modify Out-Logfile to implment a -Information switch, which is used to create a [INFO] tag on any status updates from the program. Modified Get-HawkTenatnEntraIDAdmin and Get-AllUnifiedAuditLogEntry to pass the -Informational parameter to Out-LogFile for information updates provided by those functions. --- .../Get-HawkTenantAdminInboxRuleRemoval.ps1 | 2 +- .../Tenant/Get-HawkTenantEntraIDAdmin.ps1 | 2 +- .../functions/Get-AllUnifiedAuditLogEntry.ps1 | 6 ++-- Hawk/internal/functions/Out-LogFile.ps1 | 29 ++++++++++++++++--- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 index 5b8c808..64c0aaa 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 @@ -60,7 +60,7 @@ Function Get-HawkTenantAdminInboxRuleRemoval { [array]$RemovedInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand if ($RemovedInboxRules.Count -gt 0) { - Out-LogFile ("Found " + $RemovedInboxRules.Count + " admin inbox rule removals in audit logs") + Out-LogFile ("Found " + $RemovedInboxRules.Count + " admin inbox rule removals in audit logs") -Information # Write raw audit data for reference $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Removal_History_Raw.json" diff --git a/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 b/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 index 1c7a20c..8cb7735 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantEntraIDAdmin.ps1 @@ -35,7 +35,7 @@ try { # Retrieve all directory roles from Microsoft Graph $directoryRoles = Get-MgDirectoryRole -ErrorAction Stop - Out-LogFile "Retrieved $(($directoryRoles | Measure-Object).Count) directory roles" + Out-LogFile "Retrieved $(($directoryRoles | Measure-Object).Count) directory roles" -Information # Process each role and its members $roles = foreach ($role in $directoryRoles) { diff --git a/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 b/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 index ec7870f..cf466ff 100644 --- a/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 +++ b/Hawk/internal/functions/Get-AllUnifiedAuditLogEntry.ps1 @@ -52,7 +52,7 @@ # Since we have more than 1k results we need to keep returning results until we have them all while ($Run) { $Output += & $searchScript - + # Check for null results if so warn and stop if ($null -eq $Output) { Out-LogFile ("[WARNING] - Unified Audit log returned no results.") @@ -70,12 +70,12 @@ } # if our resultindex = our resultcount then we have everything and should stop elseif ($Output[-1].Resultindex -ge $Output[-1].ResultCount) { - Out-LogFile ("Retrieved all results.") + Out-LogFile ("Retrieved all results.") -Information $Run = $false } # Output the current progress - Out-LogFile ("Retrieved:" + $Output[-1].ResultIndex.tostring().PadRight(5, " ") + " Total: " + $Output[-1].ResultCount) + Out-LogFile ("Retrieved:" + $Output[-1].ResultIndex.tostring().PadRight(5, " ") + " Total: " + $Output[-1].ResultCount) -Information } } diff --git a/Hawk/internal/functions/Out-LogFile.ps1 b/Hawk/internal/functions/Out-LogFile.ps1 index 9fae30f..1ee85bf 100644 --- a/Hawk/internal/functions/Out-LogFile.ps1 +++ b/Hawk/internal/functions/Out-LogFile.ps1 @@ -4,8 +4,15 @@ Writes output to a log file with a time date stamp. .DESCRIPTION Writes output to a log file with a time date stamp and appropriate prefixes - based on the type of message (action, notice, etc.). By default, messages are - also displayed on the screen unless the -NoDisplay switch is used. + based on the type of message. By default, messages are also displayed on the screen + unless the -NoDisplay switch is used. + + Message types: + - Action: Represent ongoing operations or procedures. + - Investigate (notice, silentnotice): Represent events that require attention or hold + investigative value. + - Information: Represent successful completion or informational status updates + that do not require action or investigation. .PARAMETER string The log message to be written. @@ -24,6 +31,10 @@ Switch indicating the message should only be written to the log file, not displayed in the console. + .PARAMETER Information + Switch indicating the log entry provides informational status or completion messages, + for example: "Retrieved all results" or "Completed data export successfully." + .EXAMPLE Out-LogFile "Routine scan completed." @@ -47,6 +58,12 @@ Writes investigative detail to the log and _Investigate.txt file without printing to the console. This is useful for adding detail to a previously logged [INVESTIGATE] event without cluttering the console. + .EXAMPLE + Out-LogFile "Retrieved all results successfully" -Information + + Writes a log message indicating a successful or informational event. + The output is prefixed with [INFO], suitable for status updates or completion notices. + .EXAMPLE Out-LogFile "Executing periodic health check" -NoDisplay @@ -61,7 +78,8 @@ [switch]$action, [switch]$notice, [switch]$silentnotice, - [switch]$NoDisplay + [switch]$NoDisplay, + [switch]$Information ) Write-PSFMessage -Message $string -ModuleName Hawk -FunctionName (Get-PSCallstack)[1].FunctionName @@ -102,6 +120,9 @@ $ScreenOutput = $false $LogOutput = $false } + elseif ($Information) { + $logstring = "[$timestamp] - [INFO] - $string" + } else { $logstring = "[$timestamp] - $string" } @@ -115,4 +136,4 @@ if ($ScreenOutput) { Write-Information -MessageData $logstring -InformationAction Continue } -} \ No newline at end of file +} From 63e051fa690f21a5db73d035107a19ab7a6c12f8 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 16:59:07 -0500 Subject: [PATCH 15/28] Get-HawkTenantAdminInboxRuleHistory updated to use -Information tagging when providing status updates. --- Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 index d5547fa..637d901 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 @@ -63,7 +63,7 @@ Function Get-HawkTenantAdminInboxRuleHistory { [array]$NewInboxRules = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand if ($NewInboxRules.Count -gt 0) { - Out-LogFile ("Found " + $NewInboxRules.Count + " admin inbox rule changes in audit logs") -Action + Out-LogFile ("Found " + $NewInboxRules.Count + " admin inbox rule changes in audit logs") -Information # Write raw audit data with action flag $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Creation_History_Raw.json" From 4b04292fec55a96451ab70963a831c8ebe6c76aa Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 17:06:35 -0500 Subject: [PATCH 16/28] Re-name Get-HawkAdminInboxRuleHistory to Get-HawkAdminInboxRuleCreation for more clarity. --- Hawk/Hawk.psd1 | 2 +- ... Get-HawkTenantAdminInboxRuleCreation.ps1} | 22 +++++++++---------- .../Get-HawkTenantAdminInboxRuleRemoval.ps1 | 22 +++++++++---------- .../Tenant/Start-HawkTenantInvestigation.ps1 | 8 +++---- 4 files changed, 27 insertions(+), 27 deletions(-) rename Hawk/functions/Tenant/{Get-HawkTenantAdminInboxRuleHistory.ps1 => Get-HawkTenantAdminInboxRuleCreation.ps1} (88%) diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index df3989f..f19b7b0 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -58,7 +58,7 @@ 'Get-HawkUserInboxRule', 'Get-HawkUserMailboxAuditing', 'Search-HawkTenantActivityByIP', - 'Get-HawkTenantAdminInboxRuleHistory', + 'Get-HawkTenantAdminInboxRuleCreation', 'Get-HawkTenantAdminInboxRuleModification', 'Get-HawkTenantAdminInboxRuleRemoval', 'Search-HawkTenantEXOAuditLog', diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleCreation.ps1 similarity index 88% rename from Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 rename to Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleCreation.ps1 index 637d901..5d3b417 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleHistory.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleCreation.ps1 @@ -1,4 +1,4 @@ -Function Get-HawkTenantAdminInboxRuleHistory { +Function Get-HawkTenantAdminInboxRuleCreation { <# .SYNOPSIS Retrieves audit log entries for inbox rules that were historically created within the tenant. @@ -18,23 +18,23 @@ Function Get-HawkTenantAdminInboxRuleHistory { For current, active rules, use Get-HawkTenantInboxRules. .OUTPUTS - File: Simple_Admin_Inbox_Rules_Creation_History.csv/.json + File: Simple_Admin_Inbox_Rules_Creation.csv/.json Path: \Tenant Description: Simplified view of created inbox rule events. - File: Admin_Inbox_Rules_Creation_History.csv/.json + File: Admin_Inbox_Rules_Creation.csv/.json Path: \Tenant Description: Detailed audit log data for created inbox rules. - File: _Investigate_Admin_Inbox_Rules_Creation_History.csv/.json + File: _Investigate_Admin_Inbox_Rules_Creation.csv/.json Path: \Tenant Description: A subset of historically created rules flagged as suspicious. - File: Investigate_Admin_Inbox_Rules_Creation_History_Raw.json + File: Investigate_Admin_Inbox_Rules_Creation_Raw.json Path: \Tenant Description: Raw audit data for suspicious created rules. .EXAMPLE - Get-HawkTenantAdminInboxRuleHistory + Get-HawkTenantAdminInboxRuleCreation Retrieves events for all admin inbox rules created and available within the audit logs within the configured search window. @@ -66,7 +66,7 @@ Function Get-HawkTenantAdminInboxRuleHistory { Out-LogFile ("Found " + $NewInboxRules.Count + " admin inbox rule changes in audit logs") -Information # Write raw audit data with action flag - $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Creation_History_Raw.json" + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Creation_Raw.json" Out-LogFile "Writing raw audit data to: $RawJsonPath" -Action $NewInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath @@ -74,8 +74,8 @@ Function Get-HawkTenantAdminInboxRuleHistory { $ParsedRules = $NewInboxRules | Get-SimpleUnifiedAuditLog if ($ParsedRules) { Out-LogFile "Writing parsed admin inbox rule creation data" -Action - $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Creation_History" -csv -json - $NewInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Creation_History" -csv -json + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Creation" -csv -json + $NewInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Creation" -csv -json # Check for suspicious rules using the helper function $SuspiciousRules = $ParsedRules | Where-Object { @@ -87,10 +87,10 @@ Function Get-HawkTenantAdminInboxRuleHistory { Out-LogFile "Found suspicious admin inbox rule creation requiring investigation" -Notice Out-LogFile "Writing suspicious rule creation data" -Action - $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Creation_History" -csv -json -Notice + $SuspiciousRules | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Creation" -csv -json -Notice # Write raw data for suspicious rules with action flag - $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Creation_History_Raw.json" + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Creation_Raw.json" Out-LogFile "Writing raw suspicious rule data to: $RawSuspiciousPath" -Action $SuspiciousRules | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 index 64c0aaa..4b54332 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleRemoval.ps1 @@ -17,19 +17,19 @@ Function Get-HawkTenantAdminInboxRuleRemoval { For current, active rules, use Get-HawkTenantInboxRules. .OUTPUTS - File: Simple_Admin_Inbox_Rules_Removal_History.csv/.json + File: Simple_Admin_Inbox_Rules_Removal.csv/.json Path: \Tenant Description: Simplified view of removed inbox rule events. - File: Admin_Inbox_Rules_Removal_History.csv/.json + File: Admin_Inbox_Rules_Removal.csv/.json Path: \Tenant Description: Detailed audit log data for removed inbox rules. - File: _Investigate_Admin_Inbox_Rules_Removal_History.csv/.json + File: _Investigate_Admin_Inbox_Rules_Removal.csv/.json Path: \Tenant Description: A subset of historically removed rules flagged as suspicious. - File: Investigate_Admin_Inbox_Rules_Removal_History_Raw.json + File: Investigate_Admin_Inbox_Rules_Removal_Raw.json Path: \Tenant Description: Raw audit data for suspicious removed rules. @@ -63,17 +63,17 @@ Function Get-HawkTenantAdminInboxRuleRemoval { Out-LogFile ("Found " + $RemovedInboxRules.Count + " admin inbox rule removals in audit logs") -Information # Write raw audit data for reference - $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Removal_History_Raw.json" + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Removal_Raw.json" $RemovedInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath # Process and output the results $ParsedRules = $RemovedInboxRules | Get-SimpleUnifiedAuditLog if ($ParsedRules) { # Output simple format for easy analysis - $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Removal_History" -csv -json + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Removal" -csv -json # Output full audit logs for complete record - $RemovedInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Removal_History" -csv -json + $RemovedInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Removal" -csv -json # Check for suspicious removals $SuspiciousRemovals = $ParsedRules | Where-Object { @@ -85,15 +85,15 @@ Function Get-HawkTenantAdminInboxRuleRemoval { Out-LogFile "Found suspicious admin inbox rule removals requiring investigation" -Notice # Output files with timestamps - $csvPath = Join-Path -Path $TenantPath -ChildPath "_Investigate_Admin_Inbox_Rules_Removal_History.csv" - $jsonPath = Join-Path -Path $TenantPath -ChildPath "_Investigate_Admin_Inbox_Rules_Removal_History.json" + $csvPath = Join-Path -Path $TenantPath -ChildPath "_Investigate_Admin_Inbox_Rules_Removal.csv" + $jsonPath = Join-Path -Path $TenantPath -ChildPath "_Investigate_Admin_Inbox_Rules_Removal.json" Out-LogFile "Additional Information: $csvPath" -Notice Out-LogFile "Additional Information: $jsonPath" -Notice - $SuspiciousRemovals | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Removal_History" -csv -json -Notice + $SuspiciousRemovals | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Removal" -csv -json -Notice # Write raw data for suspicious rules - $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Removal_History_Raw.json" + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Removal_Raw.json" $SuspiciousRemovals | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath # Log details about why each removal was flagged diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index dc1913f..4c5d60d 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -56,17 +56,17 @@ # Search-HawkTenantEXOAuditLog # } - if ($PSCmdlet.ShouldProcess("Admin Inbox Rule History Audit Log", "Search Admin Inbox Rule History")) { - Out-LogFile "Running Get-HawkTenantAdminInboxRuleHistory" -action + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Creation Audit Log", "Search Admin Inbox Rule Creation")) { + Out-LogFile "Running Get-HawkTenantAdminInboxRuleCreation" -action Get-HawkTenantAdminInboxRuleHistory } - if ($PSCmdlet.ShouldProcess("Admin Inbox Rule History Modification Audit Log", "Search Admin Inbox Rule Modification History")) { + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Modification Audit Log", "Search Admin Inbox Rule Modification")) { Out-LogFile "Running Get-HawkTenantInboxRuleModification" -action Get-HawkTenantAdminInboxRuleModification } - if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Removal Audit Log", "Search Admin Inbox Rule Removal History")) { + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Removal Audit Log", "Search Admin Inbox Rule Removal")) { Out-LogFile "Running Get-HawkTenantAdminInboxRuleRemoval" -action Get-HawkTenantAdminInboxRuleRemoval } From 40e1070a84648e13dce92e34dbb801b0f85358a8 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 17:07:40 -0500 Subject: [PATCH 17/28] Re-name Get-HawkAdminInboxRuleHistory to Get-HawkAdminInboxRuleCreation for more clarity. --- ...et-HawkTenantAdminInboxRuleModification.ps1 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 index aa44d84..74257e8 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminInboxRuleModification.ps1 @@ -20,19 +20,19 @@ Function Get-HawkTenantAdminInboxRuleModification { For current, active rules, use Get-HawkTenantInboxRules. .OUTPUTS - File: Simple_Admin_Inbox_Rules_Modification_History.csv/.json + File: Simple_Admin_Inbox_Rules_Modification.csv/.json Path: \Tenant Description: Simplified view of inbox rule modification events. - File: Admin_Inbox_Rules_Modification_History.csv/.json + File: Admin_Inbox_Rules_Modification.csv/.json Path: \Tenant Description: Detailed audit log data for modified inbox rules. - File: _Investigate_Admin_Inbox_Rules_Modification_History.csv/.json + File: _Investigate_Admin_Inbox_Rules_Modification.csv/.json Path: \Tenant Description: A subset of historically modified rules flagged as suspicious. - File: Investigate_Admin_Inbox_Rules_Modification_History_Raw.json + File: Investigate_Admin_Inbox_Rules_Modification_Raw.json Path: \Tenant Description: Raw audit data for suspicious rule modifications. .EXAMPLE @@ -69,7 +69,7 @@ Function Get-HawkTenantAdminInboxRuleModification { Out-LogFile ("Found " + $ModifiedInboxRules.Count + " admin inbox rule modifications in audit logs") -Action # Write raw audit data with action flag - $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Modification_History_Raw.json" + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Admin_Inbox_Rules_Modification_Raw.json" Out-LogFile "Writing raw audit data to: $RawJsonPath" -Action $ModifiedInboxRules | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath @@ -77,8 +77,8 @@ Function Get-HawkTenantAdminInboxRuleModification { $ParsedRules = $ModifiedInboxRules | Get-SimpleUnifiedAuditLog if ($ParsedRules) { Out-LogFile "Writing parsed admin inbox rule modification data" -Action - $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Modification_History" -csv -json - $ModifiedInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Modification_History" -csv -json + $ParsedRules | Out-MultipleFileType -FilePrefix "Simple_Admin_Inbox_Rules_Modification" -csv -json + $ModifiedInboxRules | Out-MultipleFileType -FilePrefix "Admin_Inbox_Rules_Modification" -csv -json # Check for suspicious modifications using the helper function $SuspiciousModifications = $ParsedRules | Where-Object { @@ -90,10 +90,10 @@ Function Get-HawkTenantAdminInboxRuleModification { Out-LogFile "Found suspicious rule modifications requiring investigation" -Notice Out-LogFile "Writing suspicious rule modification data" -Action - $SuspiciousModifications | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Modification_History" -csv -json -Notice + $SuspiciousModifications | Out-MultipleFileType -FilePrefix "_Investigate_Admin_Inbox_Rules_Modification" -csv -json -Notice # Write raw data for suspicious modifications with action flag - $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Modification_History_Raw.json" + $RawSuspiciousPath = Join-Path -Path $TenantPath -ChildPath "Investigate_Admin_Inbox_Rules_Modification_Raw.json" Out-LogFile "Writing raw suspicious modification data to: $RawSuspiciousPath" -Action $SuspiciousModifications | ConvertTo-Json -Depth 10 | Out-File -FilePath $RawSuspiciousPath From 787295f8ea2ff477d71083dcd509f83b5ff92e66 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 17:09:21 -0500 Subject: [PATCH 18/28] Make appropraite call to Get-HawkTenantAdminInbixRuleCreation --- Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 4c5d60d..8d16d26 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -58,7 +58,7 @@ if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Creation Audit Log", "Search Admin Inbox Rule Creation")) { Out-LogFile "Running Get-HawkTenantAdminInboxRuleCreation" -action - Get-HawkTenantAdminInboxRuleHistory + Get-HawkTenantAdminInboxRuleCreation } if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Modification Audit Log", "Search Admin Inbox Rule Modification")) { From f009d4b535922762e203ed843a9da540d2d8ec6b Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 18:53:51 -0500 Subject: [PATCH 19/28] Add Get-HawkTenantAdminMailBoxPermissionChange function. --- Hawk/Hawk.psd1 | 1 + ...HawkTenantAdminMailboxPermissionChange.ps1 | 108 ++++++++++++++++++ .../Tenant/Start-HawkTenantInvestigation.ps1 | 31 +++-- 3 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index f19b7b0..22e2255 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -61,6 +61,7 @@ 'Get-HawkTenantAdminInboxRuleCreation', 'Get-HawkTenantAdminInboxRuleModification', 'Get-HawkTenantAdminInboxRuleRemoval', + 'Get-HawkTenantAdminMailboxPermissionChange', 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 new file mode 100644 index 0000000..0c257b2 --- /dev/null +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 @@ -0,0 +1,108 @@ +Function Get-HawkTenantAdminMailboxPermissionChange { + <# + .SYNOPSIS + Retrieves audit log entries for mailbox permission changes within the tenant. + + .DESCRIPTION + Searches the Unified Audit Log for mailbox permission changes and flags any grants + of FullAccess, SendAs, or Send on Behalf permissions for investigation. + Excludes normal system operations on Discovery Search Mailboxes. + + .OUTPUTS + File: Simple_Mailbox_Permission_Change.csv/.json + Path: \Tenant + Description: Simplified view of mailbox permission changes. + + File: Mailbox_Permission_Change.csv/.json + Path: \Tenant + Description: Detailed audit log data for permission changes. + + File: _Investigate_Mailbox_Permission_Change.csv/.json + Path: \Tenant + Description: Permission changes that granted sensitive rights. + + .EXAMPLE + Get-HawkTenantAdminMailboxPermissionChange + + Retrieves mailbox permission change events from the audit logs. + #> + [CmdletBinding()] + param() + + Test-EXOConnection + Send-AIEvent -Event "CmdRun" + + Out-LogFile "Analyzing mailbox permission changes from audit logs" -Action + + # Create tenant folder if it doesn't exist + $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" + if (-not (Test-Path -Path $TenantPath)) { + New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null + } + + try { + # Search for mailbox permission changes + Out-LogFile "Searching audit logs for mailbox permission changes" -action + $searchCommand = "Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations 'Add-MailboxPermission','Add-RecipientPermission','Add-ADPermission'" + [array]$PermissionChanges = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand + + if ($PermissionChanges.Count -gt 0) { + Out-LogFile ("Found " + $PermissionChanges.Count + " mailbox permission changes in audit logs") + + # Process and output the results + $ParsedChanges = $PermissionChanges | Get-SimpleUnifiedAuditLog + if ($ParsedChanges) { + # Output simple format for easy analysis + $ParsedChanges | Out-MultipleFileType -FilePrefix "Simple_Mailbox_Permission_Change" -csv -json + + # Output full audit logs for complete record + $PermissionChanges | Out-MultipleFileType -FilePrefix "Mailbox_Permission_Change" -csv -json + + # Check for sensitive permissions, excluding Discovery Search Mailbox system operations + $SensitiveGrants = $ParsedChanges | Where-Object { + # First check if this is potentially sensitive permission + ($_.Param_AccessRights -match 'FullAccess|SendAs' -or + $_.Operation -eq 'Add-ADPermission' -or + $_.Operation -match 'Add-RecipientPermission') -and + # Then exclude DiscoverySearchMailbox system operations + -not ( + $_.UserId -eq "NT AUTHORITY\SYSTEM (Microsoft.Exchange.ServiceHost)" -and + $_.ObjectId -like "*DiscoverySearchMailbox*" -and + $_.Param_User -like "*Discovery Management*" + ) + } + + if ($SensitiveGrants) { + Out-LogFile "Found sensitive permission grants requiring investigation" -Notice + $SensitiveGrants | Out-MultipleFileType -FilePrefix "_Investigate_Mailbox_Permission_Change" -csv -json -Notice + + # Log details about sensitive permission grants + foreach ($change in $SensitiveGrants) { + $permType = if ($change.Param_AccessRights -match 'FullAccess') { + "FullAccess" + } elseif ($change.Param_AccessRights -match 'SendAs' -or + $change.Operation -eq 'Add-ADPermission' -or + $change.Operation -match 'Add-RecipientPermission') { + "SendAs/Send on Behalf" + } else { + "Other sensitive permission" + } + + Out-LogFile "Permission change by $($change.UserId) at $($change.CreationTime)" -Notice + Out-LogFile "Details: Granted $permType to $($change.Param_User) on mailbox $($change.Param_Identity)" -Notice + } + } + } + else { + Out-LogFile "Error: Failed to parse mailbox permission audit data" -Notice + } + } + else { + Out-LogFile "No mailbox permission changes found in audit logs" + } + } + catch { + Out-LogFile "Error analyzing mailbox permission changes: $($_.Exception.Message)" -Notice + Write-Error -ErrorRecord $_ -ErrorAction Continue + } +} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 8d16d26..4d08699 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -56,21 +56,30 @@ # Search-HawkTenantEXOAuditLog # } - if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Creation Audit Log", "Search Admin Inbox Rule Creation")) { - Out-LogFile "Running Get-HawkTenantAdminInboxRuleCreation" -action - Get-HawkTenantAdminInboxRuleCreation - } + # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Creation Audit Log", "Search Admin Inbox Rule Creation")) { + # Out-LogFile "Running Get-HawkTenantAdminInboxRuleCreation" -action + # Get-HawkTenantAdminInboxRuleCreation + # } - if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Modification Audit Log", "Search Admin Inbox Rule Modification")) { - Out-LogFile "Running Get-HawkTenantInboxRuleModification" -action - Get-HawkTenantAdminInboxRuleModification - } + # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Modification Audit Log", "Search Admin Inbox Rule Modification")) { + # Out-LogFile "Running Get-HawkTenantInboxRuleModification" -action + # Get-HawkTenantAdminInboxRuleModification + # } - if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Removal Audit Log", "Search Admin Inbox Rule Removal")) { - Out-LogFile "Running Get-HawkTenantAdminInboxRuleRemoval" -action - Get-HawkTenantAdminInboxRuleRemoval + # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Removal Audit Log", "Search Admin Inbox Rule Removal")) { + # Out-LogFile "Running Get-HawkTenantAdminInboxRuleRemoval" -action + # Get-HawkTenantAdminInboxRuleRemoval + # } + + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Permission Change Audit Log", "Search Admin Inbox Permission Changes")) { + Out-LogFile "Running Get-HawkTenantAdminMailboxPermissionChange" -action + Get-HawkTenantAdminMailboxPermissionChange } + + + + # if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { # Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action # Get-HawkTenantEDiscoveryLogs From e2cd6e6a338e5c6a1af76e8c96136b445d31f70c Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 18:56:41 -0500 Subject: [PATCH 20/28] Add Get-HawkTenantAdminMailBoxPermissionChange function to include rules to flag for risky permissions (e.g. FullAaccess, SendAs, Send on Behalf). This is adds to the investigative techniques provided by hawk that were not included before. --- .../Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 index 0c257b2..d56588f 100644 --- a/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminMailboxPermissionChange.ps1 @@ -5,7 +5,7 @@ Function Get-HawkTenantAdminMailboxPermissionChange { .DESCRIPTION Searches the Unified Audit Log for mailbox permission changes and flags any grants - of FullAccess, SendAs, or Send on Behalf permissions for investigation. + of FullAccess, SendAs, or Send on Behalf permissions for investigations. Excludes normal system operations on Discovery Search Mailboxes. .OUTPUTS From a7884b9650419bb6de4743f0aa1b182504080032 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Thu, 19 Dec 2024 19:29:00 -0500 Subject: [PATCH 21/28] Add initial code for Get-HawkTenantImpersonationAccess. --- Hawk/Hawk.psd1 | 1 + .../Get-HawkTenantImpersonationAccess.ps1 | 135 ++++++++++++++++++ .../Tenant/Start-HawkTenantInvestigation.ps1 | 6 +- 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index 22e2255..dbe4b5b 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -62,6 +62,7 @@ 'Get-HawkTenantAdminInboxRuleModification', 'Get-HawkTenantAdminInboxRuleRemoval', 'Get-HawkTenantAdminMailboxPermissionChange', + 'Get-HawkTenantImpersonationAccess', 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', diff --git a/Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 b/Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 new file mode 100644 index 0000000..8e6d4d7 --- /dev/null +++ b/Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 @@ -0,0 +1,135 @@ +Function Get-HawkTenantImpersonationAccess { + <# + .SYNOPSIS + Checks for Exchange impersonation roles and their assignments in the tenant. + + .DESCRIPTION + This function examines Exchange impersonation configuration by: + 1. Finding all roles containing the Impersonate-ExchangeUser cmdlet + 2. Identifying all users and groups assigned to those roles + + Non-default configurations (more than one role or assignment) are flagged + for investigation as they may indicate excessive impersonation rights. + + .OUTPUTS + File: Impersonation_Roles.csv/.json/.xml + Path: \Tenant + Description: List of roles with impersonation rights (default config) + + File: _Investigate_Impersonation_Roles.csv/.json/.xml + Path: \Tenant + Description: List of roles with impersonation rights (non-default config) + + File: Impersonation_Rights.csv/.json/.xml + Path: \Tenant + Description: List of users/groups with impersonation rights (default config) + + File: _Investigate_Impersonation_Rights.csv/.json/.xml + Path: \Tenant + Description: List of users/groups with impersonation rights (non-default config) + + .EXAMPLE + Get-HawkTenantImpersonationAccess + + Checks impersonation roles and assignments, flagging any non-default configurations. + #> + [CmdletBinding()] + param() + + Test-EXOConnection + Send-AIEvent -Event "CmdRun" + + Out-LogFile "Analyzing Exchange impersonation access" -Action + + # Create tenant folder if it doesn't exist + $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" + if (-not (Test-Path -Path $TenantPath)) { + New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null + } + + try { + # Check for impersonation roles + Out-LogFile "Searching for roles with Impersonate-ExchangeUser rights" -action + [array]$TenantImpersonatingRoles = Get-ManagementRoleEntry "*\Impersonate-ExchangeUser" -ErrorAction Stop + + switch ($TenantImpersonatingRoles.Count) { + 0 { + Out-LogFile "No impersonation roles found - This is unusual and should be investigated" -Notice + return + } + 1 { + Out-LogFile "Found default number of impersonation roles (1)" + $TenantImpersonatingRoles | Out-MultipleFileType -FilePrefix "Impersonation_Roles" -csv -json -xml + } + default { + Out-LogFile "Found $($TenantImpersonatingRoles.Count) impersonation roles - Default is 1" -Notice + Out-LogFile "Additional impersonation roles may indicate overly broad permissions" -Notice + $TenantImpersonatingRoles | Out-MultipleFileType -FilePrefix "_Investigate_Impersonation_Roles" -csv -json -xml -Notice + + # Log details about each role for investigation + foreach ($role in $TenantImpersonatingRoles) { + Out-LogFile "Found impersonation role: $($role.Role)" -Notice + } + } + } + + # Check role assignments + Out-LogFile "Checking who has been assigned impersonation roles" -action + $RoleAssignments = @() + foreach ($Role in $TenantImpersonatingRoles) { + try { + $assignments = Get-ManagementRoleAssignment -Role $Role.Role -GetEffectiveUsers -Delegating:$false -ErrorAction Stop + if ($assignments) { + $RoleAssignments += $assignments + } + } + catch { + Out-LogFile "Error getting assignments for role $($Role.Role): $($_.Exception.Message)" -Notice + continue + } + } + + switch ($RoleAssignments.Count) { + 0 { + Out-LogFile "No impersonation role assignments found - This is unusual and should be investigated" -Notice + } + 1 { + Out-LogFile "Found default number of impersonation assignments (1)" + $RoleAssignments | Out-MultipleFileType -FilePrefix "Impersonation_Rights" -csv -json -xml + + # Log who has the default assignment + Out-LogFile "Default impersonation assigned to: $($RoleAssignments[0].RoleAssignee)" + } + default { + Out-LogFile "Found $($RoleAssignments.Count) impersonation assignments - Default is 1" -Notice + Out-LogFile "Multiple assignments may indicate excessive impersonation rights" -Notice + $RoleAssignments | Out-MultipleFileType -FilePrefix "_Investigate_Impersonation_Rights" -csv -json -xml -Notice + + # Log details about each assignment for investigation + foreach ($assignment in $RoleAssignments) { + Out-LogFile "Found assignment: Role: $($assignment.Role) assigned to: $($assignment.RoleAssignee)" -Notice + } + } + } + + # Provide summary if non-default configuration found + if ($TenantImpersonatingRoles.Count -gt 1 -or $RoleAssignments.Count -gt 1) { + Out-LogFile "INVESTIGATION REQUIRED: Non-default impersonation configuration detected" -Notice + if ($TenantImpersonatingRoles.Count -gt 1) { + Out-LogFile "- Multiple impersonation roles found ($($TenantImpersonatingRoles.Count))" -Notice + } + if ($RoleAssignments.Count -gt 1) { + Out-LogFile "- Multiple impersonation assignments found ($($RoleAssignments.Count))" -Notice + } + Out-LogFile "Excessive impersonation rights could allow unauthorized mailbox access" -Notice + } + elseif ($TenantImpersonatingRoles.Count -eq 0 -or $RoleAssignments.Count -eq 0) { + Out-LogFile "WARNING: Missing expected impersonation configuration" -Notice + Out-LogFile "Default configuration should have 1 role and 1 assignment" -Notice + } + } + catch { + Out-LogFile "Error analyzing impersonation access: $($_.Exception.Message)" -Notice + Write-Error -ErrorRecord $_ -ErrorAction Continue + } +} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 4d08699..1e66c50 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -76,10 +76,14 @@ Get-HawkTenantAdminMailboxPermissionChange } - + if ($PSCmdlet.ShouldProcess("Checks for Exchange Impersonation Role Assignments", "Search For Exchange Impersonation Role Assignments")) { + Out-LogFile "Running Get-HawkTenantImpersonationAccess" -action + Get-HawkTenantImpersonationAccess + } + # if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { # Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action # Get-HawkTenantEDiscoveryLogs From 691afff1b65e5f9ad9c22aae055a018dfa06c364 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Fri, 20 Dec 2024 09:39:13 -0500 Subject: [PATCH 22/28] Remove Get-HawkTenantImpersonationAccess as RBAC application impersonation is being retired FEB 2025. --- Hawk/Hawk.psd1 | 1 - .../Get-HawkTenantImpersonationAccess.ps1 | 135 ------------------ .../Tenant/Start-HawkTenantInvestigation.ps1 | 7 - 3 files changed, 143 deletions(-) delete mode 100644 Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index dbe4b5b..22e2255 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -62,7 +62,6 @@ 'Get-HawkTenantAdminInboxRuleModification', 'Get-HawkTenantAdminInboxRuleRemoval', 'Get-HawkTenantAdminMailboxPermissionChange', - 'Get-HawkTenantImpersonationAccess', 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', diff --git a/Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 b/Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 deleted file mode 100644 index 8e6d4d7..0000000 --- a/Hawk/functions/Tenant/Get-HawkTenantImpersonationAccess.ps1 +++ /dev/null @@ -1,135 +0,0 @@ -Function Get-HawkTenantImpersonationAccess { - <# - .SYNOPSIS - Checks for Exchange impersonation roles and their assignments in the tenant. - - .DESCRIPTION - This function examines Exchange impersonation configuration by: - 1. Finding all roles containing the Impersonate-ExchangeUser cmdlet - 2. Identifying all users and groups assigned to those roles - - Non-default configurations (more than one role or assignment) are flagged - for investigation as they may indicate excessive impersonation rights. - - .OUTPUTS - File: Impersonation_Roles.csv/.json/.xml - Path: \Tenant - Description: List of roles with impersonation rights (default config) - - File: _Investigate_Impersonation_Roles.csv/.json/.xml - Path: \Tenant - Description: List of roles with impersonation rights (non-default config) - - File: Impersonation_Rights.csv/.json/.xml - Path: \Tenant - Description: List of users/groups with impersonation rights (default config) - - File: _Investigate_Impersonation_Rights.csv/.json/.xml - Path: \Tenant - Description: List of users/groups with impersonation rights (non-default config) - - .EXAMPLE - Get-HawkTenantImpersonationAccess - - Checks impersonation roles and assignments, flagging any non-default configurations. - #> - [CmdletBinding()] - param() - - Test-EXOConnection - Send-AIEvent -Event "CmdRun" - - Out-LogFile "Analyzing Exchange impersonation access" -Action - - # Create tenant folder if it doesn't exist - $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" - if (-not (Test-Path -Path $TenantPath)) { - New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null - } - - try { - # Check for impersonation roles - Out-LogFile "Searching for roles with Impersonate-ExchangeUser rights" -action - [array]$TenantImpersonatingRoles = Get-ManagementRoleEntry "*\Impersonate-ExchangeUser" -ErrorAction Stop - - switch ($TenantImpersonatingRoles.Count) { - 0 { - Out-LogFile "No impersonation roles found - This is unusual and should be investigated" -Notice - return - } - 1 { - Out-LogFile "Found default number of impersonation roles (1)" - $TenantImpersonatingRoles | Out-MultipleFileType -FilePrefix "Impersonation_Roles" -csv -json -xml - } - default { - Out-LogFile "Found $($TenantImpersonatingRoles.Count) impersonation roles - Default is 1" -Notice - Out-LogFile "Additional impersonation roles may indicate overly broad permissions" -Notice - $TenantImpersonatingRoles | Out-MultipleFileType -FilePrefix "_Investigate_Impersonation_Roles" -csv -json -xml -Notice - - # Log details about each role for investigation - foreach ($role in $TenantImpersonatingRoles) { - Out-LogFile "Found impersonation role: $($role.Role)" -Notice - } - } - } - - # Check role assignments - Out-LogFile "Checking who has been assigned impersonation roles" -action - $RoleAssignments = @() - foreach ($Role in $TenantImpersonatingRoles) { - try { - $assignments = Get-ManagementRoleAssignment -Role $Role.Role -GetEffectiveUsers -Delegating:$false -ErrorAction Stop - if ($assignments) { - $RoleAssignments += $assignments - } - } - catch { - Out-LogFile "Error getting assignments for role $($Role.Role): $($_.Exception.Message)" -Notice - continue - } - } - - switch ($RoleAssignments.Count) { - 0 { - Out-LogFile "No impersonation role assignments found - This is unusual and should be investigated" -Notice - } - 1 { - Out-LogFile "Found default number of impersonation assignments (1)" - $RoleAssignments | Out-MultipleFileType -FilePrefix "Impersonation_Rights" -csv -json -xml - - # Log who has the default assignment - Out-LogFile "Default impersonation assigned to: $($RoleAssignments[0].RoleAssignee)" - } - default { - Out-LogFile "Found $($RoleAssignments.Count) impersonation assignments - Default is 1" -Notice - Out-LogFile "Multiple assignments may indicate excessive impersonation rights" -Notice - $RoleAssignments | Out-MultipleFileType -FilePrefix "_Investigate_Impersonation_Rights" -csv -json -xml -Notice - - # Log details about each assignment for investigation - foreach ($assignment in $RoleAssignments) { - Out-LogFile "Found assignment: Role: $($assignment.Role) assigned to: $($assignment.RoleAssignee)" -Notice - } - } - } - - # Provide summary if non-default configuration found - if ($TenantImpersonatingRoles.Count -gt 1 -or $RoleAssignments.Count -gt 1) { - Out-LogFile "INVESTIGATION REQUIRED: Non-default impersonation configuration detected" -Notice - if ($TenantImpersonatingRoles.Count -gt 1) { - Out-LogFile "- Multiple impersonation roles found ($($TenantImpersonatingRoles.Count))" -Notice - } - if ($RoleAssignments.Count -gt 1) { - Out-LogFile "- Multiple impersonation assignments found ($($RoleAssignments.Count))" -Notice - } - Out-LogFile "Excessive impersonation rights could allow unauthorized mailbox access" -Notice - } - elseif ($TenantImpersonatingRoles.Count -eq 0 -or $RoleAssignments.Count -eq 0) { - Out-LogFile "WARNING: Missing expected impersonation configuration" -Notice - Out-LogFile "Default configuration should have 1 role and 1 assignment" -Notice - } - } - catch { - Out-LogFile "Error analyzing impersonation access: $($_.Exception.Message)" -Notice - Write-Error -ErrorRecord $_ -ErrorAction Continue - } -} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 1e66c50..8a36099 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -76,13 +76,6 @@ Get-HawkTenantAdminMailboxPermissionChange } - if ($PSCmdlet.ShouldProcess("Checks for Exchange Impersonation Role Assignments", "Search For Exchange Impersonation Role Assignments")) { - Out-LogFile "Running Get-HawkTenantImpersonationAccess" -action - Get-HawkTenantImpersonationAccess - } - - - # if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { # Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action From ac9814c412a58ffa9d118c6d6bee39e517e7dd9f Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Fri, 20 Dec 2024 11:42:04 -0500 Subject: [PATCH 23/28] Removing function run time as this was for debugging purposes. --- Hawk/Hawk.psd1 | 1 + ...t-HawkTenantAdminEmailForwardingChange.ps1 | 216 ++++++++++++++++++ .../Tenant/Start-HawkTenantInvestigation.ps1 | 12 +- 3 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index 22e2255..6b89c92 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -62,6 +62,7 @@ 'Get-HawkTenantAdminInboxRuleModification', 'Get-HawkTenantAdminInboxRuleRemoval', 'Get-HawkTenantAdminMailboxPermissionChange', + 'Get-HawkTenantAdminEmailForwardingChange', 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', diff --git a/Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 b/Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 new file mode 100644 index 0000000..b22eeb8 --- /dev/null +++ b/Hawk/functions/Tenant/Get-HawkTenantAdminEmailForwardingChange.ps1 @@ -0,0 +1,216 @@ +Function Get-HawkTenantAdminEmailForwardingChange { + <# + .SYNOPSIS + Retrieves audit log entries for email forwarding changes made within the tenant. + + .DESCRIPTION + This function queries the Microsoft 365 Unified Audit Log for events related to email + forwarding configuration changes (Set-Mailbox with forwarding parameters). It focuses on + tracking when and by whom forwarding rules were added or modified, helping identify potential + unauthorized data exfiltration attempts. + + Key points: + - Monitors changes to both ForwardingAddress and ForwardingSMTPAddress settings + - Resolves recipient information for ForwardingAddress values + - Flags all forwarding changes for review as potential security concerns + - Provides historical context for forwarding configuration changes + + .OUTPUTS + File: Simple_Forwarding_Changes.csv/.json + Path: \Tenant + Description: Simplified view of forwarding configuration changes. + + File: Forwarding_Changes.csv/.json + Path: \Tenant + Description: Detailed audit log data for forwarding changes. + + File: Forwarding_Recipients.csv/.json + Path: \Tenant + Description: List of unique forwarding destinations configured. + + .EXAMPLE + Get-HawkTenantAdminEmailForwardingChange + + Retrieves all email forwarding configuration changes from the audit logs within the specified + search window. + #> + [CmdletBinding()] + param() + + # Test the Exchange Online connection to ensure the environment is ready for operations. + Test-EXOConnection + # Log the execution of the function for audit and telemetry purposes. + Send-AIEvent -Event "CmdRun" + + # Initialize timing variables for status updates + $startTime = Get-Date + $lastUpdate = $startTime + + # Log the start of the analysis process for email forwarding configuration changes. + Out-LogFile "Analyzing email forwarding configuration changes from audit logs" -Action + + # Ensure the tenant-specific folder exists to store output files. If not, create it. + $TenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant" + if (-not (Test-Path -Path $TenantPath)) { + New-Item -Path $TenantPath -ItemType Directory -Force | Out-Null + } + + try { + # Define both operations and broader search terms to cast a wider net. + $searchCommand = @" +Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations @( + 'Set-Mailbox', + 'Set-MailUser', + 'Set-RemoteMailbox', + 'Enable-RemoteMailbox' +) +"@ + + # Fetch all specified operations from the audit log + [array]$AllMailboxChanges = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand + + # Log search completion time + Out-LogFile "Unified Audit Log search completed" -Information + + Out-LogFile "Filtering results for forwarding changes..." -Action + + # Enhanced filtering to catch more types of forwarding changes + [array]$ForwardingChanges = $AllMailboxChanges | Where-Object { + $auditData = $_.AuditData | ConvertFrom-Json + $parameters = $auditData.Parameters + ($parameters | Where-Object { + $_.Name -in @( + 'ForwardingAddress', + 'ForwardingSMTPAddress', + 'ExternalEmailAddress', + 'PrimarySmtpAddress', + 'RedirectTo', # Added from other LLM suggestion + 'DeliverToMailboxAndForward', # Corrected parameter name + 'DeliverToAndForward' # Alternative parameter name + ) -or + # Check for parameter changes enabling forwarding + ($_.Name -eq 'DeliverToMailboxAndForward' -and $_.Value -eq 'True') -or + ($_.Name -eq 'DeliverToAndForward' -and $_.Value -eq 'True') + }) + } + + Out-LogFile "Completed filtering for forwarding changes" -Information + + if ($ForwardingChanges.Count -gt 0) { + # Log the number of forwarding configuration changes found. + Out-LogFile ("Found " + $ForwardingChanges.Count + " change(s) to user email forwarding") -Information + + # Write raw JSON data for detailed reference and potential troubleshooting. + $RawJsonPath = Join-Path -Path $TenantPath -ChildPath "Forwarding_Changes_Raw.json" + $ForwardingChanges | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath + + # Parse the audit data into a simpler format for further processing and output. + $ParsedChanges = $ForwardingChanges | Get-SimpleUnifiedAuditLog + if ($ParsedChanges) { + # Write the simplified data for quick analysis and review. + $ParsedChanges | Out-MultipleFileType -FilePrefix "Simple_Forwarding_Changes" -csv -json -Notice + + # Write the full audit log data for comprehensive records. + $ForwardingChanges | Out-MultipleFileType -FilePrefix "Forwarding_Changes" -csv -json -Notice + + # Initialize an array to store processed forwarding destination data. + $ForwardingDestinations = @() + + Out-LogFile "Beginning detailed analysis of forwarding changes..." -Action + foreach ($change in $ParsedChanges) { + # Add a status update every 30 seconds + $currentTime = Get-Date + if (($currentTime - $lastUpdate).TotalSeconds -ge 30) { + Out-LogFile "Processing forwarding changes... ($($ForwardingDestinations.Count) destinations found so far)" -Action + $lastUpdate = $currentTime + } + + $targetUser = $change.ObjectId + + # Process ForwardingSMTPAddress changes if detected in the audit log. + if ($change.Parameters -match "ForwardingSMTPAddress") { + $smtpAddress = ($change.Parameters | Select-String -Pattern "ForwardingSMTPAddress:\s*([^,]+)").Matches.Groups[1].Value + if ($smtpAddress) { + # Add the SMTP forwarding configuration to the destinations array. + $ForwardingDestinations += [PSCustomObject]@{ + UserModified = $targetUser + TargetSMTPAddress = $smtpAddress.Split(":")[-1].Trim() # Remove "SMTP:" prefix if present. + ChangeType = "SMTP Forwarding" + ModifiedBy = $change.UserId + ModifiedTime = $change.CreationTime + } + } + } + + # Process ForwardingAddress changes if detected in the audit log. + if ($change.Parameters -match "ForwardingAddress") { + $forwardingAddress = ($change.Parameters | Select-String -Pattern "ForwardingAddress:\s*([^,]+)").Matches.Groups[1].Value + if ($forwardingAddress) { + try { + # Attempt to resolve the recipient details from Exchange Online. + $recipient = Get-EXORecipient $forwardingAddress -ErrorAction Stop + + # Determine the recipient's type and extract the appropriate address. + $targetAddress = switch ($recipient.RecipientType) { + "MailContact" { $recipient.ExternalEmailAddress.Split(":")[-1] } + default { $recipient.PrimarySmtpAddress } + } + + # Add the recipient forwarding configuration to the destinations array. + $ForwardingDestinations += [PSCustomObject]@{ + UserModified = $targetUser + TargetSMTPAddress = $targetAddress + ChangeType = "Recipient Forwarding" + ModifiedBy = $change.UserId + ModifiedTime = $change.CreationTime + } + } + catch { + # Log a warning if the recipient cannot be resolved. + Out-LogFile "Unable to resolve forwarding recipient: $forwardingAddress" -Notice + # Add an unresolved entry for transparency in the output. + $ForwardingDestinations += [PSCustomObject]@{ + UserModified = $targetUser + TargetSMTPAddress = "UNRESOLVED:$forwardingAddress" + ChangeType = "Recipient Forwarding (Unresolved)" + ModifiedBy = $change.UserId + ModifiedTime = $change.CreationTime + } + } + } + } + } + + + Out-LogFile "Completed processing forwarding changes" -Information + + if ($ForwardingDestinations.Count -gt 0) { + # Log the total number of forwarding destinations detected. + Out-LogFile ("Found " + $ForwardingDestinations.Count + " forwarding destinations configured") -Information + # Write the forwarding destinations data to files for review. + $ForwardingDestinations | Out-MultipleFileType -FilePrefix "Forwarding_Recipients" -csv -json -Notice + + # Log details about each forwarding destination for detailed auditing. + foreach ($dest in $ForwardingDestinations) { + Out-LogFile "Forwarding configured: $($dest.UserModified) -> $($dest.TargetSMTPAddress) ($($dest.ChangeType)) by $($dest.ModifiedBy) at $($dest.ModifiedTime)" -Notice + } + } + } + else { + # Log a warning if the parsing of audit data fails. + Out-LogFile "Error: Failed to parse forwarding change audit data" -Notice + } + } + else { + # Log a message if no forwarding changes are found in the logs. + Out-LogFile "No forwarding changes found in filtered results" -Information + Out-LogFile "Retrieved $($AllMailboxChanges.Count) total operations, but none involved forwarding changes" -Information + } + } + catch { + # Log an error if the analysis encounters an exception. + Out-LogFile "Error analyzing email forwarding changes: $($_.Exception.Message)" -Notice + Write-Error -ErrorRecord $_ -ErrorAction Continue + } +} + diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index 8a36099..ae4ddb4 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -71,9 +71,15 @@ # Get-HawkTenantAdminInboxRuleRemoval # } - if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Permission Change Audit Log", "Search Admin Inbox Permission Changes")) { - Out-LogFile "Running Get-HawkTenantAdminMailboxPermissionChange" -action - Get-HawkTenantAdminMailboxPermissionChange + # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Permission Change Audit Log", "Search Admin Inbox Permission Changes")) { + # Out-LogFile "Running Get-HawkTenantAdminMailboxPermissionChange" -action + # Get-HawkTenantAdminMailboxPermissionChange + # } + + + if ($PSCmdlet.ShouldProcess("Admin Email Forwarding Change Change Audit Log", "Search Admin Email Forwarding Changes")) { + Out-LogFile "Running Get-HawkTenantAdminEmailForwardingChange" -action + Get-HawkTenantAdminEmailForwardingChange } From 8e51608e3195dc700ab316b683951a99f049aca4 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Fri, 20 Dec 2024 12:04:16 -0500 Subject: [PATCH 24/28] Remove Search-HawkTenantEXOAuditLog as this has been separated into separate and distinct functions, all modernized to used non deprecated modules. --- .../Tenant/Search-HawkTenantEXOAuditLog.ps1 | 234 ------------------ .../Tenant/Start-HawkTenantInvestigation.ps1 | 134 +++++----- 2 files changed, 64 insertions(+), 304 deletions(-) delete mode 100644 Hawk/functions/Tenant/Search-HawkTenantEXOAuditLog.ps1 diff --git a/Hawk/functions/Tenant/Search-HawkTenantEXOAuditLog.ps1 b/Hawk/functions/Tenant/Search-HawkTenantEXOAuditLog.ps1 deleted file mode 100644 index 1470cb4..0000000 --- a/Hawk/functions/Tenant/Search-HawkTenantEXOAuditLog.ps1 +++ /dev/null @@ -1,234 +0,0 @@ -Function Search-HawkTenantEXOAuditLog { - <# -.SYNOPSIS - Searches the admin audit logs for possible bad actor activities -.DESCRIPTION - Searches the Exchange admin audkit logs for a number of possible bad actor activies. - * New inbox rules - * Changes to user forwarding configurations - * Changes to user mailbox permissions - * Granting of impersonation rights -.OUTPUTS - - File: Simple_New_InboxRule.csv - Path: \ - Description: cmdlets to create any new inbox rules in a simple to read format - - File: New_InboxRules.xml - Path: \XML - Description: Search results for any new inbox rules in CLI XML format - - File: _Investigate_Simple_New_InboxRule.csv - Path: \ - Description: cmdlets to create inbox rules that forward or delete email in a simple format - - File: _Investigate_New_InboxRules.xml - Path: \XML - Description: Search results for newly created inbox rules that forward or delete email in CLI XML - - File: _Investigate_New_InboxRules.txt - Path: \ - Description: Search results of newly created inbox rules that forward or delete email - - File: Simple_Forwarding_Changes.csv - Path: \ - Description: cmdlets that change forwarding settings in a simple to read format - - File: Forwarding_Changes.xml - Path: \XML - Description: Search results for cmdlets that change forwarding settings in CLI XML - - File: Forwarding_Recipients.csv - Path: \ - Description: List of unique Email addresses that were setup to recieve email via forwarding - - File: Simple_Mailbox_Permissions.csv - Path: \ - Description: Cmdlets that add permissions to users in a simple to read format - - File: Mailbox_Permissions.xml - Path: \XML - Description: Search results for cmdlets that change permissions in CLI XML - - File: _Investigate_Impersonation_Roles.csv - Path: \ - Description: List all users with impersonation rights if we find more than the default of one - - File: _Investigate_Impersonation_Roles.csv - Path: \XML - Description: List all users with impersonation rights if we find more than the default of one as CLI XML - - File: Impersonation_Rights.csv - Path: \ - Description: List all users with impersonation rights if we only find the default one - - File: Impersonation_Rights.csv - Path: \XML - Description: List all users with impersonation rights if we only find the default one as CLI XML -.EXAMPLE - Search-HawkTenantEXOAuditLog - - Searches the tenant audit logs looking for changes that could have been made in the tenant. -#> - - Test-EXOConnection - Send-AIEvent -Event "CmdRun" - - Out-LogFile "Searching EXO Audit Logs" -Action - Out-LogFile "Searching Entire Admin Audit Log for Specific cmdlets" - - #Make sure our values are null - $TenantInboxRules = $Null - $TenantSetInboxRules = $Null - $TenantRemoveInboxRules = $Null - - - # Search for the creation of ANY inbox rules - Out-LogFile "Searching for ALL Inbox Rules Created in the Shell" -action - [array]$TenantInboxRules = Search-UnifiedAuditLog -RecordType ExchangeAdmin -Operations New-InboxRule -StartDate $Hawk.StartDate -EndDate $Hawk.EndDate - - # If we found anything report it and log it - if ($TenantInboxRules.count -gt 0) { - - Out-LogFile ("Found " + $TenantInboxRules.count + " Inbox Rule(s) created from PowerShell") - $TenantInboxRules | Get-SimpleAdminAuditLog | Out-MultipleFileType -fileprefix "Simple_New_InboxRule" -csv -json - $TenantInboxRules | Out-MultipleFileType -fileprefix "New_InboxRules" -csv -json - } - - # Search for the Modification of ANY inbox rules - Out-LogFile "Searching for ALL Inbox Rules Modified in the Shell" -action - [array]$TenantSetInboxRules = Search-AdminAuditLog -Cmdlets Set-InboxRule -StartDate $Hawk.StartDate -EndDate $Hawk.EndDate - - # If we found anything report it and log it - if ($TenantSetInboxRules.count -gt 0) { - - Out-LogFile ("Found " + $TenantSetInboxRules.count + " Inbox Rule(s) created from PowerShell") - $TenantSetInboxRules | Get-SimpleAdminAuditLog | Out-MultipleFileType -fileprefix "Simple_Set_InboxRule" -csv -json - $TenantSetInboxRules | Out-MultipleFileType -fileprefix "Set_InboxRules" -csv -json - } - - # Search for the Modification of ANY inbox rules - Out-LogFile "Searching for ALL Inbox Rules Removed in the Shell" -action - [array]$TenantRemoveInboxRules = Search-AdminAuditLog -Cmdlets Remove-InboxRule -StartDate $Hawk.StartDate -EndDate $Hawk.EndDate - - # If we found anything report it and log it - if ($TenantRemoveInboxRules.count -gt 0) { - - Out-LogFile ("Found " + $TenantRemoveInboxRules.count + " Inbox Rule(s) created from PowerShell") - $TenantRemoveInboxRules | Get-SimpleAdminAuditLog | Out-MultipleFileType -fileprefix "Simple_Remove_InboxRule" -csv -json - $TenantRemoveInboxRules | Out-MultipleFileType -fileprefix "Remove_InboxRules" -csv -json - } - - # Searching for interesting inbox rules - Out-LogFile "Searching for Interesting Inbox Rules Created in the Shell" -action - [array]$InvestigateInboxRules = Search-AdminAuditLog -StartDate $Hawk.StartDate -EndDate $Hawk.EndDate -cmdlets New-InboxRule -Parameters ForwardTo, ForwardAsAttachmentTo, RedirectTo, DeleteMessage - - # if we found a rule report it and output it to the _Investigate files - if ($InvestigateInboxRules.count -gt 0) { - Out-LogFile ("Found " + $InvestigateInboxRules.count + " Inbox Rules that should be investigated further.") -notice - $InvestigateInboxRules | Get-SimpleAdminAuditLog | Out-MultipleFileType -fileprefix "_Investigate_Simple_New_InboxRule" -csv -json -Notice - $InvestigateInboxRules | Out-MultipleFileType -fileprefix "_Investigate_New_InboxRules" -xml -txt -Notice - } - - # Look for changes to user forwarding - Out-LogFile "Searching for user Forwarding Changes" -action - [array]$TenantForwardingChanges = Search-AdminAuditLog -Cmdlets Set-Mailbox -Parameters ForwardingAddress, ForwardingSMTPAddress -StartDate $Hawk.StartDate -EndDate $Hawk.EndDate - - if ($TenantForwardingChanges.count -gt 0) { - Out-LogFile ("Found " + $TenantForwardingChanges.count + " Change(s) to user Email Forwarding") -notice - $TenantForwardingChanges | Get-SimpleAdminAuditLog | Out-MultipleFileType -FilePrefix "Simple_Forwarding_Changes" -csv -json -Notice - $TenantForwardingChanges | Out-MultipleFileType -FilePrefix "Forwarding_Changes" -xml -Notice - - # Make sure our output array is null - [array]$Output = $null - - # Checking if addresses were added or removed - # If added compile a list - Foreach ($Change in $TenantForwardingChanges) { - - # Get the user object modified - $user = ($Change.CmdletParameters | Where-Object ($_.name -eq "Identity")).value - - # Check the ForwardingSMTPAddresses first - if ([string]::IsNullOrEmpty(($Change.CmdletParameters | Where-Object { $_.name -eq "ForwardingSMTPAddress" }).value)) { } - # If not null then push the email address into $output - else { - [array]$Output = $Output + ($Change.CmdletParameters | Where-Object { $_.name -eq "ForwardingSMTPAddress" }) | Select-Object -Property @{Name = "UserModified"; Expression = { $user } }, @{Name = "TargetSMTPAddress"; Expression = { $_.value.split(":")[1] } } - } - - # Check ForwardingAddress - if ([string]::IsNullOrEmpty(($Change.CmdletParameters | Where-Object { $_.name -eq "ForwardingAddress" }).value)) { } - else { - # Here we get back a recipient object in EXO not an SMTP address - # So we need to go track down the recipient object - $recipient = Get-EXORecipient (($Change.CmdletParameters | Where-Object { $_.name -eq "ForwardingAddress" }).value) -ErrorAction SilentlyContinue - - # If we can't resolve the recipient we need to log that - if ($null -eq $recipient) { - Out-LogFile ("Unable to resolve forwarding Target Recipient " + ($Change.CmdletParameters | Where-Object { $_.name -eq "ForwardingAddress" })) -notice - } - # If we can resolve it then we need to push the address the mail was being set to into $output - else { - # Determine the type of recipient and handle as needed to get out the SMTP address - Switch ($recipient.RecipientType) { - # For mailcontact we needed the external email address - MailContact { - [array]$Output += $recipient | Select-Object -Property @{Name = "UserModified"; Expression = { $user } }; @{Name = "TargetSMTPAddress"; Expression = { $_.ExternalEmailAddress.split(":")[1] } } - } - # For all others I believe primary will work - Default { - [array]$Output += $recipient | Select-Object -Property @{Name = "UserModified"; Expression = { $user } }; @{Name = "TargetSMTPAddress"; Expression = { $_.PrimarySmtpAddress } } - } - } - } - } - } - - # Output our email address user modified pairs - Out-logfile ("Found " + $Output.count + " email addresses set to be forwarded mail") -notice - $Output | Out-MultipleFileType -FilePrefix "Forwarding_Recipients" -csv -json -Notice - - } - - # Look for changes to mailbox permissions - Out-LogFile "Searching for Mailbox Permissions Changes" -Action - [array]$TenantMailboxPermissionChanges = Search-AdminAuditLog -StartDate $Hawk.StartDate -EndDate $Hawk.EndDate -cmdlets Add-MailboxPermission - - if ($TenantMailboxPermissionChanges.count -gt 0) { - Out-LogFile ("Found " + $TenantMailboxPermissionChanges.count + " changes to mailbox permissions") - $TenantMailboxPermissionChanges | Get-SimpleAdminAuditLog | Out-MultipleFileType -fileprefix "Simple_Mailbox_Permissions" -csv -json - $TenantMailboxPermissionChanges | Out-MultipleFileType -fileprefix "Mailbox_Permissions" -xml - - ## TODO: Possibly check who was added with permissions and see how old their accounts are - } - - # Look for change to impersonation access - Out-LogFile "Searching Impersonation Access" -action - [array]$TenantImpersonatingRoles = Get-ManagementRoleEntry "*\Impersonate-ExchangeUser" - if ($TenantImpersonatingRoles.count -gt 1) { - Out-LogFile ("Found " + $TenantImpersonatingRoles.count + " Impersonation Roles. Default is 1") -notice - $TenantImpersonatingRoles | Out-MultipleFileType -fileprefix "_Investigate_Impersonation_Roles" -csv -json -xml -Notice - } - elseif ($TenantImpersonatingRoles.count -eq 0) { } - else { - $TenantImpersonatingRoles | Out-MultipleFileType -fileprefix "Impersonation_Roles" -csv -json -xml - } - - $Output = $null - # Search all impersonation roles for users that have access - foreach ($Role in $TenantImpersonatingRoles) { - [array]$Output += Get-ManagementRoleAssignment -Role $Role.role -GetEffectiveUsers -Delegating:$false - } - - if ($Output.count -gt 1) { - Out-LogFile ("Found " + $Output.count + " Users/Groups with Impersonation rights. Default is 1") -notice - $Output | Out-MultipleFileType -fileprefix "Impersonation_Rights" -csv -json -xml - $Output | Out-MultipleFileType -fileprefix "_Investigate_Impersonation_Rights" -csv -json -xml -Notice - } - elseif ($Output.count -eq 1) { - Out-LogFile ("Found default number of Impersonation users") - $Output | Out-MultipleFileType -fileprefix "Impersonation_Rights" -csv -json -xml - } - else { } - -} \ No newline at end of file diff --git a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 index ae4ddb4..b4b6a3d 100644 --- a/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 +++ b/Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1 @@ -41,41 +41,35 @@ Send-AIEvent -Event "CmdRun" # Wrap operations in ShouldProcess checks - # if ($PSCmdlet.ShouldProcess("Tenant Configuration", "Get configuration data")) { - # Out-LogFile "Running Get-HawkTenantConfiguration" -action - # Get-HawkTenantConfiguration - # } - - # if ($PSCmdlet.ShouldProcess("EDiscovery Configuration", "Get eDiscovery configuration")) { - # Out-LogFile "Running Get-HawkTenantEDiscoveryConfiguration" -action - # Get-HawkTenantEDiscoveryConfiguration - # } - - # if ($PSCmdlet.ShouldProcess("Exchange Audit Log", "Search audit logs")) { - # Out-LogFile "Running Search-HawkTenantEXOAuditLog" -action - # Search-HawkTenantEXOAuditLog - # } - - # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Creation Audit Log", "Search Admin Inbox Rule Creation")) { - # Out-LogFile "Running Get-HawkTenantAdminInboxRuleCreation" -action - # Get-HawkTenantAdminInboxRuleCreation - # } - - # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Modification Audit Log", "Search Admin Inbox Rule Modification")) { - # Out-LogFile "Running Get-HawkTenantInboxRuleModification" -action - # Get-HawkTenantAdminInboxRuleModification - # } - - # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Removal Audit Log", "Search Admin Inbox Rule Removal")) { - # Out-LogFile "Running Get-HawkTenantAdminInboxRuleRemoval" -action - # Get-HawkTenantAdminInboxRuleRemoval - # } - - # if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Permission Change Audit Log", "Search Admin Inbox Permission Changes")) { - # Out-LogFile "Running Get-HawkTenantAdminMailboxPermissionChange" -action - # Get-HawkTenantAdminMailboxPermissionChange - # } + if ($PSCmdlet.ShouldProcess("Tenant Configuration", "Get configuration data")) { + Out-LogFile "Running Get-HawkTenantConfiguration" -action + Get-HawkTenantConfiguration + } + + if ($PSCmdlet.ShouldProcess("EDiscovery Configuration", "Get eDiscovery configuration")) { + Out-LogFile "Running Get-HawkTenantEDiscoveryConfiguration" -action + Get-HawkTenantEDiscoveryConfiguration + } + + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Creation Audit Log", "Search Admin Inbox Rule Creation")) { + Out-LogFile "Running Get-HawkTenantAdminInboxRuleCreation" -action + Get-HawkTenantAdminInboxRuleCreation + } + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Modification Audit Log", "Search Admin Inbox Rule Modification")) { + Out-LogFile "Running Get-HawkTenantInboxRuleModification" -action + Get-HawkTenantAdminInboxRuleModification + } + + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Removal Audit Log", "Search Admin Inbox Rule Removal")) { + Out-LogFile "Running Get-HawkTenantAdminInboxRuleRemoval" -action + Get-HawkTenantAdminInboxRuleRemoval + } + + if ($PSCmdlet.ShouldProcess("Admin Inbox Rule Permission Change Audit Log", "Search Admin Inbox Permission Changes")) { + Out-LogFile "Running Get-HawkTenantAdminMailboxPermissionChange" -action + Get-HawkTenantAdminMailboxPermissionChange + } if ($PSCmdlet.ShouldProcess("Admin Email Forwarding Change Change Audit Log", "Search Admin Email Forwarding Changes")) { Out-LogFile "Running Get-HawkTenantAdminEmailForwardingChange" -action @@ -83,48 +77,48 @@ } - # if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { - # Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action - # Get-HawkTenantEDiscoveryLogs - # } + if ($PSCmdlet.ShouldProcess("EDiscovery Logs", "Get eDiscovery logs")) { + Out-LogFile "Running Get-HawkTenantEDiscoveryLogs" -action + Get-HawkTenantEDiscoveryLogs + } - # if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { - # Out-LogFile "Running Get-HawkTenantDomainActivity" -action - # Get-HawkTenantDomainActivity - # } + if ($PSCmdlet.ShouldProcess("Domain Activity", "Get domain activity")) { + Out-LogFile "Running Get-HawkTenantDomainActivity" -action + Get-HawkTenantDomainActivity + } - # if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { - # Out-LogFile "Running Get-HawkTenantRBACChange" -action - # Get-HawkTenantRBACChange - # } + if ($PSCmdlet.ShouldProcess("RBAC Changes", "Get RBAC changes")) { + Out-LogFile "Running Get-HawkTenantRBACChange" -action + Get-HawkTenantRBACChange + } - # if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { - # Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action - # Get-HawkTenantAzureAppAuditLog - # } + if ($PSCmdlet.ShouldProcess("Azure App Audit Log", "Get app audit logs")) { + Out-LogFile "Running Get-HawkTenantAzureAppAuditLog" -action + Get-HawkTenantAzureAppAuditLog + } - # if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { - # Out-LogFile "Running Get-HawkTenantEXOAdmins" -action - # Get-HawkTenantEXOAdmins - # } + if ($PSCmdlet.ShouldProcess("Exchange Admins", "Get Exchange admin list")) { + Out-LogFile "Running Get-HawkTenantEXOAdmins" -action + Get-HawkTenantEXOAdmins + } - # if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { - # Out-LogFile "Running Get-HawkTenantConsentGrant" -action - # Get-HawkTenantConsentGrant - # } + if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) { + Out-LogFile "Running Get-HawkTenantConsentGrant" -action + Get-HawkTenantConsentGrant + } - # if ($PSCmdlet.ShouldProcess("Entra ID Admins", "Get Entra ID admin list")) { - # Out-LogFile "Running Get-HawkTenantEntraIDAdmin" -action - # Get-HawkTenantEntraIDAdmin - # } + if ($PSCmdlet.ShouldProcess("Entra ID Admins", "Get Entra ID admin list")) { + Out-LogFile "Running Get-HawkTenantEntraIDAdmin" -action + Get-HawkTenantEntraIDAdmin + } - # if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { - # Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetail" -action - # Get-HawkTenantAppAndSPNCredentialDetail - # } + if ($PSCmdlet.ShouldProcess("App and SPN Credentials", "Get credential details")) { + Out-LogFile "Running Get-HawkTenantAppAndSPNCredentialDetail" -action + Get-HawkTenantAppAndSPNCredentialDetail + } - # if ($PSCmdlet.ShouldProcess("Entra ID Users", "Get Entra ID user list")) { - # Out-LogFile "Running Get-HawkTenantEntraIDUser" -action - # Get-HawkTenantEntraIDUser - # } + if ($PSCmdlet.ShouldProcess("Entra ID Users", "Get Entra ID user list")) { + Out-LogFile "Running Get-HawkTenantEntraIDUser" -action + Get-HawkTenantEntraIDUser + } } \ No newline at end of file From 39bc0203e2a11b3b4748c0250443a638cb39d223 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Fri, 20 Dec 2024 12:05:17 -0500 Subject: [PATCH 25/28] Remove Search-HawkTenantEXOAuditLog from Hawk.psd1 as it is no longer required. --- Hawk/Hawk.psd1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Hawk/Hawk.psd1 b/Hawk/Hawk.psd1 index 6b89c92..00a2a3b 100644 --- a/Hawk/Hawk.psd1 +++ b/Hawk/Hawk.psd1 @@ -63,7 +63,6 @@ 'Get-HawkTenantAdminInboxRuleRemoval', 'Get-HawkTenantAdminMailboxPermissionChange', 'Get-HawkTenantAdminEmailForwardingChange', - 'Search-HawkTenantEXOAuditLog', 'Show-HawkHelp', 'Start-HawkTenantInvestigation', 'Start-HawkUserInvestigation', From e414fa35b9840774b8392af62f1858960411d264 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Fri, 20 Dec 2024 12:26:14 -0500 Subject: [PATCH 26/28] Updated changelog.md --- Hawk/changelog.md | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Hawk/changelog.md b/Hawk/changelog.md index 34f7fb4..80646f4 100644 --- a/Hawk/changelog.md +++ b/Hawk/changelog.md @@ -60,18 +60,19 @@ - Removed Robust Cloud Command from build as it was not being used in the code base anymore - Updated PowerShell API key in GitHub to fix build.yml issue where the Hawk would not publish to gallery on merge to main -## 3.2.3 (2024-12-09) - -- **Migration to Microsoft Graph**: Replaced all AzureAD functionality with Microsoft Graph commands, including updates to functions like `Get-HawkTenantAppAndSPNCredentialDetails` (now using `Get-MgServicePrincipal` and `Get-MgApplication`). - -- **Directory Role Management**: Updated `Get-HawkTenantAZAdmins` to use Microsoft Graph (`Get-MgRoleDefinition` and `Get-MgRoleAssignment`), renamed to `Get-HawkTenantEntraIDAdmin`, and enhanced output for better role tracking. - -- **Consent Grant Updates**: Migrated `Get-HawkTenantConsentGrant` to Graph commands (`Get-MgOauth2PermissionGrant` and `Get-MgServicePrincipalAppRoleAssignment`), ensuring consistent output and backward compatibility. - -- **Removed AzureAD Dependencies**: Eliminated AzureAD references in the Hawk.psd1 manifest and removed the deprecated `Test-AzureADConnection.ps1`. Updated manifest to rely solely on Microsoft Graph modules (v2.25.0). - -- **Simplified Authentication**: Streamlined Graph API connections by removing unnecessary commands like `Select-MgProfile` and improving `Test-GraphConnection` for default behaviors. - -- **Improved Logging and Naming**: Standardized log outputs (e.g., `AzureADUsers` to `EntraIDUsers`) and aligned function outputs with updated naming conventions. - -- This release completes the migration to Microsoft Graph, fully deprecating AzureAD and aligning Hawk with modern Microsoft standards. +## 3.2.3 (2024-12-20) + +- Replaced all AzureAD functionality with Microsoft Graph commands. +- Updated Get-HawkTenantAZAdmins to use Microsoft Graph. +- Migrated Get-HawkTenantConsentGrant to Graph commands. +- Removed AzureAD Dependencies: Eliminated AzureAD references in the Hawk.psd1 manifest and removed the deprecated Test-AzureADConnection.ps1. +- Simplified Authentication: Streamlined Graph API connections by removing unnecessary commands like Select-MgProfile and improving Test-GraphConnection. +- Improved Logging and Naming: Standardized log outputs (e.g., AzureADUsers to EntraIDUsers) and aligned function outputs with updated naming conventions. +- Removed Search-HawkTenantEXOAuditLog as it was deprecated and replaced with modern, modular functions, as listed below: +- Added Get-HawkTenantAdminInboxRuleModification, which retrieves audit log entries for inbox rules that were historically modified within the tenant. +- Added Get-HawkTenantAdminEmailForwardingChange, which retrieves audit log entries for email forwarding changes made within the tenant. +- Added Get-HawkTenantAdminInboxRuleCreation, which retrieves audit log entries for inbox rules that were historically created within the tenant. +- Added Get-HawkTenantAdminInboxRuleRemoval, which retrieves audit log entries for inbox rules that were removed within the tenant. +- Added Get-HawkTenantAdminMailboxPermissionChange, which retrieves audit log entries for mailbox permission changes within the tenant. +- Added internal helper function Test-SuspiciousInboxRule, which detects suspicious inbox rule patterns. +- Removed ability to detect RBAC Application Impersonation as this is being deprecated / removed in FEB 2025. From 55fc27c440bc7afb0674d7797192841a64294e11 Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Fri, 20 Dec 2024 12:26:34 -0500 Subject: [PATCH 27/28] Removed resolving IP binary. --- Hawk/Resolving IP Locations | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Hawk/Resolving IP Locations diff --git a/Hawk/Resolving IP Locations b/Hawk/Resolving IP Locations deleted file mode 100644 index 46b134b..0000000 --- a/Hawk/Resolving IP Locations +++ /dev/null @@ -1 +0,0 @@ -ÿþ \ No newline at end of file From 2baabd30ff0142538135e409467b64465500071e Mon Sep 17 00:00:00 2001 From: Jonathan Butler Date: Fri, 20 Dec 2024 12:29:32 -0500 Subject: [PATCH 28/28] Updated change log. --- Hawk/changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Hawk/changelog.md b/Hawk/changelog.md index 80646f4..1350ffa 100644 --- a/Hawk/changelog.md +++ b/Hawk/changelog.md @@ -76,3 +76,5 @@ - Added Get-HawkTenantAdminMailboxPermissionChange, which retrieves audit log entries for mailbox permission changes within the tenant. - Added internal helper function Test-SuspiciousInboxRule, which detects suspicious inbox rule patterns. - Removed ability to detect RBAC Application Impersonation as this is being deprecated / removed in FEB 2025. +- Updated Out-Log file, adding -Information parameter for tagging prompts with INFO for status updates. +- Updated Out-Log file, modifying -Notice parameter for tagging prompts with INVESTIGATE in brackets instead of asterisks, for uniformity purposes.