pentesting.cloud part 2: “Is there an echo in here?” AWS CTF walkthrough

Pawel Rzepa
InfoSec Write-ups
Published in
6 min readDec 1, 2022

--

In this blog post I’m going to show you a technique of uncovering a CloudFormation values protected by the NoEcho property. In other words, you gonna learn how to display secrets from already deployed CloudFormation stacks, hidden behind ****.

This is the walkthroug of the Is there an echo in here? challenge from the pentesting.cloud CTF. There are many awesome AWS security-related challenges, so if you haven’t tried it yet, then skip reading the spoilers and try to solve it by yourself! But if you got stuck on this challenge or simply just want to see the trick you can directly jump to the main section 😉

3, 2, 1… let’s start!

Following the challenge instructions I deployed the “echo-in-here” CloudFormation stack. That’s what we’re looking for:

The flag is an md5 hash located in flag.txt in the root folder of the s3 bucket created by the challenge.

To find it we can use the dedicated IAM user named pentesting-user who’s granted with the following permissions:

Let’s analyze the Lambda function which pentesting-user can invoke:

This simple function will display all environmental variables (including access key ID, secret access key and session token of the attached execution role!), but only if you pass the right password in the event object. The password can be found in the deployed CloudFormation stack. However, it’s masked…😔 Is there a way to view it? Sure it is!

Discovering values of NoEcho Parameters

If you don’t want to hardcode a specific value in the CloudFormation template, then you can pass it as a Parameter when creating a stack. However, the values of the Parameters are reflected to anyone who’s allowed to make a DescribeStacks API call. But this value can be masked if the Parameter in a CloudFormation template has the poperty NoEcho: true. As a result no matter if you open the stack’s Parameters tab in the AWS Console Management or AWS CLI the value will be masked, e.g.:

$ aws cloudformation describe-stacks --query "Stacks[].Parameters[*]" --profile pentesting-user

Output:

[
[
{
"ParameterKey": "Password",
"ParameterValue": "****"
}
]
]

Some AWS users (I’ve seen it many times in the wild) have wrong thinking that it’s a secure way of passing secrets, like for example DB passwords, although the AWS documentation clearly states, that the recommended approach is using dynamic parameters (e.g. referencing the value of the secret stored in the AWS Systems Manager Parameter Store or AWS Secrets Manager) ¯\_(ツ)_/¯

The pentesting-user has the cloudformation:UpdateStack permission, which is enough to unmask the password value. All we have to do is to… <drumroll🥁> … update the stack with NoEcho property set to false (or simply remove it). But hold your horses, just editing/removing the Parameter property will not be recognized by the CloudFormation service as… a change 😕 Let me demonstrate it.

To update the stack we certainly need a template. The pentesting-user has the “cloudformation:Get*” permissions so we can get a template from already created stack (in the CloudFormation dashboard simply click on the stack name and then go to the Template tab):

Select all and save it as template.yaml file. If you only remove the NoEcho: trueline and try to call the update-stack* operation, then you’ll get the following error message:

$ aws cloudformation update-stack --stack-name echo-in-here --template-body file://template.yaml --parameters ParameterKey=Password,UsePreviousValue=true --capabilities CAPABILITY_NAMED_IAM --profile pentesting-user

An error occurred (ValidationError) when calling the UpdateStack operation: No updates are to be performed.

* — please note that if you don’t want to update the parameter value, but instead use already existing value, then you have to explicitly specify it via UsePreviousValue=true during the update-stack action.

The pentesting-user has no permission to modify any resource, however a tiny change of the CloudFormation template in the Resource section will solve the issue 🤯 So let’s replace the !Ref S3Bucket from the original template.yaml with the name of already created S3 bucket (so there’s no change into any resource, but such change is recognized by the CloudFormation service as a new template file):

So let’s try one more time running the same above command, but this time with updated template.yaml file:

$ aws cloudformation update-stack --stack-name echo-in-here --template-body file://template.yaml --parameters ParameterKey=Password,UsePreviousValue=true --capabilities CAPABILITY_NAMED_IAM --profile pentesting-user

{
"StackId": "arn:aws:cloudformation:us-west-2:XXXXXXXXXXXX:stack/echo-in-here/36f1c740-70c0-11ed-b156-0699d225df8d"
}

Once the update is finished let’s get back to the CloudFormation echo-in-here stack’s Parameters tab and… voilà we can see the unmasked Password value:

Now, let’s back to the echo-in-here-VulnerableLambda-7ZS04BaNqpSH Lambda function which pentesting-user can invoke. When you invoke the Lambda function from the AWS Console Management (simply click the Test button in the Lambda function Code tab) then you can pass the arguments in the Event.json file where you should use the unmasked password:

Once the Lambda is executed you can see all the environmental variables of executed function including credentials used by the assumed execution role:

Let’s now configure the compromised Lambda execution role in the local terminal as the compromised-role profile. You can do it by using the following commands:

# specify the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and the region:
$ aws configure --profile compromised-role

# specify the AWS_SESSION_TOKEN:
$ aws configure --profile compromised-role set aws_session_token PUT_AWS_SESSION_TOKEN_HERE

# check if the profile is correctly configured:
$ aws sts get-caller-identity --profile compromised-role

{
"UserId": "AROAQWTRZHKUAF6QTSLWX:echo-in-here-VulnerableLambda-7ZS04BaNqpSH",
"Account": "XXXXXXXXXXXX",
"Arn": "arn:aws:sts::XXXXXXXXXXXX:assumed-role/echo-in-here-VulnerableRole-UBOWSUETXTJV/echo-in-here-VulnerableLambda-7ZS04BaNqpSH"
}

Finally, we can download and read the flag.txt file:

Conclusions

The Is there an echo in here? challenge focuses on an important security threat of unauthorized access to sensitive data passed as a parameter to the CloudFormation stack. An important lesson here is that any secrets, required by a stack resources, should be stored outside of the CloudFormation (e.g. in AWS Systems Manager Parameter Store or AWS Secrets Manager) and dynamically referred from the CloudFormation template. Additionally, such secrets should be encrypted, what would add additional layer of access control (the principal not only requires a permission to access the secret, but also needs a permission to decrypt the secret on the KMS CMK key policy).

Please let me know if you’re interested in next parts of the pentesting.cloud challenges walkthrougs by giving a 👏 to this article or following me on Twitter / LinkedIn.

From Infosec Writeups: A lot is coming up in the Infosec every day that it’s hard to keep up with. Join our weekly newsletter to get all the latest Infosec trends in the form of 5 articles, 4 Threads, 3 videos, 2 GitHub Repos and tools, and 1 job alert for FREE!

--

--

Interested in pentesting and cloud security | OSCP | eMAPT | AWS SAA | AWS CSS