Query Details

Fed Cred Az Activity Without Sign In Workflow

Query

id: 4918822d-6b9a-49cf-ac81-c9d418fdbcd9
name: 'Azure Activity with Federated Credentials outside of GitHub Workflow activity'
description: |
  'Service Principal with Federated Credentials has been used for Azure Management but no GitHub workflow or sign-in event was audited in the activity time window.'
severity: Medium
requiredDataConnectors: []
queryFrequency: 4h
queryPeriod: 4h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Persistence
  - Impact
relevantTechniques:
  - T1098
  - T1496
query: |
  // Workflow runs and sign-ins from GitHub
  let GitHubFederated = _GetWatchlist('GitHubFederatedCredentials');
  let GitHubEvents = GitHubFederated
  | extend ServicePrincipalId = tostring(ServicePrincipalId)
  | extend GitHubOrganization = tostring(split(Repo, "/")[0])
  | extend GitHubRepository = tostring(split(Repo, "/")[1])
  | extend FedCredSubjectIdentifier = SubjectIdentifier
  | join kind=inner (
  AADServicePrincipalSignInLogs
  | where ServicePrincipalCredentialKeyId == "00000000-0000-0000-0000-000000000000"
  )on $left.ServicePrincipalId == $right.ServicePrincipalId
  | project AADSignInTime = TimeGenerated, AADCorrelationId = CorrelationId, IPAddress, ServicePrincipalResource = ResourceDisplayName, AADSignInLocation = Location, ServicePrincipalId, ServicePrincipalCredentialKeyId, AADSignInResult = ResultType, AADTokenId = UniqueTokenIdentifier, FedCredSubjectIdentifier = SubjectIdentifier, GitHubRepoName = Repo
  | extend GitHubOrganization = tostring(split(GitHubRepoName, "/")[0])
  | extend GitHubRepository = tostring(split(GitHubRepoName, "/")[1])
  | join kind=inner (
      GitHubAuditLogPolling_CL
      | where action_s == "workflows.completed_workflow_run"
      | project GitHubRepoName = repo_s, WorkflowRunId = workflow_run_id_d, WorkflowName = name_s, WorkflowActor = actor_s, WorkflowStartedTime = started_at_t, WorkflowCompletedTime = completed_at_t, WorkflowConslusion = conclusion_s
      ) on $left.GitHubRepoName == $right.GitHubRepoName
  | where AADSignInTime between (todatetime(WorkflowStartedTime) .. todatetime(WorkflowCompletedTime));
  // Azure Activities from Federated Credentials 
  GitHubFederated
  | extend ServicePrincipalId = tostring(ServicePrincipalId)
  | join kind=inner (
  AzureActivity
  | extend AzClaims = parse_json(Claims_d)
  | extend AzObjProp = parse_json(Properties_d)
  | extend AzResourceId = tostring(AzObjProp.entity)
  | extend AzActivityResource = tostring(AzClaims.aud)
  | project AzCorrelationId = CorrelationId, AzTimeStamp = TimeGenerated, AzIpAddress = CallerIpAddress, AzSpId = Caller, AzClaims = parse_json(Claims_d), AzObjProp = parse_json(Properties_d), AzResourceId = tostring(AzObjProp.entity), AzActivityResource = tostring(AzClaims.aud)
  )on $left.ServicePrincipalId == $right.AzSpId
  | join kind=leftouter GitHubEvents on $left.AzSpId == $right.ServicePrincipalId, $left.AzIpAddress == $right.IPAddress
  | where isempty(WorkflowStartedTime) or AzTimeStamp !between (WorkflowStartedTime .. WorkflowCompletedTime)  
  | project AzResourceId, AzSpId, ServicePrincipalId, ServicePrincipalName, AzIpAddress, IPAddress, WorkflowStartedTime, WorkflowCompletedTime, AzTimeStamp
  | extend timestamp = AzTimeStamp, AccountCustomEntity = ServicePrincipalName, IPCustomEntity = AzIpAddress

entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: AccountCustomEntity
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
  - entityType: AzureResource
    fieldMappings:
      - identifier: ResourceId
        columnName: AzResourceId        
version: 1.1.0

Explanation

This query is looking for instances where a Service Principal with Federated Credentials has been used for Azure Management, but no GitHub workflow or sign-in event was audited during the specified time window. It checks for workflow runs and sign-ins from GitHub, as well as Azure activities from Federated Credentials. The query frequency is every 4 hours, and the severity is medium. The relevant techniques are T1098 and T1496, related to persistence and impact. The query does not require any specific data connectors.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: January 29, 2023

Tables

GitHubAuditLogPolling_CLAADServicePrincipalSignInLogsAzureActivity

Keywords

AzureActivity,FederatedCredentials,GitHubWorkflow,Sign-inEvent,ServicePrincipal,WorkflowRuns,Sign-ins,GitHub,AADServicePrincipalSignInLogs,AADSignInTime,AADCorrelationId,IPAddress,ServicePrincipalResource,AADSignInLocation,AADSignInResult,AADTokenId,FedCredSubjectIdentifier,GitHubRepoName,GitHubOrganization,GitHubRepository,GitHubAuditLogPolling_CL,WorkflowRunId,WorkflowName,WorkflowActor,WorkflowStartedTime,WorkflowCompletedTime,WorkflowConslusion,AzureActivity,AzClaims,AzObjProp,AzResourceId,AzActivityResource,AzCorrelationId,AzTimeStamp,AzIpAddress,AzSpId,AccountCustomEntity,IPCustomEntity,timestamp

Operators

idnamedescriptionseverityrequiredDataConnectorsqueryFrequencyqueryPeriodtriggerOperatortriggerThresholdtacticsrelevantTechniquesqueryentityMappingsversion

Actions