GCP Cloud Function Abuse
Article discussing GCP Cloud Function Abuse covering Local File Inclusion (LFI), Server-Side Request Forgery (SSRF), and Command Injection vulnerabilities. Explains how these vulnerabilities can be exploited to get access to authorization tokens and other sensitive information.
To start, how do we know we are interacting with a Google Cloud Function (GCF)? If the developer opted to not use a custom domain, then Cloud Functions URL typically looks something like https://function-vulnapp2-bvvciwqnka-ue.a.run.app/
. If they are using a custom domain name, then try to look for the following headers as a tip-off:
By default, all GCFs are configured to require authorization to trigger. This is done by supplying the usual Authorization: Bearer <your-jwt-here>
header along with your request. If you see this pop up in your proxy history, it is worth taking a look at the bearer token to see exactly what account is being used to authorize the request. We'll dig into that more another time. For the purpose of this post, I've included some resources in the GitHub repository so you can stand up your own vulnerable GCF and follow along. The GCF will not require authorization though, so no need to worry about it. You will need to alter the variables.tf
file to include a proper GPC Project ID so that the terraform script knows where to put everything.
Local File Inclusion (LFI)
So, you've found a vulnerable application and it seems to be running as a GCF. What can we do with that though?
There aren't many interesting files to look at unfortunately. You may be lucky though and find some hidden treasure inside the application's source files. In our example function, we have gone with Python as our language of choice.
We have the ability in our example to list directory contents, however you may not be so lucky in the real world. You will find the rest of the source artifacts inside /workspace
. The default naming for a Python GCF script is main.py
so that's what we'll try to view.
Server-Side Request Forgery (SSRF)
With SSRF vulnerabilities in GCF, you can obviously try to also pull down information just as you would with an LFI vulnerability utilizing the file://
protocol. But are there things specific to GCP that we can access?
There is a metadata endpoint available that will return valid authorization tokens for the Service Account used for the GCF. However, GCP requires that you supply a custom HTTP header to interact with it. This mean that the majority of SSRF vulnerabilities won't get you anything really interesting. For this article though, that isn't much fun.
If you are enjoying this article your support would be greatly appreciated!
So, our vulnerable application, for no real reason at all, supports the gopher://
protocol. Using the Gopher protocol, it is possible to build full request messages with custom headers. In this rare situation, we can pull down authorization information for the GCF and begin enumerating the access it has been given.
In the above URL, we are constructing a valid HTTP request within the Gopher URL. Because we're dealing with Flask, we need to double URL encode the payload for it to execute properly. In addition to the authorization token, we can also view what scopes the service account has assigned to it.
Command Injection
Considering the source code could look like basically anything, having any directory structure that works, it may be pretty hard to pull out the source code that you want. In this case, hopefully you've found some way to exploit a command injection or remote code execution vulnerability. If you have, then there is a packaged version of the source code located at /workspace/.googlebuild/source-code.tar.gz
. Attempting to pull this file with the example LFI will throw a 500
error, however with command injection we should be able to pull it out.
Since we don't have things like netcat
available in a GCF we have to get a little creative for exfiltration. sftp
is available, as is curl
. For this post, we're going to utilize curl
's ability to post multipart form-data and send it to a VM setup with a python script to receive files. Credit goes to this StackOverflow user for providing a simple Python script for exfiltration. The script used is copied below:
With that script running on port 80, all we need to do is inject the following command to receive our file:
Secret Manager
If the application requires the use of sensitive information, then a good developer is likely to use the GCP Secret Manager to avoid leaving it in the source itself. There are two ways in which you can attach a secret to the GCF. The first option available is to reference it as an environment variable. In this case, any vulnerability that would allow you to read those variables would expose the secrets attached. You are allowed to supply the name and value of the environment variable, so it could be anything really.
The second option available is to mount the secret somewhere on the file system. When attaching the secret to the GCF, you supply the mount location you want it to be located at. The name of the secret will be the actual name of the secret in Secret Manager.
Conclusions
While this is in no way an exhaustive set of examples of how you might utilize a vulnerability in a GCF to gain further access, I hope it sheds some light on what is possible. It is very important to keep your Service Account permissions as restricted as possible to avoid an attacker pivoting from a GCF to other cloud infrastructure.
If you felt I was missing something that should have been included, or would like something explained in more detail, please feel free to reach out to me over Twitter @codymartin.