# SSRF

### What is SSRF vulnerability?

***

SSRF stands for Server Side Request Forgery. SSRF is a vulnerability where server makes a request on behalf of user without proper validation. It targets the endpoints that uses url to fetch something so we can exploit it. The attacker abuses the server as a proxy to fetch the data from the backend or database. You can say its like, if you cannot get the data from database directly then you can use the server as your butler to get the data from database for you.

### Detection

***

Look for an endpoint where website takes a url to get the data, it could be:

* Parameters - `?url=` , `?path=` , `?uri=` , `?image_url=` , `?callback=`&#x20;
* URL fetcher - uploading images, pdfs, or webhooks using url.
* File imports - uploading file via url
* API integrations - using API to get the data
* XML parsers - Using url inside xxe payload to pivot SSRF

There are more such as webhooks, pdf generations, metadata services, etc. Basically any user supplied input where you can put/use url that the server fetches on the behalf of you.

To check different types of variation try different payloads from: <https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Request%20Forgery/README.md>

SSRF automation tool: <https://github.com/swisskyrepo/SSRFmap>

### Reflected SSRF (In-bound)

***

Check if you are getting any response or error for an internal request, it could be against local server or backend server.&#x20;

1. Identify input parameter accepting URLs
2. Submit internal service URL (e.g., `http://localhost:8080/admin`)
3. Read response or error directly

Example Payloads:

```
http://localhost/admin
http://127.0.0.1:8080/
http://169.254.169.254/latest/meta-data/ (AWS)
http://internal-service.company.local/api/secret
```

If not local server, try internal server such as [`http://192.168.0.1:8080/admin`](http://192.168.0.1:8080/admin)  , it is not necessary that it will give you response. You might need to

* Fuzz the last octet of ip to check if there is any running service or discover another host
* Fuzz the port number to check if there is any other running service.
* Fuzz the endpoint, try obfuscated words, double url encoded, etc.

Use ffuf to fuzz ip octect or port number (better than writing a whole python script):

```
## Create a txt file containing ip range 1 to 255
❯ ffuf -w ./octect.txt -u 'http://target.net/product/stock' -X POST \
           -d "stockApi=http://192.168.0.FUZZ:8080/admin" \
           -H "Content-Type: application/x-www-form-urlencoded" \
           -mc 200,302 -v
```

You can do the same with Port fuzzing:

```
## Create a txt file containing port range 1 to 65535
ffuf -w ./ports.txt -u https://target.net/endpoint -X POST \
     -d "stockApi=http://127.0.0.1:FUZZ" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -mc 200,500 -v
```

Similarly, you can fuzz directory, not just admin endpoint using ffuf.

{% hint style="info" %}
Reflected SSRF is all about getting visible response or error that might confirm SSRF vulnerability.
{% endhint %}

Let's explore a real Reflected SSRF vuln, I was solving a HTB machine when I encountered this CVE-2023-27163 from request basket which is an open source project: <https://www.rbaskets.in/web>

<figure><img src="/files/h2mhMBC3X1wcbJTSc20z" alt=""><figcaption></figcaption></figure>

This request-basket version 1.2.1 was vulnerable to reflected SSRF. Here is the POC repo for this CVE:

<https://github.com/entr0pie/CVE-2023-27163>&#x20;

Now, if i create a new basket here, I get to see that it hits the POST request on api endpoint:

<figure><img src="/files/eUhtpiKgrXDxXtrkwkVB" alt=""><figcaption></figcaption></figure>

Let me just send this request to repeater and try to create a new basket manually but with some spicyness, i mean some parameters:

<figure><img src="/files/Ht2KZdn9MSgkSznZt9Oe" alt=""><figcaption></figcaption></figure>

I created a new basket "UwU" using these 2 parameters and it was a success:

```json
{
	"forward_url":"https://webhook.site/ae28bd70-aed0-414a-845f-b0f2f50d7e38",
	"proxy_response":true
}
```

I am using webhook.site to get the hit which will let me confirm if its really hitting the target. You can use redirectmeto, httpbin, interact sh, etc. There are multiple sites that act as a webhook, or you can even use ngrok. Now if i hit the endpoint "UwU" in my browser:

<figure><img src="/files/kHOLjzhvnLsQfALUonxP" alt=""><figcaption></figcaption></figure>

It hit the url that i provided in `forward_url` parameter, but where did i get these parameters? Well, the request-basket is an open source project so you can find its repo with v1.2.1: <https://github.com/darklynx/request-baskets/tree/v1.2.1>

Now, if you look at the source code of file `basket.go`  :

```go
// BasketConfig describes single basket configuration.
type BasketConfig struct {
	ForwardURL    string `json:"forward_url"`
	ProxyResponse bool   `json:"proxy_response"`
	InsecureTLS   bool   `json:"insecure_tls"`
	ExpandPath    bool   `json:"expand_path"`
	Capacity      int    `json:"capacity"`
}

// Forward forwards request data to specified URL
func (req *RequestData) Forward(client *http.Client, config BasketConfig, basket string) (*http.Response, error) {
	forwardURL, err := url.ParseRequestURI(config.ForwardURL)
	if err != nil {
		return nil, fmt.Errorf("invalid forward URL: %s - %s", config.ForwardURL, err)
	}
```

So, when you send JSON data in API request, the code map that JSON data with this struct. Technically, the server recieves these JSON parameters in maps in `config.ForwardURL` which then forward it to the user-supplied url on behalf of the user. Using `proxy_response`  parameters so that the server response can be reflected.

Now, look at the file `handler.go` :&#x20;

```go
	// validate URL
	if len(config.ForwardURL) > 0 {
		if _, err := url.ParseRequestURI(config.ForwardURL); err != nil {
			return err
		}
	}
```

This is root cause that does validate the URL format, basically syntax of the provided url. But it does not:

* Resolve DNS
* Check IP ranges
* Block localhost or internal networks
* Enforce Whitelist or Blacklist

So, If i just put localhost in the `forward_url` parameter, it should fetch the internal service that is running internally?

<figure><img src="/files/J160dFTGWg8vox5cmSCq" alt=""><figcaption></figcaption></figure>

I created another basket called linlin but this time i used localhost and look at the response, it was a success. Now if I go to linlin endpoint, it should forward the request to the localhost:

<figure><img src="/files/Ki3JeiN436VmmyCOZQNZ" alt=""><figcaption></figcaption></figure>

Hence, A successful Reflected SSRF exploit. In the machine there was another command injection vulnerability that i chained with SSRF to get the reverseshell.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kaizoku.gitbook.io/notes/web-vulnerabilities/ssrf.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
