SSRF: The Complete Practical Guide to Server-Side Request Forgery

SSRF to RCE and Compromise

Turning SSRF into code execution: gopher byte-smuggling into Redis and FastCGI, dict and file schemes, and chaining stolen cloud credentials.

Published

SSRF is a launchpad, not usually the endgame. Reaching an internal service is step one, and making that service do something is step two. With the right protocol tricks you can send arbitrary bytes to internal daemons and turn a request primitive into command execution, and with stolen metadata credentials you can move straight into the cloud control plane. How far you get depends on what schemes and bytes the fetcher lets you control.

Why SSRF is a launchpad

A plain SSRF reads pages and scans ports. To reach code execution you need two more things: a way to deliver the exact bytes an internal service expects, and a service that does something dangerous when it receives them. The escalation is about upgrading from "fetch an HTTP URL" to "send raw bytes to a TCP port," and then pointing that at a service with a known abuse.

Smuggling bytes with gopher

The gopher:// scheme is the workhorse, because it lets you send an arbitrary byte stream to a host and port rather than a shaped HTTP request. You URL-encode the payload, including the CRLF line endings the target protocol needs:

gopher://127.0.0.1:6379/_<url-encoded Redis commands>

Against an unauthenticated Redis, you can write keys that become something executable, for example setting the config to write a file into a web root or a cron directory and then saving, which lands a web shell or a scheduled command. The same idea delivers a FastCGI request to a PHP-FPM socket to run code, or speaks SMTP to send mail from the inside. gopher is a generic TCP client expressed as a URL.

dict and file for reads and probes

Lighter schemes are useful even when you cannot smuggle full payloads:

dict://127.0.0.1:6379/info      line-oriented probe, reads a service banner/info
file:///etc/passwd              local file read, no network needed
ftp://127.0.0.1/                internal FTP reach

dict:// sends a single line to a port and reads the reply, which is a clean way to fingerprint a service. file:// skips the network entirely and reads local files, so a fetcher that allows it leaks server files directly.

Hitting an internal service with a known exploit

Sometimes the internal target is simply a service with a published vulnerability that was never patched because it was "not exposed." An SSRF that can reach it makes it exposed. An internal admin console, an old search server, or a management API with a known RCE becomes reachable, and you send the exploit request from the server's trusted position.

Chaining cloud credentials into takeover

If the SSRF reached the metadata service (see cloud metadata abuse), the escalation is different and often bigger. You take the stolen temporary credentials and call the cloud provider's APIs as that role. Depending on the role's permissions, that can mean reading storage, enumerating and modifying resources, or pivoting toward broader access. No internal RCE needed, just the keys the metadata service handed over.

Put the pieces together with a common real shape. A link-preview feature fetches a URL you supply. You confirm SSRF, find the fetcher allows gopher://, and discover an unauthenticated Redis on loopback. You smuggle Redis commands that write a cron job, wait for it to fire, and you have command execution on the host. One "paste a link" box became a shell.

The defensive lesson is the mirror image: allow only http and https, never gopher, dict, file, or ftp. Keep internal services authenticated even on the internal network, and isolate the fetcher so a successful SSRF reaches nothing worth smuggling to. From here, a single foothold often opens a whole subnet, which is internal network pivoting. Try the full chain on a free live target.

← Back to SSRF: The Complete Practical Guide to Server-Side Request Forgery