Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

GSA Enriched Office 365 - PowerShell or non-browser mailbox login activity

Back
Id49a4f65a-fe18-408e-afec-042fde93d3ce
RulenameGSA Enriched Office 365 - PowerShell or non-browser mailbox login activity
DescriptionDetects mailbox login from Exchange PowerShell. All accounts can use it by default, but admins can change it. Whitelist benign activities.
TacticsExecution
Persistence
Collection
TechniquesT1059
T1098
T1114
Required data connectorsAzureActiveDirectory
KindScheduled
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global Secure Access/Hunting Queries/powershell_or_nonbrowser_MailboxLogin.yaml
Version2.0.2
Arm template49a4f65a-fe18-408e-afec-042fde93d3ce.json
Deploy To Azure
let starttime = todatetime('{{StartTimeISO}}');
    let endtime = todatetime('{{EndTimeISO}}');
    // EnrichedMicrosoft365AuditLogs query
    let EnrichedMailboxLogin = EnrichedMicrosoft365AuditLogs
        | where TimeGenerated between (starttime .. endtime)
        | where Workload == "Exchange" and Operation == "MailboxLogin"
        | extend ClientApplication = tostring(parse_json(AdditionalProperties).ClientInfoString)
        | where ClientApplication == "Client=Microsoft.Exchange.Powershell; Microsoft WinRM Client"
        | extend TenantName = tostring(parse_json(AdditionalProperties).TenantName)
        | extend MailboxOwner = tostring(parse_json(AdditionalProperties).MailboxOwnerUPN)
        | extend LogonType = tostring(parse_json(AdditionalProperties).LogonType)
        | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Count = count() by Operation, TenantName, UserType, UserId, MailboxOwner, LogonType, ClientApplication
        | extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)
        | extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')
        | extend AccountName = iff(UserId contains '\\', tostring(split(UserId, '\\')[1]), AccountName)
        | extend AccountNTDomain = iff(UserId contains '\\', tostring(split(UserId, '\\')[0]), '');
    // OfficeActivity query
    let OfficeMailboxLogin = OfficeActivity
        | where TimeGenerated between (starttime .. endtime)
        | where OfficeWorkload == "Exchange" and Operation == "MailboxLogin"
        | where ClientInfoString == "Client=Microsoft.Exchange.Powershell; Microsoft WinRM Client"
        | extend LogonType = "Unknown"  // If LogonType does not exist, create a placeholder
        | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Count = count() by Operation, OrganizationName, UserType, UserId, MailboxOwnerUPN, LogonType, ClientInfoString
        | extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)
        | extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')
        | extend AccountName = iff(UserId contains '\\', tostring(split(UserId, '\\')[1]), AccountName)
        | extend AccountNTDomain = iff(UserId contains '\\', tostring(split(UserId, '\\')[0]), '');
    // Combine Enriched and Office queries
    let CombinedMailboxLogin = EnrichedMailboxLogin
        | union OfficeMailboxLogin
        | summarize arg_min(StartTime, *) by UserId, Operation
        | project StartTime, EndTime, Operation, TenantName, OrganizationName, UserType, UserId, MailboxOwner, LogonType, ClientApplication, ClientInfoString, Count, AccountName, AccountUPNSuffix, AccountNTDomain;
    // Final output
    CombinedMailboxLogin
        | order by StartTime desc;
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global Secure Access/Hunting Queries/powershell_or_nonbrowser_MailboxLogin.yaml
relevantTechniques:
- T1059
- T1098
- T1114
name: GSA Enriched Office 365 - PowerShell or non-browser mailbox login activity
query: |
  let starttime = todatetime('{{StartTimeISO}}');
      let endtime = todatetime('{{EndTimeISO}}');
      // EnrichedMicrosoft365AuditLogs query
      let EnrichedMailboxLogin = EnrichedMicrosoft365AuditLogs
          | where TimeGenerated between (starttime .. endtime)
          | where Workload == "Exchange" and Operation == "MailboxLogin"
          | extend ClientApplication = tostring(parse_json(AdditionalProperties).ClientInfoString)
          | where ClientApplication == "Client=Microsoft.Exchange.Powershell; Microsoft WinRM Client"
          | extend TenantName = tostring(parse_json(AdditionalProperties).TenantName)
          | extend MailboxOwner = tostring(parse_json(AdditionalProperties).MailboxOwnerUPN)
          | extend LogonType = tostring(parse_json(AdditionalProperties).LogonType)
          | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Count = count() by Operation, TenantName, UserType, UserId, MailboxOwner, LogonType, ClientApplication
          | extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)
          | extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')
          | extend AccountName = iff(UserId contains '\\', tostring(split(UserId, '\\')[1]), AccountName)
          | extend AccountNTDomain = iff(UserId contains '\\', tostring(split(UserId, '\\')[0]), '');
      // OfficeActivity query
      let OfficeMailboxLogin = OfficeActivity
          | where TimeGenerated between (starttime .. endtime)
          | where OfficeWorkload == "Exchange" and Operation == "MailboxLogin"
          | where ClientInfoString == "Client=Microsoft.Exchange.Powershell; Microsoft WinRM Client"
          | extend LogonType = "Unknown"  // If LogonType does not exist, create a placeholder
          | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Count = count() by Operation, OrganizationName, UserType, UserId, MailboxOwnerUPN, LogonType, ClientInfoString
          | extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)
          | extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')
          | extend AccountName = iff(UserId contains '\\', tostring(split(UserId, '\\')[1]), AccountName)
          | extend AccountNTDomain = iff(UserId contains '\\', tostring(split(UserId, '\\')[0]), '');
      // Combine Enriched and Office queries
      let CombinedMailboxLogin = EnrichedMailboxLogin
          | union OfficeMailboxLogin
          | summarize arg_min(StartTime, *) by UserId, Operation
          | project StartTime, EndTime, Operation, TenantName, OrganizationName, UserType, UserId, MailboxOwner, LogonType, ClientApplication, ClientInfoString, Count, AccountName, AccountUPNSuffix, AccountNTDomain;
      // Final output
      CombinedMailboxLogin
          | order by StartTime desc;  
id: 49a4f65a-fe18-408e-afec-042fde93d3ce
entityMappings:
- fieldMappings:
  - columnName: AccountName
    identifier: Name
  - columnName: AccountUPNSuffix
    identifier: UPNSuffix
  - columnName: AccountNTDomain
    identifier: NTDomain
  entityType: Account
requiredDataConnectors:
- connectorId: AzureActiveDirectory
  dataTypes:
  - EnrichedMicrosoft365AuditLogs
description-detailed: |
  'This will help you determine if mailbox login was done from Exchange PowerShell session. 
  By default, all accounts you create in Office 365 are allowed to use Exchange Online PowerShell. 
  Administrators can use Exchange Online PowerShell to enable or disable a user's ability to connect to Exchange Online PowerShell.
  Whitelist any benign scheduled activities using exchange PowerShell if applicable in your environment.
  References: https://docs.microsoft.com/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps'  
description: |
    'Detects mailbox login from Exchange PowerShell. All accounts can use it by default, but admins can change it. Whitelist benign activities.'
kind: Scheduled
tactics:
- Execution
- Persistence
- Collection
version: 2.0.2
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/49a4f65a-fe18-408e-afec-042fde93d3ce')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/49a4f65a-fe18-408e-afec-042fde93d3ce')]",
      "properties": {
        "alertRuleTemplateName": "49a4f65a-fe18-408e-afec-042fde93d3ce",
        "customDetails": null,
        "description": "'Detects mailbox login from Exchange PowerShell. All accounts can use it by default, but admins can change it. Whitelist benign activities.'\n",
        "description-detailed": "'This will help you determine if mailbox login was done from Exchange PowerShell session. \nBy default, all accounts you create in Office 365 are allowed to use Exchange Online PowerShell. \nAdministrators can use Exchange Online PowerShell to enable or disable a user's ability to connect to Exchange Online PowerShell.\nWhitelist any benign scheduled activities using exchange PowerShell if applicable in your environment.\nReferences: https://docs.microsoft.com/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps'\n",
        "displayName": "GSA Enriched Office 365 - PowerShell or non-browser mailbox login activity",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "AccountUPNSuffix",
                "identifier": "UPNSuffix"
              },
              {
                "columnName": "AccountNTDomain",
                "identifier": "NTDomain"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Global Secure Access/Hunting Queries/powershell_or_nonbrowser_MailboxLogin.yaml",
        "query": "let starttime = todatetime('{{StartTimeISO}}');\n    let endtime = todatetime('{{EndTimeISO}}');\n    // EnrichedMicrosoft365AuditLogs query\n    let EnrichedMailboxLogin = EnrichedMicrosoft365AuditLogs\n        | where TimeGenerated between (starttime .. endtime)\n        | where Workload == \"Exchange\" and Operation == \"MailboxLogin\"\n        | extend ClientApplication = tostring(parse_json(AdditionalProperties).ClientInfoString)\n        | where ClientApplication == \"Client=Microsoft.Exchange.Powershell; Microsoft WinRM Client\"\n        | extend TenantName = tostring(parse_json(AdditionalProperties).TenantName)\n        | extend MailboxOwner = tostring(parse_json(AdditionalProperties).MailboxOwnerUPN)\n        | extend LogonType = tostring(parse_json(AdditionalProperties).LogonType)\n        | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Count = count() by Operation, TenantName, UserType, UserId, MailboxOwner, LogonType, ClientApplication\n        | extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)\n        | extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')\n        | extend AccountName = iff(UserId contains '\\\\', tostring(split(UserId, '\\\\')[1]), AccountName)\n        | extend AccountNTDomain = iff(UserId contains '\\\\', tostring(split(UserId, '\\\\')[0]), '');\n    // OfficeActivity query\n    let OfficeMailboxLogin = OfficeActivity\n        | where TimeGenerated between (starttime .. endtime)\n        | where OfficeWorkload == \"Exchange\" and Operation == \"MailboxLogin\"\n        | where ClientInfoString == \"Client=Microsoft.Exchange.Powershell; Microsoft WinRM Client\"\n        | extend LogonType = \"Unknown\"  // If LogonType does not exist, create a placeholder\n        | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Count = count() by Operation, OrganizationName, UserType, UserId, MailboxOwnerUPN, LogonType, ClientInfoString\n        | extend AccountName = iff(UserId contains '@', tostring(split(UserId, '@')[0]), UserId)\n        | extend AccountUPNSuffix = iff(UserId contains '@', tostring(split(UserId, '@')[1]), '')\n        | extend AccountName = iff(UserId contains '\\\\', tostring(split(UserId, '\\\\')[1]), AccountName)\n        | extend AccountNTDomain = iff(UserId contains '\\\\', tostring(split(UserId, '\\\\')[0]), '');\n    // Combine Enriched and Office queries\n    let CombinedMailboxLogin = EnrichedMailboxLogin\n        | union OfficeMailboxLogin\n        | summarize arg_min(StartTime, *) by UserId, Operation\n        | project StartTime, EndTime, Operation, TenantName, OrganizationName, UserType, UserId, MailboxOwner, LogonType, ClientApplication, ClientInfoString, Count, AccountName, AccountUPNSuffix, AccountNTDomain;\n    // Final output\n    CombinedMailboxLogin\n        | order by StartTime desc;\n",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Collection",
          "Execution",
          "Persistence"
        ],
        "techniques": [
          "T1059",
          "T1098",
          "T1114"
        ],
        "templateVersion": "2.0.2"
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}