Cloudflare发现传统扫描器漏检的恶意JavaScript

Cloudflare AI··作者 Denzil Correa

关键信息

这些活动采用了不同的行为,包括条件触发、通过不可见iframe发起无点击联盟请求、拦截点击、抑制监控,以及从远程服务器加载更多代码。Cloudflare的GNN将JavaScript作为代码图进行分析,并把不到全部分析流量0.3%的脚本交给轻量级LLM复核,同时使用多个大型模型组成的模型集群调查复杂案例。

资讯摘要

Cloudflare介绍了四起恶意JavaScript活动,其客户端安全ML系统在商店网站的实时流量中发现了这些活动。八个恶意载荷可以让页面看起来完全正常,却在后台窃取联盟营销收益、劫持搜索或点击、篡改分析数据,或者询问远程服务器下一步执行什么代码。Cloudflare表示,发现过程由系统自动完成,人员只在系统发出警报后逐一核实。随后使用安全扫描工具复查时,八个载荷中有七个完全没有出现在VirusTotal中,而URLScan没有对任何一个载荷给出恶意判定。

Cloudflare还提到Lnkr家族的一个具体版本:它在URLScan中被索引了近两年半,却一直显示“未分类”,包括2024年1月的一次直接扫描;VirusTotal目前虽然将该脚本标为恶意,但公开历史无法显示这一判定何时产生。四起活动没有共享一个通用特征,其中一个会等待设备、国家、时间、来源页面或浏览器状态符合条件,其他活动则隐藏联盟请求、拦截点击、抑制监控,或从远程服务器加载更多代码。Cloudflare称,其GNN会分析JavaScript的结构和调用关系,而不只是依赖网址或字节哈希;随后由轻量级LLM降低误报,并由多个前沿模型组成的模型集群进一步调查复杂脚本。

Cloudflare发现传统扫描器漏检的恶意JavaScript

资讯正文

当扫描器漏过攻击:Cloudflare Client-Side Security 如何保护在线商店

现代在线商店表面上可能完全正常,但恶意 JavaScript 却在后台运行:窃取联盟营销收入、劫持搜索和点击、篡改分析数据,或者向远程服务器询问下一步该执行什么。页面能够加载,商品正常显示,结账流程也能运行——然而浏览器可能正悄悄执行着一些网站所有者从未授权的操作。

这正是我们的 Client-Side Security 机器学习(ML)模型旨在揭示的盲点。本文将介绍四起行动,涉及八个有效载荷;我们的 Page Shield ML 已在真实环境中发现了它们。

这些恶意有效载荷的检测过程是自动完成的;系统发出告警后,才由人工逐一核实每项发现。当我们随后使用安全扫描工具复查这些活动时,八个有效载荷中有七个完全没有出现在 VirusTotal 中,而 URLScan 对其中任何一个都没有给出恶意判定。与此同时,Page Shield ML 在实时流量中捕获了全部八个。

例如,尽管安全研究人员早在多年前就记录了更广泛的 Lnkr 家族,但其中一个特定版本的有效载荷在 URLScan 中被收录了近两年半,状态一直是“无分类”(No classification),包括 2024 年 1 月进行直接扫描期间也是如此。只有在这个案例中,VirusTotal 更早收录了该有效载荷:虽然它目前已将该脚本标记为恶意,但公开历史并未显示这一判定最初是在何时作出的。与此同时,Page Shield ML 在一家在线零售商的店铺中实时、独立地发现了完全相同的字节。更广泛地说,一个哈希值可能早已为人所知,但其背后的代码可能要过很久才会被归类为恶意。如果你的防御系统要等到出现这一标签才采取行动,那就已经太晚了。你需要的是能够解析 JavaScript 本身、并大规模对其进行判定的 ML。

事实上,看到一个文件并不等于理解它。棘手之处在于,这四起行动没有共通的通用特征,也没有共同的隐藏技术。其中一个只有在设备、国家/地区、时间、引荐来源或浏览器状态符合其等待的条件时才会被激活。另一个则把一次无需点击的联盟营销请求隐藏在不可见的 iframe 中。其他脚本会拦截点击、压制监控,或根据条件从远程服务器加载额外代码。要捕获它们,你必须观察这些部分如何协同工作:脚本何时被唤醒、它隐藏了什么、拦截了什么,以及接下来获取了什么。只检查一次页面是不够的;正如这些案例所显示的那样,这类脚本经过专门设计,会一直保持安静,直到合适的受害者出现。这就是为什么持续的浏览器可见性,决定了你是能够捕获攻击,还是会彻底错过它。

我们如何大规模检测并标记 JavaScript

本文介绍的四起行动,正是由同一个 GNN(图神经网络)发现的;此前,该 GNN 还捕获过恶意 npm 软件包,以及在野外活动的 Magecart 支付窃取器。GNN 不会把 JavaScript 当作一整块平面文本来处理;它会将代码作为一个图进行推理:这是一棵连接代码符号的语法树,能够揭示哪些代码调用了哪些代码、攻击者试图掩盖什么,以及哪些部分仍在向外部服务器回传信息。这种结构有助于它识别经过压缩、重命名以及一定程度混淆后的可疑模式,而不必依赖已知 URL 或字节特征。

GNN 标记为恶意的少数脚本(占全部分析流量的比例不到 0.3%)会被送至 Workers AI 上的轻量级大语言模型(LLM),进行实时的第二意见判断。这一流程在保持高召回率的同时,进一步降低了误报率。当 LLM 对 GNN 的判断予以确认后,客户就会收到警报。

为了大规模调查最复杂的脚本,我们使用了一组前沿模型,并将其称为“教师”(由自动化裁判组成的集成模型)。这组模型来自大约六个不同的模型系列,其中包括运行在 Workers AI 上的开放权重模型。我们会将每个模型作为一个智能体启动,让它们分别在全新的、彼此独立的会话中分析同一个可疑脚本。在有需要时,这些智能体可以使用受限的 JavaScript 评估器,解包小段代码并揭示隐藏的行为。我们很快还将通过 Cloudflare Sandbox 在隔离环境中开展更深入的分析,从而扩展这一工作流程。

这些前沿模型有时会得出不同结论,尤其是在面对最复杂的脚本时。我们将这种分歧视为一种信号,而不是噪声。每个标签都会算作一票,并根据模型在 Artificial Analysis Intelligence Index(人工分析智能指数)中的得分进行加权,最终生成四个标签上的概率分布:良性、支付信息窃取(Magecart)、其他恶意软件和加密货币挖矿。因此,人工审核人员只需要检查被标记为恶意、或没有形成明确三分之二多数意见的脚本。随后,我们会将这些标签分布反馈到 GNN 的训练中,帮助它识别越来越细微的案例。这个反馈闭环目前仍有一部分需要人工完成,不过我们已经开始将其自动化。

我们捕获到的四种恶意 JavaScript 操作

这四种操作的目的大不相同,从窃取佣金,到窃取商店已经付费获取的消费者分析数据。窃取佣金并不等同于窃取信用卡信息;同样,劫持搜索也不同于窃取密码。如果一个机器学习模型只了解其中一种手法,就会对其他手法毫无察觉。相反,我们的 Page Shield ML 必须始终警惕各种类型的恶意行为。

现在,让我们深入了解每种操作及其运作方式。

操作一:在非营业时段劫持联盟佣金

想象一个宁静的周日下午:一名消费者用手机点击了某件商品。脚本没有按照正常方式处理这次点击,而是从攻击者预先选定的列表中,在新标签页打开一个商品页或营销活动落地页,并让原标签页通过联盟链接跳转。商店前台看起来仍然运转正常。如果消费者随后(无论当时还是稍后)完成购买,这次绕道就会劫持归因,将这笔销售以及由此产生的任何佣金记到一个并未赢得该推荐的账户名下。

商店损失了什么

商店可能会向一个并未带来这名消费者的账户支付本不应得的佣金。更糟糕的是,如果这次推荐原本来自合法合作伙伴,强制发起的请求可能会错误地归因,将功劳和潜在报酬从真正完成这项工作的合作伙伴手中转走。这种损害可能不止影响一笔佣金:一旦合作伙伴不再信任归因系统,他们也可能不再信任背后的零售商。

攻击链

符合条件的移动端访客 → 产品点击被拦截 → 脚本选定的页面在新标签页中打开,同时原标签页经由攻击者的联盟营销路径跳转

它是如何隐藏起来的

我们发现了五个相关的脚本构建版本:捕获时其中两个处于活动状态,另外三个已暂停。每个活动变体在执行操作前都会使用不同的一组门槛条件进行检查,例如访客的设备和当地时间、该伎俩最近是否已经运行过、产品按钮是否已经出现,以及用户是否真的点击了该按钮。除非满足某个变体的特定条件,否则这套迷宫般的规则会让恶意行为在短暂的自动化访问期间保持不可见。活动脚本使用 MutationObserver(一种 JavaScript API)监视页面初次加载后动态出现的产品卡片和按钮。这样一来,它们就能拦截这些延迟出现元素上的点击,而只加载一次 HTML、随后立即停止的爬虫可能会完全错过这条重定向路径。

在较新的活动变体中,脚本会拦截符合条件的点击,并将一个为期三天的冷却期写入 localStorage(让脚本在该设备上保持数天不活动)。随后,它会执行双标签页操作:在新标签页中打开由攻击者选定的产品页面,以保持购物者继续浏览;与此同时,原标签页会快速、无明显迹象地经由攻击者的联盟营销跟踪链接再返回商店,从而在后台植入攻击者的归因 Cookie。控制台隐藏和自我防御式的源代码检查增加了分析难度,而冷却期和狭窄的运行时间安排则限制了恶意路径在正常购物过程中出现的频率。

下面这段经过清理的代码摘录展示了载荷如何挂钩动态产品卡片并执行双标签页绕行。为便于阅读,我们简化了标识符、重新排版了代码,并将目标 URL 做了中和处理。

```javascript

// 监视延迟渲染的产品元素并挂钩点击事件

new MutationObserver((_, observer) => {

const tile = document.querySelector(TARGET_SELECTOR);

if (!tile) return;

observer.disconnect();

tile.addEventListener("click", (e) => {

// 如果该设备上的冷却期仍处于活动状态,则退出

const stored = JSON.parse(localStorage.getItem(STORAGE_KEY) || "null");

if (stored && stored.expires > Date.now()) return;

e.preventDefault();

e.stopPropagation();

localStorage.setItem(

STORAGE_KEY,

JSON.stringify({ value: "tracked", expires: Date.now() + COOLDOWN_MS }),

);

// 在新标签页中让购物者继续浏览……

window.open(target.link, "_blank");

// ……同时让原标签页经由攻击者的联盟营销链接进行跳转

setTimeout(() => {

window.location.href = target.redirectUrl;

}, 200);

}); // 注意:某些变体添加了 { once: true },以便在第一次点击后解除绑定

}).observe(document.body, { childList: true, subtree: true });

```

那些已暂停的构建版本显示出,即使不移除脚本,该活动也可以悄然停止。它们内嵌的配置将状态设为 status: "paused",因此会在安装点击处理程序之前退出。这些暂停脚本携带了针对不同购物者的冷却期配置,分别为 3 天、4 天和 5 天。其中一个暂停脚本甚至记录了一条版本历史注释,明确说明该活动是在 Black Friday 之后暂停的。

为了首先触达访客,该行动利用了网站的营销供应链:电商网站嵌入的第三方脚本和标签管理器,用于跟踪广告活动和分析数据。一条已确认的投递路径经过了两个原本看似普通的标签管理器:Google Tag Manager → 另一个标签管理器 → 恶意脚本。有效载荷就是通过这种方式到达浏览器的,但这并不能证明其中任何一个标签管理器遭到了入侵。

攻击者甚至伪装了托管脚本的域名,以通过快速的营销审核。一台投递主机隐藏得非常巧妙:adtargett[.]com 只比 adtarget[.]com 多了一个“t”;后者是一个于 1998 年注册的广告域名。这个相似域名于 2025 年注册,而在我们检查时,其主页自称“Adtarget.com - Performance Marketing Agency”。这就是域名仿冒(typosquatting):通过模仿一家真实的广告代理机构,该主机混入日常营销标签之中,悄悄投递恶意有效载荷,劫持购物者的点击,并通过联盟分成链接将其重定向。

行动二:无点击的联盟盗取

虽然第一种骗局仍然需要点击,但这一种所需的操作更少。购物者可以打开预订页面,在产品选项上停留片刻,却完全不需要触碰任何广告。然而在后台,脚本可能已经发送了一个联盟请求,使之后的交易看起来像是由其他人引导购物者完成的。事实上,当满足脚本设定的条件时,有效载荷会通过隐藏的 iframe,或通过一个会自动点击自身的链接发送该请求。

对于受到影响的旅游企业而言,这种攻击可能破坏客户获取的经济账目:一次合法的预订或购买,可能被记到一个并未实际促成交易的联盟账户名下。代码证明了存在隐蔽、自动化的联盟请求,但目前无法观察到任何特定请求是否实际导致了归因完成、账户入账或佣金支付。

按时间触发的浏览器 → 隐蔽联盟请求(屏幕外 iframe)→ 1 小时限流 Cookie → 被阻止时,自动点击隐藏链接作为备用方案

该脚本通过两层机制隐藏联盟请求:选择性执行(预检网络闸门和每小时调度),以及隐蔽投递(屏幕外 iframe)。第一层尤其令人意外,因为其中的国家标签与实际地理位置并无关联:购物者和商店所在的位置都不会决定这一选择。

首先,脚本调用一个基于公共 IP 的地理定位服务,却忽略该服务返回的所有内容,包括购物者所在的国家。我们无法确定它为何要求请求成功,却忽略返回的数据;这可能是为了迷惑调查人员,也可能只是早期版本遗留下来的代码。有趣的是,如果地理定位请求失败,脚本会静默停止;其 Promise 链以 .catch(() => {}) 结束。虽然尚无法证明这是有意设计的,但这种失败即关闭(fail-closed)行为可能有助于脚本逃避网络受限的沙箱环境。

接下来,脚本没有使用获取到的地理位置数据,而是将三个 TradeDoubler(一个联盟营销网络)的配置对象包含在有效载荷中,标签分别为 {AU、US 和 UK}。这些设置块嵌入在代码中,每个都包含一个联盟 URL 以及起止时间。脚本在 JavaScript 中计算 Asia/Kolkata 时间,检查这些配置的时间窗口,然后根据固定的奇偶小时规则选择三者之一;否则,本次运行将跳过联盟请求。这一选择是确定性的。

调度安排与浏览器状态检查结合起来,形成了按时间门控的选择性执行机制,也就是一种隐藏(cloaking)。当这些条件无法同时满足时,联盟行为就会保持休眠状态,因此一次性的检查可能无法发现它。

脚本选定配置后,会写入一个名为 affiliateClicked_<market> 的本地 Cookie,将其作为一小时的重试节流机制,以便不会立即针对该地区再次触发(这是客户端节流,用于避免产生噪声,并非联盟网络的归因 Cookie)。接着,它会在屏蔽 referrer 的情况下,通过一个不可见的屏幕外 iframe 加载该联盟 URL。iframe 是主要的投递路径,但它还带有激进的备用机制:如果 iframe 出错,或在一到两秒后仍未完成加载,脚本就会创建一个没有 target 属性的隐藏链接(<a>),并以编程方式点击它,这可能会导致用户当前活动标签页发生跳转。对于符合条件的购物者来说,一切看起来都没有异常:他们看不到广告,不需要点击任何东西,也可以像什么都没发生过一样关闭标签页。

至于脚本的混淆方式,它简单但很有效:甚至连属性名也是逐个字符拼接出来的。下面这段经过清理的摘录展示了有效载荷如何创建一个不可见的屏幕外 iframe。我们重命名了关键标识符,并重新排版代码以提高可读性。目标地址已被移除。

function loadAttribution(target) {

const frame = document['c'+'r'+'e'+'a'+'t'+'e'+'E'+'l'+'e'+'m'+'e'+'n'+'t'](

'i'+'f'+'r'+'a'+'m'+'e'

frame['s'+'r'+'c'] = target;

frame['r'+'e'+'f'+'e'+'r'+'r'+'e'+'r'+'P'+'o'+'l'+'i'+'c'+'y'] =

'n'+'o'+'-'+'r'+'e'+'f'+'e'+'r'+'r'+'e'+'r';

frame['s'+'t'+'y'+'l'+'e']['c'+'s'+'s'+'T'+'e'+'x'+'t'] =

'w'+'i'+'d'+'t'+'h'+':'+'1'+'p'+'x'+';'+'h'+'e'+'i'+'g'+'h'+'t'+':'+'1'+'p'+'x'+';'+

'p'+'o'+'s'+'i'+'t'+'i'+'o'+'n'+':'+'a'+'b'+'s'+'o'+'l'+'u'+'t'+'e'+';'+

'l'+'e'+'f'+'t'+':'+'-'+'9'+'9'+'9'+'9'+'p'+'x'+';'+

'v'+'i'+'s'+'i'+'b'+'i'+'l'+'i'+'t'+'y'+':'+'h'+'i'+'d'+'d'+'e'+'n';

document['b'+'o'+'d'+'y']['a'+'p'+'p'+'e'+'n'+'d'+'C'+'h'+'i'+'l'+'d'](frame);

}

操作 3:老牌搜索劫持者,如今变成商店后门

多年前,Lnkr 恶意软件家族曾因藏身于可疑的浏览器扩展中而登上新闻,并拦截 Google 和 Bing 的搜索,将结果重定向以攫取广告收入。如今,攻击者重新利用这套代码库,在一家在线零售商的网站中植入了后门。

当扫描器漏过攻击:Cloudflare Client-Side Security 如何保护网上商店

由于该脚本运行在商店而不是搜索引擎上,其旧有的重定向伎俩一直处于休眠状态。这一次,脚本被用来向攻击者回传遥测数据。更危险的是,它为攻击者提供了一扇远程入口,使其能够随时在客户的浏览器中任意下载并运行新的 JavaScript,而无需接触服务器上的任何文件。它甚至保留了从浏览器扩展时代沿用下来的一种老伎俩:如果有人在 Google 中输入“virus”或“popup”之类的词,它就会关闭。从外部看,这家商店仍在照常销售,丝毫没有暴露出任何异常。

这家商店失去了对客户浏览器中运行哪些代码的控制权。攻击者在暗中跟踪访客会话,并拥有一个直接的后门,可以随时向店铺推送并运行他们想要的任何 JavaScript。

HTML 引用的脚本 → 分析人员规避机制 → 并行的主机条件分支(休眠的搜索分支与活动的后门)→ 任意远程 JavaScript 执行

与通过标签管理器投放的攻击活动不同,这个脚本是直接嵌入商户 HTML 中的。我们无法确定最初的入侵途径;但在实践中,直接修改 HTML 通常是通过被攻陷的商店管理员凭据、未经授权的模板编辑,或遭感染的第三方主题或插件完成的。

从内部看,该脚本是一个模块化工具包,同时携带活动代码和休眠代码。它较早的模块——透明点击覆盖层、搜索引擎查询拦截器、扩展商店链接重写器,以及针对拼写相似域名的重定向功能,例如将 buking[.]com 重定向为 booking[.]com——只会在特定目标网站上唤醒,因此在这家店铺上一直处于关闭状态。多个嵌入式域名(sugabit[.]net、votetoda[.]com、cdnpps[.]us,以及遥测端点 hanstrackr[.]com)都位于这些已禁用的模块中。

在这家商店中,活动分支主要集中于规避检测、遥测和远程控制:

— 在安全研究人员面前装死。这是一种从浏览器扩展时代继承下来的规避技巧:脚本会监控搜索输入和 URL 查询参数,寻找具有代表性的广告软件相关词语。搜索一个安全关键词,会让脚本在本次访问期间暂停。搜索两个或更多关键词,则会向 localStorage 写入一个持久的退出记录,在该分析人员的设备上永久静默脚本,从而使重复测试无法发现任何异常。尽管这一检查机制最初是为了在搜索引擎上躲避分析人员而设计的,但据我们所能确定的情况,它被硬编码为专门针对 Google 搜索 URL,并且在商户店铺上一直处于休眠状态。

— 动态远程代码执行。脚本无需修改店铺就能改变自身行为。虽然硬编码的域名(scrprime[.]com、youronlinesearches[.]com、jullyambery[.]net)与以往捕获到的版本完全相同,但这些端点返回什么内容则完全由攻击者决定。脚本可以向控制端回传访客遥测数据,向这些服务器请求新指令,并将新的 JavaScript 直接下载到购物者的浏览器中。实际上,这为攻击者提供了一个实时后门,使其能够在店铺上运行任意代码。我们无法确定实际投放了哪些第二阶段载荷。

当扫描器错过攻击:Cloudflare Client-Side Security 如何保护网店

总的来说,对网站进行静态快照检查时,只能看到正常的店面;而底层的状态检查、反分析陷阱和远程加载分支却暴露了这个后门。

操作4:付费移动端隐匿器

这家商店已经花钱通过移动广告或营销活动把这名访客吸引过来。恶意脚本先放行这次访问,随后切断商家的可见性:分析数据停止、实时支持聊天窗口消失,一个恶意观察者开始记录这家商店刚刚花钱买来的这次会话的遥测数据。

在幕后,除非这次访问符合一套精心设计的条件,否则有效载荷拒绝运行:必须是确切的目标店面、窄屏移动设备,并且在访问的前两个页面内带有营销活动标签。它在笔记本电脑、企业网络、云服务提供商和 VPN 上保持休眠状态,因此最有可能调试该页面的工程师始终看不到它被触发。该脚本还会在特定的美国城市和地区保持休眠,并依靠一个手工制作的、包含 325 个 IP 字符串的拒绝列表来躲避自动扫描器和安全分析人员。只有在这些条件满足后,脚本才会尝试拆除商店的监控机制,替换广告和分析服务的身份标识,并向外部服务器回连。从错误的设备或网络再次查看页面,永远不会触发它。与此同时,店面仍在继续销售。

对于一家直接面向消费者的零售商而言,这个恶意软件专门针对商店通过付费搜索和营销活动(ppc、cpc、sms、paid)花钱获取的高价值流量。这些顾客仍然可以买东西,但商店面临三项明确威胁:广告归因被转移以及发布商获得不应得的收益;九种可观测性工具中的关键会话分析数据丢失;以及帮助聊天和联系表单被压制,导致购物者无法提问或报告异常。在沙箱浏览器环境中进行的动态分析证实,替代分析脚本已加载并触发了跟踪信标(即为记录访客活动而发送的不可见网络请求);但攻击者是否确实成功获取了会话遥测数据,或实际上转移了广告收入,仍未得到证实。

带有营销活动标签的移动端访问 → 多层隐匿与网络闸门 → 监控遭到破坏 → 广告、分析和支持控件被重写

为了融入商店的营销供应链,攻击者从 sdk-amazonaws[.]com 投递了有效载荷。这是一个于 2024 年注册的仿冒域名,与官方 Amazon Web Services 域名 amazonaws.com(注册于 2005 年)完全没有关联。为进一步加深欺骗,攻击者还在该域名前添加了一个仿冒热门电商营销平台的子域名。这种叠加了两层受信品牌的域名仿冒,伪造出极具迷惑性的伪装,专门设计用来绕过快速标签审查。Amazon Web Services 和遭到冒充的营销平台均未参与此次攻击,也未遭到任何入侵。

脚本加载到浏览器后,在触发主要有效载荷之前,执行了一套异常密集的隐匿检查关卡:

目标主机与浏览环境。该脚本会验证 `window.location.hostname` 是否与其针对的特定商户主机相匹配(在其他任何位置都会立即退出),确保当前窗口处于顶层,而不是嵌入式 iframe 中,并检查路径中是否不包含 `/challenge`。它还会验证浏览器中是否尚未存在跟踪标记 Cookie(`_cart_dr` 和 `_logo_alt`)。

设备与活动筛选。访问者的视口宽度必须小于 477 像素(即手持智能手机)。此外,访问者必须通过带有六种特定 UTM 媒介之一的首次触达活动(即访问者最初的引荐)进入:`ppc`、`cpc`、`sms`、`paid`、`flow` 或 `campaign`。UTM 是 Urchin Tracking Module 的缩写,是用于跟踪营销活动的标准 URL 标签。该访问还必须是其会话中的第一次或第二次页面加载。奇怪的是,虽然代码包含一个名义上的非 UTM 路径,但它要求会话页面计数同时大于 -1 且小于 -2,这在数学上是不可能的,因此该分支完全无法触发。这可能是另一种干扰分析的技巧,也可能只是代码修改后遗留下来的内容。

“随机”门控始终会通过。代码包含一个看似概率性限流的条件(`Math.random() <= threshold`),让执行看起来是间歇性的。然而,在我们解开混淆后的算术运算后,发现该阈值恰好等于 1。由于 JavaScript 的 `Math.random()` 始终返回严格小于 1 的值,这一门控条件总是为真。与无法触发的非活动分支一样,这个条件实际上从未真正作出任何决定。它可能是遗留的限流逻辑,也可能是为了迷惑阅读混淆数学表达式的人而刻意设置的伪装。无论如何,捕获到的载荷从未利用它来跳过符合条件的访问者。

第三方 IP 情报。该脚本使用内嵌密钥查询外部第三方 IP 情报 API。它要求连接来自美国的移动消费者网络;但如果响应将其标记为企业网络、托管设施、云服务提供商、bogon 地址、Tor 出口节点、VPN、代理、转发中继或一般性威胁指标,脚本就会立即退出。

地理位置排除。对于来自特定地区(`US-NY`、`US-CA` 和 `US-NHDD`)或来自旧金山、普利茅斯、康普顿、霍普金顿和拉斐特等城市的访问者,该载荷不会激活。

325 条目 IP 子串陷阱。该脚本会将访问者的 IP 与内嵌的拒绝列表进行比对,列表中包含 325 个完整的 IPv4 地址字符串。去重后,这些地址对应于 313 个唯一地址,分布在 249 个不同的三段式前缀中。作者没有执行结构化的 CIDR(无类别域间路由)子网匹配,而是简单地从访问者的 IPv4 地址中去掉最后一个八位组,然后进行原始子串搜索:`!denylistString.includes(visitorPrefix)`。

用精简后的伪代码表示,这个多层主激活漏斗如下:

```javascript

// 1. 上下文、设备和活动门控

let eligible = isTopWindow && host === EXPECTED_HOST && !path.includes("/challenge");

eligible &&= !hasCookie("_cart_dr") && !hasCookie("_logo_alt");

eligible &&= viewportWidth < 477 && [1, 2].includes(sessionPage);

```

eligible &&= ["ppc", "cpc", "sms", "paid", "flow", "campaign"].includes(utmMedium);

eligible &&= Math.random() <= 1; // 表面上的随机门控始终解析为 true

// 2. IP 情报与地理门控(获取外部 API 数据)

eligible &&= ipInfo.country === "US" && ipInfo.isMobile && !ipInfo.isBusiness;

eligible &&= !ipInfo.isCloud && !ipInfo.isProxy && !ipInfo.isVpn && !ipInfo.isTor && !ipInfo.isThreat;

eligible &&= !["US-NY", "US-CA", "US-NHDD"].includes(ipInfo.region);

eligible &&= !EXCLUDED_CITIES.includes(ipInfo.city);

// 3. 325 条目 IP 前缀检查(原始子字符串匹配)

let clientPrefix = ipInfo.ip.slice(0, ipInfo.ip.lastIndexOf("."));

eligible &&= !DENYLIST_STRING.includes(clientPrefix);

if (!eligible) return; // 只有符合条件的消费者移动端会话才能通过这层伪装

破坏可观测性并劫持身份:

只有在所有主要门控条件都通过后,该脚本才会执行其有效载荷:

- 使监控工具失明。它会搜索 DOM,并移除九种不同可观测性和分析服务的脚本标签:Lucky Orange、Segment、Optimizely、New Relic、Bugsnag、LogRocket、Hotjar、Microsoft Clarity,以及该商店的 Google Tag Manager 容器(GTM-<redacted>)。对于剩余的内联脚本,它还会将对这些工具的引用替换为未定义的虚拟标识符(hji0),使得对这些工具的调用静默失败,试图令商店的错误报告和监控系统失去感知能力。

- 压制客户支持。它注入 CSS 并移除相关元素,以隐藏支持聊天和联系表单容器,切断客户与商店支持人员之间的直接联系。

- 替换广告和分析身份。它清除 Google Ads 全局变量(google_ad_modifications、adsbygoogle),拆除现有广告位(ca-pub-<original>),并使用替换后的发布商 ID(ca-pub-<replacement>)加载 Google Ads。随后,它注入一个新的 Microsoft Clarity 会话回放脚本,并为其配置恶意的替换项目 ID。

更简单的独立信标与 600 天标记:

与精心设计的主要伪装形成鲜明对比的是,该有效载荷还包含若干次级信标分支(这些独立运行的程序会悄悄向外部服务器发送请求,以确认访问已经发生),完全绕过视口、主机名、营销活动、地理位置和 IP 门控。如果访客已经浏览到第二个页面或更后面的页面,脚本就会写入一个持久 Cookie(_cart_dr=1),其有效期恰好为 600 天(51,840,000,000 毫秒),并向 maper[.]info 上的远程遥测端点发起一个不可见的零像素图片请求;这是一个用于记录浏览器已执行到这一步的跟踪信标。

另一个分支会检查备用标记(_logo_alt)。如果检测到该标记,就会触发第二个遥测 .png 信标(这是该脚本会查找、但不会自行写入的 Cookie;很可能由配套脚本植入)。这样一来,攻击者便获得了一个简单且持久的命中计数器,可为整个商店的所有访客记录基本流量信息(端点会记录 IP 和 User-Agent),同时将高风险的广告劫持例程严格隐藏在移动端伪装之后,仅针对高价值的付费流量触发。这说明,只分析一个可见效果,并不能揭示多用途载荷的完整影响范围。

入侵指标(IOC)

我们发布这些指标,是为了帮助安全团队和研究人员在自己的环境中检测并搜寻这些活动。所有指标均直接取自捕获到的载荷及其网络连接。文中列出的 URL 均已去武器化处理。部分指标被隐去或泛化,因为公开这些信息可能会无意中泄露受影响组织的身份。列出的域名反映了在这些攻击期间观察到的、参与投递、重定向或遥测链路的基础设施;列出某个共享服务或托管服务提供商,并不意味着该服务或提供商本身专门用于恶意活动。

给防御者的四点启示

综合来看,这些行动讲述了一个不断升级的故事:攻击者改变了目标、投递路径和伪装方式,但浏览器仍然必须执行他们的逻辑。其中有四点启示尤为突出。

行为胜过特征匹配。这些行动追求不同形式的变现和操纵,但每个载荷仍然必须在浏览器中执行某些行为:观察事件、检查状态、修改页面、安排任务、发起网络请求,或加载下一阶段载荷。这正是结构分析所关注的内容:恶意载荷无论 URL、特征和目标如何变化,都必须携带的那套逻辑。

选择性执行是攻击的一部分,而不是脚注。设备、时间、地理位置、引荐来源、会话、网络和冷却时间等门控条件,都可能让只访问一次并获取静态快照的爬虫失效。持续可见性至关重要,因为攻击可能只在某一个浏览器、某一种状态、某一个时刻出现。

混淆提高了分析成本,但在这些案例中并没有阻止检测。自我防御循环、抑制控制台输出、调试器陷阱、轮换字符串表以及无效分支,都增加了分析难度。尽管存在这些障碍,Page Shield ML 仍然发现了全部四起行动。快速的内部模型可以大规模筛出可疑代码,而前沿模型则会调查最棘手的案例。它们之间的分歧凸显了最复杂的混淆和逻辑,帮助我们缩小关注范围。

上下文才能完整呈现全貌。孤立来看似乎普通的代码,一旦防御者将静态分析与动态上下文联系起来,就可能暴露其恶意角色:它是如何到达的、哪种浏览器状态激活了它、它建立了哪些连接,以及它在运行时究竟做了什么。

持续了解客户端执行情况

这四起行动都依赖不同层面的误导手法,但它们有一个共同限制:其 JavaScript 必须在浏览器中执行。公共扫描器和静态爬虫可能无法发现受限制的行为。持续观测有助于弄清楚真实访客与页面互动时,这些代码究竟执行了什么操作。

Cloudflare Client-Side Security 可在所有套餐中提供这种可见性。你可以在“安全性”设置中启用 Continuous script monitoring,以跟踪网店中的第一方和第三方脚本;而自动化恶意脚本检测和告警功能则随 Client-Side Security Advanced 提供。你可以直接在 Cloudflare 控制面板中查看脚本活动并管理检测结果。

来源与参考

  1. 原始链接
  2. When scanners miss the attack: how Cloudflare Client-Side Security protects storefronts

收录于 2026-09-17