Introduction
Server-side request forgery is a web vulnerability that allows an attacker to induce the server-side application to make requests to an undesired location. In a typical SSRF attack, the attacker can cause the server to establish a connection with internal services only within the organization's infrastructure.
In other cases, they may be able to force the server to connect to external systems, which can result in the disclosure of sensitive data such as authorization credentials. A successful SSRF attack can often lead to unauthorized actions or access to data within the organization, either within the vulnerable application itself or on other core systems that the application can communicate with.
Attack against the system
The attacker induces the application to send an HTTP request to the server hosting the application, via its loopback interface. This usually involves providing a URL with a hostname such as 127.0.0.1 (a reserved IP address that points to the loopback adapter) or localhost (a commonly used name for the same adapter).
For example, consider a shopping application that allows the user to see if an item is in stock at a particular store. To provide stock information, the application needs to call various back-end REST APIs. The function is implemented by passing the URL to the relevant back-end API endpoint via an HTTP request from the frontend, and the browser executes this request:
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 124
stockApi=http://stock.alibaba.net:8081/product/stock/check%3FproductId%3D6%26storeId%3D1
In this situation, an attacker can modify the request to specify a local URL to the server itself. For example:
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 124
stockApi=http://localhost/admin
Here, the server retrieves the content of the /admin URL and returns it to the user. When the request to the /admin URL comes from the local machine itself, normal access controls are bypassed. The application grants full access to the administrative functionality because the request appears to come from an approved location.
Why do applications behave this way and implicitly trust requests coming from the local machine? This can happen for various reasons:
- Access control verification may be implemented in a different component located in front of the application server. When a connection is made with the server itself, verification is bypassed.
- For disaster recovery purposes, the application may allow administrative access without authentication to any user coming from the local machine. This enables an administrator to recover the system in case they lose their credentials.
- The administration interface may be listening on a different port number from that of the main application and may therefore not be directly accessible by users.
This kind of trust relationship, where requests coming from the local machine are treated differently from regular requests, is often what makes SSRF a critical vulnerability.
Attack against the back-end
Another type of trust relationship that often occurs with server-side request forgery (SSRF) is when the application server can interact with other core systems that are not directly accessible by users. These systems often have non-routable private IP addresses. Since backend systems are typically protected by network topology, they often have weaker security postures. In many cases, internal backend systems contain sensitive features accessible without authentication by anyone who can interact with the systems.
In the previous example, suppose there is an administration interface at the main URL https://192.168.0.68/admin. Here, an attacker can exploit the SSRF vulnerability to access the administration interface by submitting the following request:
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 124
stockApi=http://192.168.0.21/admin
How to prevent this attack?
Using input filters based on a white list
Some applications block inputs containing hostnames such as 127.0.0.1 and localhost, or sensitive URLs such as /admin. In this situation, there is a workaround:
Using another IP representation of 127.0.0.1, such as 2130706433, 017700000001, or 127.1.
Registering your own domain name that resolves to 127.0.0.1. Masking blocked strings using URL encoding or case variation. Using input filters based on a black list Some applications only allow inputs that match, start with, or contain a whitelist of authorized values. The URL specification contains a number of features that are likely to be overlooked when implementing ad hoc URL analysis and validation:
You can embed credentials in a URL before the hostname, using the @ character: https://expected-host@attacker-host You can use the # character to indicate a URL fragment: https://attacker-host#expected-host You can leverage the DNS naming hierarchy to place the required entry in a fully qualified DNS name that you control: https://expected-host.attacker-host You can encode characters in the URL to confuse the URL analysis code. This is particularly useful if the code implementing the filter handles URL-encoded characters differently from the code that executes the main HTTP request. You can use combinations of these techniques together. Filters can be bypassed with a redirection It is sometimes possible to bypass any type of filter-based defenses by exploiting an open redirection vulnerability. In the previous SSRF example, suppose the URL submitted by the user is strictly validated to prevent malicious exploitation of SSRF behavior. However, the application whose URLs are allowed contains an open redirection vulnerability. If the API used to perform the backend HTTP request supports redirects, you can create a URL that satisfies the filter and generates a redirected request to the desired backend target. For example:
/product/nextProduct?currentProductId=6&path=http://attacke-user.net
This redirects us to http://attacker-user.net and thus we can bypass this obstacle by using:
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 124
stockApi=http://alibaba.net/product/nextProduct?currentProductId=6&path=http://192.168.0.21/admin
This SSRF exploit works because the application first validates that the provided stockAPI URL is on an authorized domain, which is the case. The application then requests the provided URL, which triggers the open redirection. It follows the redirection and makes a request to the internal URL chosen by the attacker.
Strengthen the application layer
It is advisable not to rely solely on the network layer and to use direct application checking. Always clean any input that the user sends to your application. Remove bad characters, normalize input (double quotes instead of single quotes, for example). Thus, create endpoint-level role validations.
Enable authentication on all services
Ensure that authentication is enabled on all services running on your network, even if they do not require it. Services such as memcached, redis, mongo, and others do not require authentication for normal operations, but this means they can be exploited.