Server-side request forgery (SSRF) attacks consist of an attacker tricking the server into making an unauthorised request. The name itself implies that a request that should have otherwise been made by the server has been forged by the attacker.
SSRF attacks are far more dangerous than cross-site request forgery (CSRF) attacks. That’s because, in a way, CSRF attacks involve an attacker hijacking a user’s web browser and performing unauthorised actions on the user’s behalf.
During an active CSRF exploit, the malicious activity triggers from the client-side, and it is typically the individual user or their assets being targeted. Of course, CSRF attacks become dangerous when the targeted user has administrator privileges to the web application -- in such a case the entire application could be compromised.
SSRF attacks, on the other hand, target the web server itself without any necessary involvement or interaction from its users. Just by making a malicious HTTP request to the server, the attacker can instruct the back end to perform malicious actions.
Capital One’s major data breach of 2019 that affected approximately 106 million users across the US and Canada stemmed from an SSRF vulnerability exploit. Some of the compromised information included customer names, addresses, contact information, dates of birth, US Social Security numbers (SSNs), Canadian Social Insurance numbers (SINs), credit scores, payment history, and self-reported income.
Many cybersecurity experts including Cloudflare’s Evan Johnson pinned the incident on an SSRF attack. More recently, both the actively exploited Microsoft Exchange zero-days from March 2021 (CVE-2021-26855) and the recently discovered ProxyShell exploits are the result of SSRF flaws.
How does an SSRF attack work?
When making a request to a web server or clicking on a hyperlink, visitors are provided files that are meant to be seen by the world -- that is, those present in the public_html or www folders. Anything present in private folders or databases is typically restricted to more privileged users, such as server administrators.
However, files and assets that are directly accessible to the general audience surfing the web might be accessible by the server itself. For example, as a visitor, you can easily request a public URL like https://www.csoonline.com/uk/events but not the sensitive system files on CSO’s server such as /etc/shadow or /etc/passwd. The web server can likely access these files.
Basic or non-blind SSRF
In a vulnerable environment, a web application running on a server could also have access to these files. The basis of any SSRF attack is that a publicly accessible (web) server can be tricked by the end user into providing access to sensitive files on that server or access to other, more privileged systems or operations that are otherwise restricted for the end user.
For example, take the example of a vulnerable e-commerce site at shop.example.com that uses multiple servers. Users can visit shop.example.com to browse through the products, but the product detail sits on another server, to which users don’t have direct access. Let’s assume the server behind shop.example.com does.
So, when you click on a product, the shop’s main server makes a secondary request. To keep it simple, let’s assume it’s a simple GET request with the URL visible in your browser’s address bar: shop.example.com/?url=shop-server-2.example.com/product555/
Going to this complete URL provides you with the details for product #555. If an attacker can reasonably deduce that they don’t have direct access to http://shop-server-2.example.com/product555/ but shop.example.com does, they have now found a way to use shop’s main server as the middle ground. They can potentially exploit this web server to gain access to restricted assets and files.
If shop.example.com has lax protection and is vulnerable to SSRF, an attacker could simply navigate to shop.example.com/?url=file:///etc/passwd and very likely the vulnerable server now returns contents of the sensitive /etc/passwd file if no protections are in place.
Depending on the attacker’s goal, the same URL could be modified to include localhost or an internal IP address, along with a custom port number, among other things.
This is just one of the very basic examples of many possibilities SSRF attacks have to offer. The above scenario demonstrates a “basic” or non-blind SSRF in which a malicious request made by the attacker results in visible data being returned by the server.
Such attacks are excellent for threat actors looking to exfiltrate data from secret files and assets or to check if specific system ports are open and running services.
Blind SSRF attacks, on the other hand, do not necessarily return any data but rather focus on performing unauthorised actions on the server’s backend. With blind SSRF attacks, the attacker’s focus would be to, for example, modify something on the server, alter or delete files, change permissions, and perform a variety of unauthorised operations rather than going for data exfiltration.
As an extension of the example above, suppose the above URL was modified to go to shop.example.com/?url=http://example.com/some-very-large-file.png where the server keeps attempting to fetch an abnormally large file from an external server.
Such a request may cause shop.example.com’s web server to crash, resulting in denial of service (DoS) for everyone. This type of SSRF attack is “blind” as the focus isn’t on retrieving a visible response or data but rather performing a detrimental action on the server’s behalf.
How to mitigate SSRF vulnerabilities
The basis of mitigating SSRF flaws remains to prevent users from influencing input that reaches your internal applications. Your internal applications should never blindly trust the input or assume that it’s coming from an authentic source.
For example, in the above example of shop.example.com, why does the server even accept file:/// URLs? The same would go for ftp:// or application-specific URI schemas such as slack: or skype:. The system should ideally be restricted to only a select few protocols, such as HTTP and HTTPS, depending on the needs of the application.
There are better ways to conduct the same operation described in this example so that a URL parameter to an internal server never needs to be passed from the client side.
How about just passing a product number—shop.example.com/?product=555—and letting shop.example.com’s back end fetch details for product 555 from another server, the address to which is hard-coded on the back-end? You would do this only after sanitising the numerical “product” parameter, and ensuring it is free of any malicious data.
Secondly, if the logic of the program cannot be modified and it absolutely needs a URL, an allowlist and denylist approach is a solution. For example, some applications implementing OAuth-based logins submit “redirect URLs” among other URL parameters in-between requests, and have been found to be vulnerable to SSRF.
Allowlist or whitelisting approaches are safer as the program allows access to only the permitted objects or in this context, locations, making the process more selective and secure. The denylist approach, on the other hand, denies access to only certain locations of your choosing, such as localhost or 127.0.0.1 but allows everything else.
Denylist approaches run the risk of a clever attacker finding workarounds, e.g., via HTTP redirects, obfuscated URLs, DNS rebinding, or more realistically the server administrator forgetting to include something on the denylist that then gets the attention of the attacker.
As with most vulnerabilities, SSRF flaws can be squashed by adopting a trusting no-one mindset -- sanitising input and minimising the possibility of input being influenced by the end user. Additionally, adopting the principle of least privilege where the system only grants access to APIs and internal systems that are absolutely necessary for the operation via an allowlist is a strong approach toward curtailing SSRF exploits.