引言
Meta Conversions API Gateway 是 Meta(前 Facebook)推出的一套服务端事件传输方案,用于帮助企业将用户行为、购买数据等网站事件,直接从服务器发送到 Meta 平台,从而绕过 Facebook Pixel 这类传统的浏览器端埋点方式。
这个 Gateway 本质上充当了一个中间层:负责收集、处理并安全地把来自网站或 App 的事件数据传递给 Meta。与依赖 Cookie 和浏览器信号的客户端追踪不同,Conversions API Gateway 即使在用户关闭 Cookie、使用广告拦截器,或受到浏览器隐私策略限制的情况下,依然能够保证数据成功送达 Meta。
Conversions API Gateway 与 capig-events.js
Conversions API Gateway(gw.conversionsapigateway.com)是 Meta 官方托管的一套 Gateway 实例。为了支持转化事件的采集与处理,该 Gateway 会对外提供一个名为 capig-events.js的 JavaScript 脚本,路径如下:
https://gw.conversionsapigateway.com/sdk/<pixel_id>/capig-events.js
在 Meta 自家的体系中,这个脚本并不是由开发者手动引入的,而是由 Meta 的 fbq 客户端 JavaScript 模块自动加载。因此,它会在以下站点上执行:
- www.meta.com
- business.facebook.com
- developers.facebook.com
- 各类第三方客户网站
Bug #1:盲目信任 event.origin,化身脚本加载器
第一个漏洞完全存在于客户端,位于 capig-events.js中,只在一个特定条件下触发:页面存在 window.opener。
当 window.opener 存在时,脚本会注册一个 message 事件监听器,用于接收 IWL 的配置数据。问题出在:信任边界被直接跨越了。当收到 msg_type 为 IWL_BOOTSTRAP 的消息时,脚本只校验了 pixel_id 是否存在于内部列表中,却完全没有验证消息来源。
CSP and COOP 限制
从表面上看,CSP(Content Security Policy)和 COOP(Cross-Origin-Opener-Policy)似乎在很大程度上限制了这个漏洞的利用。在 www.meta.com 上,CSP 默认不允许加载任意外部脚本。
CSP Bypass
在未登录状态下,一些 Meta 页面(尤其是 /help/ 路径下)会放宽 CSP,允许加载第三方分析或统计服务。这一步直接扩大了攻击面。
Cross-Origin-Opener-Policy 绕过
在 Facebook Android App 的 WebView环境中,利用 window.name 复用配合 window.open(),可以重新获得对 opener 的访问权限。
Iframe Hijacking
在实际环境中,meta.com 很可能会通过 iframe 加载第三方内容,例如广告或社交插件。我们正是利用了其中某个第三方组件的漏洞,完全劫持了该 iframe,并从这个被控制的 iframe 中发送恶意 postMessage。
攻击流程总结
攻击流程如下,场景发生在 Facebook App 的 WebView 中,用户已登录 Facebook:
0) 用户在 Facebook 应用内打开攻击者控制的链接
1) 攻击者网站上的脚本执行 opener 绕过,并将用户重定向到 https://www.meta.com/help/
2) 在 help 页面中,被劫持的 iframe 跳转到 (*.THIRD-PARTY.com)(该域名被 Meta 的 CSP 允许),并向父窗口(www.meta.com)发送 IWL_BOOTSTRAP postMessage
3) 同时,攻击者在 (*.THIRD-PARTY.com) 上托管 /sdk/{pixel_id}/iwl.js,其中包含 XSS payload
4) www.meta.com 从该第三方站点加载并执行 iwl.js,XSS 在 meta.com 上下文中触发
漏洞影响
该漏洞触发于:
- www.meta.com
- 未登录状态
- Facebook App WebView 环境
最终目标是将其升级为 Facebook 账号接管(ATO)。
Bug #2:Gateway 后端中的存储型 JavaScript 注入
第二个漏洞存在于服务端,而且严重程度可以说更高。在提交完第一个漏洞后,我开始直接审计 Gateway 的源码,也正是在这个过程中,我注意到:这个被加载的 iwl.js脚本,实际上到底在干什么?
动态脚本
cbq.loadPlugin 和 cbq.config.set 这两个调用我非常熟悉——它们在 Meta Pixel 和 Signals 的前端脚本中大量存在。这让我意识到: : :
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf
客服小蜜蜂(微信:freebee1024)

