Query Details

AWS Guard Duty Alert

Query

id: 86d74cc5-40f3-4d0b-aa86-c5926f0aff33
name: "AWS Guard Duty Alert"
version: 1.0.3
kind: Scheduled
description: Amazon GuardDuty is a threat detection service that continuously monitors your AWS accounts and workloads for malicious activity and delivers detailed security findings for visibility and remediation. This templates create an alert for each Amazon GuardDuty finding.
severity: Medium
queryFrequency: 1h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
query: |-
  // https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings.html
  AWSGuardDuty 
  | where ingestion_time() > ago(1h)
  | extend TimeGenerated = TimeCreated
  // Parse the finding
  // https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-format.html
  // Example: "ThreatPurpose:ResourceTypeAffected/ThreatFamilyName.DetectionMechanism!Artifact"
  | extend findingTokens = split(ActivityType, ":")
  | extend ThreatPurpose=findingTokens[0]
  | extend findingTokens=split(findingTokens[1], "/")
  | extend ResourceTypeAffected=findingTokens[0]
  | extend findingTokens= split(findingTokens[1], ".")
  | extend ThreatFamilyName=findingTokens[0]
  | extend findingTokens=split(findingTokens[1], "!")
  | extend DetectionMechanism=findingTokens[0], Artifact=findingTokens[1]
  // Assign severity level
  // https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings.html#guardduty_findings-severity
  | extend Severity = 
      case (
      Severity >= 7.0,
      "High",
      Severity between (4.0 .. 6.9),
      "Medium",
      Severity between (1.0 .. 3.9),
      "Low",
      "Unknown"
  )
  // Pull out any available resource details we can extract entities from. These may not exist in the alert.
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_Resource.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_AccessKeyDetails.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_RdsDbUserDetails.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_KubernetesDetails.html
  | extend AccessKeyDetails=ResourceDetails.accessKeyDetails
  | extend RdsDbUserDetails=ResourceDetails.rdsDbUserDetails
  | extend KubernetesDetails=ResourceDetails.kubernetesDetails
  // Pull out any available action details we can extract entities from. These may not exist in the alert.
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_Action.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_AwsApiCallAction.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_KubernetesApiCallAction.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_NetworkConnectionAction.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_RdsLoginAttemptAction.html
  | extend ServiceAction = 
      case(
      isnotempty(ServiceDetails.action.awsApiCallAction),
      ServiceDetails.action.awsApiCallAction,
      isnotempty(ServiceDetails.action.kubernetesApiCallAction),
      ServiceDetails.action.kubernetesApiCallAction,
      isnotempty(ServiceDetails.action.networkConnectionAction),
      ServiceDetails.action.networkConnectionAction,
      isnotempty(ServiceDetails.action.rdsLoginAttemptAction),
      ServiceDetails.action.rdsLoginAttemptAction,
      dynamic(null)
  )
  // The IPv4 remote address of the connection
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_RemoteIpDetails.html
  // or
  // The IP of the Kubernetes API caller and the IPs of any proxies or load balancers between the caller and the API endpoint 
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_KubernetesApiCallAction.html
  | extend RemoteIpAddress = 
      coalesce(
      tostring(ServiceAction.remoteIpDetails.ipAddressV4),
      tostring(parse_json(ServiceAction.sourceIPs)[0])
  )
  // The IPv4 local address of the connection
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_LocalIpDetails.html
  | extend LocalIpAddress = ServiceAction.localIpDetails.ipAddressV4
  // The AWS account ID of the remote API caller.
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_AwsApiCallAction.html
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_RemoteAccountDetails.html
  | extend RemoteAWSAccountId = ServiceAction.remoteAccountDetails.accountId
  // The IAM access key details (user information) of a user that engaged in the activity that prompted GuardDuty to generate a finding
  // https://docs.aws.amazon.com/guardduty/latest/APIReference/API_AccessKeyDetails.html
  | extend AccountUpn = 
      case(
      AccessKeyDetails.userType == "IAMUser",
      AccessKeyDetails.userName,
      AccessKeyDetails.userType == "AssumedRole",
      split(AccessKeyDetails.principalId, ":", 1)[0],
      isnotempty(RdsDbUserDetails.user),
      RdsDbUserDetails.user,
      isnotempty(KubernetesDetails.kubernetesUserDetails.username),
      KubernetesDetails.kubernetesUserDetails.username,
      ""
  )
  | extend AccountName = split(AccountUpn, "@", 0)[0]
  | extend UPNSuffix = split(AccountUpn, "@", 1)[0]
  // Clean up the output
  | extend GuardDutyDetails =
      bag_pack( 
      "DetectorId",
      ServiceDetails.detectorId,
      "Partition",
      Partition,
      "Region",
      Region
  )
  | extend FindingLink = 
      iff(
      isnotempty(Region) and isnotempty(Id),
      strcat("https://", Region, ".console.aws.amazon.com/guardduty/home?region=", Region, "#/findings?fId=", Id),
      ""
  )
  // Add additional entity information if malware was found
  | join kind=leftouter (
      AWSGuardDuty
      | where isnotempty(ServiceDetails.ebsVolumeScanDetails.scanDetections.highestSeverityThreatDetails.threatName)
      | extend threatNames = ServiceDetails.ebsVolumeScanDetails.scanDetections.threatDetectedByName.threatNames
      | mv-expand threatNames
      | mv-expand threatNames.filePaths
      | extend Directory = threatNames_filePaths.filePath
      | extend FileHashes = threatNames_filePaths.hash
      | extend Name = threatNames_filePaths.fileName
      | sort by Id
      | extend CurrentRowNumber=row_number(2, prev(Id) != Id)
      | extend MalwareInformation = bag_pack(@"$id", CurrentRowNumber, "Asset", false, "Type", "file", "Directory", Directory, "Name", Name)
      | project Id, MalwareInformation
      | summarize MalwareEntities = make_set(MalwareInformation) by Id
      )
      on Id
  | project-away *1
  | project-rename 
      FindingArn=Arn,
      FindingId=Id,
      AWSAccountId=AccountId
  | project-away 
      ActivityType, 
      findingTokens,
      Partition,
      Region, 
      SchemaVersion,
      TimeCreated,
      Type
  | extend ProductName = 'AWS Guard Duty'
  | extend ProviderName = 'AWS'
  | extend CloudApplicationId = '11599'
  | extend IsSample = iff(ServiceDetails.additionalInfo.['sample'] == "true", true, false)
suppressionEnabled: false
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 1h
    matchingMethod: AllEntities
    groupByEntities: []
    groupByAlertDetails:
    groupByCustomDetails: []
eventGroupingSettings:
  aggregationKind: AlertPerResult
alertDetailsOverride:
  alertDisplayNameFormat: "{{Title}}"
  alertDescriptionFormat: "{{Description}}"
  alertTacticsColumnName: ThreatPurpose
  alertSeverityColumnName: Severity
  alertDynamicProperties:
    - alertProperty: AlertLink
      value: FindingLink
    - alertProperty: ProductName
      value: ProductName
    - alertProperty: ProviderName
      value: ProviderName
customDetails:
  ThreatFamilyName: ThreatFamilyName
  ResourceTypeAffected: ResourceTypeAffected
  AWSAccountId: AWSAccountId
  ThreatPurpose: ThreatPurpose
  Artifact: Artifact
  DetectionMechanism: DetectionMechanism
  IsSample: IsSample
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: UPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: RemoteIpAddress
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: LocalIpAddress
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: CloudApplicationId
sentinelEntitiesMappings:
  - columnName: MalwareEntities
suppressionDuration: 1h

Explanation

This query is used to create an alert for each finding in Amazon GuardDuty, a threat detection service for AWS accounts. The query filters the findings based on their ingestion time and parses the finding details. It assigns severity levels to the findings and extracts resource and action details. It also extracts entity information related to malware findings. The query then cleans up the output and maps the entities to specific columns. The alert configuration includes incident creation and grouping settings, as well as alert details override and custom details.

Details

Fabian Bader profile picture

Fabian Bader

Released: September 23, 2023

Tables

AWSGuardDuty

Keywords

AWSGuardDuty,ingestion_time,ago,TimeGenerated,findingTokens,ThreatPurpose,ResourceTypeAffected,ThreatFamilyName,DetectionMechanism,Artifact,Severity,AccessKeyDetails,RdsDbUserDetails,KubernetesDetails,ServiceAction,RemoteIpAddress,LocalIpAddress,RemoteAWSAccountId,AccountUpn,AccountName,UPNSuffix,GuardDutyDetails,FindingLink,Region,Id,ServiceDetails,EbsVolumeScanDetails,threatNames,filePaths,Directory,FileHashes,Name,CurrentRowNumber,MalwareInformation,FindingArn,FindingId,AWSAccountId,ActivityType,Partition,SchemaVersion,TimeCreated,Type,ProductName,ProviderName,CloudApplicationId,IsSample,suppressionEnabled,createIncident,groupingConfiguration,reopenClosedIncident,lookbackDuration,matchingMethod,groupByEntities,groupByAlertDetails,groupByCustomDetails,aggregationKind,alertDisplayNameFormat,alertDescriptionFormat,alertTacticsColumnName,alertSeverityColumnName,alertDynamicProperties,ThreatFamilyName,ResourceTypeAffected,AWSAccountId,ThreatPurpose,Artifact,DetectionMechanism,IsSample,AccountName,UPNSuffix,RemoteIpAddress,LocalIpAddress,CloudApplicationId,MalwareEntities,suppressionDuration

Operators

whereextendsplitcasecoalescetostringparse_jsonisnotemptydynamiciffbag_packstrcatjoinmv-expandsortrow_numbermake_setproject-awayproject-renamesuppressionEnabledcreateIncidentenabledreopenClosedIncidentlookbackDurationmatchingMethodgroupByEntitiesaggregationKindalertDisplayNameFormatalertDescriptionFormatalertTacticsColumnNamealertSeverityColumnNamealertDynamicPropertiesentityTypefieldMappingsidentifiercolumnName

Actions