-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Add ASIM Network Session parser and hunting queries for AWS GuardDuty #14769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
OluOlus
wants to merge
5
commits into
Azure:master
Choose a base branch
from
OluOlus:add-guardduty-asim-parser
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
4042e94
Merge pull request #1 from Azure/master
OluOlus f7467c2
Add ASIM Network Session parser and hunting queries for AWS GuardDuty
OluOlus e8da806
Address automated review feedback
OluOlus fdd1338
Address second round of automated review feedback
OluOlus 1a13beb
Register new GuardDuty hunting queries in the AWS solution manifest
OluOlus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
213 changes: 213 additions & 0 deletions
213
Parsers/ASimNetworkSession/Parsers/ASimNetworkSessionAWSGuardDuty.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,213 @@ | ||
| Parser: | ||
| Title: Network Session ASIM parser for AWS GuardDuty findings | ||
| Version: '0.1.2' | ||
| LastUpdated: Jul 28, 2026 | ||
| Product: | ||
| Name: AWS GuardDuty | ||
| Normalization: | ||
| Schema: NetworkSession | ||
| Version: '0.2.6' | ||
| References: | ||
| - Title: ASIM Network Session Schema | ||
| Link: https://aka.ms/ASimNetworkSessionDoc | ||
| - Title: ASIM | ||
| Link: https://aka.ms/AboutASIM | ||
| - Title: Amazon GuardDuty finding types | ||
| Link: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-active.html | ||
| - Title: Amazon GuardDuty finding format | ||
| Link: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-format.html | ||
| Description: | | ||
| This ASIM parser supports normalizing AWS GuardDuty findings that carry network context (service.action.networkConnectionAction or service.action.awsApiCallAction) to the ASIM Network Session normalized schema. Findings are ingested through the Microsoft Sentinel AWS S3 connector into the AWSGuardDuty table; findings without network context (for example, pure S3 policy or EKS control-plane findings) are filtered out by this parser and are better served by AssumedRole/S3/EKS-specific content. | ||
| ParserName: ASimNetworkSessionAWSGuardDuty | ||
| EquivalentBuiltInParser: _ASim_NetworkSession_AWSGuardDuty | ||
| ParserParams: | ||
| - Name: disabled | ||
| Type: bool | ||
| Default: false | ||
| ParserQuery: | | ||
| let parser = (disabled: bool = false) { | ||
| AWSGuardDuty | ||
| | where not(disabled) | ||
| // Only findings that carry network context are in scope for this parser. | ||
| // (DNS_REQUEST is intentionally excluded: GuardDuty's dnsRequestAction has no | ||
| // remoteIpDetails, so it cannot be normalized to a network session here.) | ||
| | extend ActionType_ = tostring(ServiceDetails.action.actionType) | ||
| | where ActionType_ in ("NETWORK_CONNECTION", "AWS_API_CALL", "PORT_PROBE") | ||
| | extend | ||
| NetworkAction_ = ServiceDetails.action.networkConnectionAction, | ||
| ApiCallAction_ = ServiceDetails.action.awsApiCallAction, | ||
| PortProbeAction_ = ServiceDetails.action.portProbeAction | ||
| // A port-probe finding can list several probed ports/remote IPs; expand so each probe | ||
| // becomes its own normalized session instead of silently keeping only the first. This is a | ||
| // no-op for other action types (PortProbeAction_ is null, so mv-expand yields one row unchanged). | ||
| | mv-expand PortProbeDetail_ = PortProbeAction_.portProbeDetails | ||
| // The IP GuardDuty flagged as the other party in the session (not yet Src/Dst - direction is resolved below). | ||
| | extend RemoteDetails_ = case( | ||
| ActionType_ == "NETWORK_CONNECTION", NetworkAction_.remoteIpDetails, | ||
| ActionType_ == "AWS_API_CALL", ApiCallAction_.remoteIpDetails, | ||
| ActionType_ == "PORT_PROBE", PortProbeDetail_.remoteIpDetails, | ||
| dynamic(null) | ||
| ) | ||
| | extend RemoteIp_ = tostring(RemoteDetails_.ipAddressV4) | ||
| | where isnotempty(RemoteIp_) | ||
| | extend | ||
| InstanceDetails_ = ResourceDetails.instanceDetails, | ||
| NetIf0_ = ResourceDetails.instanceDetails.networkInterfaces[0] | ||
| // Local (AWS-side) and remote port, and connection direction. AWS_API_CALL has no local | ||
| // network peer (it targets an AWS control-plane API, not a traceable endpoint), and | ||
| // PORT_PROBE is always effectively inbound - GuardDuty does not report a port for the prober. | ||
| | extend | ||
| LocalIp_ = coalesce(tostring(NetIf0_.privateIpAddress), tostring(NetIf0_.publicIp), ""), | ||
| LocalPort_ = case( | ||
| ActionType_ == "NETWORK_CONNECTION", toint(NetworkAction_.localPortDetails.port), | ||
| ActionType_ == "PORT_PROBE", toint(PortProbeDetail_.localPortDetails.port), | ||
| int(null) | ||
| ), | ||
| RemotePort_ = case( | ||
| ActionType_ == "NETWORK_CONNECTION", toint(NetworkAction_.remotePortDetails.port), | ||
| int(null) | ||
| ), | ||
| IsApiCall_ = ActionType_ == "AWS_API_CALL", | ||
| IsInbound_ = ActionType_ == "PORT_PROBE" | ||
| or (ActionType_ == "NETWORK_CONNECTION" and tostring(NetworkAction_.connectionDirection) == "INBOUND") | ||
| // ASIM event metadata | ||
| | extend | ||
| EventStartTime = TimeCreated, | ||
| EventEndTime = TimeCreated, | ||
| EventType = "NetworkSession", | ||
| EventSchema = "NetworkSession", | ||
| EventSchemaVersion = "0.2.6", | ||
| EventVendor = "AWS", | ||
| EventProduct = "GuardDuty", | ||
| EventProductVersion = SchemaVersion, | ||
| EventCount = toint(1), | ||
| EventResult = case( | ||
| ActionType_ == "PORT_PROBE", "Failure", | ||
| tobool(NetworkAction_.blocked) == true, "Failure", | ||
| "Success" | ||
| ), | ||
| EventSeverity = case( | ||
| Severity >= 7, "High", | ||
| Severity >= 4, "Medium", | ||
| Severity >= 1, "Low", | ||
| "Informational" | ||
| ), | ||
| EventOriginalSeverity = tostring(Severity), | ||
| EventMessage = Title, | ||
| EventOriginalType = ActivityType, | ||
| EventOriginalUid = Id, | ||
| EventUid = strcat("guardduty-", Id) | ||
| // Source/destination, resolved by direction. Inbound & port-probe: the remote party | ||
| // initiated, so it is Src and the AWS resource is Dst. Outbound: the reverse. AWS_API_CALL: | ||
| // the caller is always Src; there is no meaningful destination endpoint to report. | ||
| | extend | ||
| SrcIpAddr = case(IsApiCall_, RemoteIp_, IsInbound_, RemoteIp_, LocalIp_), | ||
| DstIpAddr = case(IsApiCall_, "", IsInbound_, LocalIp_, RemoteIp_), | ||
| SrcPortNumber = case(IsApiCall_, int(null), IsInbound_, RemotePort_, LocalPort_), | ||
| DstPortNumber = case(IsApiCall_, int(null), IsInbound_, LocalPort_, RemotePort_), | ||
| SrcHostname = case(IsApiCall_ or IsInbound_, "", tostring(InstanceDetails_.instanceId)), | ||
| DstHostname = case(not(IsApiCall_) and IsInbound_, tostring(InstanceDetails_.instanceId), ""), | ||
| SrcDvcId = case(IsApiCall_ or IsInbound_, "", tostring(InstanceDetails_.instanceId)), | ||
| DstDvcId = case(not(IsApiCall_) and IsInbound_, tostring(InstanceDetails_.instanceId), ""), | ||
| SrcDomain = case(IsApiCall_ or IsInbound_, "", tostring(NetIf0_.vpcId)), | ||
| DstDomain = case(not(IsApiCall_) and IsInbound_, tostring(NetIf0_.vpcId), ""), | ||
| SrcGeoCountry = case(IsApiCall_ or IsInbound_, tostring(RemoteDetails_.country.countryName), ""), | ||
| DstGeoCountry = case(not(IsApiCall_) and not(IsInbound_), tostring(RemoteDetails_.country.countryName), ""), | ||
| SrcGeoCity = case(IsApiCall_ or IsInbound_, tostring(RemoteDetails_.city.cityName), ""), | ||
| DstGeoCity = case(not(IsApiCall_) and not(IsInbound_), tostring(RemoteDetails_.city.cityName), ""), | ||
| SrcDescription = case(IsApiCall_ or IsInbound_, tostring(RemoteDetails_.organization.org), ""), | ||
| DstDescription = case(not(IsApiCall_) and not(IsInbound_), tostring(RemoteDetails_.organization.org), "") | ||
| | extend | ||
| SrcDvcIdType = iff(isnotempty(SrcDvcId), "Other", ""), | ||
| DstDvcIdType = iff(isnotempty(DstDvcId), "Other", ""), | ||
| SrcDomainType = iff(isnotempty(SrcDomain), "Other", ""), | ||
| DstDomainType = iff(isnotempty(DstDomain), "Other", "") | ||
| // Network fields. NetworkApplicationProtocol is derived from the destination port, | ||
| // i.e. whichever side holds the well-known service port once direction is resolved. | ||
| | extend | ||
| NetworkProtocol = toupper(tostring(coalesce(NetworkAction_.protocol, dynamic("")))), | ||
| // Derived from the same direction logic as Src/Dst above, not just connectionDirection, | ||
| // since NetworkAction_ (and so connectionDirection) is null for PORT_PROBE and AWS_API_CALL. | ||
| NetworkDirection = case( | ||
| IsApiCall_, "Unknown", | ||
| IsInbound_, "Inbound", | ||
| ActionType_ == "NETWORK_CONNECTION" and tostring(NetworkAction_.connectionDirection) == "OUTBOUND", "Outbound", | ||
| "Unknown" | ||
| ), | ||
| NetworkSessionId = Id, | ||
| // Not zero - GuardDuty does not report byte/packet counts, so these are unknown, not measured zeros. | ||
| NetworkBytes = long(null), | ||
| NetworkPackets = long(null), | ||
| NetworkApplicationProtocol = case( | ||
| DstPortNumber == 80, "HTTP", | ||
| DstPortNumber == 443, "HTTPS", | ||
| DstPortNumber == 53, "DNS", | ||
| DstPortNumber == 22, "SSH", | ||
| DstPortNumber == 3389, "RDP", | ||
| "" | ||
| ) | ||
| // Device (the EC2 instance or resource the finding is about, when present) | ||
| | extend | ||
| DvcId = tostring(InstanceDetails_.instanceId), | ||
| DvcIdType = iff(isnotempty(tostring(InstanceDetails_.instanceId)), "Other", ""), | ||
| DvcHostname = tostring(InstanceDetails_.instanceId), | ||
| DvcOs = case( | ||
| tostring(InstanceDetails_.platform) == "windows", "Windows", | ||
| isnotempty(tostring(InstanceDetails_.platform)), tostring(InstanceDetails_.platform), | ||
| "" | ||
| ), | ||
| // Only NETWORK_CONNECTION carries a "blocked" flag; defaulting AWS_API_CALL/PORT_PROBE | ||
| // to "Allow" here would be a fabricated result, not an observed one. | ||
| DvcAction = case( | ||
| ActionType_ == "NETWORK_CONNECTION", iff(tobool(NetworkAction_.blocked) == true, "Deny", "Allow"), | ||
| "" | ||
| ), | ||
| DvcInterface = tostring(NetIf0_.networkInterfaceId) | ||
| // Threat fields - always point at the remote party GuardDuty actually flagged, | ||
| // regardless of which ASIM side (Src/Dst) it landed on above. | ||
| | extend | ||
| ThreatName = ActivityType, | ||
| ThreatRiskLevel = toint(Severity * 10), | ||
| ThreatOriginalRiskLevel = tostring(Severity), | ||
| ThreatField = iff(IsApiCall_ or IsInbound_, "SrcIpAddr", "DstIpAddr"), | ||
| ThreatIpAddr = RemoteIp_, | ||
| ThreatIsActive = true, | ||
| ThreatFirstReportedTime = TimeCreated, | ||
| ThreatLastReportedTime = TimeGenerated | ||
| // Rule fields | ||
| | extend | ||
| RuleName = ActivityType, | ||
| RuleNumber = int(0), | ||
| RuleAction = "Alert" | ||
| // AWS-specific context, packed for ASIM AdditionalFields | ||
| | extend AdditionalFields = bag_pack( | ||
| "AwsAccountId", AccountId, | ||
| "AwsRegion", Region, | ||
| "AwsPartition", Partition, | ||
| "VpcId", tostring(NetIf0_.vpcId), | ||
| "SubnetId", tostring(NetIf0_.subnetId), | ||
| "InstanceId", tostring(InstanceDetails_.instanceId), | ||
| "InstanceType", tostring(InstanceDetails_.instanceType), | ||
| "GuardDutyFindingArn", Arn, | ||
| "GuardDutyActionType", ActionType_, | ||
| "RemoteAsn", tostring(RemoteDetails_.organization.asn), | ||
| "RemoteIsp", tostring(RemoteDetails_.organization.isp) | ||
| ) | ||
| | project | ||
| EventStartTime, EventEndTime, EventType, EventSchema, EventSchemaVersion, | ||
| EventVendor, EventProduct, EventProductVersion, EventCount, EventResult, | ||
| EventSeverity, EventOriginalSeverity, EventMessage, EventOriginalType, | ||
| EventOriginalUid, EventUid, | ||
| SrcIpAddr, SrcPortNumber, SrcHostname, SrcDvcId, SrcDvcIdType, SrcDomain, SrcDomainType, | ||
| SrcGeoCountry, SrcGeoCity, SrcDescription, | ||
| DstIpAddr, DstPortNumber, DstHostname, DstDvcId, DstDvcIdType, DstDomain, DstDomainType, | ||
| DstGeoCountry, DstGeoCity, DstDescription, | ||
| NetworkProtocol, NetworkDirection, NetworkSessionId, NetworkBytes, NetworkPackets, NetworkApplicationProtocol, | ||
| DvcId, DvcIdType, DvcHostname, DvcOs, DvcAction, DvcInterface, | ||
| ThreatName, ThreatRiskLevel, ThreatOriginalRiskLevel, ThreatField, ThreatIpAddr, | ||
| ThreatIsActive, ThreatFirstReportedTime, ThreatLastReportedTime, | ||
| RuleName, RuleNumber, RuleAction, | ||
| AdditionalFields, | ||
| TimeGenerated | ||
| }; | ||
| parser (disabled) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
...on Web Services/Hunting Queries/AWS_GuardDuty_EKSPrivilegeEscalationCredentialAccess.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| id: 869d2742-80d8-4b72-89ad-af31ea6b7437 | ||
| name: AWS GuardDuty - EKS privilege escalation and credential access | ||
| description: | | ||
| Identifies AWS GuardDuty findings against EKS/Kubernetes resources that indicate privilege escalation, credential access, or defense-evasion activity in a cluster (privileged containers, sensitive host-path mounts, anonymous or unusual API-server access, and instance-credential exfiltration from a node). Groups by cluster and Kubernetes identity so a hunter can see which workload or user is repeatedly implicated. | ||
| Reference: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-kubernetes.html | ||
| requiredDataConnectors: | ||
| - connectorId: AWSS3 | ||
| dataTypes: | ||
| - AWSGuardDuty | ||
| tactics: | ||
| - PrivilegeEscalation | ||
| - CredentialAccess | ||
| - Persistence | ||
| relevantTechniques: | ||
| - T1611 | ||
| - T1552 | ||
| - T1078 | ||
| query: | | ||
| AWSGuardDuty | ||
| | where ActivityType has "Kubernetes" | ||
| or ActivityType has_any ( | ||
| "PrivilegeEscalation:IAMUser/InstanceCredentialExfiltration", | ||
| "UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration" | ||
| ) | ||
| | extend | ||
| ThreatPurpose = tostring(split(ActivityType, ":")[0]), | ||
| ClusterName = tostring(ResourceDetails.eksClusterDetails.name), | ||
| ClusterArn = tostring(ResourceDetails.eksClusterDetails.arn), | ||
| K8sUserName = tostring(ResourceDetails.kubernetesDetails.kubernetesUserDetails.username), | ||
| K8sWorkload = tostring(ResourceDetails.kubernetesDetails.kubernetesWorkloadDetails.name), | ||
| K8sNamespace = tostring(ResourceDetails.kubernetesDetails.kubernetesWorkloadDetails.namespace), | ||
| InstanceId = tostring(ResourceDetails.instanceDetails.instanceId), | ||
| CallerIp = coalesce( | ||
| tostring(ServiceDetails.action.kubernetesApiCallAction.sourceIps[0]), | ||
| tostring(ServiceDetails.action.awsApiCallAction.remoteIpDetails.ipAddressV4) | ||
| ) | ||
| | extend Identity = coalesce(K8sUserName, InstanceId, "unknown") | ||
| | summarize | ||
| FindingCount = count(), | ||
| FindingTypes = make_set(ActivityType, 10), | ||
| Workloads = make_set_if(K8sWorkload, isnotempty(K8sWorkload), 10), | ||
| Namespaces = make_set_if(K8sNamespace, isnotempty(K8sNamespace), 10), | ||
| CallerIps = make_set_if(CallerIp, isnotempty(CallerIp), 10), | ||
| MaxSeverity = max(Severity), | ||
| FirstSeen = min(TimeCreated), | ||
| LastSeen = max(TimeGenerated) | ||
| by AccountId, Region, ThreatPurpose, ClusterName, ClusterArn, Identity | ||
| | order by MaxSeverity desc, FindingCount desc | ||
| entityMappings: | ||
| - entityType: CloudApplication | ||
| fieldMappings: | ||
| - identifier: AppId | ||
| columnName: AccountId | ||
| version: 1.0.2 |
43 changes: 43 additions & 0 deletions
43
...s/Amazon Web Services/Hunting Queries/AWS_GuardDuty_HighSeverityFindingsCrossAccount.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| id: d9329491-ab19-4903-aa0f-7affb388b011 | ||
| name: AWS GuardDuty - High severity findings clustered by account and actor | ||
| description: | | ||
| Surfaces AWS GuardDuty findings with severity 7.0 or higher, grouped by AWS account, activity family and the underlying actor (instance, IAM principal, or access key) so a hunter can quickly spot an account or identity generating a disproportionate share of high-severity activity, rather than triaging findings one at a time. | ||
| Reference: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_findings.html#guardduty_findings-severity | ||
| requiredDataConnectors: | ||
| - connectorId: AWSS3 | ||
| dataTypes: | ||
| - AWSGuardDuty | ||
| tactics: | ||
| - Discovery | ||
| - InitialAccess | ||
| relevantTechniques: | ||
| - T1580 | ||
| query: | | ||
| AWSGuardDuty | ||
| | where Severity >= 7.0 | ||
| | extend | ||
| ThreatPurpose = tostring(split(ActivityType, ":")[0]), | ||
| ResourceType = tostring(ResourceDetails.resourceType), | ||
| InstanceId = tostring(ResourceDetails.instanceDetails.instanceId), | ||
| AccessKeyUserName = tostring(ResourceDetails.accessKeyDetails.userName), | ||
| RemoteIp = coalesce( | ||
| tostring(ServiceDetails.action.networkConnectionAction.remoteIpDetails.ipAddressV4), | ||
| tostring(ServiceDetails.action.awsApiCallAction.remoteIpDetails.ipAddressV4) | ||
| ) | ||
| | extend Actor = coalesce(AccessKeyUserName, InstanceId, "unknown") | ||
| | summarize | ||
| FindingCount = count(), | ||
| DistinctFindingTypes = dcount(ActivityType), | ||
| FindingTypes = make_set(ActivityType, 10), | ||
| RemoteIps = make_set_if(RemoteIp, isnotempty(RemoteIp), 10), | ||
| FirstSeen = min(TimeCreated), | ||
| LastSeen = max(TimeGenerated) | ||
| by AccountId, Region, ThreatPurpose, ResourceType, Actor | ||
| | where FindingCount >= 2 | ||
| | order by FindingCount desc | ||
| entityMappings: | ||
| - entityType: CloudApplication | ||
| fieldMappings: | ||
| - identifier: AppId | ||
| columnName: AccountId | ||
| version: 1.0.2 |
47 changes: 47 additions & 0 deletions
47
Solutions/Amazon Web Services/Hunting Queries/AWS_GuardDuty_S3PublicExposure.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| id: 81ff8c3c-b7c1-40ff-9389-800fcf2d484e | ||
| name: AWS GuardDuty - Publicly exposed or weakly protected S3 buckets | ||
| description: | | ||
| Identifies AWS GuardDuty findings that flag an S3 bucket becoming publicly accessible, having public-access-block protections disabled, or showing anomalous discovery/exfiltration activity against its objects. Groups by bucket so a hunter can see the full sequence of policy-weakening and access events against a single bucket over the lookback period. | ||
| Reference: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-s3.html | ||
| requiredDataConnectors: | ||
| - connectorId: AWSS3 | ||
| dataTypes: | ||
| - AWSGuardDuty | ||
| tactics: | ||
| - Exfiltration | ||
| - Discovery | ||
| - DefenseEvasion | ||
| relevantTechniques: | ||
| - T1530 | ||
| - T1580 | ||
| query: | | ||
| AWSGuardDuty | ||
| | where ResourceDetails.resourceType == "S3Bucket" | ||
| and ActivityType has_any ("Policy:S3", "Exfiltration:S3", "Discovery:S3", "Impact:S3", "Stealth:S3") | ||
| | extend | ||
| ThreatPurpose = tostring(split(ActivityType, ":")[0]), | ||
| BucketName = tostring(ResourceDetails.s3BucketDetails[0].name), | ||
| BucketArn = tostring(ResourceDetails.s3BucketDetails[0].arn), | ||
| PublicAccessEffective = tostring(ResourceDetails.s3BucketDetails[0].publicAccess.effectivePermission), | ||
| ActorUserName = tostring(ResourceDetails.accessKeyDetails.userName), | ||
| CallerIp = tostring(ServiceDetails.action.awsApiCallAction.remoteIpDetails.ipAddressV4) | ||
| // A missing/empty s3BucketDetails array would otherwise collapse every unrelated finding | ||
| // without a bucket ARN into one bogus group. | ||
| | where isnotempty(BucketArn) | ||
| | summarize | ||
| FindingCount = count(), | ||
| FindingTypes = make_set(ActivityType, 10), | ||
| PublicAccessStates = make_set_if(PublicAccessEffective, isnotempty(PublicAccessEffective), 5), | ||
| Actors = make_set_if(ActorUserName, isnotempty(ActorUserName), 10), | ||
| CallerIps = make_set_if(CallerIp, isnotempty(CallerIp), 10), | ||
| MaxSeverity = max(Severity), | ||
| FirstSeen = min(TimeCreated), | ||
| LastSeen = max(TimeGenerated) | ||
| by AccountId, Region, ThreatPurpose, BucketName, BucketArn | ||
| | order by MaxSeverity desc, FindingCount desc | ||
| entityMappings: | ||
| - entityType: CloudApplication | ||
| fieldMappings: | ||
| - identifier: AppId | ||
| columnName: AccountId | ||
| version: 1.0.2 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.