Tuesday, October 9, 2018

Runtime Lambda Protection (Part 3) – "Self-Inspection"

Serverless functions, like AWS Lambda, are uniquely placed and transient in nature. These functions need a non-standard approach for both pentesting as well as defense. In the past blogs, we have covered the following two aspects for protecting lambda functions using the 'protectLambda' utility of the 'lambdaScanner' toolkit (can be downloaded from here).

1.    Runtime Lambda Protection – "Self Defense" from Inside (here)
2.    Runtime Lambda Protection (Part 2) – Monitoring, Analytics and Alerts (Real-Time) (here)

In this blog, we will be describing an enhancement of the 'protectLambda' utility through which we can validate the code of the lambda function just before its execution and allow/deny the execution of the function on the results of this validation. We can define a regular expression to check for loopholes in the code of the lambda function – every time the code would be checked against this regex and the execution of the function would be denied if a security violation is detected in the code. Below is a basic diagram of how the module of the 'protectLambda' utility will be placed in the overall architecture of the application; right before the execution of the function.

 

 

Leveraging "code_protect" Module:

In order to leverage this module, one needs to include the 'protectLambda' utility to their project. 'protectLambda' will wrap around the lambda function and monitor both incoming events as well as outgoing steams (described in earlier blog posts) and check the code of the function, at runtime, before its execution. This can be achieved by defining a regex in the file called "code_protect.txt" as shown in the figure below: -



One can define a set of rules, via regex, which will get validated before execution of the function at runtime. Hence, it will be like performing SAST at runtime.

For example, we define the following rule in "code_protect.txt": -

.*(call|check_output|system|popen|run|local|spawn).*\(.*

This rule will not allow the developer to use API/code, which can be used to run underlying command execution. We are covering most of the combinations of calls via above regular expression.

Let’s assume we have a function where developer is using the following line of code.

filetype = subprocess.check_output(command,shell=True).decode("utf-8")

Now, we have added the 'protectLambda' utility to the lambda function as shown below: -

 

If we try to invoke the lambda function now, we will get the following response: -

Response:
"Security Violation..."


Request ID:
"e9b59241-cbb5-11e8-ac44-058b44f83258"

Function Logs:
START RequestId: e9b59241-cbb5-11e8-ac44-058b44f83258 Version: $LATEST
Code Rule violation for  .*(call|check_output|system|popen|run|local|spawn).*\(.*
END RequestId: e9b59241-cbb5-11e8-ac44-058b44f83258
REPORT RequestId: e9b59241-cbb5-11e8-ac44-058b44f83258    Duration: 88.89 ms    Billed Duration: 100 ms     Memory Size: 128 MB    Max Memory Used: 22 MB  

Outcome/response of the function execution was as below: -

Response:
"Security Violation..."


We got a security violation alert since the developer has violated the rules of coding (according to the defined regex) and dangerous APIs/calls are used. In this case, we will also see the following line in the log: -

START RequestId: e9b59241-cbb5-11e8-ac44-058b44f83258 Version: $LATEST
Code Rule Violation for .*(call|check_output|system|popen|run|local|spawn).*\(.*

In this way, the 'protectLambda' utility protects the execution of the function if the code is vulnerable using the rules defined through "code_protect.txt". Similar protection for the incoming event stream and outgoing responses through "in_protect.txt" and "out_protect.txt" respectively was discussed in an earlier blog post.

Conclusion:


The nature of lambda functions and the method through which the functions are triggered make the traditional defense solutions inappropriate for serverless functions. So, as the first line of defense, the 'protectLambda' utility can guard against the code of the function, incoming stream of events as well as outgoing responses through a pre-defined set of rules. This defense technique along with a proper logging and monitoring mechanism would be a comprehensive approach for the protection of lambda functions at run-time.

Article by Amish Shah and Shreeraj Shah