Skip to content

Commit

Permalink
Merge pull request #1087 from JohnDuprey/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
JohnDuprey authored Aug 21, 2024
2 parents 1d37e17 + 53a6935 commit 0851d28
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 120 deletions.
271 changes: 166 additions & 105 deletions Durable_BECRun/run.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,122 +6,183 @@ Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -m
$TenantFilter = $Context.input.tenantfilter
$SuspectUser = $Context.input.userid
$UserName = $Context.input.username
Write-Host "Working on $UserName"
Write-Information "Working on $UserName"
try {
$startDate = (Get-Date).AddDays(-7)
$endDate = (Get-Date)
$auditLog = (New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-AdminAuditLogConfig').UnifiedAuditLogIngestionEnabled
$7dayslog = if ($auditLog -eq $false) {
$ExtractResult = 'AuditLog is disabled. Cannot perform full analysis'
} else {
$sessionid = Get-Random -Minimum 10000 -Maximum 99999
$operations = @(
'New-InboxRule',
'Set-InboxRule',
'UpdateInboxRules',
'Remove-MailboxPermission',
'Add-MailboxPermission',
'UpdateCalendarDelegation',
'AddFolderPermissions',
'MailboxLogin',
'UserLoggedIn'
)
$startDate = (Get-Date).AddDays(-7)
$startDate = (Get-Date).AddDays(-7).ToUniversalTime()
$endDate = (Get-Date)
$SearchParam = @{
SessionCommand = 'ReturnLargeSet'
Operations = $operations
sessionid = $sessionid
startDate = $startDate
endDate = $endDate
Write-Information 'Getting audit logs'
$auditLog = (New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Get-AdminAuditLogConfig').UnifiedAuditLogIngestionEnabled
$7dayslog = if ($auditLog -eq $false) {
$ExtractResult = 'AuditLog is disabled. Cannot perform full analysis'
} else {
$sessionid = Get-Random -Minimum 10000 -Maximum 99999
$operations = @(
'New-InboxRule',
'Set-InboxRule',
'UpdateInboxRules',
'Remove-MailboxPermission',
'Add-MailboxPermission',
'UpdateCalendarDelegation',
'AddFolderPermissions',
'MailboxLogin',
'UserLoggedIn'
)
$startDate = (Get-Date).AddDays(-7)
$endDate = (Get-Date)
$SearchParam = @{
SessionCommand = 'ReturnLargeSet'
Operations = $operations
sessionid = $sessionid
startDate = $startDate
endDate = $endDate
}
do {
New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Search-unifiedAuditLog' -cmdParams $SearchParam -Anchor $Username
Write-Information "Retrieved $($logsTenant.count) logs"
$logsTenant
} while ($LogsTenant.count % 5000 -eq 0 -and $LogsTenant.count -ne 0)
$ExtractResult = 'Successfully extracted logs from auditlog'
}
Write-Information 'Getting last sign-in'
Try {
$URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$SuspectUser')&`$top=1&`$orderby=createdDateTime desc"
$LastSignIn = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'CreatedDateTime'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } },
id,
@{ Name = 'AppDisplayName'; Expression = { $_.resourceDisplayName } },
@{ Name = 'Status'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } },
@{ Name = 'IPAddress'; Expression = { $_.ipAddress } }
} catch {
$LastSignIn = [PSCustomObject]@{
AppDisplayName = 'Unknown - could not retrieve information. No access to sign-in logs'
CreatedDateTime = 'Unknown'
Id = '0'
Status = 'Could not retrieve additional details'
}
}
do {
New-ExoRequest -tenantid $Tenantfilter -cmdlet 'Search-unifiedAuditLog' -cmdParams $SearchParam -Anchor $Username
Write-Host "Retrieved $($logsTenant.count) logs" -ForegroundColor Yellow
$logsTenant
} while ($LogsTenant.count % 5000 -eq 0 -and $LogsTenant.count -ne 0)
$ExtractResult = 'Successfully extracted logs from auditlog'
}
Try {
$URI = "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=(userId eq '$SuspectUser')&`$top=1&`$orderby=createdDateTime desc"
$LastSignIn = New-GraphGetRequest -uri $URI -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'CreatedDateTime'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } },
id,
@{ Name = 'AppDisplayName'; Expression = { $_.resourceDisplayName } },
@{ Name = 'Status'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } },
@{ Name = 'IPAddress'; Expression = { $_.ipAddress } }
} catch {
$LastSignIn = [PSCustomObject]@{
AppDisplayName = 'Unknown - could not retrieve information. No access to sign-in logs'
CreatedDateTime = 'Unknown'
Id = '0'
Status = 'Could not retrieve additional details'
Write-Information 'Getting user devices'
#List all users devices
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($SuspectUser)
$base64IdentityParam = [Convert]::ToBase64String($Bytes)
Try {
$Devices = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $tenantfilter -scope ExchangeOnline
} catch {
$Devices = $null
}
}
#List all users devices
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($SuspectUser)
$base64IdentityParam = [Convert]::ToBase64String($Bytes)
Try {
$Devices = New-GraphGetRequest -uri "https://outlook.office365.com:443/adminapi/beta/$($TenantFilter)/mailbox('$($base64IdentityParam)')/MobileDevice/Exchange.GetMobileDeviceStatistics()/?IsEncoded=True" -Tenantid $tenantfilter -scope ExchangeOnline
} catch {
$Devices = $null
}
$PermissionsLog = ($7dayslog | Where-Object -Property Operations -In 'Remove-MailboxPermission', 'Add-MailboxPermission', 'UpdateCalendarDelegation', 'AddFolderPermissions' ).AuditData | ConvertFrom-Json -Depth 100 | ForEach-Object {
$perms = if ($_.Parameters) {
$_.Parameters | ForEach-Object { if ($_.Name -eq 'AccessRights') { $_.Value } }
} else
{ $_.item.ParentFolder.MemberRights }
$objectID = if ($_.ObjectID) { $_.ObjectID } else { $($_.MailboxOwnerUPN) + $_.item.ParentFolder.Path }
[pscustomobject]@{
Operation = $_.Operation
UserKey = $_.UserKey
ObjectId = $objectId
Permissions = $perms

try {
$PermissionsLog = ($7dayslog | Where-Object -Property Operations -In 'Remove-MailboxPermission', 'Add-MailboxPermission', 'UpdateCalendarDelegation', 'AddFolderPermissions' ).AuditData | ConvertFrom-Json -ErrorAction Stop | ForEach-Object {
$perms = if ($_.Parameters) {
$_.Parameters | ForEach-Object { if ($_.Name -eq 'AccessRights') { $_.Value } }
} else
{ $_.item.ParentFolder.MemberRights }
$objectID = if ($_.ObjectID) { $_.ObjectID } else { $($_.MailboxOwnerUPN) + $_.item.ParentFolder.Path }
[pscustomobject]@{
Operation = $_.Operation
UserKey = $_.UserKey
ObjectId = $objectId
Permissions = $perms
}
}
} catch {
$PermissionsLog = @()
}
}

$RulesLog = @(($7dayslog | Where-Object -Property Operations -In 'New-InboxRule', 'Set-InboxRule', 'UpdateInboxRules').AuditData | ConvertFrom-Json) | ForEach-Object {
Write-Host ($_ | ConvertTo-Json)
[pscustomobject]@{
ClientIP = $_.ClientIP
CreationTime = $_.CreationTime
UserId = $_.UserId
RuleName = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleName') { $_.Value } })
RuleCondition = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleCondition') { $_.Value } })
try {
$RulesLog = @(($7dayslog | Where-Object -Property Operations -In 'New-InboxRule', 'Set-InboxRule', 'UpdateInboxRules').AuditData | ConvertFrom-Json -ErrorAction Stop) | ForEach-Object {
Write-Information ($_ | ConvertTo-Json)
[pscustomobject]@{
ClientIP = $_.ClientIP
CreationTime = $_.CreationTime
UserId = $_.UserId
RuleName = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleName') { $_.Value } })
RuleCondition = ($_.OperationProperties | ForEach-Object { if ($_.Name -eq 'RuleCondition') { $_.Value } })
}
}
} catch {
$RulesLog = @()
}

Write-Information 'Getting last 50 logons'
try {
$Last50Logons = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?`$filter=userDisplayName ne 'On-Premises Directory Synchronization Service Account'&`$top=50&`$orderby=createdDateTime desc" -tenantid $TenantFilter -noPagination $true | Select-Object @{ Name = 'CreatedDateTime'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } },
id,
@{ Name = 'AppDisplayName'; Expression = { $_.resourceDisplayName } },
@{ Name = 'Status'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } },
@{ Name = 'IPAddress'; Expression = { $_.ipAddress } }, UserPrincipalName, UserDisplayName
} catch {
$Last50Logons = @(
[PSCustomObject]@{
AppDisplayName = 'Unknown - could not retrieve information. No access to sign-in logs'
CreatedDateTime = 'Unknown'
Id = '0'
Status = 'Could not retrieve additional details'
Exception = $_.Exception.Message
}
)
}

$Requests = @(
@{
id = 'PasswordChanges'
url = "users?`$select=lastPasswordChangeDateTime,displayname,UserPrincipalName&`$filter=lastPasswordChangeDateTime ge $($startDate.ToString('yyyy-MM-ddTHH:mm:ssZ'))"
method = 'GET'
}
@{
id = 'NewUsers'
url = "users?`$select=displayname,userPrincipalName,createdDateTime?`$filter=createdDateTime ge $($startDate.ToString('yyyy-MM-ddTHH:mm:ssZ'))"
method = 'GET'
}
@{
id = 'MFADevices'
url = "users/$($SuspectUser)/authentication/methods"
method = 'GET'
}
@{
id = 'NewSPs'
url = "servicePrincipals?`$select=displayName,createdDateTime,id,appDisplayName&`$filter=createdDateTime ge $($startDate.ToString('yyyy-MM-ddTHH:mm:ssZ'))"
method = 'GET'
}
@{
id = 'Last50Logons'
url = "auditLogs/signIns?`$top=50&`$orderby=createdDateTime desc&`$filter=createdDateTime ge $($startDate.ToString('yyyy-MM-ddTHH:mm:ssZ')) and userDisplayName ne 'On-Premises Directory Synchronization Service Account'"
method = 'GET'
}
)

Write-Information 'Getting bulk requests'

$GraphResults = New-GraphBulkRequest -Requests $Requests -tenantid $TenantFilter -asapp $true
$PasswordChanges = $GraphResults | Where-Object { $_.id -eq 'PasswordChanges' } | Select-Object -ExpandProperty body
$NewUsers = $GraphResults | Where-Object { $_.id -eq 'NewUsers' } | Select-Object -ExpandProperty body
$MFADevices = $GraphResults | Where-Object { $_.id -eq 'MFADevices' } | Select-Object -ExpandProperty body
$NewSPs = $GraphResults | Where-Object { $_.id -eq 'NewSPs' } | Select-Object -ExpandProperty body


$Results = [PSCustomObject]@{
AddedApps = @($NewSPs)
SuspectUserMailboxLogons = @($Last50Logons)
LastSuspectUserLogon = @($LastSignIn)
SuspectUserDevices = @($Devices)
NewRules = @($RulesLog)
MailboxPermissionChanges = @($PermissionsLog)
NewUsers = @($NewUsers)
MFADevices = @($MFADevices)
ChangedPasswords = @($PasswordChanges)
ExtractedAt = (Get-Date).ToString('s')
ExtractResult = $ExtractResult
}
}
$PasswordChanges = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`select=lastPasswordChangeDateTime,displayname,UserPrincipalName" -Tenantid $tenantfilter | Where-Object { $_.lastPasswordChangeDateTime -gt $startDate }
$NewUsers = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users?`$select=displayname,UserPrincipalName,CreatedDateTime" -Tenantid $tenantfilter | Where-Object { $_.CreatedDateTime -gt $startDate }
$MFADevices = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($SuspectUser)/authentication/methods" -Tenantid $tenantfilter
$NewSPs = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/servicePrincipals?`$select=displayName,createdDateTime,id,AppDisplayName&`$filter=createdDateTime ge $($startDate.ToString('yyyy-MM-ddTHH:mm:ssZ'))" -Tenantid $tenantfilter
$Last50Logons = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/auditLogs/signIns?`$top=50&`$orderby=createdDateTime desc" -tenantid $TenantFilter -noPagination $true -verbose | Select-Object @{ Name = 'CreatedDateTime'; Expression = { $(($_.createdDateTime | Out-String) -replace '\r\n') } },
id,
@{ Name = 'AppDisplayName'; Expression = { $_.resourceDisplayName } },
@{ Name = 'Status'; Expression = { if (($_.conditionalAccessStatus -eq 'Success' -or 'Not Applied') -and $_.status.errorCode -eq 0) { 'Success' } else { 'Failed' } } },
@{ Name = 'IPAddress'; Expression = { $_.ipAddress } }, UserPrincipalName
$Results = [PSCustomObject]@{
AddedApps = @($NewSPs)
SuspectUserMailboxLogons = @($Last50Logons)
LastSuspectUserLogon = @($LastSignIn)
SuspectUserDevices = @($Devices)
NewRules = @($RulesLog)
MailboxPermissionChanges = @($PermissionsLog)
NewUsers = @($NewUsers)
MFADevices = @($MFADevices)
ChangedPasswords = @($PasswordChanges)
ExtractedAt = (Get-Date).ToString('s')
ExtractResult = $ExtractResult
}

} catch {
$errMessage = Get-NormalizedError -message $_.Exception.Message
$results = [pscustomobject]@{'Results' = "$errMessage" }
$errMessage = Get-NormalizedError -message $_.Exception.Message
$CippError = Get-CippException -Exception $_
$results = [pscustomobject]@{'Results' = "$errMessage"; Exception = $CippError }
}

$Table = Get-CippTable -tablename 'cachebec'
$Table.Force = $true
Add-CIPPAzDataTableEntity @Table -Entity @{
UserId = $Context.input.userid
Results = "$($results | ConvertTo-Json -Depth 10)"
RowKey = $Context.input.userid
PartitionKey = 'bec'
}
UserId = $Context.input.userid
Results = "$($results | ConvertTo-Json -Depth 10)"
RowKey = $Context.input.userid
PartitionKey = 'bec'
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ function Invoke-ExecSAMAppPermissions {
[CmdletBinding()]
param($Request, $TriggerMetadata)

$User = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json

switch ($Request.Query.Action) {
'Update' {
try {
$Permissions = $Request.Body.Permissions
$Entity = @{
'PartitionKey' = 'CIPP-SAM'
'RowKey' = 'CIPP-SAM'
'Permissions' = [string]($Permissions.Permissions | ConvertTo-Json -Depth 10 -Compress)
'Permissions' = [string]($Permissions | ConvertTo-Json -Depth 10 -Compress)
'UpdatedBy' = $User.UserDetails ?? 'CIPP-API'
}
$Table = Get-CIPPTable -TableName 'AppPermissions'
$null = Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force
$Body = @{
'Results' = 'Permissions Updated'
}
Write-LogMessage -user $request.headers.'x-ms-client-principal' -API 'ExecSAMAppPermissions' -message 'CIPP-SAM Permissions Updated' -Sev 'Info' -LogData $Permissions
} catch {
$Body = @{
'Results' = $_.Exception.Message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,35 @@ Function Invoke-ExecBECRemediate {
Write-Host $TenantFilter
Write-Host $SuspectUser
$Results = try {
$Step = 'Reset Password'
Set-CIPPResetPassword -userid $username -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $User
$Step = 'Disable Account'
Set-CIPPSignInState -userid $username -AccountEnabled $false -tenantFilter $TenantFilter -APIName $APINAME -ExecutingUser $User
$Step = 'Revoke Sessions'
Revoke-CIPPSessions -userid $SuspectUser -username $request.body.username -ExecutingUser $User -APIName $APINAME -tenantFilter $TenantFilter

$Step = 'Disable Inbox Rules'
$Rules = New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'Get-InboxRule' -cmdParams @{Mailbox = $username; IncludeHidden = $true }
$RuleDisabled = 0
New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'Get-InboxRule' -cmdParams @{Mailbox = $username; IncludeHidden = $true } | Where-Object { $_.Name -ne 'Junk E-Mail Rule' } | ForEach-Object {
$null = New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'Disable-InboxRule' -cmdParams @{Confirm = $false; Identity = $_.Identity }
"Disabled Inbox Rule $($_.Identity) for $username"
$RuleDisabled++
if (($Rules | Measure-Object).Count -gt 0) {
$Rules | Where-Object { $_.Name -ne 'Junk E-Mail Rule' } | ForEach-Object {
$null = New-ExoRequest -anchor $username -tenantid $TenantFilter -cmdlet 'Disable-InboxRule' -cmdParams @{Confirm = $false; Identity = $_.Identity }
"Disabled Inbox Rule $($_.Identity) for $username"
$RuleDisabled++
}
}
if ($RuleDisabled) {
if ($RuleDisabled -gt 0) {
"Disabled $RuleDisabled Inbox Rules for $username"
} else {
"No Inbox Rules found for $username. We have not disabled any rules."
}

Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $SuspectUser" -sev 'Info'
Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $username" -sev 'Info'

} catch {
$ErrorMessage = Get-CippException -Exception $_
$results = [pscustomobject]@{'Results' = "Failed to execute remediation. $($ErrorMessage.NormalizedError)" }
Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $SuspectUser failed" -sev 'Error' -LogData $ErrorMessage
Write-LogMessage -API 'BECRemediate' -tenant $tenantfilter -message "Executed Remediation for $username failed at the $Step step" -sev 'Error' -LogData $ErrorMessage
}
$results = [pscustomobject]@{'Results' = @($Results) }

Expand Down
Loading

0 comments on commit 0851d28

Please sign in to comment.