Description
A 500-point web challenge that went unsolved during picoCTF 2023, with no public solution since. The live instance ships an unusually large source archive (around 1 GB), which points at a multi-service / multi-tier application rather than a single small app. The page below is an honest, clearly-labeled methodology for the most likely vulnerability class (an SSRF-to-internal-service chain), not a verified step-by-step solve.
Setup
Pull the live instance's source.tar.gz (it is large, around 1 GB; budget disk and bandwidth) and map the services it bundles before touching the app.
Open the challenge URL and use Burp Suite to intercept and replay requests.
# Navigate to http://<HOST>:<PORT_FROM_INSTANCE># Download and unpack the (large) source bundle, then enumerate the internal services it defines.Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Identify the SSRF vectorObservationI noticed the challenge ships a roughly 1 GB multi-service source archive, which suggested the app accepts user-supplied URLs or resource identifiers to fetch remote content, the classic SSRF entry point in multi-tier applications.Find an endpoint that fetches a URL or resource specified by user input. This is the SSRF entry point.Learn more
Server-Side Request Forgery (SSRF) occurs when a server makes an HTTP (or other protocol) request to a URL controlled by the attacker. Attackers use SSRF to access internal services that are not exposed to the public internet: internal APIs, metadata services (e.g., AWS IMDSv1 at 169.254.169.254), and services bound to localhost.
Look for parameters with names like
url,endpoint,src,href,redirect, orfetch. Also look for features that fetch remote content: link previews, webhook validators, PDF generators, and image importers are classic SSRF surfaces.Test with a URL you control (e.g., a requestbin or webhook.site URL) to confirm the server is making outbound requests with your input.
Step 2
Pivot to internal services via SSRFObservationI noticed SSRF confirmed that the server makes outbound requests with my input, which suggested probing loopback addresses and RFC1918 ranges to find unauthenticated internal services that are invisible from the public internet.Use the SSRF vector to probe internal addresses (127.0.0.1, 10.0.0.0/8) and find a running internal service that exposes sensitive data.bash# Try internal endpoints:bashcurl 'http://<HOST>/fetch?url=http://127.0.0.1/'bashcurl 'http://<HOST>/fetch?url=http://127.0.0.1:8080/'bashcurl 'http://<HOST>/fetch?url=http://169.254.169.254/latest/meta-data/'What didn't work first
Tried: Sending the SSRF payload directly in the browser address bar instead of through curl or Burp Suite
The browser issues the request from your machine, not the server, so you reach only public addresses you already have access to. The SSRF only works when the server-side backend fetches the URL; you must send the parameter to the vulnerable endpoint and let the server make the outbound connection.
Tried: Using http://localhost/ instead of http://127.0.0.1/ when the server blocks the string 'localhost'
Many SSRF filters block the hostname 'localhost' but not its numeric equivalents. If the raw IP is also filtered, try decimal (2130706433), hex (0x7f000001), or IPv6 ([::1]). Stopping at localhost means missing the bypass entirely when a denylist is in place.
Learn more
Once SSRF is confirmed, enumerate internal services by trying common ports (80, 8080, 8443, 3000, 5000, 6379 for Redis, 27017 for MongoDB, 9200 for Elasticsearch). The server's response body, status code, and response time reveal whether each port is open.
Many internal services have no authentication because they are assumed to be unreachable from outside. An internal admin panel, debug endpoint, or metadata service may immediately disclose sensitive data when accessed through SSRF.
SSRF filter bypasses include: using alternative IP representations (
0x7f000001,2130706433, or[::1]for 127.0.0.1), protocol switches (file://, dict://, gopher://), URL redirectors, and DNS rebinding.Step 3
Chain with injection to read the flagObservationI noticed the internal service reachable via SSRF accepts parameters that resemble file paths or query inputs, which suggested chaining the pivot with path traversal or SQL injection to escalate from network access to direct flag disclosure.If the internal service is vulnerable to injection (SQLi, command injection, path traversal), chain the SSRF with injection to read the flag file.bash# Example: SSRF to internal API + path traversal:bashcurl 'http://<HOST>/fetch?url=http://127.0.0.1:8080/read?file=../../flag'bash# Example: SSRF to internal API + SQLi:bashcurl 'http://<HOST>/fetch?url=http://127.0.0.1:8080/users?id=1+UNION+SELECT+flag+FROM+flags--'Expected output
picoCTF{...}What didn't work first
Tried: Attempting path traversal directly against the external-facing host before confirming an internal service handles file reads
The external app almost certainly sanitizes or forbids path traversal. The traversal only succeeds against the internal service reachable via SSRF, which lacks the same input validation. You need to pivot through the SSRF channel first and target the internal service's file-read or API endpoint.
Tried: Injecting SQL directly into the external app's parameters instead of tunneling the SQLi through the SSRF payload
The external app is the SSRF vector, not the SQLi target. The internal service at 127.0.0.1 is what exposes the vulnerable SQL query. Injecting into the outer app's parameters hits a different code path that has no SQL query to exploit; the payload must be URL-encoded inside the url= parameter so the internal service receives and evaluates it.
Learn more
Chained vulnerabilities - using one bug to access a second, more impactful bug - are common in real-world attacks. SSRF is particularly useful as a pivot because internal services often have weaker input validation than internet-facing ones.
In this challenge, the SSRF lets you reach an internal service, and that service has a secondary vulnerability (injection, traversal, or a sensitive endpoint) that gives you the flag. Enumerate the internal service's routes and parameters carefully.
SSRF was included in the OWASP Top 10 in 2021 (A10:2021). High-profile real-world SSRF incidents include the Capital One breach (2019), which used SSRF against the AWS instance metadata service to steal IAM credentials.
Step 4
Exfiltrate the flagObservationI noticed the internal service relayed its response back through the SSRF fetch endpoint, which suggested the flag would appear directly in that relayed HTTP response once the injection chain succeeded.Read the flag from the internal response and submit it.Learn more
The flag will appear in the server's response once the chain is successful. If the internal service returns the flag directly in its HTTP response, your SSRF fetch endpoint will relay it back to you. If the internal service only writes the flag to a file, use a secondary path traversal or file-read endpoint to fetch it.
When exfiltration through the same SSRF channel is blocked (e.g., response size limits or content filtering), consider out-of-band channels: cause the internal service to make a DNS lookup or HTTP request to a server you control, encoding the flag in the subdomain or URL path.
Interactive tools
- Reverse Shell GeneratorGenerate reverse shell payloads (bash, nc, python, perl, ruby, php, node, powershell) and matching listeners. Set host and port once, copy any variant.
Flag
Reveal flag
picoCTF{...}
Challenge unsolved during the competition; this page is a methodology template for SSRF + injection chains, not a verified step-by-step solution. Concrete endpoints and payloads will vary.