OWASP Top 10 - 2021 (task 22)
This challenge deals with a Server-Side Request Forgery (SSRF) vulnerability that is present in the server query parameter.
Last updated
This challenge deals with a Server-Side Request Forgery (SSRF) vulnerability that is present in the server query parameter.
Last updated
Extra practice challenge: "Going the extra mile"
There's a way to use SSRF to gain access to the site's admin area. Can you find it?
A GET request is sent to the following href to download the resume:
/download?server=secure-file-storage.com:8087&id=75482342
General format of the HTTP URL:
http://<url>:8087/download?server=<server_addr>&id=<file_id>
Admin interface only available from localhost!!!
This tells us that the admin page can only be accessed from within the machine itself. The goal now will be to find a SSRF vulnerability to redirect the request to the localhost admin URL instead.
I have noticed that an error messages with snippets of the code-base (sensitive information) is shown when a non-integer value is provided to the id
query parameter via a GET request.
For example, when the value t
is provided, the following info and code snippet is shown in the error message.
A GET request to http://<url>:8087/download?server=&id=t
gives the following error details:
ValueError: invalid literal for int() with base 10: 't'
From the code snippet in the error message, I have discovered that the final HTTP URL where the request is being sent is generated in the following format:
Where the server
query parameter is taken directly from the server query parameter value. The id query parameter value is used directly to generate the final URL value, however, it does not have a direct exploitable impact. This tells us that we can potentially control the final URL where the GET request is being sent.
Thus, the goal is to craft a payload to the server query parameter to forge a request to the localhost admin URL: http://localhost:8087/admin
- allowing us to retrieve the admin page content.
server
query parameterThe placeholder <url>
will be used as a general value. As detailed from part 1 in the Enumeration section, the goal will be to redirect the GET request to the localhost admin page at port 8087 - placeholder value should be replaced with localhost:8087/admin
.
Null terminator/byte (%00
)
http://<url>:8087/download?server=<url>%2500&id=1
The input to the id parameter will be a random integer value. While the value to the server query parameter will be the target URL with the %00
character at the end. The goal is to forcefully terminate the string value, to have the server ignore the part after the input.
<url>%00/public-docs-k057230990384293/<filename>
-> <url>
However, this method does not work, and produces the following error message:
ValueError: embedded null byte
?
(query symbol) (✔ Working method)
Inserting a ? character at the end of the server query parameter value will trick the server to treat the rest of the input ('/public-docs-k057230990384293/' + filename
) as a query. Thus, effectively ignoring its values, allowing an attacker to fully control the server address.
A GET request to the following payload allows us to send a request to the /admin path from within the server localhost, bypassing the restrictions.
http://<target_url>:8087/download?server=localhost:8087/admin?&id=1
#
(URI fragment) (✔ Working method)
Similar to the query symbol, inserting an URI fragment symbol (#
) at the end of the server query parameter value will trick the server to treat the rest of the input as a fragment.
First attempt of payload:
http://<target_url>:8087/download?server=localhost:8087/admin#&id=1
**Tested on Google Chrome and Firefox
Some browsers may remove the section after the hash symbol (#
):
.../.../admin#&id=1
-> .../.../admin
The final URL causes the id query parameter to be removed, which gives the following error:
No file selected...
A fix will be to encode the hash symbol (%23
):
.../.../admin%23&id=1
-> .../.../admin#&id=1
Hence, the final GET request URL is:
http://<target_url>:8087/download?server=localhost:8087/admin%23&id=1
Visiting the following URL (GET request), presented me with a webpage displaying the following message: