SSRF with whitelist based input filter
Description
This lab has a stock check feature which fetches data from an internal system.
To solve the lab, change the stock check URL to access the admin interface at http://localhost/admin
and delete the user carlos
.
The developer has deployed an anti-SSRF defense you will need to bypass.
Approach
Upon gaining access to the lab, I immediately focused on exploring the "stock check" functionality to understand its mechanics. As expected, this feature initiated a POST
request to /product/stock
, with a crucial parameter named stockApi
, intended to fetch data from an external URL.
However, my attempt to redirect it to localhost
was met with a "400 Bad Request" error, indicating that the external stock check host must be stock.weliketoshop.net
. i do get this error
Determined to bypass this filter, I experimented with various techniques in the request. Initially, I attempted to embed credentials directly into the URL using the format http://USERNAME@HOSTNAME
, leading to a Could not connect to external stock check service
response.
It did get through, so now I will attempt to use the #
character to indicate a URL fragment. Anything following the #
is considered an element on that page, with the hostname preceding it. The URL format is as follows:
http://Hostname#element
so this trick is going to indicate that what comes after it is an element which is in our case the @stock.weliketoshop.net
(we need the @
there because it is the reason that it is letting us write something gets accepted before the acquired hostname).
response:
This error suggests that the #
isn't being processed, so I attempted to URL-encode it, but without success. However, when I double URL-encoded it, everything worked smoothly
However, I encountered another error, which was logical because at this stage, the system attempted to reach 'ichyaboy' as if it were a hostname, resulting in an error due to its nonexistence. Therefore, I adjusted it to 'localhost', which granted me access.
Now, I need to access the admin panel and delete the user 'Carlos'. To achieve this, all I need to do is send the following request:
It might appear perplexing to some of you why /admin
is positioned at the end of the URL rather than directly following localhost
. The trick lies in the fact that, as mentioned earlier, anything after the #
symbol is interpreted as an element until it encounters a /
, which is then analyzed as a path. Consequently, the server accesses that designated path.
Let me break it for you:
http://Hostname#Element/Path
http://localhost#@stock.weliketoshop.net/admin
after double URL encode of #
http://localhost%2523@stock.weliketoshop.net/admin
Now, all that remains is to delete the user 'Carlos', and the pathway to do so becomes evident from the response when accessing the admin panel, which contains <a href="/admin/delete?username=carlos">
So, sending a GET
request to /admin/delete?username=carlos
will initiate the deletion process. Therefore, my request appears as follows:
This request successfully deleted the "Carlos" user, thereby resolving the lab.