SSRF on a Headless Browser Becomes Critical!

9 months ago 56
BOOK THIS SPACE FOR AD
ARTICLE AD

Alvaro Balada

When I’m frustrated and I haven’t found bugs for a long time, I like to write about my found bugs. This time, I’m going to talk about my first critical vulnerability. I found this bug on a private program on Intigriti, I will call it REDACTED.

Before explaining the bug I’d like to explain the vulnerable part of the application.

This application is used to create dashboards with images, videos and dynamic graphics using external data.

A Dashboard example looked like this:

The main flow of this application is:

Create a dashboardEdit it with some images, videos and graphics with data.Save ItExport It to PDF or PNG

The Dashboard functionality relies on javascript to retrieve the JSON structure of the dashboard.

Data retrieved from /JSONDATA, used to paint the dashboard

{
"title":"Hello",
"items":[
{
"type":"imageobject",
"url":"https://brrrr",
},
{
"type":"graphic-type",
"data":"",
"row":""
},
...
]
}

This data can be modified sending a petition to the same API endpoint with the same data format, the dashboard data can contain multiple data types with multiple parameters

This Dashboard can be exported to PDF or PNG.

A common way to export something to PDF is through a Headless Browser

Headless Browser is a browser without User Interface that loads a webpage, it can be used to automate some web tasks.

I exported the dashboard to PDF and I extracted the metadata of the PDF.

The PDF was created using Chromium.

That means that a browser is running in the backend, if we inject some html, it will be loaded by the internal browser and we can get SSRF.

SSRF allows an attacker to cause the server-side application to make requests to an unintended location

I tried multiple injections and XSS but I didn’t find anything. After some time, I tried to understand all the parts of the Dashboard and data types.

The previous JSON showed multiple data types like “imageobject”, “videoobject”, graphics and other types, all accessible through the UI. I wanted to check all possible data types, so I opened the javascript code of the application.

A good approach to lazy loaded javascript code is search strings or endpoints, I searched for “imageobject” and I found a JSON with all possible object types including “imageobject” with an URL parameter.

Reviewing the code I found “iframeobject” and I tried to edit the dashboard to include “iframeobject” with my attacker URL.

{
"title":"Hello",
"items":[
{
"type":"iframeobject",
"url":"https://attacker"
},
...
]
}

It showed my page inside an Iframe!!

Right after that, I exported the dashboard and I received a callback on my server!!! That was a SSRF!!!

The SSRF loaded my page inside the PDF.

I tried to change the iframe URL to 127.0.0.1 and localhost but the URL parameter needed HTTPS and doesn’t allow internal ip’s.

I tried redirections, octal bypasses and a lot of techniques to load internal resources, but I realized that the browser was loading my html inside an iframe, why not create another iframe inside the iframe?

My attacker’s HTML:

It worked and loaded the internal view of the application login page.

I scanned the internal network and I found a opened port localhost:9222, that port is where the headless browser API recieves petitions!!!.

I searched for endpoints and I found that /json lists all the active browser tabs.

I exported a new PDF and booooom:

The PDF contained all the URL’s of active browser tabs, those URLs contained the user session token to retrieve the dashboard, that means that I could takeover the account of any user that generates a PDF or PNG.

I reported the vulnerability and It took less than 48h to be triaged and awarded.

Critical(9.1) — €2,000

Read Entire Article