使用Eval Villain探索客户端路径遍历(CSPT):从漏洞发现到利用

2 阅读9分钟

CSPT the Eval Villain Way!

2024年12月3日 - 发布于 Dennis Goodlett

Doyensec 的 Maxence Schmitt 最近构建了一个与他 CSPT 研究 配套的演练场。在这篇博文中,我们将演示如何使用 Eval Villain 来发现和利用 CSPT 漏洞。为此,我们将利用 Maxence 演练场中的第二个挑战。

使用 Eval Villain 逐步介绍 CSPT

下图展示了这种方法产生的效果。

[图片展示了Eval Villain的控制台输出,橙色框标注了关键信息]

我们用橙色添加了一些框和箭头来更好地说明当前情况。首先,Eval Villain 发现页面路径的一部分被用在了 fetch 请求中。 在那里,你可以清楚地看到 asdf%2f.. 被 URL 解码了。或者,如果你愿意,可以展开“Encoder function”组来检查。无论哪种方式,Eval Villain 都已经发现了 CSPT 的接收点(sink)。

第二个框位于 evSourcer 的调试语句之上。这里,第一次 fetch 请求的响应被添加到了 Eval Villain 的源(source)库中。因此,Eval Villain 警告我们,来自 CSPT 响应的 _id 参数命中了另一个 fetch 接收点。同样,你可以从“Encoder function”中获取更多细节。

从每个 fetch 的参数 arg[2/2] 中我们了解到更多信息。第一个 fetch 是一个 GET 请求,带有 "redirect":"follow",而第二个则带有 "method":"POST"。因此,我们控制了一个客户端 GET 请求的路径,一个开放重定向可能将该请求发送到我们自己的服务器。我们自己服务器的响应随后将被用于一个经过认证的 POST 请求的路径中。这张图片展示了 CSPT2CSRF 利用的整个攻击链。

所有这些注入的工具(instrumentation)都会保留下来,以帮助我们进行利用。点击提供的解决方案,我们看到下图。这精确地展示了漏洞是如何被利用的。

[图片展示了最终利用方式的细节]

亲手构建这个图景

步骤 0: 工具

你需要安装 Firefox 并安装 Eval Villain 扩展。

我们强烈建议你在演练场中亲自尝试。CSPT 是一种在博客上读起来似乎很容易,但在实际测试中遇到时却会让人望而生畏的漏洞。

步骤 1: 寻找 CSPT

登录演练场并访问“CSPT2CSRF : GET to POST Sink”页面。在 Linux 上按 ctrl+shift+i 或在 Mac 上按 cmd+option+i 打开控制台。确保 Eval Villain 已打开。在 Eval Villain 的默认配置下,你只应在控制台中看到 [EV] Functions hooked for http://127.0.0.1:3000。 但在实际测试中,我们会看到 URL 路径中明显有一个参数。默认情况下,由于误报问题,Eval Villain 不使用路径作为源。所以,让我们在“Enable/Disable”弹出菜单(点击 Eval Villain 的 Logo)中打开“Path search”。 现在,刷新页面后,Eval Villain 会告诉我们有两个对 fetch 的调用,都使用了路径。我们还不确定它们是否是 CSPT,需要检查 ../ 是否被接受,但这看起来很有希望。

[图片展示了Eval Villain发现两个fetch调用]

注意: 你可能只看到一个 fetch,这没关系。

步骤 2: 测试 CSPT

为了测试是否存在 CSPT,只需在路径末尾添加字符串 %2fasdf%2f..。这是一个好技巧,因为它会归一化到原始路径,如果网站存在漏洞,其行为将保持不变。当你刷新页面时,你会在控制台中看到如下信息。

[图片展示了添加测试字符串后的Eval Villain输出]

找到 CSPT 原语就是这么简单。如果源在 window.name 或 URL 参数中,Eval Villain 很可能会立即发现它。 由于 URL 路径是编码的,Eval Villain 为我们提供了一个编码器函数。你可以将其粘贴到控制台中,并用它来快速尝试新的 payload。该函数会自动应用 URL 编码。 有了 CSPT 原语,下一步就是了解该请求的响应是如何被使用的。为此,我们希望将这个响应作为新的源(source)注入到 Eval Villain 中。

步骤 3: 启用 evSourcer

首先,你需要在 Eval Villain 中启用全局变量 evSourcer。从弹出菜单进入配置页面,滚动到全局变量表(globals table)。启用标记为“evSourcer”的行。别忘了点击保存。

[图片展示了启用evSourcer的配置界面]

现在你可以刷新页面,并在控制台中运行 evSourcer.toString() 来验证配置更改是否生效。

[图片展示了控制台中evSourcer.toString()的输出]

你可以运行一个快速测试来试用此功能。任何进入此函数第二个参数的内容都会被放入 Eval Villain 的源库中。在使用 evSinker 之前,字符串 foobar 不会从 eval 接收点生成警告,但之后会生成。

[图片展示了evSinker功能的测试]

步骤 4: 将 CSPT 请求的响应放入 evSourcer

因此,如果我们将 CSPT 请求的响应放入 evSourcer,Eval Villain 就能告诉我们它是否命中了 eval.innerHTMLfetch 或我们已挂钩的任何其他接收点。 要找到 CSPT 请求的响应,我们只需查看 Eval Villain 给我们的堆栈跟踪。

[图片展示了Eval Villain输出的堆栈跟踪]

这里我们高亮显示了所谓的“魔法区域”。当你看到函数名从压缩过的乱码变成可读的长字符串时,这通常是你想要开始的地方。这通常意味着从库代码到开发者编写代码(或反之)的过渡。这两个函数之一很可能就是我们想要的。根据上下文,fetchNoteById 可能正在将信息返回给 Ko。因此,通过点击链接跳转到调试器中的 Ko 函数。到达那里后,通过单击代码面板左下角的 {} 图标来美化代码。 你会看到类似这样的代码:

      return (0, t.useEffect) (
        (
          () => {
            r &&
            ot.fetchNoteById(r).then((e => { // <-- 此处调用 fetchNoteById
              ot.seenNote(e._id),         // <-- 所以 `e` 很可能就是我们的 JSON 响应
              n(e)
            })).catch((e => {
              //...

fetchNoteById 显然返回了一个 Promise。这很合理,所以我们通常会设置一个断点来检查 e 并将其与 fetch 的响应进行比较。一旦验证完毕,就该进行注入(instrumentation)了。 右键点击包含 ot.seenNote 的行号,然后点击“添加条件断点”。添加 evSinker 调用,使用一个你能识别的名称来注入 e 变量。evSinker 函数总是返回 false,所以我们实际上永远不会命中这个断点。

[图片展示了在断点条件中添加evSinker的代码]

注意,我们禁用了源映射(source maps)。源映射可能会优化掉变量,使调试更加困难。此外,Firefox 有时需要一点时间来美化代码并将断点放在正确的位置,所以请耐心等待。

步骤 5: 刷新页面,检查次级接收点

现在我们只需刷新页面。由于我们在 evSinker 中将最后一个参数设为 true,我们将使用控制台调试来查看注入了什么。在控制台中启用“Debug”。我们还可以在控制台中启用 XHR 来查看其中的请求和响应。我们感兴趣的请求将直接跟随 Eval Villain 输出到控制台,因此很容易找到。这就是我们所看到的。

[图片展示了刷新页面后Eval Villain的控制台输出]

为了节省空间,我们关闭了第一个 fetch 组。它确实显示了 asdf%2f.. payload 命中了 fetch。我们打开的那个“XHR”条目没有显示目录遍历,因为它已被归一化掉了。不过 Eval Villain 让查找它变得很容易。下面的控制台调试中可以看到该“XHR”的响应被注入。然后,Eval Villain 自然能够发现它命中了 fetch 接收点。

步骤 6: 额外的小细节

你可能注意到上图中没有 arg[2/2] 的输出。该参数是一个 JavaScript 对象。默认情况下,Eval Villain 被配置为只查看字符串。打开弹出菜单,点击“types”并启用“objects”。然后当你刷新页面时,你就可以从 Eval Villain 的输出中看到传递给 fetch 的选项。

步骤 7: 利用

演练场让寻找 gadget 变得简单。只需转到页面上的“gadgets”下拉菜单。现实世界中没有这个,所以 Burp Suite 的 Bambda 搜索似乎是目前最好的选择。更多信息请参见 Maxence 的 CSPT 研究。

额外功能!在 Chrome、Electron 甚至 Web Views 中使用 Eval Villain?

Eval Villain 实际上只是一个 JavaScript 函数和配置,Firefox 会在每个页面加载前将其复制/粘贴进去。一旦注入,它仅使用控制台记录输出。因此,理论上,你可以手动将此代码复制/粘贴到任何接受 JavaScript 的地方。 Eval Villain 1.11 版本就能让你做到这一点。进入配置页面并滚动到底部。你会看到一个“Copy Injection”按钮。点击它,整个 Eval Villain 注入代码以及当前配置将被复制到你的剪贴板中。 利用这一点,我们成功地将 Eval Villain 注入到了一个经过测试的 Electron 应用中。以下屏幕截图显示了 Eval Villain 在 Burp 内置 Chrome 浏览器的条件断点中运行。

[图片展示了Eval Villain在Burp内置浏览器中运行]

或者,你可以使用 Burp 的 HTTP Mock 扩展将 Eval Villain 粘贴到 Web 响应中。我们还没有尝试过,但将来使用 Frida 将其注入到 Android 的 Web View 中将会很酷。

结论

对目标代码进行注入测试实际上并不需要很长时间。这篇博文一步步解释了如何利用 Eval Villain 来发现和利用 CSPT 漏洞。即使是在演练场中学习新技巧,Eval Villain 也能帮助我们调试小错误。 请确保针对正确的任务使用正确的工具。例如,Eval Villain 无法解码所有内容(可以看看 fragment 挑战)。Maxence 为 CSPT 开发了一个很棒的 Burp 扩展,但它缺乏对 DOM 的洞察力。其他一些工具包括 GekoDOMLogger++ 和 DOM Invader(在接收点中启用 xhr.openfetch)。混合搭配最适合你的工具。

其他相关文章: