Server-side request forgery (SSRF)
Unintended access to internal resources via exploited server
Select your ecosystem
What is server-side request forgery?
Server-side request forgery (SSRF) is a type of attack that allows an adversary to make arbitrary outbound requests from a server. In some cases, an attacker can use SSRF to pivot throughout corporate networks, exploit otherwise unreachable internal systems, or query metadata endpoints to extract secrets. The severity of SSRF can vary from informational to critical depending on some factors. The visibility of the response and the nature of assets that can be reached will help determine the severity of a given SSRF defect.
About this lesson
In this lesson, you will learn how SSRF vulnerabilities work and how to protect your applications against them. We will begin by exploiting an SSRF vulnerability in a simple application. Then we will analyze the vulnerable code and explore some options for remediation and prevention.
Ready to learn? Buckle your seat belts, put on your hacker's hat, and let's get started!
Hacking a social app
A well renowned serial entrepreneur and startup mogul known only as "Jane" has decided to build the next Facebook. She decided to call the new social network "Meetr" because it allows you to meet new friends and because "Meta" was already taken. Meetr is only in its early stages but Jane is extremely well connected. She has a meeting tomorrow morning with some potential investors, and insists the Meetr MVP be fully functional.
You have been called in last minute for an extremely lucrative five day contract to bolster the existing dev team’s efforts. Your task is to build the ability to add profile pictures to Meetr profile. You decided that instead of just allowing the upload of profile pictures, it would be awesome to use any image on the Internet by just providing a URL.
When a user sends a request with image URL, the server will request the provided image URL, return the image back to the user, and then update the profile image. Let's take a closer look at what might be possible by exploiting this SSRF vulnerability.
Firstly, we can access the web server from the machine that it is already originating from by specifying 127.0.0.1
or localhost
in the URL field.
Copy and paste the following into the terminal and hit enter:
curl https://meetr.com/user/image?imgUrl=http://localhost
Sometimes, accessing the server from localhost allows you to access additional services running on that host. Sometimes this allows an attacker to get access to administrative consoles on other ports. For example, this server has an administrative portal on port 5000 that is only accessible locally.
Copy and paste the following into the terminal and hit enter:
curl https://meetr.com/user/image?imgUrl==http://localhost:5000
Let's get some data
Bingo! We've managed to see the content of the admin app.
It looks like we could get some juicy information by visiting those endpoints: /users
, /password-reset
and /logs
. Let's take a look at /users.
Copy and paste the following into the terminal and hit enter:
curl https://meetr.com/user/image?imgUrl=http://localhost:5000/users
Exploit AWS metadata endpoint
Uh oh, it looks like we can access a full user listing!
Another very popular method for escalating SSRF on EC2 instances is to access the AWS metadata endpoint, which is located at http://169.254.169.254
or http://instance-data
.
The metadata endpoint contains valuable information about the underlying environment including hostnames, events, security groups and… credentials! Let's try querying the AWS metadata endpoint for some credentials.
Copy and paste the following into the terminal and hit enter:
curl https://meetr.com/user/image?imgUrl=http://169.254.169.254/latest/meta-data/iam/security-credentials/Admin-Role
You'll see something... Wait… are those… yep! AWS credentials!
How does server-side request forgery work?
Firstly, let's recap what took place in the interactive example above.
- As an attacker, we were able to determine that our URL input was being requested by the server, and we could see the response body
- We used this "feature" to pivot into the internal network and gain access to an administrative portal that would otherwise be inaccessible
- We then accessed AWS credentials by querying the AWS metadata endpoint
And now we will have a look at this example in more detail by going through the server-side code
Pivoting to enumerate and exploit hosts within internal networks
A vulnerable internet-facing application can be utilized to pivot into an internal network. This is useful for attackers wishing to gain an in-depth understanding of a target's internal network.
The ability to send HTTP requests on the internal network can sometimes be more sinister than just enumeration though. There are many full-blown RCE vulnerabilities that can be exploited with a single HTTP request. One such example is in Atlassian Confluence, remote code injection (RCE) via Object-Graph Navigation Language (OGNL) (OGNL) Injection (CVE-2021-26084). This attack would result in the ability to execute code on an internal confluence server, the attack vector would look something like this:
Impacts of SSRF
As demonstrated in the examples above, SSRF can be anywhere from harmless to catastrophic. This depends on a number of factors like the visibility of the response and which internal hosts are accessible.
At its absolute worst, SSRF vulnerabilities could result in:
Full compromise of cloud environments. Internal administrative dashboards being exposed. Internal hosts being exploited.
Is SSRF common?
For the first time ever, OWASP has included SSRF on the OWASP top 10 list for 2021. There was an interesting note in the OWASP draft which stated "this category represents the scenario where the industry professionals are telling us this is important, even though it's not illustrated in the data at this time". It's difficult to know whether the data is just skewed because SSRF is difficult to detect, or whether SSRF is actually rare, although SSRF is quite a common bug discovered in bug bounty programs.
Only allow external requests
If it is necessary to accept dynamic input as part of the request, ensure that only external hosts are allowed to be defined. For example, you may allow requests to 159.65.138.192
but not 10.0.0.1
, 169.254.169.254
or 192.168.10.11
.
There are some gotchas with this method:
- If a hostname is defined, be sure to check the IP address that the hostname resolves to. It is trivial to create a domain such as hacker.example.com that points to any internal IP address.
- Beware of redirects. One common technique is to host a script that redirects to a host that should be forbidden. For example, the server may request hacker.example.com, but this URL redirects to 169.254.169.254, so the server then ends up requesting the AWS metadata endpoint.
- Beware of DNS rebinding. It is common for a developer to make the mistake of following this pattern.
- Resolve provided hostname to an IP address
- Check if IP address is internal
- If it is internal, drop the request
- Otherwise, send request to hostname
- The problem is that the IP address is fetched twice; the first time to check the IP address, and the second to make the request. It is trivial to create a DNS server that responds with a different IP on every second request. If this occurs, when the IP address is checked it might be an external IP address and pass the security test, but then when the actual request is made, the hostname resolves to a dangerous internal address, allowing the SSRF to be escalated.
Reconsider the need for dynamic requests
In some cases, it is simply not necessary to take user input to define the location of a server-side request. In this case, it is better to leave it out to be on the safe side and generate the request URLs purely with static values on the server side.
Utilise an allowlist
If the hosts that need to be accessed are a finite set, implement an allowlist. When a user sends a request, check that the URL or domain from that request corresponds to one in the allowlist, if it doesn't, drop the request.
Utilize a static analysis tool
Adding a static application security testing (SAST) tool to your devops pipeline as an additional line of defence is an excellent way to catch vulnerabilities before they make it to production. There are many but our personal favourite is, of course, Snyk Code.
The plugin contains rules that will test your code for vulnerabilities when you run npm test
. It's important to note that linters like this will not catch everything. But they are a good sanity check, and the more layers of checks we have the less likely you are to introduce vulnerabilities.
Test your knowledge!
Keep learning
To learn more about SSRF, check out some other great content produced by Snyk:
- If you want to see a real life example of SSRF, watch this video about Harbor open source registry SSRF issue
- Or have a look at an example of how to obtain AWS credentials via SSRF exploit
- If you are interested in exploring other SSRF exploitation methods, this is an excellent blog post by Assetnote that outlines a bunch of exploits that can be delivered with a single HTTP request, meaning that they might be utilised to exploit a system within the local network, by pivoting through a SSRF vulnerability