My Journey to a QA Security Mindset: SSRF vulnerability

Asaf Sahar
AppsFlyer Engineering
4 min readJul 12, 2021

Intro

In my previous blog post, I discussed the first vulnerability that I learned about in my journey to a QA security mindset — IDOR. If you have not yet read the post, you can find it here.

While the IDOR vulnerability felt more intuitive and easy to test, I found the Server Side Request Forgery (SSRF) vulnerability — the next one in my journey — to be a bit more complicated. This is because SSRF requires having a basic understanding of microservice architecture and private networks.

Microservices is an architectural style that structures an application as a collection of services.

Private networks are used in organizations to allow a group of servers to communicate with each other while not being exposed to the internet.

The Dangers of SSRF

SSRF is a security vulnerability that allows an attacker to send a request to an internal service through a public service. Without this vulnerability, an attacker cannot send requests to the internal service.

The danger with SSRF, therefore, is that it can easily lead to unauthorized actions such as: Access to data, ability to execute arbitrary commands on a company’s backend systems, connection to third party systems and more.

Example

Let’s take a look at an example of a website used for shopping. This website provides users with the ability to check how many items are left for a specific product. The diagram will help you to understand which service is public and exposed to the internet and which service is internal and shouldn’t be accessible to anyone externally.

A request for this type of functionality looks like this:

Here, the server makes a request to the specified URL in the stockApiUrl parameter, retrieves the stock status, and returns it to the user.

When this happens, an attacker can modify the request to specify a URL that is local to the server itself.

Let’s look at an example.

POST request

https://www.mywebsite.com/products/item?stockApiUrl=http://localhost/admin

Here, the server fetches the contents of the /admin URL and returns it to the user.

An attacker that tries to send only the ‘http://localhost/admin’ request will not get anything because they are not connected to the private network. However, when the request to the /admin URL first comes from a server that shares the same private network, the request is successful, and the application grants full access to the administrative functionality and displays it to the user.

Add SSRF to Your Testing Plan

One useful approach that I am using to test SSRF is to create a dedicated server inside the internal network — one that acts as an internal service that is not accessible to anyone outside of the network. Our Security team at Appsflyer, in fact, has already created such a service, using openresty. All the traffic that hits this server is logged, and they have also created a dedicated Slack channel that prints the log if we succeed in hitting this service.

Let’s use the following example for an internal service: http://af-ngnix-internal-server-example:8080/tested_service/GET.json?info=uniqueIdentifier

Using the example above, I can set the stockApiUrl URL to be the value of the internal service, so that the request looks like this:

https://www.mywebsite.com/products/item?stockApiUrl=http://af-ngnix-internal-server-example:8080/tested_service/GET.json?info=uniqueIdentifier

Then using Python and Pytest, I can create a request to this URL:

https://www.mywebsite.com/products/item?stockApiUrl=http://af-ngnix-internal-server-example:8080/tested_service/GET.json?info=uniqueIdentifier .

If I succeed in hitting the internal service (the URL in stockApiUrl), a message is printed in the Slack channel. My test looks for that message in the Slack channel. If it finds the uniqueIdentifier, I will fail the test saying that the SSRF vulnerability is found and then I can print the log I found.

So now that you know all about this unique vulnerability, how about trying it out yourself? You can implement it on your website by looking for a URL value in one of your website requests. This value can be part of the HTTP query string parameter — as we saw in the example above — or in the request body. You can then replace this URL with the URL of the internal service.

Thank you for taking the time to read my post. I hope you will read my upcoming posts as well, where I plan to cover the following:

PART V: My Journey to a QA Security Mindset: Information Disclosure Vulnerability

PART VI: My Journey to a QA Security Mindset: XSS Vulnerability

PART X: TBD

--

--