StopLogging cloudtrail.amazonaws.com CloudTrail

StopLogging in CloudTrail: When Someone Turns the Audit Trail Off

Published

A request to stop a trail recording and delivering logs; CloudTrail records the call itself, and the trail then records nothing until someone calls StartLogging.

AWS's description

Suspends the recording of AWS API calls and log file delivery for the specified trail. Under most circumstances, there is no need to use this action. You can update a trail without stopping it first. This action is the only way to stop recording. For a trail enabled in all Regions, this operation must be called from the Region in which the trail was created, or an InvalidHomeRegionException will occur. This operation cannot be called on the shadow trails (replicated trails in other Regions) of a trail enabled in all Regions.

Source: AWS API reference: StopLogging · copied from AWS's documentation and refreshed weekly

Request parameters

The parameters AWS's API reference documents for StopLogging. A key is shown only where AWS's example records show it, or where every CloudTrail example names keys after the parameter with a lower-case first letter.

API parameterRequiredIn the CloudTrail record
Name Yes requestParameters.name

Fields that matter in an investigation

FieldWhat it tells you
1requestParameters.name The trail that was stopped, by name or ARN. Check whether it is your main or only trail.
2userIdentity.arn Who stopped it. Outside a documented change, this identity should be treated as compromised.
3userIdentity.type IAMUser, AssumedRole or Root. A role session from a workload or a federated user doing this is rarer than an administrator, and more alarming.
4userIdentity.accessKeyId The key that signed the call, to list everything else it did before and after.
5sourceIPAddress Where the call came from. Compare with the identity's usual addresses and with any GetCallerIdentity from a new address shortly before.
6userAgent The client. A console session, a CLI or an SDK; attack frameworks often name themselves here.
7eventTime The moment the gap starts. Everything that trail did not record runs from here to the next StartLogging.
8awsRegion For a trail enabled in all Regions, AWS requires the call from the trail's home Region, so this is where to look for it.
errorCode Empty when it worked. AccessDenied, or InvalidHomeRegionException from the wrong Region, still means someone tried.
10recipientAccountId The account whose trail it was, which matters in multi-account CloudTrail collections.

Every field is checked on each build against AWS's CloudTrail record contents and userIdentity documentation and the example and recorded StopLogging records shown below.

What the record looks like

AWS does not publish an example StopLogging record; the record below was captured during an attack simulation.

Recorded during an attack simulation: Stratus Red Team technique aws.defense-evasion.cloudtrail-stop

{
"awsRegion": "apiso-centralnorth-2r",
"eventCategory": "Management",
"eventID": "10163ed2-2253-469d-a5ee-cbc6651f8934",
"eventName": "StopLogging",
"eventSource": "cloudtrail.amazonaws.com",
"eventTime": "2024-07-31T13:06:24Z",
"eventType": "AwsApiCall",
"eventVersion": "1.10",
"managementEvent": true,
"readOnly": false,
"recipientAccountId": "123456789012",
"requestID": "14c891b6-11b5-4787-ae97-64a974977078",
"requestParameters": {
"name": "stratus-red-team-ct-stop-trail-buykxbqejv"
},
"responseElements": null,
"sourceIPAddress": "203.0.113.10",
"tlsDetails": {
"cipherSuite": "TLS_AES_128_GCM_SHA256",
"clientProvidedHostHeader": "cloudtrail.apiso-centralnorth-2r.amazonaws.com",
"tlsVersion": "TLSv1.3"
},
"userAgent": "stratus-red-team_c97089f1-1ae3-4ecc-b006-f5e8fd0f2571",
"userIdentity": {
"accessKeyId": "AKIAIOSFODNN7EXAMPLE",
"accountId": "123456789012",
"arn": "arn:aws:iam::123456789012:user/operator",
"principalId": "AIDAOC1SYDVN0AF0FMMR",
"type": "IAMUser",
"userName": "operator"
}
}

Numbered lines are the fields in the table.

A real CloudTrail record from a test detonation, published by Stratus Red Team (Datadog, Apache License 2.0) and anonymized there; account IDs, addresses, access key IDs and session tokens are replaced here with AWS's documentation values, and the operator's user name with "operator". The anonymizer also changes values such as the Region.

What it records

StopLogging suspends recording and log delivery for one trail. AWS describes it as the only way to stop recording and notes that under most circumstances there is no need to use it, because a trail can be updated without stopping. CloudTrail records the call itself, with the trail in requestParameters.name, so the record marks the start of a gap: the trail records nothing more until a StartLogging call names it again.

For a trail enabled in all Regions, the call must come from the trail’s home Region, otherwise it fails with InvalidHomeRegionException, and it cannot be run against the replicated shadow trails in other Regions. The successful record is therefore in the home Region. Other trails, organization trails and the 90 days of management events in Event history are not affected.

When it matters

Turning the trail off is how an intruder makes the next steps invisible: stop logging, do the noisy part (create users, copy data, change policies), then restart logging to make the gap look like an outage. It is MITRE ATT&CK T1562.008 (disable or modify cloud logs), and outside a documented change every successful StopLogging is an incident.

  • Any success outside a change window, by any identity.
  • A failed attempt. AccessDenied or InvalidHomeRegionException still shows an identity trying to blind you.
  • The neighbours. DeleteTrail, UpdateTrail pointing logs at another bucket, PutEventSelectors that log less, and DeleteDetector in GuardDuty around the same time from the same identity are one campaign.

How to investigate

  1. Record who stopped which trail, from where and with which key (userIdentity, requestParameters.name, sourceIPAddress, userAgent).
  2. Measure the gap: from this eventTime to the next successful StartLogging for the same trail.
  3. Fill the gap from sources the attacker did not stop: Event history for management events, an organization trail or another trail, GuardDuty findings, VPC flow logs and service access logs.
  4. Read what the same key did before the stop. Preparation such as GetCallerIdentity, role assumptions and permission checks often comes minutes earlier.
  5. Restart the trail, deactivate the key or session, and restrict cloudtrail:StopLogging with a service control policy.

Every change to trails in Microsoft Sentinel, oldest first:

AWSCloudTrail
| where TimeGenerated > ago(30d)
| where EventName in ("StopLogging", "StartLogging", "DeleteTrail", "UpdateTrail", "PutEventSelectors")
| extend Request = parse_json(RequestParameters)
| extend Trail = coalesce(tostring(Request.name), tostring(Request.trailName))
| project TimeGenerated, EventName, Trail, UserIdentityArn, UserIdentityType, SourceIpAddress, UserAgent, ErrorCode, AWSRegion
| order by TimeGenerated asc

How long each trail stayed stopped:

AWSCloudTrail
| where TimeGenerated > ago(30d)
| where EventName in ("StopLogging", "StartLogging") and isempty(ErrorCode)
| extend Trail = tostring(parse_json(RequestParameters).name)
| order by Trail asc, TimeGenerated asc
| extend NextEvent = next(EventName), NextTime = next(TimeGenerated), NextTrail = next(Trail)
| where EventName == "StopLogging"
| extend RestartedAt = iff(NextEvent == "StartLogging" and NextTrail == Trail, NextTime, datetime(null))
| project StoppedAt = TimeGenerated, Trail, StoppedBy = UserIdentityArn, SourceIpAddress, RestartedAt,
    MinutesStopped = datetime_diff('minute', coalesce(RestartedAt, now()), TimeGenerated)

In Athena, over a table on the trail’s S3 bucket (named cloudtrail_logs here; a stopped trail delivers nothing new, so run this on another trail’s logs too):

SELECT eventtime, eventname, json_extract_scalar(requestparameters, '$.name') AS trail,
       useridentity.arn, sourceipaddress, errorcode, awsregion
FROM cloudtrail_logs
WHERE eventname IN ('StopLogging', 'StartLogging')
ORDER BY eventtime;

Related events

  • StartLogging CloudTrail
  • DeleteTrail CloudTrail
  • UpdateTrail CloudTrail
  • PutEventSelectors CloudTrail
  • DeleteDetector GuardDuty

Detect it

MITRE ATT&CK: T1562.008

Frequently Asked Questions

Does StopLogging also stop CloudTrail Event history?
No. StopLogging suspends one trail. Event history in the CloudTrail console keeps the last 90 days of management events in each Region whether or not any trail is logging, so management calls made during the gap can still be listed there, although data events and anything older than 90 days are not.
Why can I not find the StopLogging event in the Region I normally search?
AWS requires StopLogging for a trail enabled in all Regions to be called from the Region where the trail was created; from anywhere else it fails with InvalidHomeRegionException, and it cannot be called on the replicated shadow trails. Search the trail's home Region, or every Region of an organization trail.
Is StopLogging ever legitimate?
Rarely. AWS itself says that under most circumstances there is no need to use the action and that a trail can be updated without stopping it first. Planned decommissioning of a duplicate trail is the usual exception, and it should be change-ticketed and followed by DeleteTrail, not by a quiet StartLogging.
How do I stop this from happening at all?
Use an organization trail, which member accounts can see but not modify or delete, and a service control policy that denies cloudtrail:StopLogging, cloudtrail:DeleteTrail and cloudtrail:UpdateTrail to everyone but a break-glass role. Then alert on any attempt, since a denied StopLogging still identifies the compromised identity.

Find every StopLogging in your own CloudTrail logs

Load CloudTrail logs (the Records files CloudTrail writes to S3, or aws cloudtrail lookup-events output) into the free browser analyzer: logging changes, new access keys, administrator grants, root activity and failed console sign-ins are flagged, with event names linked to their pages here. Nothing is uploaded.