An SSRFing Mess

Howdy hackers! This week we'll be examining Server-Side Request Forgery (SSRF). From what it is, to modern prevention mechanisms, we’ll expand our understanding and develop a methodology on how to test for it in the wild.

What is Server-Side Request Forgery?

Besides not lending itself to a “punny” blog title, Server-Side Request Forgery (SSRF) is a classification of web vulnerability in which an adversary is able to manipulate a server into sending requests on their behalf. Typically, these requests are aimed at resources not accessible within the natural flow of the application. This results in internal files and services becoming accessible to an adversary, allowing them wider scope and the potential to compromise application secrets. In much the same way, SSRF vulnerabilities can be leveraged to force the server to reach out to external sites, potentially letting it be used as a step in a larger, chained attack against another organization with trusts to the vulnerable site.

Manipulation, not Impersonation:

A key distinction to point out in the prior phrasing, SSRF attacks are a form of manipulation. They are carried out by the server itself at the direction of an adversary. This is not the same as an impersonation-based attack, such as spoofing or phishing, which rely on tricking a user into thinking you’re acting on behalf of a server or domain.

Blind SSRF:

While SSRF is typically seen as a vulnerability due to it’s potential to leak information in the response to malicious requests, there exists cases where SSRF returns no information in the HTTP response. These blind SSRFs occur when a request to the server’s backend can be manipulated and is typically confirmed by out-of-band testing. By having these blind requests reach out to a server under the adversary’s control, they’re able to confirm the presence of the vulnerability and can attempt to leverage it to achieve remote code execution (RCE). A great example of this can be found in this PortSwigger lab, where a blind SSRF is combined with the Shellshock exploit to demonstrate RCE on a vulnerable server.


Finding SSRF:

Identify Resource Calls:

Often occurring in features that rely on fetching external resources, we should test for SSRF in any endpoint that takes in user-provided URLs. This includes features such as:

  • File/Image Uploads
  • Document Processors
  • Proxy Services
  • API Endpoints
  • Etc.

Second-Order SSRF:

It's also worth our time to embed our SSRF payloads within files that are later processed by the application. By embedding URLs within a file, such as a PDF, we're able to test to see if our payload is executed when the application parses the contents of the file.

Test for Internal Access:

With our list of functionalities to test, it’s our job now to find a payload that works. Our primary goal with an SSRF vulnerability is to demonstrate the ability to arbitrarily extract information from the server. To this end, we should be mindful of the many potential configurations a private network may follow:

  • localhost
  • 127.0.0.1
  • 192.168.0.1
  • Etc.

Confirm Vulnerability:

Once we've identified the appropriate configuration for our target, we should attempt to demonstrate impact. As SSRF can potentially lead to arbitrary information disclosure, it’s quite a hard decision for an inexperienced researcher to make -- what will prove my vulnerability without being considered excessive and harmful? In cases like these, you should always take the time to reach out to the program and see if they have a specific guideline in place that they would like you to adhere to.

A traditionally accepted route to demonstrate your found SSRF is to grab the banners of commonly open ports. If you’re able to reach port 22 on a Linux server, you’ll likely be returned the banner for SSH, demonstrating your vulnerability without compromising confidentiality of the application.


Preventing SSRF:

SSRF vulnerabilities occur when an application needs to reach out to external resources as a part of its normal flow. When best-security-practices aren’t followed, these same functions can be manipulated to reach unintended resources.

Blocklists:

Serving as an archive of blacklisted addresses, blocklists are the most commonly used method for preventing SSRF vulnerabilities. Because applications need to fetch resources from constantly changing sources, implementing a blocklist of known malicious sites tends to be easier to manage than their counterpart, allowlists. Blocklists function by specifically disallowing requests to any URL found within, meaning that any URL not explicitly blocked is implicitly allowed.

In typical implementations, internal services and addresses will also be added to the blocklist, as this will help mitigate potential impact if an adversary finds an endpoint vulnerable to SSRF.

Allowlists:

The counterpart to blocklists, allowlists work by only allowing URLs that are explicitly listed to be accessed by the server. While more difficult to manage, allowlists are widely regarded as more secure than blocklists. To add some flexibility to this otherwise rigid defense, regex can be added to allow for pattern matching, though this should be checked over carefully as it does allow for room for error.

Internal Networks:

Whether using a block or an allow list, it's always a good idea to follow defense-in-depth principles. Ensuring proper internal network security is just as important in the event of a breach. By limiting an externally facing application's ability to access internal services, you’re able to reduce the potential information an adversary would gain through SSRF. Sufficient internal segregation may even stop a breach before it has a chance to spread further through your systems.


Bypassing SSRF Protections:

It should be noted that the previously mentioned protection methods are all aimed at mitigating SSRF impact, not at preventing it from being possible. As long as an application relies on user-supplied URLs, the potential for SSRF will exist.

Blocklists:

By definition, a blocklist will only prevent access to URLs explicitly disallowed. Finding workarounds to these will largely rely on bypassing string matching, though, there are a few other ideas worth mentioning.

Redirects:

If an adversary is trying to reach an internal resource but localhost is blocked, they can potentially work around this with some clever PHP code. On a malicious page they host, they can implement the following:

<?php header(“location: http://127.0.0.1”); ?>

This PHP script causes a redirect once it’s loaded, allowing the adversary to bypass the blocklist and access localhost anyways.

IPv6:

It should also be remembered that domain names and IPv4 addresses are not the only way to reach a server. Just because IPv4 addresses for localhost are sufficiently blocked doesn’t mean that the coverage is perfect. An adversary may try submitting payloads to ::1, the IPv6 version of localhost, or even fc00:: -- the IPv6 equivalent to a private, internal network.

Encoding IP Addresses:

Another clever trick an adversary may attempt is to encode the IP address. While most are familiar with IP addresses in decimal such as 127.0.0.1, it's also possible to change this into other values such as hex, dword, or even URL-encoded strings. Some alternate payloads as follows:

https://example.com/upload?file=https://0x7f.0x0.0x0.0x1#hex

https://example.com/upload?file=https://2130706433#dword

https://example.com/upload?file=https://%6c%6f%63%61%6c%68%6f%73%74#url-encoded

Allowlists:

When faced with an allowlist, an adversary will have less options. If the list is constructed with weak regex statements, it may be possible to exploit the flexibility of URL syntax to construct a URL that meets the allowlists conditions and yet exposes unintentional resources. Barring this however, the need to adhere to specific, exact strings, will require a more “living off the land” mentality.

Chaining Vulnerabilities:

With a strict allowlist in place, one of the most likely candidates for bypass relies on finding an open redirect within the allowed resources. By using an open redirect with an SSRF payload, an adversary is able to meet the conditions of the allowlist and still have the request resolve to an unintended service.


Escalating SSRF:

While SSRF is largely hailed for its capabilities in data exfiltration, it's certainly possible to achieve other ends with it. Similar to the mentality of a “pivot” in an external-to-internal penetration test, an SSRF vulnerability can allow us to shift from a web focus to an internal one.

Network Mapping:

If the server hosting our vulnerable application is not properly segmented, this can easily become our tool for scanning the rest of the network. By testing against local IP ranges and ports, we can begin to flesh out a map of the entire network as well as what services it offers internally. As many who’ve conducted an external network assessment will confirm, once you’ve made it to the interior, you’re home free nine-out-of-ten times.

Bypassing Access Controls:

Depending on the implementation of access controls throughout an application, being able to send requests on behalf of the server may be all it takes to access administrative functions. Specifically, if API endpoints don’t have properly implemented controls, the following might be possible:

https://example.com/upload?file=https://admin.example.com/delete-user?user=1337

Remote Code Execution:

While touched on at the start of this article, it’s worth mentioning again. Depending on the nature of the internal server, an SSRF vulnerability may be all it takes to find RCE. Because an adversary is able to access internal and unexpected resources, even older vulnerabilities such as Shellshock become a very real threat in allowing an adversary to fully compromise a server, and potentially the network.