// HackTheBox  ·  writeup

Heartbreaker-Denouement

HackTheBox Easy targrepPythonCloudTrail
Cloud

Scenario

Your digital forensics expertise is critical to determine whether data exfiltration has occurred from the customer’s environment. Initial findings include a compromised AWS credential, indicating a potential unauthorized access. This investigation follows from a customer report of leaked data allegedly for sale on the darknet market. By examining the compromised server and analyzing the provided AWS logs, it will not only validate the customer’s breach report but also provide valuable insights into the attacker’s tactics, enabling a more comprehensive response.

Executive Summary

An external host fuzzed the victim’s web server with a wordlist until it found the application path, then abused a flaw in a PHP page to make the server fetch resources on the attacker’s behalf. The first fetches read local files, and the next reached the cloud instance metadata service. That yielded credentials for the instance role, while a separate leaked IAM user key was used from the same infrastructure. The actor ran identity and infrastructure discovery calls across several regions, read database contents from the server’s shell history, and created snapshots of two production RDS databases. The snapshots were then shared with an AWS account the actor controlled, which completed the exfiltration entirely inside the AWS API.

Artifacts

Format note: Q8 and Q11 want comma-separated values in ascending order, and Q8 only wants regions where the IAM user’s credentials succeeded.

Reconnaissance

Q1 — What type of scanning technique was used to discover the web path of the victim's web server? Specify the name of the corresponding MITRE sub-technique.

Extract the collection and open the Apache access.log. One source, 35.169.66.138, produces a burst of requests for random and dictionary-style paths that nearly all return 404, which is directory and file brute forcing from a wordlist. MITRE files that as an Active Scanning sub-technique (T1595.003), and the name of that sub-technique is the answer.

tar xzf uac -C work/tar
grep -c ' 404 ' access.log; grep 35.169.66.138 access.log | head
Click flag to reveal Wordlist Scanning
Q2 — It seems a web request possibly could have been rerouted, potentially revealing the web server's web path to the Threat Actor. What specific HTML status code might have provided this information?

Filter the log to everything that is not a 404 and look for redirects. The request for /index.php comes back with a 3xx, and a redirect is what discloses a real path to a scanner that was otherwise getting only misses.

grep -vE ' 404 ' access.log | grep -E ' 30[0-9] '
Click to reveal answer 301

Initial Access

Q3 — In the initial payload submitted by the threat actor exploiting a weakness in the web server, what file on the server was targeted?

The Apache error.log records the application’s Input: lines for the user-supplied value. The first one using a file:// scheme names the local file the actor tried to read before moving on to the metadata address. The format hint (****:///***/******) matches a file:/// URI.

grep 'Input:' error.log | head
Click flag to reveal file:///etc/passwd
Q4 — What is the name of the vulnerability exploited by the Threat Actor to access the cloud metadata?

The page passes user input straight into file_get_contents, so the server itself fetches whatever URL or path it is given. That lets an outside attacker reach 169.254.169.254, which is only routable from the instance. The grep for that address in the logs confirms the target.

grep -r '169.254.169.254' error.log access.log
Click to reveal answer Server Side Request Forgery

Credential Access

Q5 — What time (UTC) did the Threat Actor first access the cloud metadata service of the web server instance?

The first Input: entry in error.log pointing at http://169.254.169.254 gives the time. It is the first request to the metadata service, ahead of any credential path under it.

grep 'Input: http://169.254.169.254' error.log | head -1
Click flag to reveal 2024-03-13 14:06:21

Discovery

Q6 — To gain insight into the database content, can you provide the name of at least one table?

The server’s database client history lists what the actor, or the admin before them, queried. .mysql_history names the customer table directly. A raw string search across the extracted collection for table names leads to the same file.

cat .mysql_history

Tip: The format hint ends in o, which narrows the table name down before you open the file.

Click to reveal answer CustomerInfo
Q7 — Which AWS API call functions similarly to the 'whoami' command in Windows or Linux?

Reference knowledge: the STS call that returns the account, user ID and ARN of the calling credentials is the standard first move with stolen keys. It is GetCallerIdentity, and it needs no permissions, so it works with any valid key. Filtering the merged CloudTrail JSONL on that eventName shows the actor running it.

python3 -I summarize_ct.py work/ct/all.jsonl --by eventName
Click flag to reveal GetCallerIdentity
Q8 — The compromised AWS IAM credentials were exploited by the Threat Actor. Can you identify the regions where they were used successfully? Separate regions by comma and in ascending order.

The CloudTrail files are thousands of small gzips, so merge them into one JSONL first. Then filter to the leaked IAM user (devops-ash), the attacker source IPs 35.169.66.138 and 34.202.84.37, and events with no errorCode. Group by awsRegion; two regions have successful calls.

python3 -I merge_ct.py work/tar work/ct/all.jsonl
python3 -I summarize_ct.py work/ct/all.jsonl --user devops-ash --success --by awsRegion

Gotcha: Counting every region seen from the actor’s IPs gives 17, but that includes calls made with the EC2 instance role from Q4. The question is about the IAM user’s credentials only, and that user succeeded in just two regions.

Click to reveal answer us-east-1,us-east-2
Q9 — The compromised IAM account's early access may have enabled the Threat Actor to obtain the public IP addresses of running instances before the web server attack. What API call could have exposed this information?

EC2 lists instances, including their public IPs, through a single describe call. It shows up in the IAM user’s early activity in CloudTrail, ahead of the web server exploitation.

python3 -I summarize_ct.py work/ct/all.jsonl --user devops-ash --by eventName
Click flag to reveal DescribeInstances
Q10 — Looks like the Threat Actor used multiple IP addresses. What is the total number of unsuccessful requests made by the Threat Actor as seen in the CloudTrail logs?

Take every CloudTrail event from the two attacker addresses (35.169.66.138 and 34.202.84.37) that carries an errorCode, and count them. Both addresses have to be included.

python3 -I summarize_ct.py work/ct/all.jsonl --ips 35.169.66.138,34.202.84.37 --errors --count
Click to reveal answer 742
Q11 — Can you identify the AWS identities linked to successful API calls potentially used by the threat actor to reveal infrastructure details? Exclude any identity-related calls. Separate ARNs by comma and in ascending order.

Take successful events from the attacker IPs, drop the identity calls such as GetCallerIdentity, and list the distinct userIdentity.arn values. Two identities remain: the leaked IAM user and the assumed-role session of the web server instance, which is the metadata credential from Q5.

python3 -I summarize_ct.py work/ct/all.jsonl --ips 35.169.66.138,34.202.84.37 --success --exclude-identity --by arn
Click flag to reveal arn:aws:iam::949622803460:user/devops-ash,arn:aws:sts::949622803460:assumed-role/EC2DatabaseConnection/i-0bdf91168b50e943e

Collection

Q12 — Evidence suggests that a couple of AWS RDS databases were targeted. Can you identify all DB snapshots that were created by the Threat Actor? Separate identifiers by commas and in ascending order.

Filter CloudTrail to CreateDBSnapshot and read requestParameters.dBSnapshotIdentifier. Two snapshots were created, one per production database, with the creation time embedded in the name.

python3 -I summarize_ct.py work/ct/all.jsonl --event CreateDBSnapshot --field requestParameters.dBSnapshotIdentifier
Click to reveal answer transactiondb-prod-2024-03-13-06-53,wb-customerdb-prod-2024-03-13-07-59

Exfiltration

Q13 — The threat actor successfully exfiltrated data to their account. Can you identify the AWS account ID they used?

Look at ModifyDBSnapshotAttribute events. The valuesToAdd field in the request parameters lists the account the snapshot was shared with, which is the destination account and differs from the victim account 949622803460.

python3 -I summarize_ct.py work/ct/all.jsonl --event ModifyDBSnapshotAttribute --field requestParameters.valuesToAdd
Click flag to reveal 143637014344
Q14 — Which MITRE Technique ID corresponds to the activity described in Question 13?

Sharing the snapshots with an account the actor owns is Transfer Data to Cloud Account, from MITRE ATT&CK’s Exfiltration tactic. No command is needed.

Click to reveal answer T1537

Attack Summary

PhaseAction
ReconnaissanceWordlist scan of the web server from one external IP; a 301 on /index.php exposes the real path
Initial AccessRequest-forgery payloads against the PHP page, starting with a local file read
Credential AccessPage used to reach the instance metadata service and obtain the EC2 role credentials
DiscoveryLeaked IAM user and the role run identity and instance-listing calls, successfully in two regions for the user
DiscoveryDatabase content reviewed through the server’s MySQL history
CollectionSnapshots created of two production RDS databases
ExfiltrationSnapshots shared with an attacker-owned AWS account

IOCs

TypeValue
IP (scanner, SSRF, API calls)35.169.66[.]138
IP (API calls)34.202.84[.]37
URL (metadata service target)hxxp[://]169[.]254[.]169[.]254
IAM user (leaked)arn:aws:iam::949622803460:user/devops-ash
Assumed role (instance)arn:aws:sts::949622803460:assumed-role/EC2DatabaseConnection/i-0bdf91168b50e943e
RDS snapshottransactiondb-prod-2024-03-13-06-53
RDS snapshotwb-customerdb-prod-2024-03-13-07-59
AWS account (attacker)143637014344

MITRE ATT&CK

TechniqueIDDescription
Active Scanning: Wordlist ScanningT1595.003Dictionary path brute force against the web server
Exploit Public-Facing ApplicationT1190Request forgery against the PHP page
Unsecured Credentials: Cloud Instance Metadata APIT1552.005Role credentials pulled from the metadata service
System Owner/User DiscoveryT1033GetCallerIdentity with the stolen keys
Cloud Infrastructure DiscoveryT1580DescribeInstances and other infrastructure enumeration
Data from Information RepositoriesT1213Database content reviewed through MySQL history
Modify Cloud Compute Infrastructure: Create SnapshotT1578.001CreateDBSnapshot on two production RDS databases
Transfer Data to Cloud AccountT1537Snapshots shared with an attacker-owned account

Defender Takeaways

Block user-controlled URL fetches in the web app. The page handed input to file_get_contents, which allowed both local file reads and requests to link-local addresses. Allow-list the schemes and hosts the code may fetch, and drop file:// and metadata addresses outright.

Require IMDSv2 on every instance. A single forged GET returned usable role credentials. IMDSv2 needs a session token obtained with a PUT request and a header, which a simple fetch primitive cannot produce, and a hop limit of 1 keeps proxied requests off the metadata service.

Scan for and revoke leaked IAM keys fast. The devops-ash user key worked from external addresses, and the actor used it in more than one region. Short-lived credentials, source-IP conditions on the key and alerts on GetCallerIdentity from unfamiliar addresses would have shortened the window.

Alert on RDS snapshot sharing. ModifyDBSnapshotAttribute with a foreign account in valuesToAdd is a precise exfiltration signal, and CreateDBSnapshot outside a backup window is a good precursor. A service control policy can deny sharing to accounts outside the organization.

Watch the error volume. The actor generated hundreds of failed API calls while probing permissions. A spike of AccessDenied for one principal across many services is a cheap, early alert.

Conclusion

The actor turned one forgeable web request into AWS credentials, then moved two production databases into their own account without touching the servers again. Every step from the metadata call to the snapshot share is in CloudTrail, but nothing flagged a role session or a foreign account being granted access.