Loading...
很有可能你是通过网页浏览器阅读这篇博文的。你也许会发现你的浏览器中装有多种扩展功能,这些扩展能提供额外的功能。我们通常相信从官方浏览器商店安装的扩展是安全的,但这并不总是如此,正如我们最近发现的情况一样。
这篇博文将带来有关 CacheFlow 的更多技术细节:这是一个我们在 2020 年 12 月首次报导的威胁。我们描述了一个由数十个恶意 Chrome 和 Edge 浏览器扩展组成的大规模攻击活动,总安装量超过三百万。我们已经将这些恶意扩展的存在通知了 Google 和 Microsoft,并很高兴地宣布,两家公司已于 2020 年 12 月 18 日将它们全部下架。
CacheFlow 特别值得注意的是,这些恶意扩展会试图在隐秘通道中隐藏其命令和控制流量,使用的是其分析请求中的 CacheControl HTTP 标头。我们认为这是一种新技术。此外,我们认为 Google Analytics 风格的流量的添加不仅仅是为了隐藏恶意命令,扩展的开发者似乎也对分析请求本身感兴趣。我们认为他们试图用一个解决方案来解决两个问题:命令和控制以及获取分析信息。
我们发现 CacheFlow 的攻击按以下顺序进行:
CacheFlow 恶意软体的高级概览
根据我们的数据,Avast 用户下载并安装 CacheFlow 扩展的前几个国家分别是巴西、乌克兰和法国。
安装了其中一个恶意扩展的 Avast 用户的分布
我们最初是在阅读由 CZNIC 的 Edvard Rejthar 撰写的一篇捷克语博文时了解到这场攻击活动的。他发现 Chrome 扩展 “Video Downloader for FaceBook” (ID pfnmibjifkhhblmdmaocfohebdpfppkf) 正在偷偷加载一个与扩展广告功能无关的混淆 JavaScript。根据他的发现,我们发现许多其他扩展也在做同样的事情。这些其他扩展提供了多种合法功能,其中许多是针对热门社交媒体平台的视频下载工具。在对混淆的 JavaScript 进行逆向工程后,我们发现这些扩展发布的主要恶意负载负责进行恶意浏览器重定向。不仅如此,网络罪犯还收集了有关这些恶意扩展用户的大量数据,例如他们的所有搜索引擎查询以及有关他们点击的所有信息。
这些扩展展现了相当高的隐秘性,使用了许多技巧来降低被检测的机会。首先,他们避免感染可能是网页开发者的用户。他们通过检查用户已安装的扩展或查看用户是否访问本地托管网站来判断此点。此外,这些扩展在安装后至少延迟三天才启动恶意活动,以避免早期引发警报。当恶意软件检测到浏览器开发者工具被打开时,它会立即停用其恶意功能。CacheFlow 还检查每一个 Google 搜索查询,若用户搜索了某个恶意软件的命令和控制(CampC)域名,它便会将此信息报告给其 CampC 服务器并可能会自我停用。
根据 Chrome 网上应用店的用户评价,CacheFlow 的活动似乎从 2017 年 10 月起至少已经开始。上述所有隐秘性可以解释为何它能够这么长时间未被检测到。
2017年10月的 Chrome 网上应用商店用户评价提到修改 Google 搜索结果
首先,我们将展示这些扩展用来下载和执行任意 JavaScript 的隐藏后门。我们具体描述来自 Chrome 扩展 “Downloader for Instagram” v573 (ID olkpikmlhoaojbbmmpejnimiglejmboe) 的后门,但此分析同样适用于其他扩展,因为它们隐藏的恶意代码在功能上非常相似。
“Downloader for Instagram” 在 Chrome 网上应用商店的页面
通常,分析未知的 Chrome 扩展是从 manifestjson 文件开始的。“Downloader for Instagram” 的 manifest 文件提供了一些有趣的讯息。
首先,contentsecuritypolicy 定义的方式使得可以使用臭名昭著的 “eval” 函数来加载附加的 JavaScript。然而,在扩展的源代码中寻找字符串 eval 并没有得到任何有趣的结果。正如我们稍后会展示的,该扩展确实经常使用 eval 函数,但它隐藏了其用法,所以一开始并不明显。
manifestjson 文件中的内容安全策略定义
其次,该扩展请求了许多权限,并且不立即清楚这些权限为何需要来下载 Instagram 的视频。特别有趣的是 management 权限,这使得扩展可以控制其他扩展。 webRequest 和 ltallurlsgt 权限的结合也很有趣。这两个权限使得扩展能够拦截几乎任何来自浏览器的网路请求。
恶意扩展请求的权限
最后,清单定义了两个背景脚本:js/jqueryjs 和 js/backgroundjs。这些脚本是持久性的,这意味著它们会持续运行,直到扩展被禁用。
在 manifestjson 文件中声明的背景脚本
其中一个背景脚本 backgroundjs 使用了可疑的 webRequest API。该脚本访问所有拦截到的网络请求的 HTTP 响应标头并将其值存储于 localStorage 中。
CacheFlow 将所有足够长的 HTTP 响应标头的值保存到 localStorage 中。
localStorage 的内容然后被另一个持久性恶意背景脚本 jqueryjs 读取。虽然这个脚本表面上看起来是合法的 jQuery 库,但其中插入了一些额外的函数。这些额外函数之一被误导性地命名为 parseRelative,但它的实际作用只是返回 windowlocalStorage 对象。
隐藏在 jqueryjs 中的误导性命名的 parseRelative 函数
另一个插入的并且误导性命名的函数是 initAjax。
initAjax 函数解码 localStorage[cachecontrol] 的内容并将解码后的值存储在 window 对象中。
这个函数特别关注 localStorage[cachecontrol] 的内容,这个值此时应被设置为最近收到的 CacheControl HTTP 响应标头的值。该函数用逗号分隔此标头的内容并尝试使用名为 strrevsstr 的自定义函数解密每个部分,并最终将其解析为 JSON 字符串。
strrevsstr函数用于解密字符串的扩展
明显的问题是,为何扩展会期望拦截包含加密 JSON 字符串的 CacheControl 响应标头?
答案是危害行为者利用 CacheControl 标头的内容作为隐秘通道,向恶意扩展发送隐藏命令。
作为恶意扩展定期功能的一部分,有关某些事件的分析请求会发送到 https//statsscriptprotection[]com/utmgif。这些是标准分析请求,类似于 Google Analytics。问题是,该扩展使用的服务器可能会对分析请求作出以特别格式构建的 CacheControl 响应,客户端将解码、解析并执行这些响应。
隐秘通道的流程
为了查看命令可能是什么样子,我们模拟了扩展并向 https//statsscriptprotection[]com/utmgif 发送了一个假的分析 HTTP 请求。经过几次尝试后,我们收到了特别制作的 CacheControl 响应标头。
使用 Fiddler 捕获的看似无害的分析请求,其中包含 CacheControl 响应标头中的隐藏命令
注意,响应将仅在满足某些条件的情况下包含已编码的命令。首先,GET 参数 it 必须设置为至少三天前的时间。因为这个参数包含了扩展的安装时间,这有效确保了扩展在前三天内不会表现出任何恶意行为。此外,还有基于 IP 地址的检查,由于我们重复地未从同一个源 IP 地址收到任何命令,即使我们从另一个 IP 地址收到了相同 GET 请求的命令。由于这些检查的逻辑安全隐藏在 CampC 服务器上,因此可能还有我们未了解的附加检查。
当收到的 CacheControl 标头的内容使用上述自定义 strrevsstr 函数进行解码后,我们得到以下 JSON 格式的命令。如前所述,在 initAjax 函数中,这些 JSON 中的所有属性都被存储在全局 window 对象中。
从 CacheControl 响应标头中解码的命令
火烧云梯子下载收到这样的命令后,扩展会在名为 siblingAfter 的函数中从 command[uu] 下载第二阶段的内容,该函数同样隐藏在 jqueryjs 中。这里的 command[jj] 中的美元符号代表 jQuery 对象,因此该函数使用 jQueryget 函数从 command[uu] 下载下一阶段,并将其存储在 localStoragedataDefault 中。
从 command[uu] 指定的 URL 下载下一阶段的代码片段
最后, jqueryjs 中还隐藏了另一个函数,该函数使用 command[ee] 的 eval 函数执行下载的 JavaScript。
使用 eval 函数执行下载的 JavaScript 的代码片段
下载的 JavaScript 是一个混淆过的中介下载器。其目的是通过 XHR 请求从 ulkonjohnoil[]com 下载第三阶段的负载。不幸的是,由于服务器只会在满足某些条件时发送下一阶段,因此获得包含第三阶段的响应可能非常棘手。如果成功下载,该内容将被加密并持久存储在 localStorage 中。然后它会在每次更新选项卡时使用 chrometabsonUpdated 监听器执行。
中介下载器作为恶意软体的第二阶段。
这个负载首先测试它是否可以使用 eval 和 localStorage。如果其中任何一个无法正常工作,CacheFlow 将无法执行大多数恶意功能。
去混淆的负载片段测试 eval 函数是否运行的代码,通过相加两个随机数字
此外,该负载定期检查开发者工具是否已打开。如果已打开,它会停用自己,以避免被检测。检查开发者工具之时也会在当前窗口调整大小时进行,这可能是因为用户刚刚打开了开发者工具。
去混淆的代码片段,检查开发者工具是否已开启
如前所述,恶意软件的作者竭尽所能确保隐藏的恶意负载不被发现。我们认为他们对之前的检查感到不满,于是决定进一步分析受害者,以避免感染显得更具技术能力的用户。其中一种方法是枚举受害者安装的其他扩展并将其与一个硬编码的扩展ID列表进行比较。列表中的每个扩展都被分配了一个分数,如果安装扩展的总分超过某个阈值,则扩展的列表将发送至 CampC 服务器,然后可能命令恶意负载停用。该列表上的扩展示例包括“Chrome 扩展源查看器”以及“Link Redirect Trace”或“JWT Debugger”。我们认为这种“加权”系统帮助更好地区分真实的开发系统这些系统可能会有多个扩展且得分较高和休闲用户这些用户可能只有较少的扩展,因而得分较低。
去混淆的代码片段枚举受害者已安装的其他扩展
另一种分析潜在受害者的方法是检查他们正在浏览的 URL。每当受害者导航到由某个私有 IPv4 范围内 IP 地址识别的 URL 或者访问 TLD 为 dev、local 或 localhost 的 URL 时,恶意软件会将访问的 URL 发送到其 CampC 服务器。该恶意软件还检查了所有 Google仅限 Google查询是否符合匹配其 CampC 域名和内部标识的正则表达式。这样,它便可以知道是否有人正在深入查看该扩展,并可进行行动以隐藏自己。有趣的是,正则表达式中并未完全指定域名,某些字符用特殊字符代表。我们推测这是企图使基于正则表达式创建域名黑名单变得更加困难。
检查受害者的 Google 查询是否匹配恶意软体 CampC 域名的正则表达式
此时,该恶意软件还试图收集有关受害者的信息。这些信息包括出生日期、电子邮件地址、地理位置和设备活动。例如,出生日期是从受害者的 Google 账户中输入的个人信息中检索的。再次强调,攻击者仅关注 Google:我们并未看到有关 Microsoft 账户信息的类似尝试。要获取出生日期,CacheFlow 将 XHR 请求发送到 https//myaccountgooglecom/birthday 并从响应中解析出出生日期。
去混淆的代码片段,该恶意软件试图获取受害者的出生日期
请注意,虽然这似乎是进行如此跨域请求不会被浏览器允许的,但在扩展的安全模型下,这一切都是完全可行的,因为扩展拥有 ltallurlsgt 权限。这个权限使扩展可以访问所有主机,因此可以进行任意的跨站请求。
为了使 Google 更难意识到 CacheFlow 正在滥用其服务来收集个人信息,它还注册了一个特殊的 chromewebRequestonBeforeSendHeaders 监听器。这个监听器会在所有相关 XHR 请求中删除 referer 请求标头,因此 Google 不易知晓实际上是谁在发送请求。
去混淆的代码片段,该恶意软件从用于 Google 的请求中删除 referer
最后,为了执行其主要的恶意功能,该负载使用 chrometabsexecuteScript 将另一段 JavaScript 注入每个选项卡中。
注入的脚本实现了两个功能。第一个功能是劫持点击事件。当受害者点击链接时,扩展会将有关点击的信息发送到 orgunjohnoil[]com,并可能收到命令以将受害者重定向到另一个 URL。第二个功能关于搜索引擎结果。当受害者在搜索引擎页面中时,扩展会收集搜索查询和结果。这些信息随后被发送到 CampC 服务器,该服务器可能返回命令以重定向一些搜索结果。
链接劫持是通过在整个 document 上注册 onclick 监听器来实现的。
去混淆的代码片段,显示注册 onclick 监听器
该监听器只对主按钮事件通常是“左键单击”和对具有 a 或 area 标签名的元素的点击感兴趣。如果点击满足所有条件,则会向 https//orgunjohnoil[]com/link/ 发送 XHR 请求。该请求包含一个 GET 参数 a,其中包含有关点击的拼接信息,并使用自定义的 strsstr 函数进行加密。这些信息包括当前位置、目标 URL、各种标识符等。
我们模拟了一个虚假的链接点击请求,目标为 https//facebook[]com,并收到了以下响应:
ayiudvh3jk6lNjkzMTQ0eAgYGAQRFhNYTVxbE04IBlFDFgEEHBtYQV0HThdXEwJRBANSUVBEDghQCgNOWUMXAhskaiohB3Z4YQlvSU8oaygLZkhBYCJlAW9Rf18Ecyg1TmZdFEQZABACXHxaInY0MklVQlUeTAozcyUSOwABdW9oAXUXGjswNQpgTkkzZSZFMxMJanwqQj1NDixsflIuWAl6kj3hvduiya
收到这样的响应后,恶意软件首先确保其以某个随机生成的字符串开头,并以相同的字符串反转结尾。这个字符串在示例中突出显示为 ayiudvh3jk6l是由扩展生成的并且也包含在 XHR 请求中参数 a 中。然后,扩展提取响应中间部分并使用 strrevsstr 函数解密。这将产生以下字符串:
ayiudvh3jk6lhttps//golnkam[]com/link/ru=https3A2F2Fwwwfacebook[]com2Fampcampaignid=b7YMMAqMdAL7wyzNe5m3wzampsource=uvm3rdsqc9zo69l6kj3hvduiya
再一次,恶意软件检查解密字符串的开头和结尾是否含有相同的随机生成字符串,然后提取其中的部分。如果以子字符串 http 开头,则恶意软件继续执行链接劫持。它通过临时改变用户点击的元素的 href 属性并对其执行 click 方法来模拟鼠标点击。作为一种后备机制,恶意软件只需将 windowlocation[href] 设置为链接劫持 URL。
去混淆的代码片段显示恶意软件如何劫持受害者的点击事件
第二个功能仅在受害者目前位于 Google、Bing 或 Yahoo 的搜索页面时执行。如果他们在这些页面上,恶意软件首先会收集搜索查询字符串和结果。根据搜索引擎的不同,获取搜索查询字符串的方式有所不同。对于 Google,搜索查询字符串作为第一个命名为 q 的元素的值找到。如果这个过程以某种方式失败,恶意软件还会尝试通过 q GET 参数来获取搜索查询。
去混淆的代码片段显示恶意软件如何获取搜索查询
Google 的搜索结果是通过搜寻 rc 类名的元素并遍历它们的子 a 元素来获取的。
去混淆的代码片段显示恶意软件如何获取搜索结果
一旦收集到搜索查询和结果,这些信息会通过 XHR 请求发送到 servscrpt[]de。该请求中还包含结果的加盐 MD5 校验和,这被认为是为了检测虚假请求但此检查显然可以通过重新计算 MD5 校验和轻易绕过。XHR 响应包含一个域名列表,恶意软件应该劫持这些域名的链接。劫持本身是通过在 a 元素上注册 onmousedown 监听器来实现的。当被触发时,该监听器在事件上调用 preventDefault 函数,然后使用 windowopen 将用户重定向到恶意 URL。
有趣的是,CacheFlow 还通过为某些劫持的搜索结果添加可点击的标志来修改。这被认为是为了使这些搜索结果更引人注意,从而增加受害者点击的机会。然而,标志的位置并没有很好地对齐,这使得搜索结果看起来很奇怪和可疑,因为 Google、Microsoft 或 Yahoo 可能会在格式方面投入更多的精力。
原始 Google 搜索结果上与被恶意软件修改的结果下的对比
标志是通过创建一个全新的 div 元素来添加的,该元素包含一个 img 元素。创建和格式化好这个元素后,将其插入到 DOM 中,以便它出现在原始搜索结果的左侧。标志是来自 serviceimg[]de 领域,该域为每个域名提供独特的 9045 标识。
去混淆的代码片段,展示恶意软件如何创建带有添加标志的元素
在这篇博文中,我们提供了有关 CacheFlow 的技术细节:这是一个庞大的恶意浏览器扩展网路,感染了全球数百万用户。我们描述了这些恶意扩展如何劫持受害者的点击事件并修改搜索引擎结果。由于 CacheFlow 能够有效隐藏自己,我们详细介绍了其用于隐藏事实上正在执行的恶意代码的技术。我们相信,了解这些技术的工作原理将有助于其他恶意软体研究人员在未来发现和分析类似的威胁。
完整的 IoC 列表可在 https//githubcom/avast/ioc/tree/master/CacheFlow 获得。
名称 哈希manifestjson 2bc86c14609928183bf3d94e1b6f082a07e6ce0e80b1dffc48d3356b6942c051backgroundjs bdd2ec1f2e5cc0ba3980f7f96cba5bf795a6e012120db9cab0d8981af3fa7f20jqueryjs 3dad00763b7f97c27d481242bafa510a89fed19ba60c9487a65fa4e86dcf970d中介下载器 4e236104f6e155cfe65179e7646bdb825078a9fea39463498c5b8cd99d409e7a有效载荷 ebf6ca39894fc7d0e634bd6747131efbbd0d736e65e68dcc940e3294d3c93df4注入的脚本 0f99ec8031d482d3cefa979fbd61416558e03a5079f43c2d31aaf4ea20ce28a0Chrome 扩展名称 扩展 IDInstagram 的直接消息 mdpgppkombninhkfhaggckdmencplhmgInstagram 的 DM fgaapohcdolaiaijobecfleiohcfhdfbInstagram 直接消息的隐身模式 iibnodnghffmdcebaglfgnfkgemcbchfInstagram 的下载器 olkpikmlhoaojbbmmpejnimiglejmboeInstagram 的应用电话 bhfoemlllidnfefgkeaeocnageepbaelInstagram 的故事 nilbfjdbacfdodpbdondbbkmoigehodg通用视频下载器 eikbfklcjampfnmclhjeifbmfkpkfpbnVideo Downloader for FaceBook pfnmibjifkhhblmdmaocfohebdpfppkfVimeo 视频下载器 cgpbghdbejagejmciefmekcklikpoeelZoomer for Instagram and FaceBook klejifgmmnkgejbhgmpgajemhlnijlibVK UnBlock Works fast ceoldlgkhdbnnmojajjgfapagjccblibOdnoklassniki UnBlock Works quickly mnafnfdagggclnaggnjajohakfbppaihSpotify 音乐下载器 pcaaejaejpolbbchlmbdjfiggojefllpThe New York Times News lmcajpniijhhhpcnhleibgiehhicjlnkFORBES lgjogljbnbfjcaigalbhiagkboajmkkj Instagram akdbogfpgohikflhccclloneidjkogogEdge 扩展名称 扩展 IDInstagram 的直接消息 lnocaphbapmclliacmbbgggnfnjojbjgfInstagram 下载视频和图片 bhcpgfhiobcpokfpdahijhnipenkpljiInstagram 的应用电话 dambkkeeabmnhelekdekfmabnckghdih通用视频下载器 dgjmdlifhbljhmgkjbojeejmeeplapejVideo Downloader for FaceBook emechknidkghbpiodihlodkhnljplpjmVimeo 视频下载器 hajlccgbgjdcjaommiffaphjdndpjcio音量控制器 dljdbmkffjijepjnkonndbdiakjfdcicInstagram 的故事 cjmpdadldchjmljhkigoeejegmghaabpInstagram 的上传照片 jlkfgpiicpnlbmmmpkpdjkkdolgomhmbPretty Kitty The Cat Pet njdkgjbjmdceaibhngelkkloceihelleYouTube 的视频下载器 phoehhafolaebdpimmbmlofmeibdkckpSoundCloud 音乐下载器 pccfaccnfkjmdlkollpiaialndbieibj具有直接消息 DM 的 Instagram 应用 fbhbpnjkpcdmcgcpfilooccjgemlkinnDownloader for Instagram aemaecahdckfllfldhgimjhdgiaaheanURL
abuseextensions[]comampliacion[]xyzaxfreeservice[]combxfreeservice[]comcxfreeservice[]combrowserstat[]comcheckstat[]comcheck4scamprotection[]netconnectingtothe[]netcornewus[]comdownloaderig[]comexstats[]comextfeedback[]comextstatistics[]comfiguresanalysis[]comhuffilymydiaconal[]comjastats[]comjokopinter[]comlimbourg[]commydiaconal[]comnotificationstat[]comorgunjohnoil[]comoutstolemysins[]competaline[]comrootsiz[]coms3amazonaws[]com/directcdn/j6dle93f17c30jss3amazonaws[]com/wwwjs/ga9anf7c53390jss3amazonaws[]com/wwwjs/hc8e0ccd7266cjss3amazonaws[]com/protectscript/instagramdownloaderjssafenewtab[]comscriptprotection[]comserverstatus[]xyzserviceimg[]deservscrpt[]destatsscriptprotection[]comstatslight[]comulkonjohnoil[]com