Query Details
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
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.

Fabian Bader
Released: September 23, 2023
Tables
Keywords
Operators