Cloud Security

Hacking AWS Lambda for security, fun and profit

Cloud Security
Jul 5, 2022
10 min
Rohit J
Introduction to Serverless Applications

In cloud computing, it is often the case that the cloud provider provides the infrastructure necessary to run the application. The cloud provider provides the compute and manages the resources for us. It also uses the power of cloud computing i.e., auto scalability, which means that the serverless application can be scaled according to the needs of the customer traffic. All this is done so that the developers can focus on writing code and leave the worry about managing servers to the cloud provider.

Serverless applications, also called Function-as-a-service (FaaS), is an offering which is provided by all modern cloud services providers. In this service, developers write code and the infrastructure behind the scenes is managed by the provider. Developers can write multiple functions to implement business logic and then all these functions can be easily integrated to talk to each other. This is called serverless architecture.

Below are some of the offerings from the most popular enterprise cloud providers:

  1. Azure Functions, from Microsoft
  2. AWS Lambda, from Amazon Web Services (AWS)
  3. Google Cloud Functions, from Google
  4. OpenWhisk, an open-source cloud platform from Apache/IBM
  5. Fn Project, from Oracle

We must be aware of two main concepts related to serverless applications:

Functions are stateless – The state of the serverless applications is created when the execution starts and destroyed when the function has been executed successfully. There is no state information being stored automatically about these functions. In case the users need to store the state information then a separate storage system needs to be used e.g., Database.

Functions are event driven – you need an event to occur before a function is executed. An event can be anything like a REST API request, a message added to a queue, etc. The response from the event, also known as a trigger, can be used to fire the execution of a serverless application.

In this article we will look at what AWS Lambda is and discuss various aspects of security of Lambda functions.

Overview of AWS Lambda

AWS Lambda is a serverless compute service provided by Amazon. It is priced based on the duration of the execution of the function and the number of times it is being executed. Customers are charged only for the time during which the code is being run. AWS Lambda also provides support for multiple languages starting from C#, JavaScript, Python, etc. You can author the code in any text or code editor and then upload a zip folder of your code to the IDE in AWS Management Console.

Below are a few events which can be used to trigger a lambda function:

  1. When a table is updated in Amazon DynamoDB
  2. When messages arrive from Amazon Kinesis Stream
  3. When objects in AWS S3 are modified
  4. When notifications are sent from Amazon SNS (Simple Notification System)
  5. When messages are added to Amazon SQS (Simple Queue Service)
  6. When custom events are triggered by mobile apps, web apps, or any other service
An event triggers a lambda to perform some action
Security in AWS Lambda

The security of an application is one of its most important non-functional requirements. As serverless architectures are getting more attention from the developer community, they are also catching the eye of hackers. And when it comes to serverless, AWS Lambda deployments are the most common ones we need to look at.

The distributed nature of the serverless application architecture gives a malicious attacker more room for exploitation. The greatest asset of serverless applications (scalability) is the most dangerous foe as well. It gives attackers significant entry points to the application.

Since serverless applications and technologies are trending they are naturally a target for the attackers. To account for this, the OWASP foundation had published an interpretation of the OWASP Top-10 list of Web application security risks the OWASP Serverless Top 10.

Let’s take a look at what various security implications occur in the real world using a deliberately vulnerable application – ServerlessGoat.

ServerlessGoat Demo

It is a common misconception that serverless apps are secure by default because:

There is no managed server

Serverless applications are HTTPS by default

The serverless provider takes care of the security

Just because the application does not use a managed server it does not mean that it is secure. Since there are no managed servers, it minimizes the vulnerability management/ patching part, but the risks are still applicable due to bad programming practices and cloud platform layer misconfigurations.

The folks at OWASP have also released ServerlessGoat which is an intentionally vulnerable serverless application to demonstrate some vulnerabilities that can commonly affect AWS Lambda. The OWASP ServerlessGoat application is packaged as an AWS SAM application that is available for deployment through the AWS Serverless Application Repository.

Steps to Deploy ServerlessGoat

The installation of ServerlessGoat is quite simple. It only requires a single-click to get deployed in your AWS account, which makes getting up and running a smooth experience. Deploy the below function using the Lambda repository.

  1. Make sure you are logged into your AWS account
  2. Navgate to Lambda > Create Functions > Browse serverless app repository > search for appsec-serverless-goat
  3. Click "Deploy"
  4. Click "Deploy" (again)
  5. Wait until you see the message: "Your application has been deployed"
  6. Click on "View CloudFormation Stack"
  7. Under "Outputs" you will find the URL for the application (WebsiteURL)

Let us understand Lambda attack and defense with some practical examples of attack scenarios using the ServerlessGoat. We will look at some of the vulnerabilities in detail and discuss how to defend them.

Note: All the below attacks are performed in a test non-production AWS account. Do not set up vulnerable apps/setups in prod AWS accounts.

  1. Information Gathering

The first step is to know if the application you are accessing is serverless or not! There are many ways to identify it:

  1. The API endpoint has a very predictable URL: https://{string}.execute-api.{region}.amazonaws.com/{stage}/
  2. If the application is exposed through Amazon API Gateway, the HTTP response headers might contain header names such as: x-amz-apigw-id, x-amzn-requestid, x-amzn-trace-id

3. You can also check for any exceptions that the application throws. Below you can see if we manipulate the URL of the application by removing the parameter “document_url”, it throws a default exception through which we can identify the location of the lambda function at the server side.

The above screenshots throw default exceptions and give us details about serverless / lambda service at server-side. The server is Linux, and the lambda function logic is at “/var/task/index.js”. Let’s see If we can inject some OS commands and see if we get a proper response.

2. OS Command Injection

We will blindly probe for OS command injection using a common payload like “id” invoking a command on the Linux OS system. The malicious payload is “http://foobar.com; id #”.

You can see that the id command is successfully validated, and the response is sent back as in the figure shown above. This confirms that the Lambda function is vulnerable to OS command injection.

Now we will dig for some sensitive data in the environment variables. We will run the same malicious payload but instead of id we will use env command. So, the payload will be “http://foobar.com; env #”.

Since we have got access to the AWS Session Token, Secret Key and Access Key we can further focus on compromising the AWS account.

3. Compromising the Victim AWS Account

Now, export the AWS Session Token, Secret Key and Access Key and we can now get the function’s temporary execution role using AWS Command Line Interface (CLI).

export AWS_SECRET_ACCESS_KEY = ""export AWS_ACCESS_KEY_ID = ""export AWS_SESSION_TOKEN = ""

Verify that you have got access to the Lambda function’s temporary execution role by running the command “aws sts get-caller-identity”. You should have an output as shown below.

It’s clear that we are now running under the assumed role of the function. Now we will dig deeper using the OS command injection and try to access the source code of the Lambda function. We will run the same malicious payload but instead of env we will use cat /var/task/index.js command. So, the payload will be “http://foobar.com; cat /var/task/index.js #”.

Below are the thing which we learnt from the source code review of the Lambda function:

  1. The application uses the Amazon Dynamo DB (NoSQL Database)
  2. The application uses a Node.js Package called node-uuid
  3. The application stores sensitive user information (IP address and the document URL) inside the DynamoDB table. The name is defined in the TABLE_NAME environment variable.
  4. The root cause behind the OS command injection is using untrusted user input in the child.process.execSync call
  5. The output of API invocations is stored inside an Amazon Simple Storage Service (S3) bucket. The name is stored inside an environment variable: BUCKET_NAME.

4. Exploiting Over-Privileged IAM Roles

We can confirm from the source code review of the Lambda function that the developer is inserting the client’s IP address and the document URL value into the DynamoDB table, by using the put() method of AWS.DynamoDB.DocumentClient. In a secure system, the permissions granted to the function should be least privileged and minimal, for example, only dynamodb:PutItem.

However, when the developer chose the CRUD DynamoDB policy provided by AWS Serverless Application Model (SAM), they granted the function with the following permissions:

  • dynamodb:GetItem
  • dynamodb:DeleteItem
  • dynamodb:PutItem
  • dynamodb:Scan
  • dynamodb:Query
  • dynamodb:UpdateItem
  • dynamodb:BatchWriteItem
  • dynamodb:BatchGetItem
  • dynamodb:DescribeTable

These permissions allow an attacker to exploit the OS command injection weakness to exfiltrate data from the DynamoDB table, by abusing the dynamodb:Scan permission. Use the following payload in the URL field, and see what happens (URL encode the below payload):

https://; node -e 'const AWS = require("aws-sdk"); (async () => {console.log(await new AWS.DynamoDB.DocumentClient().scan({TableName: process.env.TABLE_NAME}).promise());})();'

As you can see from the output below, we accessed the entire contents of the table

Below are some security best practices which can be implemented to secure the serverless apps.

The Path to better Serverless Security

When designing a serverless application architecture, implementing and enabling security best practices is most important for a developer. AWS has a list of security best practices that is recommended for Lambda function security integration.

These are the security best practices that should be implemented on serverless applications

  • One IAM role per function

Identity and Access Management (IAM) tole is an AWS identity that can be used to allocate permission policies about what each identity can do. All lambda functions need a single relationship with an IAM role. This ensures that even multiple functions with the same policy are triggered at the same time, all functions will be granted at the same time.

  • Protect the secrets

DB credentials, encryption keys and other keys are the best kept secrets in a lambda function. Some options to manage these secrets in the application are:

1. Encryption helpers

2. Use AWS Systems Manager parameter store

  • API authorization

API gateway allows the developer ownership over authentication and authorization and is a unique form of event source for lambda function. However, the developers are responsible for ensuring security best practices of the enabling APIs

  • VPC (Virtual Private Cloud) security

In case a Lambda function requires access to a VPC resource, the developer needs to keep in mind to enable security best practices through network ACLs (Access Control List), function-specific subnet, security groups, and routing tables that direct the Lambda functions to reach intended destinations.

  • Access control

Decreasing the attack surface by removing the direct access to APIs of any Lambda functions. The lambda APIs must be treated with extreme care and caution and any code changes must be done through automation.

  • Consider using WAF

You can use AWS WAF to protect AWS Lambda functions from common web exploits, such as SQL injection and cross-site scripting (XSS) attacks. These could affect availability and performance, compromise security, or consume excessive resources. Although, be aware of certain configurations that could dilute the security that WAF provides significantly.

  • Adjust Lambda Concurrent execution limit and throttling

Adjusting lambda function throttling can be done by increasing your account’s limit to a very high number of concurrent executions. It can also be done by reserving some executions per function, you can reserve a certain amount of your account’s total concurrency limit for a specific function.

This will allow your reserved lambda executions to be untouched by other functions and will be only used by that particular function, preventing throttling of requests due to exceeding your account’s limit.

  • Monitor application dependencies

Monitor the Lambda function dependencies using 3rd party / opensource tools such as Snyk, Black Duck, OWASP Dependency Tracker to mitigate the dependency poisoning attacks on the Lambda functions. If the dependencies go unchecked there are high chances of malicious codes being added to the dependency which in turn is consumed by the Lambda functions making it prone to publicly known vulnerabilities.

Conclusion

As we seen from the demo, all the attacks applicable to a traditional web application are also applicable to the serverless apps as well. Hence it is important to follow security best practices while developing a serverless application and to make sure that the app is regularly reviewed and tested by security teams.

HAZE WEBFLOW TEMPLATE

Build a website that actually performs better.

1
Lorem ipsum dolor sit amet consectutar
2
Lorem ipsum dolor sit amet consectutar
3
Lorem ipsum dolor sit amet consectutar