LevelBlue Completes Acquisition of Cybereason. Learn more

LevelBlue Completes Acquisition of Cybereason. Learn more

Services
Cyber Advisory
Managed Cloud Security
Data Security
Manage Detection & Response
Email Security
Managed Network Infrastructure Security
Exposure Management
Security Operations Platforms
Incident Readiness & Response
SpiderLabs Threat Intelligence
Solutions
BY TOPIC
Offensive Security
Solutions to maximize your security ROI
Operational Technology
End-to-end OT security
Microsoft Security
Unlock the full power of Microsoft Security
Securing the IoT Landscape
Test, monitor and secure network objects
Why LevelBlue
About Us
Awards and Accolades
LevelBlue SpiderLabs
LevelBlue Security Operations Platforms
Security Colony
Partners
Microsoft
Unlock the full power of Microsoft Security
Technology Alliance Partners
Key alliances who align and support our ecosystem of security offerings

From SSRF to Compromise: Case Study

Overview

I think every penetration tester has a story about the one that got away. The bug that LOOKED exploitable, but wasn’t. The ones where you’re eating into reporting time, madly trying put something together, and got absolutely nothing for your efforts. SSRF is a neat bug because it jumps trust boundaries. You go from being the user of a web application to someone on the inside, someone who can reach out and touch things on behalf of the vulnerable server. Exploiting SSRF beyond a proof-of-concept callback is often tricky because the impact is largely dependent on the environment you’re making that internal request in.

The classic example of an immediately exploitable SSRF vulnerability is one targeting cloud metadata services to retrieve credentials. This has the added bonus of occasionally turning into a cloud-wide security event as well. But what else can we do to increase the impact of SSRF?

There’s some great service-specific research out there, but this still requires knowledge of those internal endpoints. What if you don’t have a juicy metadata service and you know nothing about their internal network (or it’s out of scope)? This is the story about how I was able to finally use an SSRF technique that had taunted me mercilessly on a previous test to gain LFI on a system.

SSRF-In-The-Middle: Exploring for more

I was testing a reporting application. Users choose the report to run, ensure the preview looks good, and then collect their report in its chosen format from an inbox. The name of the application suggested that it handled reporting for multiple other systems, which would help explain the “bring your own URL” feature. When generating a report, a request is sent with a number of URL parameters that determine where the server should retrieve style information and data prior to generating the report. As you might have guessed, all of these were vulnerable to SSRF.

 

Injection_point

 

I chose to inject into the dataServerUrl parameter since that seemed like it would give me the most flexibility. I caught my initial callback with Collaborator, which gave me the body of the POST request made on my behalf to the report data server:

Captured_request

 

At this point, we have a medium-severity finding and can helpfully include a link to Mr. Tsai’s aforementioned post to flesh out the potential impact on a client’s environment. But I was on day two of a multi-week test and THIS was my second crack at the one that got away.

The attack I’m about to walk through is a sort of man-in-the-middle attack. Here’s how the legitimate request works:

  1. User requests a report from ServerA.
  2. ServerA requests report data from ServerB.
  3. ServerB responds.
  4. ServerA generates the report and returns it to the user in their chosen format.
  5. The user picks up their report from the inbox.

The user doesn’t normally see steps 2 and 3 and, even if they can communicate with ServerB, they don’t necessarily know the format of the request required to get a response. And even if they knew that they’re still just left with whatever data they were going to eventually receive anyways. That seems boring.

But this is SSRF! We can tell the server where to go. What if we were ServerB? Then we could inject content into the response and any downstream processing that might happen. This, my friends, is that.

SSRF-In-The-Middle: Exploitation

The body of my initial Collaborator callback contained everything I needed to get a response out of my ServerB. I used the body of the Collaborator request to send a request of my own to the original reporting server specified in the dataServerUrl parameter. The server helpfully responded with exactly the response the application would need to generate a report.

Captured_response

 

With the expected response in hand, I created a dummy reporting server using Flask that would serve the data in the expected format to anyone who asked. I re-ran my report, this time injecting the URL for my Flask server. The report ran perfectly and I could now start poking around the downstream reporting server by modifying the relevant parts of the data being served.

The metadata of the generated PDFs showed that Chromium was being used to create the report:

Pdf_metadata

 

Since Chromium’s PDF generation works on HTML documents (understandably), it meant that my report content was first being rendered as HTML, at which point Chromium would turn it into a PDF before the application finally delivered it to the user.

I like to review my knowledgebase entries on a given technique when working through a test and since we were dealing with SSRF and PDFs, I started with @NahamSec and @daeken’s presentation Owning the Clout Through SSRF and PDF Generators. Unfortunately, none of the techniques outlined there worked, so I shelved it for the time being and moved on.

Since I was pretty sure HTML was an intermediate step, I did a bit more digging turned up this excellent article on JavaScript injection in local PDFs. I started with the following payload:

XXYY

and received:

Window_location

 

This confirmed that my request was ending up in HTML somewhere and that I could execute arbitrary JavaScript. I then tried to squeeze some information out of Rackspace’s metadata service but was unsuccessful.

By this point, I’d been banging away at this for a while and decided to take a break for food and sleep. As always, sleep proved useful and my fresh set of eyes unearthed a nice juicy facepalm. There were two report generation options I’d been using to kick off each test iteration. I’d been alternating between the two and had been getting intermittent errors. I went back to square one and realized that I only got errors with option #2.

I retraced my steps using only the working request (hacker level: 1000) and started with an iframe injection:

ABOUT LEVELBLUE

LevelBlue is a globally recognized cybersecurity leader that reduces cyber risk and fortifies organizations against disruptive and damaging cyber threats. Our comprehensive offensive and defensive cybersecurity portfolio detects what others cannot, responds with greater speed and effectiveness, optimizes client investment, and improves security resilience. Learn more about us.

Latest Intelligence

Discover how our specialists can tailor a security program to fit the needs of
your organization.

Request a Demo