Skip to content
← Rule library
high KQL AWS

Bulk Object Download From Cloud Storage

Reads are normal. Reads at volume by one principal across many objects in an hour, excluding principals whose baseline already moves data in bulk, are not.

Rule source

s3-bulk-download-exfil.kql
// Bulk Object Download From Cloud Storage
// T1567.002 - Exfiltration to Cloud Storage
// Reads are normal; reads at volume by one principal across many objects in a
// short window, from an IP that principal has not used before, are not.

let window      = 1h;
let min_objects = 500;

AWSCloudTrail
| where TimeGenerated > ago(window)
| where EventName in ("GetObject", "CopyObject")
| where isempty(ErrorCode)
| extend Bucket = tostring(parse_json(RequestParameters).bucketName)
| summarize
      Objects     = dcount(tostring(parse_json(RequestParameters).key)),
      Buckets     = make_set(Bucket, 10),
      SourceIPs   = make_set(SourceIpAddress, 5),
      FirstSeen   = min(TimeGenerated),
      LastSeen    = max(TimeGenerated)
    by UserIdentityArn, SourceIpAddress
| where Objects >= min_objects
| join kind=leftanti (
    // Principals that move data in bulk as their job - ETL, backup, replication.
    AWSCloudTrail
    | where TimeGenerated between (ago(30d) .. ago(window))
    | where EventName == "GetObject"
    | summarize Baseline = dcount(tostring(parse_json(RequestParameters).key))
        by UserIdentityArn
    | where Baseline > 10000
    | project UserIdentityArn
  ) on UserIdentityArn
| order by Objects desc

Required telemetry

AWS CloudTrail - GetObject and CopyObject data events

Confirm this source is arriving before you judge the rule. A detection built on telemetry you do not collect looks identical to one that simply never fires.

Known false positives

  • ETL, backup and replication principals - excluded by 30 day baseline, not by name
  • Analytics jobs that legitimately scan a bucket end to end

Validation

Scripted download of 800 objects from a lab bucket under a fresh IAM role

Re-run quarterly. Rules decay because the environment moves underneath them - agent upgrades, schema changes and config edits all break detections silently.