Note: Majority of the content here was ripped directly from PortSwigger.net.
Table of Contents:
- What is Server-Side Request Forgery?
- What is the impact of these attacks?
- SSRF attacks against the server itself
- SSRF attacks against other back-end systems
- Finding Attack Surface for SSRF
- What do we look for?
- Where do we look?
- Commonly chained exploits
- Basic Bypass Techniques
- Bypassing black-list based defenses
- Bypassing white-list based defenses
- Exploitation Examples
- Example 1: Basic SSRF against the local server
- Example 2: Basic SSRF against another back-end system
- Example 3: SSRF with blacklist-based input filter
- Example 4: SSRF with whitelist-based input filter
- Example 5: SSRF with filter bypass via open redirection vulnerability
- Example 6: Exploiting XXE to perform SSRF attacks
What is Server-Side Request Forgery?
SSRF is a vulnerability that allows attackers to induce a web server to make an HTTP request that they control. Typically, this would allow the attacker to see things that they wouldn’t otherwise be able to see. For example, having the webserver make a request back to itself or to another device on the internal network it is connected to make allow attackers to extract information that isn’t publicly available.
What is the impact of these attacks?
It is common for infrastructure to be configured to trust other devices within the same internal network, or to trust devices that are managed by the same organization and their trusted third-parties. Because of this, SSRF may allow attackers to bypass authentication restrictions, location or IP-based restrictions, and more.
SSRF attacks against the server itself
In these type of attacks, the attacker will induce a HTTP request to make the webserver issue a request back to its own local loopback interface (oftentimes
localhost). This could be beneficial if restrictions are configured within parts of the webapp that are only visible when you’re accessing them locally from the webserver itself. For example, say there is an admin panel that isn’t visible to external users, but is visible to users who access it from the webserver itself. Issuing a request like this may allow an attacker to gain unauthorized access.
POST /product/stock HTTP/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 118 stockApi=http://localhost/admin
Why does this work? There are a number of reasons why a webserver may implicitly trust requests made by itself.
- Admins may rely on front-end load balancers or web application firewalls to implement access control checks BEFORE the request hits the webserver. When a connection is made back to the server itself, the check is bypassed.
- For disaster recovery purposes, applications may allow admin access without logging in for any users coming from the local machine.
- The administrative interface might be listening on a different port number than the main application, which may make it not directly reachable from the outside.
SSRF attacks against other back-end systems
It is common for internal systems to be less protected than external systems on the internet. Because of this, compromising an externally facing system with a SSRF vulnerability may allow you to interact with other devices on the internal network that trust that webserver when communicated to from INSIDE the network on non-routable private IP addresses. In many cases, internal back-end systems contain sensitive functionality that can be accessed without authentication by anyone who is able to interact with the systems.
For example, lets say there is an administrative interface at the back-end URL
https://192.168.0.68/admin. Here, an attacker can exploit the SSRF vulnerability to access the administrative interface by submitting the following request.
POST /product/stock HTTP/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 118 stockApi=http://192.168.0.68/admin
Finding Attack Surface for SSRF
Knowing about the vulnerability is great, but how do we actually hunt for it? Where do we look? What other vulnerabilities are commonly chained? Let’s answer those questions.
What do we look for?
Full URLS in Requests. This is the easiest to spot, as you will typically see the HTTP/HTTPS handlers in the request.
Partial URLs in Requests. Sometimes an application will only place a hostname or part of a URL path into the request parameters. The value submitted is then incorporated server-side into a full URL that gets requested. These may be harder to spot, and harder to exploit, because you do not have control of the entire URL that gets requested.
URLs within data formats. Some applications transmit data in formats whose specification allows the inclusion of URLs that might get requested by the data parser for the format. For example, an application that accepts and parses XML code may be vulnerable to XXE Injection, and in turn be vulnerable to SSRF via XXE.
Where do we look?
SSRF vulnerabilities are commonly found in the following:
- Anytime an application makes a call to an API.
- Look in URLs or Parameters that issue requests to HTTP/HTTPS handlers.
Commonly chained exploits
- Open Redirects may help cause more impact to an SSRF vulnerability. See lab example below.
- When the application parses XML code, XXE Injection may be utilized to cause an SSRF. See lab example below.
Basic Bypass Techniques
It is common for applications to implement defenses the prevent exploitation of SSRF attacks. This section will explain various defenses and provide some bypass techniques to try.
Bypassing black-list based defenses. Some applications will block input containing hostnames like
localhost, or sensitive URLs like
/admin. To circumvent the filter, you can use these techniques.
- Using an alternative IP representation of
127.0.0.1, such as
- Registering your own domain name that resolves to
127.0.0.1. You can use
spoofed.burpcollaborator.netfor this purpose.
- Obfuscating blocked strings using URL encoding or case variation.
Bypassing white-list based defenses. Some applications will only allow input that matches, begins with, or contains a whitelist of permitted values. The following can be used to circumvent this filter.
- You can embed credentials in a URL before the hostname, using the
@character. For example:
- You can use the
#character to indicate a URL fragment. For example:
- You can leverage the DNS naming hierarchy to place required input into a fully-qualified DNS name that you control. For example:
- You can URL-encode characters to confuse the URL-parsing code. This is particularly useful if the code that implements the filter handles URL-encoded characters differently than the code that performs the back-end HTTP request.
- You can add a period (.) to the URL within the parameter. If the Regex used for whitelisting is misconfigured, this could bypass the restriction.
- You can use combinations of these techniques together.
While watching Nahamsec’s stream, he tried bypassing using the following when he had a parameter that looked like this:
· http://%2f%2flocalhost%2fadmin%2fdelete?username=carlos · http://%2f%2flocalhost/login/../%2fadmin%2fdelete?username=carlos · http://%2f%2flocalhost/x/../%2fadmin%2fdelete?username=carlos · https://%2f%2flocalhost/login/../%2fadmin%2fdelete?username=carlos · http://%2f%2flocalhost/////admin%2fdelete?username=carlos · http://localhost/ADMIN/delete?username=carlos · http://localhost/AdMiN/delete?username=carlos
Example 1: Basic SSRF against the local server
In this example, browsing to the /admin directory returns an error stating that its only available locally from the server, or for signed in administrators.
However, a SSRF vulnerability exists within the “Check Stock” functionality of the website. Checking the stock of an item will issue a request that talks to a back-end API, which you can see in the following request.
Modifying the StockAPI parameter allows us to issue a request from the webserver, to itself, and delete a user from the admin panel.
Example 2: Basic SSRF against another back-end system
In this example, there is a device on the internal network that allows unauthenticated access to the admin interface. Since we can’t access this device externally, we’ll need to leverage the SSRF vulnerability on the externally facing webserver to communicate with it. To begin, we know that the internal network uses the following internal network scheme: 192.168.0.0/24. Armed with this knowledge, we’ll start by making a webrequest that looks like this.
We can actually leverage this vulnerability to scan the internal network for other devices. To automate this, we’ll send this request to Burp Intruder.
- Click “Clear §”, change the
http://192.168.0.1:8080/adminthen highlight the final octet of the IP address (the number 1), click “Add §”.
- Switch to the Payloads tab, change the payload type to Numbers, and enter 1, 255, and 1 in the “From” and “To” and “Step” boxes respectively.
- Click “Start attack”.
After some time, the attack should reveal that an address on the LAN returned a 200 OK.
Throw that request into Repeater, and update the parameter to include instructions for deleting a user to complete the challenge.
Example 3: SSRF with blacklist-based input filter
In this example, there are two protections that we need to bypass.
- First, we have to bypass the protections that prevent
localhost. To do so, we’ll sent a request to
127.1and confirm that we receive a response.
Second, the word “admin” is blacklisted. To get around this, we can URL-encode a character in the word, such as the ‘a’. This will encode to %61. However, this is blocked as well, so we can then encode the % sign in %61. This is referred to as “Double URL Encoding”. When ‘a’ is double URL Encoded, this would be represented as
%2561. Issuing the following request also returns a 200 OK, confirming we’ve bypassed the filter.
Finally, we can issue the request to delete the user.
Example 4: SSRF with whitelist-based input filter
In this example, there are a handful of bypasses we’ll need to implement.
First, we’ll try and issue a request to
localhost. We find that the returned response tells us “stock.weliketoshop.net” must be included in the request.
Knowing we’ll have to include that text in the request, we test to see if the application will accept embedded credentials by adding
username@ to our request. Doing so returns a different response, as if the webserver attempted to connect to “username”.
This is great, but it’s pointless if we don’t have a way to indicate a URL fragment. We can usually utilize the # sign for this, but the application rejects requests that contain that character. To get around this, we’ll Double URL Encode the # sign so that it is represented by %2523. Notice how now the request goes through.
Finally, we can replace “username” with localhost, and see that the response returns a webpage! By appending
/admin/delete?username=carlos, we can issue a request that deletes the Carlos user.
Example 5: SSRF with filter bypass via open redirection vulnerability
In this example, we have an application that contains a SSRF along with an Open Redirection. By chaining these two together, we’re able to force the webserver to issue a request that deletes an user from within the admin panel.
To begin, we’ll find the open redirect vulnerability. This is present within the “Next Product” option. Click that returns a URL that looks like the following:
We find that anything placed into the above
path parameter will get redirected. For example, the following URL would redirect to google.com
Knowing this, we can place our SSRF payload within the
path parameter of the open redirect.
Then we can abuse the SSRF to force the webserver to issue the request. Doing so will delete the Carlos user.
Example 6: Exploiting XXE to perform SSRF attacks
In this example, we have a web application that parses XML input and returns any unexpected values in the response. Because of this, we can inject an XXE that issues a SSRF on our behalf, which leads to exposed EC2 credentials.
To begin, we’ll capture the “Check Stock” request and Insert the following external entity definition in between the XML declaration and the
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "http://169.254.169.254/"> ]>
Then replace the
productId number with a reference to the external entity:
The response should contain “Invalid product ID:” followed by the response from the metadata endpoint, which will initially be a folder name. Iteratively update the URL in the DTD to explore the API until you reach
/latest/meta-data/iam/security-credentials/admin. This should return JSON containing the