Automated SQL Injection Testing of Serverless Functions On a Shoestring Budget (and Some Good Music)

* The work presented in this blog post was done together with Yuri Shapira, Security Researcher at PureSec. 

Prologue

The idea of performing automated dynamic security testing of serverless functions has been haunting me for months now. It’s also a topic that I keep hearing people complaining about, and in fact, we mentioned it in the Serverless Security Top 10 Guide that we published back in January 2018. Here’s what we wrote back then:

DAST (dynamic application security testing) tools will only provide testing coveragefor HTTP interfaces. This poses a problem when testing serverless applications thatconsume input from non-HTTP sources, or interact with back-end cloud services. Inaddition, many DAST tools have issues to effectively test web services (e.g. RESTfulservices) which don’t follow the classic HTML/HTTP request/response model andrequest format.”

Think about it for a minute – you developed a serverless function, now you want to apply the classic application security best practice of dynamically testing it for vulnerabilities (i.e. fuzz testing). If your function triggers on an HTTP request (e.g. AWS API Gateway), you’re (partially) in luck, just point your favorite DAST tool or scanner at the HTTP API endpoint, and hope for the best…

But what do you do if you want to perform the same type of dynamic testing, on a serverless function that triggers on other types of events such as AWS S3, or Azure Blob Storage Binding? That’s right – say hello to “manual pen testing”….

No DAST for you today! Come back in 1 year!

Variations on a Theme

Since SQL Injection is probably among the most infamous application layer attacks, I chose to concentrate on it first – however, what I’m about to demonstrate can be adapted for other types of automated application layer security testing.

However, before we begin, I recommend putting on some good music in the background- did you get a chance to listen to the new Father John Misty album? it got an 8.5 on Pitchfork… trust me, it’s great (listen to the 2nd track – “Mr Tillman”)

My favorite SQL Injection testing tool is SQLMap ( http://sqlmap.org/ ), which you will need to download from the home page, or to clone the github repository – it’s truly the best and most extensive tool out there, and it has everything we need in order to get started.

The only problem with SQLMap is that it was developed to test web applications rather than serverless functions. It speaks HTTP… and we need something that can invoke serverless functions.

Enter Lambda-Proxy

Calling the little tool we concocted for this PoC – ‘Lambda-Proxy’ borders with Chutzpah, however, it is a proxy, and it is for Lambda, so we’ll let it slide….
Start by cloning the github repository: https://github.com/puresec/lambda-proxy  and let’s go over how to install it, what it does, and what’s in there.
Ingredients for installation:

  • Python3
  • pip3 for the dependencies
  • SQLMap

Let’s install all the components:

/> git clone https://github.com/puresec/lambda-proxy.git
/> cd lambda-proxy
/> pip3 install -r requirements.txt

Lambda-Proxy creates an HTTP proxy listening on localhost port 8082 (we’ll get back to the localhost topic later). When it receives an HTTP POST request with a very specific structure , it will parse the request, extract the relevant data required for the test, and will invoke your AWS Lambda function using the AWS SDK client.invoke() method. But how does it know which function to test, which AWS profile to use, and in which region? That’s all defined in the template file called ‘request.txt’ – let’s take a look at it:

source_code1The request.txt template file has a simple HTTP POST request in it, with 3 variable components in the path element of the URL:
<aws_profile_name>: replace with your AWS profile name
<region>: replace with the AWS region where the function is deployed (e.g. us-east-1)
<function_name>: replace with the name of your AWS Lambda function

And then, there’s the body of the request, which is simply the event data – what you would send as the value of the –payload if you were using AWS CLI Lambda invoke.

SQLMap knows how to parse JSON messages and will go ahead with testing each and every field. If you want to test a specific field, just use (*) where you want the injection to take place. For example:

{ “uname” : “*” }

That’s it!

When 1 + 1 = 2

We’re ready, let’s get started and see how this little nifty utility does the magic. All you have to do, is run Lambda-Proxy:

/> python3 main.py
* Serving Flask app “main” (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:8082/ (Press CTRL+C to quit)

So far, so good… next, we’ll let SQLMap do it’s magic by running it in the following way:
/> /sqlmap-dev/sqlmap.py -r request.txt –dump

sqlmap_output1

SQL Map will notice the JSON format, and will ask you if you want it to process it – just hit (Y)es.
After a few seconds, and depending on your AWS Lambda function response behavior, SQLMap might ask you to answer the following question:

[[WARNING] target URL content is not stable. sqlmap will base the page comparison on a sequence matcher. If no dynamic nor injectable parameters are detected, or in case of junk results, refer to user’s manual paragraph ‘Page comparison’
how do you want to proceed? [(C)ontinue/(s)tring/(r)egex/(q)uit]

Choose whatever works in your case, the simplest would be the (s)tring option, and then choose one of the stable strings that might appear in the normal output of your function (Note: this last part might not always be there, if it doesn’t – even better).

You might get asked a few other questions during the process, if you’ve used SQLMap before, you probably know the answers, if not, don’t worry, it’s all pretty simple.

Here’s the output of the scan on my own AWS Lambda function that contains a very simple SQL Injection vulnerability, and uses a MySQL database on AWS RDS:

sqlmap_output2

Notice how the event data field ‘uname’ was found to be vulnerable. Let’s continue:

sqlmap_output3

And then…Bazinga!

sqlmap_output5

SQLMap found the vulnerable event data field, moved on to attempt data exfiltration (since I used the –dump switch), and yanked the entire database table! You can’t ask for more than this…

Why Use a Proxy You Ask?

I’m pretty sure that most of you are already thinking about other ways to implement dynamic testing similar to what we’ve done but using different approaches. For example – why not build the entire proxy with API Gateway, and a function that does the invocation?
The simple answer is that there’s a good chance the target serverless function is not open to the world via an API, it might be a function that is only scheduled to be invoked periodically, or uses a non-HTTP event trigger that is not public. Creating a RESTful API that invokes functions is risky and could end up exposing logic you didn’t want exposed.

What’s Next?

This was just a PoC, and as we were playing with it, we came up with at least a dozen features and capabilities we thought would be utterly cool and useful, here are just a few:

  • Add a preliminary phase, which retrieves a list of all the functions you have deployed, and allows you to choose the target function for testing
  • Create a catalog of common sample events, and allow you to choose which type of event you want to use for testing
  • Provide a way to encode the tested field depending on the required encoding method (e.g. Base64, Zip, etc.)
  • Add support for invoking serverless functions on other platforms (e.g. Azure Functions)

Anyway, we’ve made the project open source, so it would be cool to get some feedback and suggestions or code commits.


In my next blog post, I will show you how an AWS Lambda function that contains a fully exploitable SQL Injection vulnerability, gets virtually patched using the PureSec SSRE, and becomes immune to attacks in less than 5 minutes! Stay Tuned…



*** This is a Security Bloggers Network syndicated blog from PureSec Blog (Launch) authored by Ory Segal, PureSec CTO. Read the original post at: https://www.puresec.io/blog/automated-sql-injection-testing-of-serverless-functions-on-a-shoestring-budget-and-some-good-music