当扫描器错过攻击时:Cloudflare 客户端安全如何保护店铺

一个现代店铺可能看起来完全健康,而恶意 JavaScript 却在底下运作:吸走联盟收入、劫持搜索和点击、篡改分析数据,或向远程服务器询问下一步执行什么。页面加载、产品显示、结账正常——但浏览器可能正在悄悄做着网站所有者从未授权的事情。
这正是我们的客户端安全机器学习(ML)模型旨在揭露的盲点。本文追踪了我们的 Page Shield ML 在真实环境中发现的四个操作,涵盖八个载荷。
这些恶意载荷的检测是自动化的;只有在系统标记之后,人工才验证了每个发现。当我们随后使用安全扫描工具审查这些活动时,八个载荷中有七个在 VirusTotal 上完全不存在,URLScan 也没有对其中任何一个返回恶意判定。Page Shield ML 则在实时流量中捕获了全部八个。
例如,虽然安全研究多年前就记录了更广泛的 Lnkr 家族,但一个特定的载荷版本在 URLScan 上被索引了近两年半,标注为“无分类”,包括在 2024 年 1 月的一次直接扫描期间。只有在这个案例中,VirusTotal 更早地收录了该载荷:虽然它目前将该脚本标记为恶意,但公开历史并未揭示该判定最初是何时被赋予的。与此同时,Page Shield ML 独立地在一家在线零售商的店铺上实时发现了这些确切的字节。更广泛地说,一个哈希值可能在它背后的代码被归类为恶意之前很久就为人所知。如果你的防御等待那个标签,你就已经晚了。你需要能够解析 JavaScript 本身并大规模判断它的 ML。
事实上,看到一个文件并不等同于理解它。棘手之处在于,这四个操作没有通用的签名或共同的隐藏技术。一个除非设备、国家、时间、引荐来源或浏览器状态与它所等待的匹配,否则保持休眠。另一个将无点击的联盟请求隐藏在不可见的 iframe 中。其他的拦截点击、抑制监控,或从远程服务器有条件地加载额外代码。要抓住它们,你必须观察这些部分如何协同工作:脚本何时唤醒、它隐藏什么、它拦截什么,以及它接下来获取什么。只检查页面一次是不够的;正如这些案例所示,此类脚本被设计为在合适的受害者出现之前保持安静。这就是为什么持续的浏览器可见性决定了是抓住攻击还是完全错过它。
我们如何大规模检测和标记 JavaScript
标记本文中四个操作的同一个 GNN(图神经网络)此前已经捕获了恶意 npm 包和
。GNN 不将 JavaScript 视为扁平的文本块;它将代码作为图来推理:一个
一个真实环境中的 Magecart 支付窃取器连接代码符号,揭示什么调用了什么、攻击者试图掩埋什么,以及什么仍在向家中回传。这种结构有助于它在压缩、重命名和某些混淆中识别可疑模式,而无需依赖已知的 URL 或字节签名。
__语法树__被 GNN 标记为恶意的少数脚本(占所有分析流量不到 0.3%)会发送到一个轻量级大型语言模型(LLM)上
。这进一步减少了误报,同时保持高召回率。当 LLM 证实 GNN 的判断时,客户会收到警报。
__Workers AI 提供实时第二意见__为了大规模调查最复杂的脚本,我们使用一组前沿模型,我们称之为教师(一组自动评判者的集成)。该队列从大约六个不同的模型家族中抽取领先模型,包括在 Workers AI 上运行的开源权重模型。我们将每个模型作为智能体启动,在各自全新的独立会话中分析同一个可疑脚本。在有用时,它们的智能体工具访问权限让它们能够使用受限的 JavaScript 求值器来解包小片段并揭示隐藏行为。我们很快将用 Cloudflare Sandbox 扩展此工作流,以在隔离环境中进行更深入的分析。
前沿模型有时会意见不一,尤其是在最复杂的脚本上。我们将这种分歧视为信号,而非噪声。每个标签成为一票,按模型在Artificial Analysis Intelligence Index中的得分加权,产生四个标签上的概率分布:良性、支付窃取(
magecart## 我们捕获的四个恶意 JavaScript 操作
这四个操作做的事情非常不同,从佣金盗窃到窃取商店已经付费获取的购物者分析数据。窃取佣金不像窃取信用卡;同样,劫持搜索也不像窃取密码。如果 ML 模型只知道其中一种伎俩,它就会对其他伎俩毫无察觉。相反,我们的 Page Shield ML 必须对每一种敌对行为保持敏感。
现在,让我们更深入地了解每个操作及其运作方式。
---|---|---|
| 劫持联盟佣金 | 移动设备与时间门控;动态页面监控;点击拦截;多日冷却 |
| 无需用户点击即可窃取联盟佣金 | 屏幕外 iframe;自动点击隐藏链接回退;虚假 IP 查询请求与时间门控;每小时联盟轮换 |
| 跟踪用户并打开后门以进行任意远程 JavaScript 执行 | 旧式关键字静默;localStorage 退出;遥测;远程代码加载 |
| 在带有活动标记的移动端访客面前遮蔽商店,试图替换广告和分析工具,并隐藏支持信息 | 主机、视口和 UTM 标签门控;325 条 IP 子串列表;禁用 9 个监控/分析工具;零像素追踪信标 |
操作 1:下班后的联盟佣金劫持者
想象一个安静的周日下午:一位购物者在手机上点击了一件商品。脚本没有正常跟随这次点击,而是从攻击者预先选定的列表中在新标签页打开一个商品或活动落地页,并将原始标签页引导通过一条联盟路由。店面看起来仍然正常工作。如果购物者完成了购买(无论是当时还是之后),这次绕行就会劫持归因,将这笔销售(以及由此产生的任何佣金)记到一个并未带来该推荐的账户名下。
商店损失了什么
商店可能会向一个并未带来该购物者的账户支付一笔不应得的佣金。更糟的是,如果一位合法合作伙伴完成了推荐,这个强制请求可能会将其错误归因,把功劳和潜在付款从真正做了工作的合作伙伴那里转移走。损害可能不止一笔佣金:不再信任归因系统的合作伙伴,也可能不再信任其背后的零售商。
攻击链
符合条件的移动端访客 → 被拦截的商品点击 → 脚本选定的页面在新标签页打开 + 原始标签页跟随攻击者的联盟路由

它如何保持隐藏
我们发现了五个相关脚本构建:两个处于活动状态,三个在捕获时已暂停。每个活动变体在执行前都使用一组不同的门控,检查访客的设备和本地时间、该伎俩最近是否运行过、是否已出现商品按钮,以及是否真的有人点击它。这套迷宫般的规则让恶意行为在短暂的自动化访问期间不被发现,除非满足该变体的特定条件。活动脚本使用 MutationObserver(一种 JavaScript API)来监视页面首次加载后动态出现的商品卡片和按钮。这使它们能够拦截对这些延迟到达元素的点击,而只加载一次 HTML 就停止的爬虫则可能完全错过重定向路径。
在较晚的活动变体中,脚本拦截符合条件的点击,并向 localStorage 写入三天的冷却时间
(在该设备上休眠数天)。然后它执行双标签页操作:将攻击者选定的商品页面弹到一个新标签页中以保持购物者参与,同时原始标签页通过攻击者的联盟追踪链接快速、不被察觉地往返并返回商店,以在后台植入攻击者的归因 cookie。控制台遮蔽和自我保护式源码检查使检查更加困难,而冷却时间和狭窄的时间表限制了恶意路径在原本正常的购物过程中出现的频率。
以下经过净化的摘录展示了该载荷如何挂钩动态商品卡片并执行双标签页绕行。我们简化了标识符、重新格式化了代码,并为便于阅读而中和了目标 URL。
// 监听延迟渲染的商品元素并劫持点击
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天)。其中一个暂停的脚本甚至记录了一条版本历史注释,明确记载该活动在黑色星期五之后被暂停。
为了首先触达访客,该操作利用了网站的营销供应链:电子商务网站为跟踪广告活动和分析而嵌入的第三方脚本和标签管理器。一条已确认的投放路径经过两个原本普通的标签管理器:Google Tag Manager → 另一个标签管理器 → 恶意脚本。这就是有效载荷到达浏览器的方式,并非证明任一标签管理器已被入侵。
攻击者甚至伪装了托管脚本的域名,以通过快速的营销审查。一个投放主机就隐藏在众目睽睽之下:adtargett[.]com
与 adtarget[.]com
仅相差一个“t”,后者是一个注册于1998年的广告域名。这个仿冒域名注册于2025年,当我们检查时,其主页自称“Adtarget.com - 效果营销机构”。这就是域名仿冒:通过模仿一家真实的广告代理机构,该主机混入了常规营销标签之中,悄悄提供恶意有效载荷,劫持购物者的点击并将其重定向通过联盟支付链接。
操作2:无点击的联盟盗窃
虽然第一个骗局仍需要一次点击,但这个骗局需要的甚至更少。购物者可以打开一个预订页面,浏览产品选项,而从不触碰广告。然而在后台,脚本可能已经发送了一个联盟请求,这可能使之后的销售看起来像是其他人推荐了该购物者。事实上,当脚本的条件满足时,有效载荷会通过一个隐藏的 iframe 或一个自行点击的链接发送该请求。
商店损失了什么
对于受影响的旅游业务,该攻击可能破坏客户获取的经济效益:一笔合法的预订或购买可能被记入一个不应得的联盟账户。代码证明了隐蔽的、自动化的联盟请求,但任何特定请求在实践中是否导致了完成的归因、账户入账或已支付的佣金,仍未被观察到。
攻击链
时间门控浏览器 → 隐蔽联盟请求(屏幕外 iframe) → 1小时节流 cookie → 被阻止时,自动隐藏链接点击回退

它如何保持隐藏
该脚本将联盟请求隐藏于两层之中:选择性执行(预检网络门和每小时计划),以及隐蔽投递(屏幕外 iframe)。第一层令人惊讶,因为其国家标签与实际地理位置脱节:购物者的位置和商店的位置都不驱动这一选择。
首先,脚本调用了一个基于公共 IP 的地理定位服务,但忽略了它返回的所有内容,包括购物者的国家/地区。我们无法确定为什么它要求成功响应却忽略返回的数据;这可能是为了迷惑调查人员,或者仅仅是早期版本的残留。有趣的是,如果地理定位请求失败,脚本会静默停止;其 promise 链以 .catch(() => {}) 结束。尽管意图未经证实,这种故障关闭行为可能有助于脚本逃避网络受限的沙箱。
接下来,负载没有使用获取的地理定位数据,而是包含三个 TradeDoubler(一个联盟营销网络)配置对象,标记为 {AU
、US
和 UK
}。这些设置块嵌入在代码中,每个都包含一个联盟 URL 以及开始和结束时间。脚本在 JavaScript 中计算 Asia/Kolkata
时间,检查那些配置的时间窗口,然后应用固定的奇数/偶数小时规则来选择三者之一,否则跳过该次运行的联盟请求。选择是确定性的。
时间表和浏览器状态检查共同创建了时间门控的选择性执行,这是一种伪装形式。当这些条件不匹配时,联盟行为保持休眠,因此一次性检查可能会错过它。
一旦脚本选择了一个配置,它会写入一个名为 affiliateClicked_<market>
的本地 cookie 作为一小时的重新尝试节流,这样它就不会立即为该地区再次触发(这是客户端节流以避免噪音,而不是联盟网络的归因 cookie)。接下来,它在屏幕外的 iframe 中加载该联盟 URL,并抑制 referrer。iframe 是主要的传递路径,但它带有一个激进的回退:如果 iframe 出错或在一到两秒后未能完成加载,脚本会创建一个没有 target
属性的隐藏链接(<a>
)并以编程方式点击它,这可能会导航用户的活动标签页。对于符合条件的购物者来说,一切似乎都很正常:他们从未看到广告,无需点击,并且可以像什么都没发生一样关闭标签页。
至于脚本的混淆,它简单但有效:甚至属性名也是一个字符一个字符地组装。以下经过清理的摘录显示了负载创建了一个不可见的屏幕外 iframe。我们重命名了关键标识符并重新格式化了代码以提高可读性。目标地址已被移除。
function loadAttribution(target) {
const frame = document['c'+'r'+'e'+'a'+'t'+'e'+'E'+'l'+'e'+'m'+'e'+'n'+'t'](
https://blog.cloudflare.com/client-side-security-finds-4-malicious-campaigns/'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'](https://blog.cloudflare.com/client-side-security-finds-4-malicious-campaigns/frame);
}
操作 3:旧搜索破坏者,如今成了店铺后门
多年前,Lnkr 恶意软件家族因隐藏在可疑的浏览器扩展中而登上新闻,它拦截谷歌和必应搜索以重定向结果并赚取广告费。如今,攻击者重新利用了该代码库,将后门植入一家在线零售商的网站。
由于该脚本运行在商店而非搜索引擎上,其旧的重定向伎俩一直处于休眠状态。这一次,该脚本被用来向攻击者发送遥测数据。更危险的是,它给攻击者提供了一个远程门户,可以随时在顾客的浏览器中任意下载并运行新的 JavaScript,而无需触碰服务器上的任何文件。它甚至沿用了扩展程序时代的一个老把戏:如果有人输入“病毒”或“弹窗”之类的词到谷歌,它就会自行关闭。从外部看,商店照常销售,没有任何异常迹象。
商店失去了什么
商店失去了对顾客浏览器中运行何种代码的控制。攻击者秘密追踪访客会话,并拥有一个直接后门,可以随时在店铺前端推送并运行任何他们想要的 JavaScript。
攻击链
HTML 引用的脚本 → 分析人员规避门 → 并行主机门控分支(休眠搜索 vs. 活跃后门) → 任意远程 JavaScript 执行

它如何保持隐藏
与通过标签管理器投放的活动不同,该脚本直接嵌入商家的 HTML 中。我们无法确定确切的初始入侵途径;实际上,直接 HTML 插入通常通过被盗的商店管理员凭据、未经授权的模板编辑,或被感染的第三方主题或插件发生。
在底层,该脚本是一个模块化工具包,同时携带活跃和休眠代码。其较旧的模块(透明点击覆盖层、搜索引擎查询拦截器、扩展商店链接重写器,以及针对仿冒域名的重定向,如 buking[.]com
而非 booking[.]com
)仅在特定目标网站上唤醒,因此在这个店铺前端上一直处于关闭状态。几个嵌入的域名(sugabit[.]net
、votetoda[.]com
、cdnpps[.]us
,以及遥测端点 hanstrackr[.]com
)位于这些被禁用的模块中。
在商店上,活跃分支专注于规避、遥测和远程控制:
对安全研究人员装死。 一个继承自其浏览器扩展时代的规避伎俩:该脚本监控搜索输入和 URL 查询中的广告软件特征词。搜索一个安全关键词会使该次访问中的脚本暂停。搜索两个或更多关键词会向 localStorage
写入一条持久的选择退出记录,永久静默该分析人员机器上的脚本,这样重复测试将一无所获。虽然最初是为了在搜索引擎上躲避分析人员,但据我们所知,此检查是硬编码专门针对谷歌搜索 URL 的,在商家的店铺前端上保持休眠。动态远程代码执行。 该脚本无需修改店铺前端即可改变其行为。虽然硬编码的域名(scrprime[.]com
、youronlinesearches[.]com
、jullyambery[.]net
) 与较早的捕获结果完全相同,这些端点返回什么完全由攻击者决定。该脚本可以回传访客遥测数据、向这些服务器请求新指令,并将新的 JavaScript 直接拉取到购物者的浏览器中。实际上,这为攻击者提供了一个实时后门,可在店铺前端运行任意代码。我们无法确定实际提供了哪些第二阶段载荷。
总而言之,网站的静态快照仅显示正常的店铺前端,而底层的状态检查、反分析陷阱和远程加载分支则暴露了后门。
操作 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
和
)尚未存在于浏览器中。logoalt设备与活动过滤。访问者的视口宽度必须小于477
像素(即手持智能手机)。此外,访问者必须通过首次触达(访问者的初始引荐)活动到达,且该活动带有六种特定 UTM 媒介(Urchin Tracking Module,用于跟踪营销活动的标准 URL 标签)之一:ppc
、cpc
、sms
、paid
、flow
或campaign
。它还必须是其会话中的第一次或第二次页面加载。奇怪的是,虽然代码中包含一个名义上的非 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 地址字符串的嵌入式拒绝列表进行比对。去重后,这些代表 249 个不同的三字节前缀下的 313 个唯一地址。作者没有执行结构化的 CIDR(无类别域间路由)子网匹配,而是简单地从访问者的 IPv4 地址中剥离最后一个字节,并运行原始子串搜索:!denylistString.includes(visitorPrefix)
。
用简化伪代码表示,多层主要激活漏斗如下所示:
// 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 天标记:
与精心设计的主要伪装形成鲜明对比的是,有效载荷还包含次级信标分支(独立例程,静默 ping 外部服务器以确认访问),这些分支完全绕过了视口、主机名、活动、地理位置和 IP 关卡。如果访问者位于第二页或更后,脚本会写入一个持久性 cookie(_cart_dr=1
),其过期时间恰好为 600 天(51,840,000,000 毫秒),并向 maper[.]info
上的远程遥测端点(用于记录浏览器到达此步骤的跟踪信标)发送一个不可见的零像素图像请求。
另一个分支检查备用标记(_logo_alt
),这将触发第二个遥测 .png
信标(此脚本查找但从未自行写入的 cookie;可能由伴随脚本植入)。这为攻击者提供了一个简单、持久的点击计数器,用于记录整个商店所有访问者的基本流量(端点上记录 IP 和 User-Agent),同时将其高风险的广告劫持例程严格隐藏在移动端伪装(高价值付费到达)之后。这表明为什么仅分析一个可见效果并不能揭示多用途有效载荷的全部影响范围。
入侵指标(IOC)
我们发布这些指标以帮助安全团队和研究人员在自己的环境中检测和搜寻这些活动。所有指标均直接来自捕获的有效载荷及其网络连接。列出的 URL 已进行去毒处理。部分指标已被保留或泛化,因为发布它们可能会无意中泄露受影响组织的身份。列出的域名反映了在这些攻击期间观察到的参与投递、重定向或遥测链的基础设施;包含并不表示共享服务或托管提供商完全是恶意的。
---|---|---|
| adtargett[.]com | 脚本投递和联盟重定向仿冒域名 |
| gdataroute[.]com | 在攻击链中观察到的联盟重定向短链接服务 |
| scrprime[.]com | 浏览器劫持脚本投递域名 |
| searchvalidation[.]com | 搜索劫持和流量重定向域名 |
| sugabit[.]net | 强制搜索重定向域名 |
| youronlinesearches[.]com | 条件性远程脚本投递域名 |
| hublosk[.]com | 远程脚本投递域名 |
| jullyambery[.]net | 远程 JavaScript API 与命令域名 |
| votetoda[.]com | 注入载荷投递域名 |
| hanstrackr[.]com | 隐藏访客遥测域名 |
| adrs[.]me | 在攻击链中观察到的域名抢注流量重定向服务 |
| youradexchange[.]com | 在攻击链中观察到的变现重定向服务 |
| cdnpps[.]us | 注入广告框架投递域名 |
| sdk-amazonaws[.]com | 滥用品牌信任的仿冒脚本投递域名 |
| maper[.]info | 条件性访客遥测信标域名 |
给防御者的四条经验教训
综合来看,这些操作讲述了一个不断升级的故事:攻击者改变了目标、投递路径和伪装方式,但浏览器仍然必须执行其逻辑。有四条经验教训尤为突出。
行为胜过特征。 这些操作追求不同形式的变现和操纵,但每个载荷仍然必须在浏览器中行动:观察事件、检查状态、修改页面、安排任务、发起网络请求或加载下一阶段。这正是结构分析所要寻找的:敌对载荷必须携带的逻辑,即便 URL、特征和目标发生变化。
选择性执行是攻击的一部分,而非附注。 设备、时间、地理位置、来源、会话、网络和冷却期等门控条件,都能击败只访问一次并拍摄静态快照的爬虫。持续可见性至关重要,因为攻击可能只对某一个浏览器、在某一种状态下、在某一时刻显现。
混淆提高了分析成本,但在这些案例中并未阻止检测。 自我防御循环、控制台抑制、调试器陷阱、轮换字符串表和死分支使分析变得复杂。尽管存在这些障碍,Page Shield ML 仍然发现了全部四项操作。快速的内部模型可大规模发现可疑代码,而前沿模型则调查最棘手的案例。它们之间的分歧凸显了最棘手的混淆和逻辑,帮助我们缩小关注范围。
上下文让图景完整。 孤立来看显得普通的代码,一旦防御者将静态分析与动态上下文联系起来,就能揭示其恶意角色:它是如何到达的、哪种浏览器状态激活了它、它打开了哪些连接,以及它在运行时实际做了什么。
对客户端执行的持续可见性
这四项操作依赖于不同层面的误导,但它们都有一个共同的约束:其 JavaScript 必须在浏览器中执行。公共扫描器和静态爬取可能会遗漏受门控的行为。持续观察有助于厘清当真实访客与页面交互时代码实际做了什么
Cloudflare 客户端安全在所有套餐中提供这种可见性。你可以在安全设置下开启持续脚本监控,以跟踪店面中的第一方和第三方脚本,而自动化恶意脚本检测和警报可通过以下方式获得
客户端安全高级版。
Cloudflare 仪表板
