Lambda functions are at the core of applications. These functions are invoked, through various events, from various sources like browser, mobile devices or via API calls etc. The events through which the lambda functions are invoked have a pre-defined format for event payloads. The payloads sent via events are eventually consumed by the user-defined code (functions). An attacker, with a malicious intent, can exploit the vulnerable code by poisoning the event payload.
Lambda function can consume one or multiple events over various different streams. It has its own event model with a defined structure as shown in the figure below: -
Figure – Lambda invocation and access points
As shown in the figure: - the end client interacts with the lambda function through event payloads using channels like HTTP(S), APIs or any other means. It is possible to have asynchronous invocation or polling of events. Hence, there are various possible ways to invoke the function, it all depends on how these functions are being written and exposing entry points. In the above figure, lambda function can be consuming events like SNS, SQS, S3, Kinesis, Lex, Alexa, CloudFront, API Gateway etc. There is a long list of these events. These events would have a pre-defined payload, for example here is an event payload for Amazon SQS.
{
"queueUrl": "https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue",
"messages": [
{
"body": "Hello ….. message",
"receiptHandle": "MessageReceiptHandle",
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
"attributes": {
"ApproximateFirstReceiveTimestamp": "1523232000001",
"SenderId": "123456789012",
"ApproximateReceiveCount": "1",
"SentTimestamp": "1523232000000"
},
"messageAttributes": {}
}
]
}
Hence, we can use these templates for our testing and pass on to the functions at the point of invocation.
In the previous posts we have seen techniques to do function enumeration and profiling. For example: - a simple code like below would list down critical information about the “login” function.
The output for “login” function call is as below: -
We can start assessing the function with the following techniques in a comprehensive way: -
1. DAST – we can invoke functions, send across various event payloads and analyse the responses and behaviour which would help in identifying various known vulnerabilities.
2. SAST – we can fetch the code from Code-Location and try to identify vulnerabilities from the source code itself. It will be a heavy task, depending on the nature and size of the code.
3. IAST & Logging – we can analyse various logs from Amazon including xRay (Instrumentation SDK of Amazon). Also, one can use this SDK for runtime analysis and collect micro logs.
4. Deployment Testing – we can analyse deployment of the function using all three above listed testing methodologies; one of the important aspect is to look into the permissions given to users/function.
Hence, we can go ahead and do a full 360-degree assessment of the function by utilizing all these techniques to discover possible vulnerabilities.
Let’s look at the possible functions deployed as part of the application: -
As shown in the figure, the function is using SQS, S3 and DynamoDB as a part of application usage. Functions can be invoked over API gateway using HTTP calls. All logs will go to CloudWatch, both from the function as well as APIs. Also, assuming that xRay is enabled on the function, additional logs can be fetched from AWS as well.
Looking at the above structure, we can perform DAST from two points – through API gateway and AWS SDK with limited access to functions. We can directly invoke and fuzz the stream. We can do SAST by fetching code from SDK calls and review the entire code base for the function. Fetching all logs including xRay can be leveraged as part of IAST methodology.
We can start fuzzing and scanning lambda functions by simply invoking the function with a list of payloads. Here is a simple script, which can take various payloads and run them against the function. You can add more values to the “payload” list and fuzz the events. Here we have just passed and filled the event with key-value pairs. You can add any messaging events by using a proper defined structure.
We get the following responses back and can see the entire object with messages coming out. The “RequestId” can be noted here, using which various logs can be searched and the request can be traced. We will cover tracing in the next blog post.
Moreover, there might be a leak of information sensitive to the application which would be known by analysing the messages displayed to the users in response. Using this information, say for an example a SQL error is seen in the response, one can craft various payloads and exploit the issue if an actual vulnerability exists.
As shown in the enumeration section above, we can get a profile of the lambda functions. From the profile, we can see that the function is mapped to Amazon API Gateway. This information can be leveraged and using the API ID, the function can directly be called over HTTP. This request would pass through the HTTP channel, which would bring the implementation of various mechanisms like WAF into picture as well. Below is a simple way to invoke the function from the browser directly: -
We can again analyse responses as well as note the "RequestId", which can further be used to search and trace the request across logs to see different touch points.
It is quite obvious that one can leverage AWS API directly for testing Lambda functions. A set of test cases and pen test users (with varying access) can be created to conduct thorough testing from a security standpoint. Tests can be run against a list of all functions to check for various attacks ranging from injections to logical bypasses. Though, it is imperative to involve manual intelligence to analyse the behaviour of the functions more closely to identify the correct touch points and security vulnerabilities. Automated techniques can be applied on top of it by leveraging SDK from AWS. Thus, a comprehensive DAST analysis is easy and doable on Lambda functions through penetration testing of these functions. We will look into tracing in the next blog post.
Article by Amish Shah & Shreeraj Shah
Lambda Function Event Model:
Lambda function can consume one or multiple events over various different streams. It has its own event model with a defined structure as shown in the figure below: -
As shown in the figure: - the end client interacts with the lambda function through event payloads using channels like HTTP(S), APIs or any other means. It is possible to have asynchronous invocation or polling of events. Hence, there are various possible ways to invoke the function, it all depends on how these functions are being written and exposing entry points. In the above figure, lambda function can be consuming events like SNS, SQS, S3, Kinesis, Lex, Alexa, CloudFront, API Gateway etc. There is a long list of these events. These events would have a pre-defined payload, for example here is an event payload for Amazon SQS.
{
"queueUrl": "https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue",
"messages": [
{
"body": "Hello ….. message",
"receiptHandle": "MessageReceiptHandle",
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
"attributes": {
"ApproximateFirstReceiveTimestamp": "1523232000001",
"SenderId": "123456789012",
"ApproximateReceiveCount": "1",
"SentTimestamp": "1523232000000"
},
"messageAttributes": {}
}
]
}
Hence, we can use these templates for our testing and pass on to the functions at the point of invocation.
Quick Recap on Function Enumeration and Profiling:
In the previous posts we have seen techniques to do function enumeration and profiling. For example: - a simple code like below would list down critical information about the “login” function.
Methodology for assessing Lambda Functions:
We can start assessing the function with the following techniques in a comprehensive way: -
1. DAST – we can invoke functions, send across various event payloads and analyse the responses and behaviour which would help in identifying various known vulnerabilities.
2. SAST – we can fetch the code from Code-Location and try to identify vulnerabilities from the source code itself. It will be a heavy task, depending on the nature and size of the code.
3. IAST & Logging – we can analyse various logs from Amazon including xRay (Instrumentation SDK of Amazon). Also, one can use this SDK for runtime analysis and collect micro logs.
4. Deployment Testing – we can analyse deployment of the function using all three above listed testing methodologies; one of the important aspect is to look into the permissions given to users/function.
Hence, we can go ahead and do a full 360-degree assessment of the function by utilizing all these techniques to discover possible vulnerabilities.
Let’s look at the possible functions deployed as part of the application: -
As shown in the figure, the function is using SQS, S3 and DynamoDB as a part of application usage. Functions can be invoked over API gateway using HTTP calls. All logs will go to CloudWatch, both from the function as well as APIs. Also, assuming that xRay is enabled on the function, additional logs can be fetched from AWS as well.
Looking at the above structure, we can perform DAST from two points – through API gateway and AWS SDK with limited access to functions. We can directly invoke and fuzz the stream. We can do SAST by fetching code from SDK calls and review the entire code base for the function. Fetching all logs including xRay can be leveraged as part of IAST methodology.
Assessing Function using DAST:
We can start fuzzing and scanning lambda functions by simply invoking the function with a list of payloads. Here is a simple script, which can take various payloads and run them against the function. You can add more values to the “payload” list and fuzz the events. Here we have just passed and filled the event with key-value pairs. You can add any messaging events by using a proper defined structure.
We get the following responses back and can see the entire object with messages coming out. The “RequestId” can be noted here, using which various logs can be searched and the request can be traced. We will cover tracing in the next blog post.
Moreover, there might be a leak of information sensitive to the application which would be known by analysing the messages displayed to the users in response. Using this information, say for an example a SQL error is seen in the response, one can craft various payloads and exploit the issue if an actual vulnerability exists.
As shown in the enumeration section above, we can get a profile of the lambda functions. From the profile, we can see that the function is mapped to Amazon API Gateway. This information can be leveraged and using the API ID, the function can directly be called over HTTP. This request would pass through the HTTP channel, which would bring the implementation of various mechanisms like WAF into picture as well. Below is a simple way to invoke the function from the browser directly: -
We can again analyse responses as well as note the "RequestId", which can further be used to search and trace the request across logs to see different touch points.
Conclusion:
It is quite obvious that one can leverage AWS API directly for testing Lambda functions. A set of test cases and pen test users (with varying access) can be created to conduct thorough testing from a security standpoint. Tests can be run against a list of all functions to check for various attacks ranging from injections to logical bypasses. Though, it is imperative to involve manual intelligence to analyse the behaviour of the functions more closely to identify the correct touch points and security vulnerabilities. Automated techniques can be applied on top of it by leveraging SDK from AWS. Thus, a comprehensive DAST analysis is easy and doable on Lambda functions through penetration testing of these functions. We will look into tracing in the next blog post.
Article by Amish Shah & Shreeraj Shah