// HackTheBox  ·  writeup

OpTinselTrace24-3: Blizzard Breakdown

HackTheBox Medium grepstringsPECmdregipyPython
Cloud

Scenario

In this scenario, players are tasked with identifying and investigating insider threats by analyzing various artifacts, while also learning how to conduct an AWS incident analysis.

Executive Summary

A victim was talked into running a remote-access tool and sharing its connection ID over IRC, which let an outside operator take control of the workstation. From the desktop the operator read an AWS access key out of a Sticky Notes database and used it from their own IP against a single S3 bucket. CloudTrail shows the operator suspending bucket versioning to remove the rollback path, requesting expedited restores of archived objects, and attempting to delete the largest data file, which was denied. They finished by overwriting objects with corrupted copies uploaded in the original storage class so the change would look routine. The workstation triage and the CloudTrail log together cover the whole chain.

Artifacts

Timestamp note: The remote-access tool logs in the workstation’s local time (UTC-8). CloudTrail is UTC. Any answer asking for UTC from a workstation log needs converting first.

Command and Control

Q1 — The Victim Elf shared credentials that allowed the Rogue Elf to access the workstation. What was the Client ID that was shared?

The IceChat logs hold the private conversation between the victim and the operator. In the Query folder, the log for 2024-11-13 shows the victim typing a number in a spaced-out format at 04:20. That is the remote-access client ID, and it is submitted as digits only.

grep -riE "[0-9]{2,3} [0-9]{3} [0-9]{3}" IceChat/Logs/Query/

Gotcha: The ID is typed with spaces in the chat, but the answer format is eight characters, so strip them.

Click flag to reveal 95192516
Q3 — What is the name of the executable the victim ran to enable remote access to their system?

The remote-access tool left its own directory on disk, and Prefetch confirms it actually ran. Parse the matching .pf file with PECmd for the executable name and last run time. The run time of 12:07 UTC lines up with the chat conversation, which also pins down the host timezone in Q4.

PECmd -f AA_V3.EXE-2B85CCB4.pf
Click flag to reveal AA_V3.EXE
Q4 — What time (UTC) did the Rogue Elf connect to the victim's workstation?

The tool’s access.log records the inbound connection, but in local time (04:23:34). From Q3, Prefetch shows the first run at 12:07 UTC while the chat shows the same moment at 04:07, so the host sits at UTC-8 and the connection is eight hours later in UTC. This offset was reasoned from that correlation rather than read from the registry, because regipy could not return the TimeZoneInformation key from the SYSTEM hive.

cat access.log
.venv/bin/python3 -I -c "import sys; from regipy.registry import RegistryHive; print(RegistryHive(sys.argv[1]).get_key('ControlSet001\\Control\\TimeZoneInformation').get_values())" SYSTEM

Gotcha: The raw access.log time is the local clock. The date is the same either way, but the hour is wrong for a UTC answer.

Click to reveal answer 2024-11-13 12:23:34
Q2 — What is the IP address of the Rogue Elf used during the attack?

Every CloudTrail event made with the stolen key carries the same sourceIPAddress, and no other address appears for that access key. The same address also appears next to the operator’s nickname in a WHOIS line in the IRC logs.

python3 -I -c "import json,collections as c; print(c.Counter(json.loads(l).get('sourceIPAddress') for l in open('work/ct.jsonl')))"
Click to reveal answer 146.70.202.35

Credential Access

Q5 — The Rogue Elf compromised an AWS Access Key. What is the AWS Access Key ID obtained from the victim's workstation?

Access key IDs start with AKIA and are 20 characters long. The collection includes the Sticky Notes plum.sqlite database, whose recent edits sit in the write-ahead log, so run strings over the -wal file and match the key pattern. The same ID is the principal in the CloudTrail events, which ties the stolen key to the S3 activity.

strings -n 8 plum.sqlite-wal | grep -oE "AKIA[A-Z0-9]{16}"
Click flag to reveal AKIA52GPOBQCBFYGAYHI

Collection

Q6 — Which S3 bucket did the Rogue Elf target during the incident?

Filter the merged CloudTrail file to the key from Q5 and count the bucketName request parameter. One bucket accounts for all the activity.

python3 -I -c "import json,collections as c; print(c.Counter((json.loads(l).get('requestParameters') or {}).get('bucketName') for l in open('work/ct.jsonl') if 'AKIA52GPOBQCBFYGAYHI' in l))"
Click to reveal answer arctic-archive-freezer
Q7 — Within the targeted S3 bucket, what is the name of the main directory where the files were stored?

Object-level events (GetObject, RestoreObject, PutObject) carry the object key in requestParameters.key. The first path segment of every key is the main directory.

python3 -I -c "import json,collections as c; print(c.Counter(((json.loads(l).get('requestParameters') or {}).get('key') or '').split('/')[0] for l in open('work/ct.jsonl')))"
Click flag to reveal Claus_Operation_Data

Impact

Q8 — What time (UTC) did the Rogue Elf disable versioning for the S3 bucket?

Versioning is controlled by PutBucketVersioning. The request body sets the status to Suspended, and CloudTrail eventTime is already UTC.

python3 -I -c "import json; [print(e['eventTime'], e['eventName'], e['requestParameters']) for e in map(json.loads, open('work/ct.jsonl')) if e['eventName']=='PutBucketVersioning']"
Click to reveal answer 2024-11-13 15:31:15
Q9 — What is the MITRE ATT&CK Technique ID associated with the method used in Question 8?

Suspending versioning stops S3 keeping prior object versions, which removes the victim’s ability to roll back later overwrites and deletes. ATT&CK files that under Inhibit System Recovery.

Gotcha: T1562 (Impair Defenses) looks like the natural fit for “turning off a protection”, but the question wants the recovery-focused technique.

Click flag to reveal T1490
Q10 — What time (UTC) was the first restore operation successfully initiated for the S3 objects?

The objects sit in an archive storage class, so reading them first needs RestoreObject. List every RestoreObject event in order. The earliest attempts carry an error and started nothing; the first event without an errorCode is the successful one.

python3 -I -c "import json; [print(e['eventTime'], e.get('errorCode'), (e.get('requestParameters') or {}).get('key')) for e in map(json.loads, open('work/ct.jsonl')) if e['eventName']=='RestoreObject']"

Gotcha: The first RestoreObject calls fail with KeyTooLongError. Skip them.

Click to reveal answer 2024-11-13 15:43:49
Q11 — Which retrieval option did the Rogue Elf use to restore the S3 objects?

The RestoreObject request body includes a RestoreRequest with a Tier field. It names the retrieval option.

python3 -I -c "import json; [print((e.get('requestParameters') or {}).get('RestoreRequest')) for e in map(json.loads, open('work/ct.jsonl')) if e['eventName']=='RestoreObject']"
Click flag to reveal expedited
Q12 — What is the filename of the S3 object that the Rogue Elf attempted to delete?

A DeleteObject event with an AccessDenied error code marks an attempt that did not succeed. It was made at 16:04:09 UTC, and the key in the request is the target.

python3 -I -c "import json; [print(e['eventTime'], e.get('errorCode'), e['requestParameters']) for e in map(json.loads, open('work/ct.jsonl')) if e['eventName']=='DeleteObject']"
Click to reveal answer GiftList_Worldwide.csv
Q13 — What is the size (MB) of the S3 object that the Rogue Elf targeted in Question 12?

CloudTrail has no object size field, but the GetObject events for the Q12 file record bytesTransferredOut. Summing them gives 159383552 bytes, which is 152 MiB (159383552 / 1048576). The size was derived from transfer counts rather than read from a bucket listing.

python3 -I -c "import json; print(sum(json.loads(l)['additionalEventData']['bytesTransferredOut'] for l in open('work/ct.jsonl') if '\"GetObject\"' in l and 'GiftList_Worldwide.csv' in l))"

Tip: Copy the byte count as raw text and divide by 1048576 once at the end. The format wants an integer.

Click flag to reveal 152
Q14 — The Rogue Elf uploaded corrupted files to the S3 bucket. What time (UTC) was the first object replaced during the attack?

Replacement shows up as PutObject calls into the targeted prefix. Sort the PutObject events by time and take the earliest.

python3 -I -c "import json; print(sorted(e['eventTime'] for e in map(json.loads, open('work/ct.jsonl')) if e['eventName']=='PutObject')[0])"
Click to reveal answer 2024-11-13 16:10:03
Q15 — What storage class was used for the S3 objects to mimic the original settings and avoid suspicion?

The PutObject request parameters include x-amz-storage-class. The corrupted uploads reuse the archive class of the originals.

python3 -I -c "import json,collections as c; print(c.Counter(((json.loads(l).get('requestParameters') or {}).get('x-amz-storage-class')) for l in open('work/ct.jsonl') if '\"PutObject\"' in l))"

Tip: The value in CloudTrail is upper case. The answer format is lower case.

Click flag to reveal glacier

Attack Summary

PhaseAction
Command and ControlVictim shares a remote-access client ID over IRC and runs the tool
Command and ControlOperator connects to the workstation
Credential AccessAWS access key read from the Sticky Notes database
CollectionStolen key used from the operator’s IP against one S3 bucket
ImpactBucket versioning suspended
ImpactExpedited restores of archived objects
ImpactDelete of the large CSV attempted and denied
ImpactObjects overwritten with corrupted files in the original storage class

Forensic Timeline

Timestamp (UTC)Event
2024-11-13 12:07Remote-access tool executed on the workstation (Prefetch)
2024-11-13 12:23:34Operator connects to the workstation
2024-11-13 15:31:15PutBucketVersioning sets versioning to suspended
2024-11-13 15:43:49First successful RestoreObject
2024-11-13 16:04:09DeleteObject on the CSV denied
2024-11-13 16:10:03First PutObject overwrite

IOCs

TypeValue
IP146.70.202[.]35
ExecutableAA_V3.EXE
Remote-access client ID95192516
AWS access keyAKIA52GPOBQCBFYGAYHI
S3 bucketarctic-archive-freezer
S3 prefixClaus_Operation_Data
Targeted objectGiftList_Worldwide.csv

MITRE ATT&CK

TechniqueIDDescription
Remote Access SoftwareT1219Remote-access tool run by the victim and used for the operator’s session
Unsecured Credentials: Credentials In FilesT1552.001AWS key stored in a Sticky Notes database
Valid Accounts: Cloud AccountsT1078.004Stolen key used from an external IP
Data from Cloud StorageT1530GetObject and RestoreObject against the bucket
Inhibit System RecoveryT1490Bucket versioning suspended
Data DestructionT1485Attempted delete of the large CSV
Data Manipulation: Stored Data ManipulationT1565.001Objects overwritten with corrupted files

Defender Takeaways

Long-lived access keys do not belong in a sticky note. The key sat in plain text on a workstation and worked from any IP. Use short-lived role credentials, and scan endpoints for AKIA strings.

Alert on PutBucketVersioning with a suspended status. It is rare and high-signal, and here it came well before the destructive steps. Pair it with MFA Delete or an SCP that denies it, and keep Object Lock on critical buckets.

Watch the key’s source IP. All the malicious activity came from one external address. An IP condition on the access key policy, or a GuardDuty finding for unusual use, would have flagged it.

Treat archive restores and overwrites as events. RestoreObject on an archive tier followed by PutObject matching the original storage class is deliberate. Data-event logging on the bucket is what made this reconstruction possible.

Remote-access tools run by users need controls. The victim shared a connection ID in chat and handed over the desktop. Application control on unapproved remote-access tools and user training close that entry point.

Conclusion

The operator went from a chat message to a tampered S3 bucket in a few hours, using only a key from a sticky note and one remote-access session. The sharpest lesson is the order of operations: versioning was suspended before anything was restored, deleted or overwritten, so that first event was the warning.