This note documents detection patterns related to AWS Account & Cloud Resource Abuse using CloudTrail and supporting telemetry.
Cloud attacks are not about binaries — they are about identity and API abuse.
Authentication → Identity Abuse → Privilege Escalation → Resource Access → Exfiltration → Cleanup
Triage with Splunk
# Install
docker pull splunk/splunk:latest
# Start (LOCALHOST ONLY - SAFE)
docker run -d --name splunk `
-p 127.0.0.1:8000:8000 `
-p 127.0.0.1:8089:8089 `
-e SPLUNK_GENERAL_TERMS=--accept-sgt-current-at-splunk-com `
-e SPLUNK_START_ARGS=--accept-license `
-e SPLUNK_PASSWORD="password" `
splunk/splunk
# Stop / Cleanup (burn after use mindset)
docker stop splunk
docker start splunk
docker rm splunk
Normalize JSON Records
# CloudTrail stores multiple events inside Records[]
# MUST flatten or Splunk will break parsing
# For non-compressed logs
find CloudTrail/ -name '*.json' -exec cat {} + | jq -c '.Records[]' > cloudtrail.json
# For .gz logs
find CloudTrail/ -name '*.json.gz' -exec zcat {} + | jq -c '.Records[]' > cloudtrail.json
Ingest with Splunk
# Enable delete (useful during iteration)
"Settings" -> "Roles" -> "admin" -> Tick "can_delete"
# Copy logs into container
docker cp TARGET_LOGS/ splunk:/
# Verify container
docker exec -it splunk bash
# Add data (IMPORTANT: ignore Digest logs)
"Home" -> "Add Data" -> "Monitor" -> "(Files & Directories)" -> "Finish"
# Timestamp Fix (CloudTrail = UTC)
"Timestamp" -> "Advanced" ->
"Time zone" = "GMT"
"Timestamp format" = "%Y-%m-%dT%H:%M:%SZ"
"Timestamp fields" = "eventTime"
# Prevent truncation of JSON
"Advanced" -> "New setting" ->
"TRUNCATE" = "0"
"Save As" -> "CloudTrail"
# Reset index during testing
* | delete
Key Fields
| Field | Why It Matters | What to Look For |
|---|---|---|
userIdentity.type | Identity context | IAMUser, AssumedRole, AWSService |
userIdentity.userName | Actor identity | Unexpected users, service accounts |
userIdentity.accessKeyId | Credential tracking | Pivot compromised keys |
userIdentity.sessionContext.sessionIssuer.userName | Role execution | Lambda / EC2 acting as role |
sourceIPAddress | Origin | Rare IPs, geo changes, non-AWS IPs |
userAgent | Execution method | aws-cli, Boto3, custom scripts |
eventSource | Service | IAM, S3, Lambda, CloudWatch |
eventName | Action | Core of detection |
awsRegion | Location | Unusual regions |
requestParameters.role | Role assignment | Detect PassRole abuse |
requestParameters.policyArn | Privilege changes | AdministratorAccess |
requestParameters.bucketName | Data target | Exfil location |
requestParameters.key | Object accessed | File-level visibility |
requestParameters.prefix | Targeted access | Directory-based exfil |
responseElements | Outcome | Success vs failure |
Direct Indicators
| Log Source | Event Name | Meaning | Forensic Value | Notes |
|---|---|---|---|---|
| CloudTrail | ConsoleLogin | Successful AWS login | Critical | Check MFAUsed, sourceIPAddress, responseElements.ConsoleLogin ("Success"), unusual geo/IP |
| CloudTrail | CreateUser | New IAM user created | Critical | Look at userIdentity, sourceIPAddress, immediate follow-up actions (keys/policies) |
| CloudTrail | CreateAccessKey | Access key created | Critical | Check userIdentity.userName, pivot on accessKeyId, often followed by CLI usage |
| CloudTrail | DeleteAccessKey | Access key removed | High | Could indicate cleanup or key rotation |
| CloudTrail | AttachUserPolicy | Policy attached to user | Critical | Inspect requestParameters.policyArn, look for AdministratorAccess |
| CloudTrail | PutUserPolicy | Inline policy added | Critical | Check requestParameters.policyDocument, often stealth escalation |
| CloudTrail | SetDefaultPolicyVersion | Policy version switched | Critical | Classic privesc, compare old vs new policy permissions |
| CloudTrail | AddUserToGroup | User added to group | Critical | Check group privileges (admin groups = escalation) |
| CloudTrail | CreateRole | New role created | High | Check trust policy (AssumeRolePolicyDocument) |
| CloudTrail | UpdateAssumeRolePolicy | Trust policy modified | Critical | Enables role abuse / cross-account access |
| CloudTrail | PassRole (implicit) | Role assigned to resource | Critical | NOT logged directly → infer via requestParameters.role in resource creation |
| CloudTrail | AssumeRole | Role assumed | Critical | Inspect userIdentity.sessionContext.sessionIssuer.userName, track lateral movement |
| CloudTrail | GetCallerIdentity | Identity check | Medium | Often attacker first action after gaining creds |
| CloudTrail | ListUsers / ListRoles | IAM enumeration | High | Recon phase, often follows initial access |
| CloudTrail | GetPolicyVersion | Policy inspection | High | Attacker reading permissions before escalation |
| CloudTrail | RunInstances | EC2 instance launched | Critical | Check requestParameters.iamInstanceProfile, attacker compute |
| CloudTrail | StartInstances | Instance started | High | Could indicate reusing existing infra |
| CloudTrail | StopInstances | Instance stopped | Medium | Anti-forensics / cost control |
| CloudTrail | TerminateInstances | Instance deleted | High | Cleanup / evidence destruction |
| CloudTrail | CreateFunction20150331 | Lambda created | Critical | Check requestParameters.role, handler, runtime, small codeSize suspicious |
| CloudTrail | Invoke | Lambda executed | Critical | Execution event → pivot to actions done by role |
| CloudTrail | UpdateFunctionCode | Lambda code modified | Critical | Payload update / persistence |
| CloudTrail | GetObject | Object downloaded from S3 | Critical | Check requestParameters.bucketName, object key, spike = exfil |
| CloudTrail | PutObject | Object uploaded to S3 | High | Check if external IP, staging/exfil |
| CloudTrail | DeleteObject | Object deleted | High | Anti-forensics |
| CloudTrail | ListBuckets | S3 enumeration | High | Often first step before exfil |
| CloudTrail | ListObjects / ListObjectsV2 | Object enumeration | Critical | Pre-exfil step, check prefix |
| CloudTrail | DeleteBucketReplication | Replication removed | High | Could disable persistence |
| CloudTrail | PutBucketReplication | Replication added | Critical | Data exfil persistence mechanism |
| CloudTrail | DeleteTrail | CloudTrail deleted | Critical | Logging disabled → attacker covering tracks |
| CloudTrail | StopLogging | Logging disabled | Critical | Immediate blindspot |
| CloudTrail | CreateTrail | New trail created | Medium | Could be attacker-controlled logging |
| CloudTrail | DeleteLogGroup | Logs deleted (CloudWatch) | Critical | Anti-forensics |
| CloudTrail | DescribeLogGroups | Log discovery | High | Attacker mapping logging |
| CloudTrail | DeleteDetector | GuardDuty disabled | Critical | Detection evasion |
| CloudTrail | ListDetectors | GuardDuty enumeration | High | Recon |
| CloudTrail | PutRolePolicy | Inline role policy added | Critical | Privilege escalation via roles |
| CloudTrail | AttachRolePolicy | Managed policy attached to role | Critical | Often used with AdministratorAccess |
| CloudTrail | CreateLoginProfile | Console password created | Critical | Enables interactive login |
| CloudTrail | UpdateAccessKey | Access key status change | High | May indicate persistence or cleanup |
Indirect Indicators (Behavioral Detection)
| Indicator | What To Look For | Forensic Value | Notes |
|---|---|---|---|
| Login from rare IP | New sourceIPAddress, new ASN, new country | Critical | Compare against historical IPs for that user; cloud attackers often rotate IPs |
| No MFA login | MFAUsed=false in ConsoleLogin | Critical | Especially suspicious for privileged users or console access |
| Suspicious UserAgent | aws-cli, Boto3, custom scripts, unusual clients | Critical | Human attackers often use aws-cli; compare vs expected service agents (Lambda, EC2) |
| Burst of IAM actions | Multiple IAM API calls in short timeframe | Critical | e.g. ListPolicies → GetPolicyVersion → SetDefaultPolicyVersion = privesc chain |
| New access key after login | CreateAccessKey shortly after auth | Critical | Indicates persistence; pivot on accessKeyId immediately |
| Policy attached to user | AttachUserPolicy, PutUserPolicy | Critical | Look for AdministratorAccess or broad * permissions |
| Policy version switch | SetDefaultPolicyVersion | Critical | Classic escalation — attacker activates more permissive version |
| Role assigned to resource | requestParameters.role in Create* events | Critical | Indicates iam:PassRole abuse (not logged directly) |
| AssumeRole anomalies | AssumeRole from new IP / unusual user | Critical | Check sessionIssuer, cross-account ARNs = lateral movement |
| Identity using multiple IPs | Same userIdentity.userName with many IPs | High | Indicates attacker hopping infrastructure |
| Same IP across multiple users | Single IP tied to many identities | High | Credential reuse / attacker infrastructure |
| Rapid API chaining | Many different eventName in seconds | Critical | Automated attacker scripts (not human clicking) |
| Unusual region activity | Events in new awsRegion | High | Attackers often use different regions |
| Lambda creation + execution | CreateFunction → Invoke close together | Critical | Payload deployment + execution |
| Small Lambda payload | codeSize very small (<1KB) | High | Often simple exfil scripts |
| S3 access spike | Many GetObject in short time | Critical | Data exfiltration |
| S3 prefix targeting | requestParameters.prefix used | Critical | Targeted data theft (e.g. CustomerB/2024-12-09/) |
| External IP + S3 access | GetObject from non-AWS IP | Critical | Strong exfil indicator |
| Unexpected role usage | Role used outside normal service | Critical | e.g. Lambda role used manually |
| CLI usage on service account | aws-cli for non-human account | Critical | Service accounts should not use CLI |
| GuardDuty activity | ListDetectors, DeleteDetector | Critical | Attacker discovering/disabling detection |
| Logging tampering | StopLogging, DeleteTrail, DeleteLogGroup | Critical | Equivalent to clearing logs |
| Resource cleanup after activity | TerminateInstances, Delete* | High | Anti-forensics |
| Short-lived sessions | Rapid start/stop activity | Medium | Failed attack or recon |
| Odd time activity | Outside business hours | High | Combine with other signals for confidence |
Quick Triage Queries
General
# Active Identities
index=* userIdentity.type!="AWSService"
| stats count by userIdentity.userName
| sort -count
# Source IP
index=*
| stats count by sourceIPAddress
| sort -count
# User Agent
index=*
| stats count by userAgent
| sort -count
# Full Timeline
index=* userIdentity.type!="AWSService"
| eval _time=strptime(eventTime, "%Y-%m-%dT%H:%M:%SZ")
| table _time userIdentity.userName eventName sourceIPAddress
| sort _time
Scrutiny
# On bucket
* requestParameters.bucketName="forela-fileshare"
| table eventName, _time, sourceIPAddress, userIdentity.arn
| sort _time
# By denied access failures
* sourceIPAddress="54.242.59.197" errorCode=AccessDenied
| table eventName, _time, userAgent, userIdentity.arn
| sort _time
Common Tools / Tradecraft
| Tool / Method | Usage |
|---|---|
| AWS CLI | Native attacker interface |
| boto3 / SDKs | Programmatic abuse |
| Stolen credentials | Initial access |
| IAM abuse | Privilege escalation |
| Terraform / scripts | Mass changes |
| Pacu | AWS exploitation framework |
| CloudSploit / ScoutSuite | Recon tools |
| Custom scripts | Automation |
Relevant Artifacts
Cloud Logs
- CloudTrail (PRIMARY)
- CloudTrail Insights (anomaly detection)
- CloudWatch Logs
IAM
- Users, Roles, Policies
- Access keys (active/inactive)
- Trust relationships
Storage (S3)
- Object access logs
- Bucket policies
- Public exposure settings
Compute (EC2)
- Instance metadata
- Security groups
- AMI usage
Network
- VPC Flow Logs
- Public IP activity
- Security group changes
Other
- AWS Config (resource changes)
- GuardDuty findings
- Route53 DNS logs
Decision Tree
-
Was there a login?
- ConsoleLogin
- MFA used?
- Source IP expected?
-
Identity abused?
- CreateAccessKey
- CreateUser
- AssumeRole
-
Privilege escalation?
- AttachUserPolicy
- PutUserPolicy
- UpdateAssumeRolePolicy
-
Discovery?
- ListUsers
- ListBuckets
- GetCallerIdentity
-
Resource abuse?
- RunInstances
- S3 access (GetObject)
-
Defense evasion?
- DeleteTrail
- StopLogging
-
Timeline correlation
- Login → IAM → Resource → Exfil
Attack Patterns
Credential Abuse + Exfil
GetCallerIdentity
→ ListBuckets
→ ListObjects
→ GetObject (mass)
Privilege Escalation via Policy
ListPolicies
→ GetPolicyVersion
→ SetDefaultPolicyVersion
→ AttachUserPolicy (Admin)
Lambda-Based Execution (Stealth)
CreateFunction
→ PassRole
→ Invoke
→ GetObject / IAM actions
Persistence via IAM
CreateUser
→ CreateAccessKey
→ AttachUserPolicy (Admin)
Defense Evasion
ListDetectors
→ DeleteDetector
→ DescribeLogGroups
→ DeleteLogGroup
→ StopLogging
MITRE ATT&CK References
- T1078 Valid Accounts
- T1098 Account Manipulation
- T1069 Permission Groups Discovery
- T1087 Account Discovery
- T1021 Remote Services (via AssumeRole)
- T1530 Data from Cloud Storage
- T1485 Data Destruction
- T1562 Impair Defenses