In the cloud, it’s common to implement decoupled components that integrate and process client data transparently. Without adequate security controls at each component; multiple vulnerabilities will provide an attack path for threats to exploit. One common path includes vulnerable applications running on AWS EC2 with default instance metadata services (IMDS) configurations and server side request forgeries (SSRF). Let’s discover how that attack path can be missed from scans, and how to fix them.
EC2’s IMDS is designed to provide developers with information about a given instance at runtime so that additional decisions can be made or passed to other components within an application. The IMDS provides details such as the instance IP, security groups, and role credentials. Pulling the configuration details about the instance at runtime provides the flexibility for the application to pull data without having to make external calls using the AWS CLI or SDK. For example, the following query to IMDS returns endpoint categories that can then be further traversed for the specific instance data:
[ec2-user ~]$ curl http://169.254.169.254/latest/meta-data/
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
instance-action
instance-id
instance-type
local-hostname
local-ipv4
mac
A server side request forgery (SSRF) performs unauthorized requests on behalf of the original client from untrusted user input. For example, an application takes user input to perform multiple calculations. If the application on that service or instance does not perform all of those functions for every calculation; the input is then queried to other API services and the data is returned back to the client. To illustrate further, observe the diagram below showing the differences between a server side and typical client side request:
If that original user input for the request is not properly validated and scrubbed of injectable data; SSRF and other known injection attacks can lead to sensitive information disclosure on the running service and other accessible back end services. Attackers may also leverage SSRF vulnerabilities to scan internal and external services using the vulnerable service as a proxy depending on network access controls in use. For example, an injectable input could scan for domain controllers leveraging LDAP queries:
Imagine that a developer is creating a PHP based application which takes in user input and performs sentiment analysis. The data is returned back to the client where there are negative phrases highlighted and a score. The developer mocks up the code in non-production and is delighted to find scans coming back clean.
Some best practices are in place as part of the development process including: infrastructure as code (IaC), short lived account credentials, CI/CD scans, and local scanning prior to pushing to the repo. An example workflow illustration is provided below:
The above example shows the standard development workflow. Note that the CI/CD in this case consists of Github as version control with Snyk performing scans on the code itself. Terraform cloud will be used as a runner and a state back end to push to an example AWS account.
In the example application the PHP vulnerable code to deploy is the following:
In the above, you can see that the GET submission form has no input validation other than the fact that the user cannot enter an empty URL. Many static code scanning tools can discover security related issues. However, not all tools have security specific use cases and it should never replace appropriate code review. For the attack to work, an SSRF vulnerable application must be running on AWS EC2 using the default IMDSv1 configuration.
For example, if the vulnerable code used is deployed as a bootstrap within the EC2 user data, will the CI/CD scanner find the vulnerable code? Many scanners will not follow the links, which is one way to accidentally deploy the vulnerable PHP as shown below:
There’s lots of things we can do with such injectable code if this application was also connected or allowed access to other service types. SSRF payloads come in a variety of forms. After an attacker has performed enough reconnaissance on the vulnerable target, the AWS IMDS (version 1) payload would be suitable for this use case. Below are some examples of other unique payloads an attacker can take beyond what is shown in this article:
http://127.0.0.1:8080
file:///etc/passwd
, file:///etc/shadow
, file:///var/www/.htpasswd
ldap://domaincontroller:389
<iframe> src=file:///etc/shadow</iframe>
#use MiTM burp for response or onError document.writehttp://169.254.169.254/latest/user-data/iam/security-credentials/
, http://169.254.169.254/latest/user-data/iam/security-credentials/ <ROLE NAME>
http://metadata.google.internal/computeMetadata/v1/project/project-id
http://169.254.169.254/metadata/instance/network/interface/0
In the above, the most applicable test case is to leverage AWS IMDS v1 to grab the role credentials: “http://169.254.169.254/latest/user-data/iam/security-credentials” to enumerate the role name followed by the same URL plus the role-name “/iam/security-credentials/<ROLE-NAME>”.
To ensure that the application is vulnerable to SSRF, utilize a local proxy, such as Burp and enter in a test payload such as “http://ifconfig.me” which will return that host’s public IP. If there are no client side captures of results going to ifconfig.me, then we have confirmed the application performs server side requests. See the figure below for more details:
Next, add the payload selected for AWS IMDSv1. After enumerating the role name, the application pulls the credentials in use by the instance:
The attacker can now leverage that credential externally into AWS CLI, SDK, or other attacker specific tooling for the duration of that token and for the next regenerated credentials as long as the SSRF vulnerability exists.
There are multiple layers of defense that can be implemented to mitigate the specific attack vector leveraged to exploit this. Among them include infrastructure focused controls including:
It’s worth noting that the move to IMDSv2 should not be taken lightly or without testing. Some applications need modification to configurations because of the protections put in place. Examples of IMDSv1 to IMDSv2 considerations include:
IMDSv2 incorporates the requirement of collecting data with an additional HTTP method of “PUT” requesting a metadata token in the HTTP headers before the GET or HEAD request including the request header and token. This is further illustrated below:
To mitigate this using the CLI against existing running instances, a developer or administrator could run the following to make the switch. This assumes that IMDSv2 is compatible with the application.
_for i in $(aws ec2 describe-instances --filters Name="instance-state-name",Values="running" | jq '.Reservations | .[] | .Instances | .[] | .InstanceId' | cut -d'"' -f2); do aws ec2 modify-instance-metadata-options --instance-id $i --http-tokens required --http-endpoint enabled; done_
However, in the above, you would only be mitigating this one specific attack path, specifically the default use of IMDSv1 and that it does not account for EC2 instances behind an auto-scaling group which the CLI command would have to be run multiple times. The recommendation is to utilize one of the preventative controls mentioned before including SCP and or an SSM automation document applied to the instance group.
Outside of the IMDS, the other root problem is the SSRF vulnerability itself. The application was allowed to be deployed because it was missed from the CI/CD scanner entirely because it was bootstrapped as a dependency while deploying the instance. That is why code review is still very important.
To mitigate other SSRF payloads and attacks, the PHP code itself needs to be patched with input validation. Here is an example set of validation and encoding techniques that can make the code more secure:
The above is borrowed example code applied for 2 different purposes. The first is to validate that we should only be scanning a specific URLS with a particular domain and that it is indeed a URL. The next protection occurs on the output in the form of encoding to ensure other injection attacks, such as XSS does not reflect back to the client.
The important takeaway is to always build security in layers. This includes processes, tooling, and configuration controls to prevent the abuse of IMDSv1 through SSRF from occurring. The “shift left” approach explained in our remediation included adding additional preventive controls using AWS SCP’s and secure code review. The runtime recommended controls included the use of WAF and AWS SSM’s automation document to enforce IMDSv2.