CloudTrail Hunt: BTLO AWeSome Lab Walkthrough
For SecureNetDynamics, the dreaded security nightmare of a ransomware attack became reality when dev_harry accidentally pushed AWS access…
CloudTrail Hunt: BTLO AWeSome Lab Walkthrough

For SecureNetDynamics, the dreaded security nightmare of a ransomware attack became reality when dev_harry accidentally pushed AWS access keys to production. Within moments, a threat actor seized the credentials, mapped out the company’s AWS cloud architecture, and looted S3 buckets for elevated keys. After securing persistence, the attacker dropped the hammer that brought operations to a screeching halt.
Below is the full forensic breakdown of how the breach occurred and how I investigated the digital footprints left in the logs for this BTLO Investigation Lab.
Question-1: When was the first successful activity seen from the compromised AWS User as per logs? (Format: YYYY-MM-DD HH:MM:SS UTC)
Before diving blindly into the logs, I reviewed the lab scenario description to gather initial threat intelligence. The overview specifically highlighted a developer with the username dev_harry. With this pivot point established, my first instinct was to isolate the CloudTrail logs (index=cloudtrail) associated with this user.
Analyzing the userAgentstrings across the filtered dataset immediately revealed two distinct patterns:
- The vast majority of requests corresponding to this username originated from automated scripts utilizing Boto3 (the AWS SDK for Python) → This is going to be the baseline.
- A smaller subset of events stood out because they were executed directly via the AWS Command Line Interface.
Recognizing that an external attacker leveraging compromised keys would likely utilize the CLI for manual reconnaissance, I targeted these specific events using the following Splunk query:
index=cloudtrail “dev_harry”
| where like(userAgent, “%aws-cli%”)
| sort eventTime
Sorting the results chronologically (using the eventTime field instead of _time with reference to the README file from the team) exposed the earliest activity. The very first event in the timeline confirmed the threat actor’s initial successful API call (made to query the meta data of EC2 instances owned by dev_harry).
From this log entry, the required timestamp was extracted: 2024-08-20 06:04:15 UTC.

Timestamp of the first successful activity from the compromised AWS user account of dev_harry.
Question-2: What was the Source IP address associated with the activities? (Format: IP Address)
Building directly upon the findings from the first question, I expanded the details of that initial anomalous AWS CLI event. Within the log structure, the network origin of the threat actor’s infrastructure was explicitly recorded in the sourceIPAddress field.

Expanded view of the log to show the IP address of the attacker, recording the first activity from the compromised AWS user’s account.
In fact, cross-referencing the logs (using the fields sidebar) confirmed that this specific IP (**3.144.171.70**) was the sole source address responsible for every single manual AWS CLI interaction attributed to the dev_harry account.

Fields sidebar listing the source IP address belonging to the threat actor.
Question-3: The attacker performed further enumeration and found an AMI image that the compromised user had access to. This AMI was used to create EC2 Instances. Find the AMI-ID. (Format: AMI-ID)
Since the question states that the attacker already managed to create EC2 instances using the stolen AMI image, I thought, why not look for machines spawned using that AMI-ID that were spawned AFTER 06:04:15 AM (the time corresponding to the attacker’s first activity in the logs), instead of looking for the logs corresponding to the enumeration efforts that led to the revelation of the said AMI-ID?
Using the query below, I filtered the events to remove those that corresponded to any unsuccessful attempts at launching the instances while using eventName=RunInstances, since this API call launches one or more Amazon EC2 instances using a specified Amazon Machine Image or AMI:
index=cloudtrail “dev_harry”
| where like(userAgent, “%aws-cli%”)
| search eventName=RunInstances NOT errorCode=*
| sort eventTime
This resulted in 1 event with the required AMI ID listed under the requestParameters field for a machine spawned with monitoring disabled (suspicious indeed).

CloudTrail log entry showing the imageId payload matching the target AMI, alongside intentionally disabled instance monitoring.

Inspecting the requestParameters.instancesSet.items{}.imageId field in Splunk to quickly isolate and verify the compromised AMI ID used by the attacker.
Question-4: The attacker changed the ingress rule of a security group, allowing everyone to connect through any port. Find this Security Group ID. (Format: Security Group ID)
At 06:32, a DescribeSecurityGroups API call ran, which was likely the attacker performing reconnaissance. As a result, I began my investigation for this question by first trying to look for any modifications in existing security groups’ ingress rules by focusing my query around API Calls for ModifySecurityGroupRules but got 0 events.
That led me to think, what if a new security group was added altogether? To check out the details of this activity, I used the following query:
index=”cloudtrail” “dev_harry” eventName=”AuthorizeSecurityGroupIngress”
|sort eventTime
(The reason why I chose this particular Event Name was because this API call is logged whenever there is an addition of a new inbound rule, as per AWS Documentation.)
Looking at the requestParameters field in the resulting log event, the specifications of the log entry at 06:36:37 completely gave away the malicious change. The groupId was explicitly marked as **sg-085becd1c5d4f7621*, and under the IP permissions, fromPortwas set to 0 with a cidrip of 0.0.0.0/0* over TCP — effectively opening the floodgates for anyone to connect through any port.

Security group configuration showing the wide-open ingress parameters, allowing unrestricted global access (0.0.0.0/0) via port 0.
Question-5: Attacker after further enumeration found the Console Login credentials of a user. What is the name of the user? (Format: Username)
To track down the compromised console credentials, I began by filtering for events that took place after the security group backdoor was created at 06:36:37. I executed the following query:
index=”cloudtrail” “dev_harry” eventTime>”2024–08–20T06:36:00Z”
| sort eventTime
Since the question specifically states that the attacker found Console Login credentials, I shifted my focus to filtering based on eventName=ConsoleLogin.
This filter returned 3 events. Looking closely at the results, 2 of those logins were from the internal cloud security team. However, the last event stood out because it was performed by a user with the username dev-neo, and the ConsoleLogin response status was explicitly marked as a success.
Checking the userIdentity block confirmed the target IAM user ARN as arn:aws:iam::764581110688:user/dev-neo.

CloudTrail log entry corresponding to the first, successful login performed by the attacker via the Console using another user’s compromised credentials.
Question-6: From which IP was this login originated? (Format: IP Address)
Referencing back to the screenshot from the user dev-neo’s successful console login, the sourceIPAddress field explicitly revealed the source IP as **103.99.35.120**.
Question-7: What policy was attached to escalate access for this compromised user? (Format: Policy ARN)
For this question, I simply focused on the specific Event Name corresponding to the attachment of a new or existing group access policy to a user, i.e., AttachUserPolicy.
I tried filtering for events corresponding to the aforementioned API Call, while making sure to filter out any unsuccessful attempts that may have been logged by the system to reduce noise. I ran the following query:
index="cloudtrail" eventName="AttachUserPolicy" NOT errorCode=*
| sort eventTime
This filtered the results to a single event that had the answer hidden inside the requestParameters.policyArn field: **arn:aws:iam::aws:policy/AdministratorAccess**

Expanded view of the CloudTrail log showing the Amazon Resource Name (ARN) of the policy attached to dev-neo to grant unrestricted, administrative access during privilege escalation attempts.
Question-8: The attacker downloaded a critical file from S3 Bucket using which an important instance can be accessed. What is the name of the File? (Format: Filename.extension)
For this question, I built the search query step-by-step in the following manner:
First, I filtered the events to include only those that happened after the privilege escalation step from the last question, i.e., eventTime>"2024-08-20T06:45:00Z".
Next, while the resulting set of events were 228 in count and quite a lot to individually search through, a cursory glance through the logs made me realize that those pertaining to S3 buckets shared a value of the eventSource field as s3.amazonaws.com. I added that to the query string.
This gave me a more focused list of values for the API calls or Event Names that were made corresponding to the S3 buckets. Thus, finally, referring to the AWS Documentation, I decided to set eventName=GetObject since it is used to retrieve file content and metadata from an S3 bucket.

Isolating the GetObject event name track down the specific file downloaded from the S3 bucket.
As a result, I used the following query string to get the answer as **devlopement-keys.pem **:
index=”cloudtrail” “dev-neo” eventSource=”s3.amazonaws.com” eventName=GetObject NOT errorCode=*
| sort eventTime

Expanded view of the log corresponding to the singular instance of the GetObject event, showing the file key (devlopement-keys.pem) downloaded by the attacker from the targeted S3 bucket.
Question-9: For more stealth access in the environment, the attackers created a user and a group with Administrative access. Find the username and groupname. (Format: Username, Groupname)
The question gives away quite a lot of information about where to begin. Since the attacker “created a user” and “created a group,” a quick Google search reveals that the appropriate API calls corresponding to the creation of a new user and a group are CreateUser and CreateGroup, respectively.
With that in mind, I ran the following queries to get to the answers (while focusing only on those events that led to a successful result):
index=”cloudtrail” eventName=”CreateUser” NOT errorCode=”AccessDenied”
| sort eventTime
index=”cloudtrail” eventName=”CreateGroup” NOT errorCode=”AccessDenied”
| sort eventTime
The user in question, dev_harry_bg, was created at 07:06:15 on 08–20–2024, while the new group’s creation was logged later at 07:07:13 on the same day.

CloudTrail log of the new user, dev_harry_bg, created by the attacker.

CloudTrail log of the new group, dev_group, created by the attacker.
In fact, a little later, the logs also indicate the addition of the new user to this new group at 07:08:33, as suggested by the screenshot below, corresponding to an API call made to AddUserToGroup.

CloudTrail log of the new user, dev_harry_bg being added to the dev_group group created by the attacker.
Question-10: The attacker got access to an Instance and a Ransomware Script was downloaded in it. Using the given Instance.zip as an artifact, identify the IP and port from where the file was downloaded. (Format: IP:Port/File.extension)
To find where the ransomware script was hosted, I needed to look inside the provided Instance.zip artifact. I knew the attacker must have used a standard command-line tool to pull the script onto the machine, so I figured it was either going to be curl or wget used to download the file.
To hunt this down quickly, I navigated to the directory and ran a recursive grep search across the files to look for those specific commands:
First, cd into the directory containing the artifact to explore, after extracting the Instance.zip file.
Then I recursively searched through the entire directory using the -r flag for grep, looking for possible command executions containing the wget or curl commands using grep -rw . -e “wget” .
The search paid off immediately and pointed me directly to a hit inside a user’s bash history file at /home/bitnami/.bash_history.

grep search results highlighting the malicious wget execution discovered inside the /home/bitnami/.bash_history log.
Looking at the extracted log entry, the command history explicitly captured the attacker executing a wget command to pull down a python script named a.py. From this specific line, I was able to extract the exact malicious hosting infrastructure: **3.144.171.70:8080/a.py**.
Question-11: The ransomware targeted only famous extension files. Find the Extension that was added to them post-encryption. (Format: Encryption Extension)
For this question, I once again took the assistance of the trusty old grep with a sprinkle of regex to recursively search through all of the files extracted in the Instance artifact directory for “famous” or the most commonly used file extensions that I could think of.
My objective was to build an expression that mimicked the name of a file to which an additional extension had been attached by ransomware, following the pattern of: <fileName>.<originalExtension>.<ransomwareEncryptionExt>.
This resulted in the following command that I ran to get the desired results:
grep -rnE “\.(docx|doc|jpeg|jpg|pdf|txt)\.[A-Za-z0–9_]+”

grep regex results matching the targeted double-extension pattern, revealing widespread .vdkx file encryption.
The first thing that popped out from the results was a considerable number of instances of .txt files carrying an additional extension of vdkx. The sheer number, as well as the type of files suggested by their names that fell "victim" to the encryption, made it easy to confidently conclude that the extension added by the ransomware was indeed **vdkx**.
메타데이터
- post_id
- 28468d641149
- slug
- cloudtrail-hunt-btlo-awesome-lab-walkthrough-28468d641149
- url
- https://medium.com/@v.g0blin/cloudtrail-hunt-btlo-awesome-lab-walkthrough-28468d641149
- canonical_url
- https://medium.com/@v.g0blin/cloudtrail-hunt-btlo-awesome-lab-walkthrough-28468d641149
- author_url
- https://medium.com/@v.g0blin
- status
- ok
- fetched_at
- 2026-06-17 08:20:12